File indexing completed on 2024-11-10 04:57:15

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 "core/renderviewport.h"
0009 #include "effect/effect.h"
0010 #include "platformsupport/scenes/qpainter/qpaintersurfacetexture.h"
0011 #include "scene/imageitem.h"
0012 #include "scene/workspacescene_qpainter.h"
0013 #include "window.h"
0014 
0015 #include <QPainter>
0016 
0017 namespace KWin
0018 {
0019 
0020 ItemRendererQPainter::ItemRendererQPainter()
0021     : m_painter(std::make_unique<QPainter>())
0022 {
0023 }
0024 
0025 ItemRendererQPainter::~ItemRendererQPainter()
0026 {
0027 }
0028 
0029 std::unique_ptr<ImageItem> ItemRendererQPainter::createImageItem(Scene *scene, Item *parent)
0030 {
0031     return std::make_unique<ImageItem>(scene, parent);
0032 }
0033 
0034 QPainter *ItemRendererQPainter::painter() const
0035 {
0036     return m_painter.get();
0037 }
0038 
0039 void ItemRendererQPainter::beginFrame(const RenderTarget &renderTarget, const RenderViewport &viewport)
0040 {
0041     QImage *buffer = renderTarget.image();
0042     m_painter->begin(buffer);
0043     m_painter->setWindow(viewport.renderRect().toRect());
0044 }
0045 
0046 void ItemRendererQPainter::endFrame()
0047 {
0048     m_painter->end();
0049 }
0050 
0051 void ItemRendererQPainter::renderBackground(const RenderTarget &renderTarget, const RenderViewport &viewport, const QRegion &region)
0052 {
0053     m_painter->setCompositionMode(QPainter::CompositionMode_Source);
0054     for (const QRect &rect : region) {
0055         m_painter->fillRect(rect, Qt::transparent);
0056     }
0057     m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
0058 }
0059 
0060 void ItemRendererQPainter::renderItem(const RenderTarget &renderTarget, const RenderViewport &viewport, Item *item, int mask, const QRegion &_region, const WindowPaintData &data)
0061 {
0062     QRegion region = _region;
0063 
0064     const QRect boundingRect = item->mapToGlobal(item->boundingRect()).toAlignedRect();
0065     if (!(mask & (Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_SCREEN_TRANSFORMED))) {
0066         region &= boundingRect;
0067     }
0068 
0069     if (region.isEmpty()) {
0070         return;
0071     }
0072 
0073     m_painter->save();
0074     m_painter->setClipRegion(region);
0075     m_painter->setClipping(true);
0076     m_painter->setOpacity(data.opacity());
0077 
0078     if (mask & Scene::PAINT_WINDOW_TRANSFORMED) {
0079         m_painter->translate(data.xTranslation(), data.yTranslation());
0080         m_painter->scale(data.xScale(), data.yScale());
0081     }
0082 
0083     renderItem(m_painter.get(), item);
0084 
0085     m_painter->restore();
0086 }
0087 
0088 void ItemRendererQPainter::renderItem(QPainter *painter, Item *item) const
0089 {
0090     const QList<Item *> sortedChildItems = item->sortedChildItems();
0091 
0092     painter->save();
0093     painter->translate(item->position());
0094     painter->setOpacity(painter->opacity() * item->opacity());
0095 
0096     for (Item *childItem : sortedChildItems) {
0097         if (childItem->z() >= 0) {
0098             break;
0099         }
0100         if (childItem->explicitVisible()) {
0101             renderItem(painter, childItem);
0102         }
0103     }
0104 
0105     item->preprocess();
0106     if (auto surfaceItem = qobject_cast<SurfaceItem *>(item)) {
0107         renderSurfaceItem(painter, surfaceItem);
0108     } else if (auto decorationItem = qobject_cast<DecorationItem *>(item)) {
0109         renderDecorationItem(painter, decorationItem);
0110     } else if (auto imageItem = qobject_cast<ImageItem *>(item)) {
0111         renderImageItem(painter, imageItem);
0112     }
0113 
0114     for (Item *childItem : sortedChildItems) {
0115         if (childItem->z() < 0) {
0116             continue;
0117         }
0118         if (childItem->explicitVisible()) {
0119             renderItem(painter, childItem);
0120         }
0121     }
0122 
0123     painter->restore();
0124 }
0125 
0126 void ItemRendererQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceItem) const
0127 {
0128     const SurfacePixmap *surfaceTexture = surfaceItem->pixmap();
0129     if (!surfaceTexture || !surfaceTexture->isValid()) {
0130         return;
0131     }
0132 
0133     QPainterSurfaceTexture *platformSurfaceTexture =
0134         static_cast<QPainterSurfaceTexture *>(surfaceTexture->texture());
0135     if (!platformSurfaceTexture->isValid()) {
0136         platformSurfaceTexture->create();
0137     } else {
0138         platformSurfaceTexture->update(surfaceItem->damage());
0139     }
0140     surfaceItem->resetDamage();
0141 
0142     const OutputTransform surfaceToBufferTransform = surfaceItem->bufferTransform();
0143     const QSizeF transformedSize = surfaceToBufferTransform.map(surfaceItem->destinationSize());
0144 
0145     painter->save();
0146     switch (surfaceToBufferTransform.kind()) {
0147     case OutputTransform::Normal:
0148         break;
0149     case OutputTransform::Rotate90:
0150         painter->translate(transformedSize.height(), 0);
0151         painter->rotate(90);
0152         break;
0153     case OutputTransform::Rotate180:
0154         painter->translate(transformedSize.width(), transformedSize.height());
0155         painter->rotate(180);
0156         break;
0157     case OutputTransform::Rotate270:
0158         painter->translate(0, transformedSize.width());
0159         painter->rotate(270);
0160         break;
0161     case OutputTransform::FlipX:
0162         painter->translate(transformedSize.width(), 0);
0163         painter->scale(-1, 1);
0164         break;
0165     case OutputTransform::FlipX90:
0166         painter->scale(-1, 1);
0167         painter->rotate(90);
0168         break;
0169     case OutputTransform::FlipX180:
0170         painter->translate(0, transformedSize.height());
0171         painter->scale(-1, 1);
0172         painter->rotate(180);
0173         break;
0174     case OutputTransform::FlipX270:
0175         painter->translate(transformedSize.height(), transformedSize.width());
0176         painter->scale(-1, 1);
0177         painter->rotate(270);
0178         break;
0179     }
0180 
0181     const QRectF sourceBox = surfaceItem->bufferSourceBox();
0182     const qreal xSourceBoxScale = sourceBox.width() / transformedSize.width();
0183     const qreal ySourceBoxScale = sourceBox.height() / transformedSize.height();
0184 
0185     const QList<QRectF> shape = surfaceItem->shape();
0186     for (const QRectF rect : shape) {
0187         const QRectF target = surfaceToBufferTransform.map(rect, surfaceItem->size());
0188         const QRectF source(sourceBox.x() + target.x() * xSourceBoxScale,
0189                             sourceBox.y() + target.y() * ySourceBoxScale,
0190                             target.width() * xSourceBoxScale,
0191                             target.height() * ySourceBoxScale);
0192 
0193         painter->drawImage(target, platformSurfaceTexture->image(), source);
0194     }
0195 
0196     painter->restore();
0197 }
0198 
0199 void ItemRendererQPainter::renderDecorationItem(QPainter *painter, DecorationItem *decorationItem) const
0200 {
0201     const auto renderer = static_cast<const SceneQPainterDecorationRenderer *>(decorationItem->renderer());
0202     QRectF dtr, dlr, drr, dbr;
0203     decorationItem->window()->layoutDecorationRects(dlr, dtr, drr, dbr);
0204 
0205     painter->drawImage(dtr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Top));
0206     painter->drawImage(dlr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Left));
0207     painter->drawImage(drr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Right));
0208     painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom));
0209 }
0210 
0211 void ItemRendererQPainter::renderImageItem(QPainter *painter, ImageItem *imageItem) const
0212 {
0213     painter->drawImage(imageItem->rect(), imageItem->image());
0214 }
0215 
0216 } // namespace KWin