File indexing completed on 2024-05-19 16:34:46

0001 /*
0002     SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "scene/itemrenderer_qpainter.h"
0008 #include "platformsupport/scenes/qpainter/qpaintersurfacetexture.h"
0009 #include "scene/imageitem.h"
0010 #include "scene/workspacescene_qpainter.h"
0011 
0012 #include <QPainter>
0013 
0014 namespace KWin
0015 {
0016 
0017 ItemRendererQPainter::ItemRendererQPainter()
0018     : m_painter(std::make_unique<QPainter>())
0019 {
0020 }
0021 
0022 ItemRendererQPainter::~ItemRendererQPainter()
0023 {
0024 }
0025 
0026 ImageItem *ItemRendererQPainter::createImageItem(Scene *scene, Item *parent)
0027 {
0028     return new ImageItem(scene, parent);
0029 }
0030 
0031 QPainter *ItemRendererQPainter::painter() const
0032 {
0033     return m_painter.get();
0034 }
0035 
0036 void ItemRendererQPainter::beginFrame(RenderTarget *renderTarget)
0037 {
0038     QImage *buffer = std::get<QImage *>(renderTarget->nativeHandle());
0039     m_painter->begin(buffer);
0040     m_painter->setWindow(renderTargetRect());
0041 }
0042 
0043 void ItemRendererQPainter::endFrame()
0044 {
0045     m_painter->end();
0046 }
0047 
0048 void ItemRendererQPainter::renderBackground(const QRegion &region)
0049 {
0050     m_painter->setCompositionMode(QPainter::CompositionMode_Source);
0051     for (const QRect &rect : region) {
0052         m_painter->fillRect(rect, Qt::transparent);
0053     }
0054     m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
0055 }
0056 
0057 void ItemRendererQPainter::renderItem(Item *item, int mask, const QRegion &_region, const WindowPaintData &data)
0058 {
0059     QRegion region = _region;
0060 
0061     const QRect boundingRect = item->mapToGlobal(item->boundingRect()).toAlignedRect();
0062     if (!(mask & (Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_SCREEN_TRANSFORMED))) {
0063         region &= boundingRect;
0064     }
0065 
0066     if (region.isEmpty()) {
0067         return;
0068     }
0069 
0070     m_painter->save();
0071     m_painter->setClipRegion(region);
0072     m_painter->setClipping(true);
0073     m_painter->setOpacity(data.opacity());
0074 
0075     if (mask & Scene::PAINT_WINDOW_TRANSFORMED) {
0076         m_painter->translate(data.xTranslation(), data.yTranslation());
0077         m_painter->scale(data.xScale(), data.yScale());
0078     }
0079 
0080     renderItem(m_painter.get(), item);
0081 
0082     m_painter->restore();
0083 }
0084 
0085 void ItemRendererQPainter::renderItem(QPainter *painter, Item *item) const
0086 {
0087     const QList<Item *> sortedChildItems = item->sortedChildItems();
0088 
0089     painter->save();
0090     painter->translate(item->position());
0091     painter->setOpacity(painter->opacity() * item->opacity());
0092 
0093     for (Item *childItem : sortedChildItems) {
0094         if (childItem->z() >= 0) {
0095             break;
0096         }
0097         if (childItem->explicitVisible()) {
0098             renderItem(painter, childItem);
0099         }
0100     }
0101 
0102     item->preprocess();
0103     if (auto surfaceItem = qobject_cast<SurfaceItem *>(item)) {
0104         renderSurfaceItem(painter, surfaceItem);
0105     } else if (auto decorationItem = qobject_cast<DecorationItem *>(item)) {
0106         renderDecorationItem(painter, decorationItem);
0107     } else if (auto imageItem = qobject_cast<ImageItem *>(item)) {
0108         renderImageItem(painter, imageItem);
0109     }
0110 
0111     for (Item *childItem : sortedChildItems) {
0112         if (childItem->z() < 0) {
0113             continue;
0114         }
0115         if (childItem->explicitVisible()) {
0116             renderItem(painter, childItem);
0117         }
0118     }
0119 
0120     painter->restore();
0121 }
0122 
0123 void ItemRendererQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceItem) const
0124 {
0125     const SurfacePixmap *surfaceTexture = surfaceItem->pixmap();
0126     if (!surfaceTexture || !surfaceTexture->isValid()) {
0127         return;
0128     }
0129 
0130     QPainterSurfaceTexture *platformSurfaceTexture =
0131         static_cast<QPainterSurfaceTexture *>(surfaceTexture->texture());
0132     if (!platformSurfaceTexture->isValid()) {
0133         platformSurfaceTexture->create();
0134     } else {
0135         platformSurfaceTexture->update(surfaceItem->damage());
0136     }
0137     surfaceItem->resetDamage();
0138 
0139     const QVector<QRectF> shape = surfaceItem->shape();
0140     for (const QRectF rect : shape) {
0141         const QMatrix4x4 matrix = surfaceItem->surfaceToBufferMatrix();
0142         const QPointF bufferTopLeft = matrix.map(rect.topLeft());
0143         const QPointF bufferBottomRight = matrix.map(rect.bottomRight());
0144 
0145         painter->drawImage(rect, platformSurfaceTexture->image(),
0146                            QRectF(bufferTopLeft, bufferBottomRight));
0147     }
0148 }
0149 
0150 void ItemRendererQPainter::renderDecorationItem(QPainter *painter, DecorationItem *decorationItem) const
0151 {
0152     const auto renderer = static_cast<const SceneQPainterDecorationRenderer *>(decorationItem->renderer());
0153     QRectF dtr, dlr, drr, dbr;
0154     decorationItem->window()->layoutDecorationRects(dlr, dtr, drr, dbr);
0155 
0156     painter->drawImage(dtr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Top));
0157     painter->drawImage(dlr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Left));
0158     painter->drawImage(drr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Right));
0159     painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom));
0160 }
0161 
0162 void ItemRendererQPainter::renderImageItem(QPainter *painter, ImageItem *imageItem) const
0163 {
0164     painter->drawImage(imageItem->rect(), imageItem->image());
0165 }
0166 
0167 } // namespace KWin