RenderStyle should not be reference counted
[WebKit-https.git] / Source / WebCore / rendering / RenderLayerModelObject.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7  * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26 #include "RenderLayerModelObject.h"
27
28 #include "RenderLayer.h"
29 #include "RenderLayerCompositor.h"
30 #include "RenderView.h"
31
32 namespace WebCore {
33
34 bool RenderLayerModelObject::s_wasFloating = false;
35 bool RenderLayerModelObject::s_hadLayer = false;
36 bool RenderLayerModelObject::s_hadTransform = false;
37 bool RenderLayerModelObject::s_layerWasSelfPainting = false;
38
39 RenderLayerModelObject::RenderLayerModelObject(Element& element, std::unique_ptr<RenderStyle> style, BaseTypeFlags baseTypeFlags)
40     : RenderElement(element, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
41 {
42 }
43
44 RenderLayerModelObject::RenderLayerModelObject(Document& document, std::unique_ptr<RenderStyle> style, BaseTypeFlags baseTypeFlags)
45     : RenderElement(document, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
46 {
47 }
48
49 RenderLayerModelObject::~RenderLayerModelObject()
50 {
51     if (isPositioned()) {
52         if (style().hasViewportConstrainedPosition())
53             view().frameView().removeViewportConstrainedObject(this);
54     }
55
56     // Our layer should have been destroyed and cleared by now
57     ASSERT(!hasLayer());
58     ASSERT(!m_layer);
59 }
60
61 void RenderLayerModelObject::destroyLayer()
62 {
63     ASSERT(!hasLayer()); // Callers should have already called setHasLayer(false)
64     ASSERT(m_layer);
65     m_layer = nullptr;
66 }
67
68 void RenderLayerModelObject::createLayer()
69 {
70     ASSERT(!m_layer);
71     m_layer = std::make_unique<RenderLayer>(*this);
72     setHasLayer(true);
73     m_layer->insertOnlyThisLayer();
74 }
75
76 bool RenderLayerModelObject::hasSelfPaintingLayer() const
77 {
78     return m_layer && m_layer->isSelfPaintingLayer();
79 }
80
81 void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
82 {
83     s_wasFloating = isFloating();
84     s_hadLayer = hasLayer();
85     s_hadTransform = hasTransform();
86     if (s_hadLayer)
87         s_layerWasSelfPainting = layer()->isSelfPaintingLayer();
88
89     // If our z-index changes value or our visibility changes,
90     // we need to dirty our stacking context's z-order list.
91     const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
92     if (oldStyle) {
93         if (parent()) {
94             // Do a repaint with the old style first, e.g., for example if we go from
95             // having an outline to not having an outline.
96             if (diff == StyleDifferenceRepaintLayer) {
97                 layer()->repaintIncludingDescendants();
98                 if (!(oldStyle->clip() == newStyle.clip()))
99                     layer()->clearClipRectsIncludingDescendants();
100             } else if (diff == StyleDifferenceRepaint || newStyle.outlineSize() < oldStyle->outlineSize())
101                 repaint();
102         }
103
104         if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
105             // When a layout hint happens, we do a repaint of the layer, since the layer could end up being destroyed.
106             if (hasLayer()) {
107                 if (oldStyle->position() != newStyle.position()
108                     || oldStyle->zIndex() != newStyle.zIndex()
109                     || oldStyle->hasAutoZIndex() != newStyle.hasAutoZIndex()
110                     || !(oldStyle->clip() == newStyle.clip())
111                     || oldStyle->hasClip() != newStyle.hasClip()
112                     || oldStyle->opacity() != newStyle.opacity()
113                     || oldStyle->transform() != newStyle.transform()
114                     || oldStyle->filter() != newStyle.filter()
115                     )
116                 layer()->repaintIncludingDescendants();
117             } else if (newStyle.hasTransform() || newStyle.opacity() < 1 || newStyle.hasFilter() || newStyle.hasBackdropFilter()) {
118                 // If we don't have a layer yet, but we are going to get one because of transform or opacity,
119                 //  then we need to repaint the old position of the object.
120                 repaint();
121             }
122         }
123     }
124
125     RenderElement::styleWillChange(diff, newStyle);
126 }
127
128 #if ENABLE(CSS_SCROLL_SNAP)
129 static bool scrollSnapContainerRequiresUpdateForStyleUpdate(const RenderStyle& oldStyle, const RenderStyle& newStyle)
130 {
131     return !(oldStyle.scrollSnapType() == newStyle.scrollSnapType()
132         && oldStyle.scrollSnapPointsX() == newStyle.scrollSnapPointsX()
133         && oldStyle.scrollSnapPointsY() == newStyle.scrollSnapPointsY()
134         && oldStyle.scrollSnapDestination() == newStyle.scrollSnapDestination());
135 }
136 #endif
137
138 void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
139 {
140     RenderElement::styleDidChange(diff, oldStyle);
141     updateFromStyle();
142
143     if (requiresLayer()) {
144         if (!layer() && layerCreationAllowedForSubtree()) {
145             if (s_wasFloating && isFloating())
146                 setChildNeedsLayout();
147             createLayer();
148             if (parent() && !needsLayout() && containingBlock()) {
149                 layer()->setRepaintStatus(NeedsFullRepaint);
150                 // There is only one layer to update, it is not worth using |cachedOffset| since
151                 // we are not sure the value will be used.
152                 layer()->updateLayerPositions(0);
153             }
154         }
155     } else if (layer() && layer()->parent()) {
156 #if ENABLE(CSS_COMPOSITING)
157         if (oldStyle->hasBlendMode())
158             layer()->parent()->dirtyAncestorChainHasBlendingDescendants();
159 #endif
160         setHasTransformRelatedProperty(false); // All transform-related propeties force layers, so we know we don't have one or the object doesn't support them.
161         setHasReflection(false);
162         // Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
163         if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint)
164             repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
165         layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
166         if (s_wasFloating && isFloating())
167             setChildNeedsLayout();
168         if (s_hadTransform)
169             setNeedsLayoutAndPrefWidthsRecalc();
170     }
171
172     if (layer()) {
173         layer()->styleChanged(diff, oldStyle);
174         if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting)
175             setChildNeedsLayout();
176     }
177
178     bool newStyleIsViewportConstrained = style().hasViewportConstrainedPosition();
179     bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition();
180     if (newStyleIsViewportConstrained != oldStyleIsViewportConstrained) {
181         if (newStyleIsViewportConstrained && layer())
182             view().frameView().addViewportConstrainedObject(this);
183         else
184             view().frameView().removeViewportConstrainedObject(this);
185     }
186
187 #if ENABLE(CSS_SCROLL_SNAP)
188     const RenderStyle& newStyle = style();
189     if (oldStyle && scrollSnapContainerRequiresUpdateForStyleUpdate(*oldStyle, newStyle)) {
190         if (RenderLayer* renderLayer = layer()) {
191             renderLayer->updateSnapOffsets();
192             renderLayer->updateScrollSnapState();
193         } else if (isBody() || isDocumentElementRenderer()) {
194             FrameView& frameView = view().frameView();
195             frameView.updateSnapOffsets();
196             frameView.updateScrollSnapState();
197             frameView.updateScrollingCoordinatorScrollSnapProperties();
198         }
199     }
200     if (oldStyle && oldStyle->scrollSnapCoordinates() != newStyle.scrollSnapCoordinates()) {
201         const RenderBox* scrollSnapBox = enclosingBox().findEnclosingScrollableContainer();
202         if (scrollSnapBox && scrollSnapBox->layer()) {
203             const RenderStyle& style = scrollSnapBox->style();
204             if (style.scrollSnapType() != ScrollSnapType::None) {
205                 scrollSnapBox->layer()->updateSnapOffsets();
206                 scrollSnapBox->layer()->updateScrollSnapState();
207                 if (scrollSnapBox->isBody() || scrollSnapBox->isDocumentElementRenderer())
208                     scrollSnapBox->view().frameView().updateScrollingCoordinatorScrollSnapProperties();
209             }
210         }
211     }
212 #endif
213 }
214
215 } // namespace WebCore
216