File indexing completed on 2024-05-12 05:31:23

0001 /*
0002     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "renderlayer.h"
0008 #include "outputlayer.h"
0009 #include "renderlayerdelegate.h"
0010 #include "renderloop.h"
0011 
0012 namespace KWin
0013 {
0014 
0015 RenderLayer::RenderLayer(RenderLoop *loop, RenderLayer *superlayer)
0016     : m_loop(loop)
0017 {
0018     setSuperlayer(superlayer);
0019 }
0020 
0021 RenderLayer::~RenderLayer()
0022 {
0023     const auto sublayers = m_sublayers;
0024     for (RenderLayer *sublayer : sublayers) {
0025         sublayer->setSuperlayer(superlayer());
0026     }
0027     setSuperlayer(nullptr);
0028 }
0029 
0030 OutputLayer *RenderLayer::outputLayer() const
0031 {
0032     return m_outputLayer;
0033 }
0034 
0035 void RenderLayer::setOutputLayer(OutputLayer *layer)
0036 {
0037     if (m_outputLayer == layer) {
0038         return;
0039     }
0040     if (m_outputLayer) {
0041         m_outputLayer->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
0042     }
0043     m_outputLayer = layer;
0044     for (RenderLayer *sublayer : std::as_const(m_sublayers)) {
0045         sublayer->setOutputLayer(layer);
0046     }
0047 }
0048 
0049 RenderLayer *RenderLayer::superlayer() const
0050 {
0051     return m_superlayer;
0052 }
0053 
0054 void RenderLayer::setSuperlayer(RenderLayer *layer)
0055 {
0056     if (m_superlayer == layer) {
0057         return;
0058     }
0059     if (m_superlayer) {
0060         m_superlayer->removeSublayer(this);
0061     }
0062     m_superlayer = layer;
0063     if (m_superlayer) {
0064         m_superlayer->addSublayer(this);
0065     }
0066     updateEffectiveVisibility();
0067 }
0068 
0069 QList<RenderLayer *> RenderLayer::sublayers() const
0070 {
0071     return m_sublayers;
0072 }
0073 
0074 void RenderLayer::addSublayer(RenderLayer *sublayer)
0075 {
0076     m_sublayers.append(sublayer);
0077     sublayer->setOutputLayer(m_outputLayer);
0078     updateBoundingRect();
0079 }
0080 
0081 void RenderLayer::removeSublayer(RenderLayer *sublayer)
0082 {
0083     m_sublayers.removeOne(sublayer);
0084     sublayer->setOutputLayer(nullptr);
0085     updateBoundingRect();
0086 }
0087 
0088 RenderLoop *RenderLayer::loop() const
0089 {
0090     return m_loop;
0091 }
0092 
0093 RenderLayerDelegate *RenderLayer::delegate() const
0094 {
0095     return m_delegate.get();
0096 }
0097 
0098 void RenderLayer::setDelegate(std::unique_ptr<RenderLayerDelegate> delegate)
0099 {
0100     m_delegate = std::move(delegate);
0101     m_delegate->setLayer(this);
0102 }
0103 
0104 QRectF RenderLayer::rect() const
0105 {
0106     return QRect(0, 0, m_geometry.width(), m_geometry.height());
0107 }
0108 
0109 QRectF RenderLayer::boundingRect() const
0110 {
0111     return m_boundingRect;
0112 }
0113 
0114 QRectF RenderLayer::geometry() const
0115 {
0116     return m_geometry;
0117 }
0118 
0119 void RenderLayer::setGeometry(const QRectF &geometry)
0120 {
0121     if (m_geometry == geometry) {
0122         return;
0123     }
0124     if (m_effectiveVisible && m_outputLayer) {
0125         m_outputLayer->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
0126     }
0127 
0128     m_geometry = geometry;
0129     addRepaintFull();
0130 
0131     updateBoundingRect();
0132     if (m_superlayer) {
0133         m_superlayer->updateBoundingRect();
0134     }
0135 }
0136 
0137 void RenderLayer::scheduleRepaint(Item *item)
0138 {
0139     m_repaintScheduled = true;
0140     m_loop->scheduleRepaint(item);
0141 }
0142 
0143 bool RenderLayer::needsRepaint() const
0144 {
0145     if (m_repaintScheduled) {
0146         return true;
0147     }
0148     if (!m_repaints.isEmpty()) {
0149         return true;
0150     }
0151     return std::any_of(m_sublayers.constBegin(), m_sublayers.constEnd(), [](RenderLayer *layer) {
0152         return layer->needsRepaint();
0153     });
0154 }
0155 
0156 void RenderLayer::updateBoundingRect()
0157 {
0158     QRectF boundingRect = rect();
0159     for (const RenderLayer *sublayer : std::as_const(m_sublayers)) {
0160         boundingRect |= sublayer->boundingRect().translated(sublayer->geometry().topLeft());
0161     }
0162 
0163     if (m_boundingRect != boundingRect) {
0164         m_boundingRect = boundingRect;
0165         if (m_superlayer) {
0166             m_superlayer->updateBoundingRect();
0167         }
0168     }
0169 }
0170 
0171 void RenderLayer::addRepaintFull()
0172 {
0173     addRepaint(rect().toAlignedRect());
0174 }
0175 
0176 void RenderLayer::addRepaint(int x, int y, int width, int height)
0177 {
0178     addRepaint(QRegion(x, y, width, height));
0179 }
0180 
0181 void RenderLayer::addRepaint(const QRect &rect)
0182 {
0183     addRepaint(QRegion(rect));
0184 }
0185 
0186 void RenderLayer::addRepaint(const QRegion &region)
0187 {
0188     if (!m_effectiveVisible) {
0189         return;
0190     }
0191     if (!region.isEmpty()) {
0192         m_repaints += region;
0193         m_loop->scheduleRepaint();
0194     }
0195 }
0196 
0197 QRegion RenderLayer::repaints() const
0198 {
0199     return m_repaints;
0200 }
0201 
0202 void RenderLayer::resetRepaints()
0203 {
0204     m_repaints = QRegion();
0205     m_repaintScheduled = false;
0206 }
0207 
0208 bool RenderLayer::isVisible() const
0209 {
0210     return m_effectiveVisible;
0211 }
0212 
0213 void RenderLayer::setVisible(bool visible)
0214 {
0215     if (m_explicitVisible != visible) {
0216         m_explicitVisible = visible;
0217         updateEffectiveVisibility();
0218     }
0219 }
0220 
0221 bool RenderLayer::computeEffectiveVisibility() const
0222 {
0223     return m_explicitVisible && (!m_superlayer || m_superlayer->isVisible());
0224 }
0225 
0226 void RenderLayer::updateEffectiveVisibility()
0227 {
0228     const bool effectiveVisible = computeEffectiveVisibility();
0229     if (m_effectiveVisible == effectiveVisible) {
0230         return;
0231     }
0232 
0233     m_effectiveVisible = effectiveVisible;
0234 
0235     if (effectiveVisible) {
0236         addRepaintFull();
0237     } else {
0238         if (m_outputLayer) {
0239             m_outputLayer->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
0240             m_loop->scheduleRepaint();
0241         }
0242     }
0243 
0244     for (RenderLayer *sublayer : std::as_const(m_sublayers)) {
0245         sublayer->updateEffectiveVisibility();
0246     }
0247 }
0248 
0249 QPoint RenderLayer::mapToGlobal(const QPoint &point) const
0250 {
0251     return mapToGlobal(QPointF(point)).toPoint();
0252 }
0253 
0254 QPointF RenderLayer::mapToGlobal(const QPointF &point) const
0255 {
0256     QPointF result = point;
0257     const RenderLayer *layer = this;
0258     while (layer) {
0259         result += layer->geometry().topLeft();
0260         layer = layer->superlayer();
0261     }
0262     return result;
0263 }
0264 
0265 QRect RenderLayer::mapToGlobal(const QRect &rect) const
0266 {
0267     return rect.translated(mapToGlobal(QPoint(0, 0)));
0268 }
0269 
0270 QRectF RenderLayer::mapToGlobal(const QRectF &rect) const
0271 {
0272     return rect.translated(mapToGlobal(QPointF(0, 0)));
0273 }
0274 
0275 QRegion RenderLayer::mapToGlobal(const QRegion &region) const
0276 {
0277     if (region.isEmpty()) {
0278         return QRegion();
0279     }
0280     return region.translated(mapToGlobal(QPoint(0, 0)));
0281 }
0282 
0283 QPoint RenderLayer::mapFromGlobal(const QPoint &point) const
0284 {
0285     return mapFromGlobal(QPointF(point)).toPoint();
0286 }
0287 
0288 QPointF RenderLayer::mapFromGlobal(const QPointF &point) const
0289 {
0290     QPointF result = point;
0291     const RenderLayer *layer = this;
0292     while (layer) {
0293         result -= layer->geometry().topLeft();
0294         layer = layer->superlayer();
0295     }
0296     return result;
0297 }
0298 
0299 QRect RenderLayer::mapFromGlobal(const QRect &rect) const
0300 {
0301     return rect.translated(mapFromGlobal(QPoint(0, 0)));
0302 }
0303 
0304 QRectF RenderLayer::mapFromGlobal(const QRectF &rect) const
0305 {
0306     return rect.translated(mapFromGlobal(QPointF(0, 0)));
0307 }
0308 
0309 QRegion RenderLayer::mapFromGlobal(const QRegion &region) const
0310 {
0311     if (region.isEmpty()) {
0312         return QRegion();
0313     }
0314     return region.translated(mapFromGlobal(QPoint(0, 0)));
0315 }
0316 
0317 } // namespace KWin
0318 
0319 #include "moc_renderlayer.cpp"