File indexing completed on 2024-05-12 17:02:07

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()));
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 QRect RenderLayer::rect() const
0105 {
0106     return QRect(0, 0, m_geometry.width(), m_geometry.height());
0107 }
0108 
0109 QRect RenderLayer::boundingRect() const
0110 {
0111     return m_boundingRect;
0112 }
0113 
0114 QRect RenderLayer::geometry() const
0115 {
0116     return m_geometry;
0117 }
0118 
0119 void RenderLayer::setGeometry(const QRect &geometry)
0120 {
0121     if (m_geometry == geometry) {
0122         return;
0123     }
0124     if (m_effectiveVisible && m_outputLayer) {
0125         m_outputLayer->addRepaint(mapToGlobal(boundingRect()));
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::updateBoundingRect()
0138 {
0139     QRect boundingRect = rect();
0140     for (const RenderLayer *sublayer : std::as_const(m_sublayers)) {
0141         boundingRect |= sublayer->boundingRect().translated(sublayer->geometry().topLeft());
0142     }
0143 
0144     if (m_boundingRect != boundingRect) {
0145         m_boundingRect = boundingRect;
0146         if (m_superlayer) {
0147             m_superlayer->updateBoundingRect();
0148         }
0149     }
0150 }
0151 
0152 void RenderLayer::addRepaintFull()
0153 {
0154     addRepaint(rect());
0155 }
0156 
0157 void RenderLayer::addRepaint(int x, int y, int width, int height)
0158 {
0159     addRepaint(QRegion(x, y, width, height));
0160 }
0161 
0162 void RenderLayer::addRepaint(const QRect &rect)
0163 {
0164     addRepaint(QRegion(rect));
0165 }
0166 
0167 void RenderLayer::addRepaint(const QRegion &region)
0168 {
0169     if (!m_effectiveVisible) {
0170         return;
0171     }
0172     if (!region.isEmpty()) {
0173         m_repaints += region;
0174         m_loop->scheduleRepaint();
0175     }
0176 }
0177 
0178 QRegion RenderLayer::repaints() const
0179 {
0180     return m_repaints;
0181 }
0182 
0183 void RenderLayer::resetRepaints()
0184 {
0185     m_repaints = QRegion();
0186 }
0187 
0188 bool RenderLayer::isVisible() const
0189 {
0190     return m_effectiveVisible;
0191 }
0192 
0193 void RenderLayer::setVisible(bool visible)
0194 {
0195     if (m_explicitVisible != visible) {
0196         m_explicitVisible = visible;
0197         updateEffectiveVisibility();
0198     }
0199 }
0200 
0201 bool RenderLayer::computeEffectiveVisibility() const
0202 {
0203     return m_explicitVisible && (!m_superlayer || m_superlayer->isVisible());
0204 }
0205 
0206 void RenderLayer::updateEffectiveVisibility()
0207 {
0208     const bool effectiveVisible = computeEffectiveVisibility();
0209     if (m_effectiveVisible == effectiveVisible) {
0210         return;
0211     }
0212 
0213     m_effectiveVisible = effectiveVisible;
0214 
0215     if (effectiveVisible) {
0216         addRepaintFull();
0217     } else {
0218         if (m_outputLayer) {
0219             m_outputLayer->addRepaint(mapToGlobal(boundingRect()));
0220         }
0221     }
0222 
0223     for (RenderLayer *sublayer : std::as_const(m_sublayers)) {
0224         sublayer->updateEffectiveVisibility();
0225     }
0226 }
0227 
0228 QPoint RenderLayer::mapToGlobal(const QPoint &point) const
0229 {
0230     QPoint result = point;
0231     const RenderLayer *layer = this;
0232     while (layer) {
0233         result += layer->geometry().topLeft();
0234         layer = layer->superlayer();
0235     }
0236     return result;
0237 }
0238 
0239 QRect RenderLayer::mapToGlobal(const QRect &rect) const
0240 {
0241     return rect.translated(mapToGlobal(QPoint(0, 0)));
0242 }
0243 
0244 QRegion RenderLayer::mapToGlobal(const QRegion &region) const
0245 {
0246     if (region.isEmpty()) {
0247         return QRegion();
0248     }
0249     return region.translated(mapToGlobal(QPoint(0, 0)));
0250 }
0251 
0252 QPoint RenderLayer::mapFromGlobal(const QPoint &point) const
0253 {
0254     QPoint result = point;
0255     const RenderLayer *layer = this;
0256     while (layer) {
0257         result -= layer->geometry().topLeft();
0258         layer = layer->superlayer();
0259     }
0260     return result;
0261 }
0262 
0263 QRect RenderLayer::mapFromGlobal(const QRect &rect) const
0264 {
0265     return rect.translated(mapFromGlobal(QPoint(0, 0)));
0266 }
0267 
0268 QRegion RenderLayer::mapFromGlobal(const QRegion &region) const
0269 {
0270     if (region.isEmpty()) {
0271         return QRegion();
0272     }
0273     return region.translated(mapFromGlobal(QPoint(0, 0)));
0274 }
0275 
0276 } // namespace KWin