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 ®ion) 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