Use a 1-byte enum class for TextDirection
[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 #include "Settings.h"
32 #include "StyleScrollSnapPoints.h"
33 #include <wtf/IsoMallocInlines.h>
34
35 namespace WebCore {
36
37 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderLayerModelObject);
38
39 bool RenderLayerModelObject::s_wasFloating = false;
40 bool RenderLayerModelObject::s_hadLayer = false;
41 bool RenderLayerModelObject::s_hadTransform = false;
42 bool RenderLayerModelObject::s_layerWasSelfPainting = false;
43
44 typedef WTF::HashMap<const RenderLayerModelObject*, RepaintLayoutRects> RepaintLayoutRectsMap;
45 static RepaintLayoutRectsMap* gRepaintLayoutRectsMap = nullptr;
46
47 RepaintLayoutRects::RepaintLayoutRects(const RenderLayerModelObject& renderer, const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
48     : m_repaintRect(renderer.clippedOverflowRectForRepaint(repaintContainer))
49     , m_outlineBox(renderer.outlineBoundsForRepaint(repaintContainer, geometryMap))
50 {
51 }
52
53 RenderLayerModelObject::RenderLayerModelObject(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
54     : RenderElement(element, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
55 {
56 }
57
58 RenderLayerModelObject::RenderLayerModelObject(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
59     : RenderElement(document, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
60 {
61 }
62
63 RenderLayerModelObject::~RenderLayerModelObject()
64 {
65     // Do not add any code here. Add it to willBeDestroyed() instead.
66 }
67
68 void RenderLayerModelObject::willBeDestroyed()
69 {
70     if (isPositioned()) {
71         if (style().hasViewportConstrainedPosition())
72             view().frameView().removeViewportConstrainedObject(this);
73     }
74
75     if (hasLayer()) {
76         setHasLayer(false);
77         destroyLayer();
78     }
79
80     RenderElement::willBeDestroyed();
81     
82     clearRepaintLayoutRects();
83 }
84
85 void RenderLayerModelObject::destroyLayer()
86 {
87     ASSERT(!hasLayer());
88     ASSERT(m_layer);
89     if (m_layer->isSelfPaintingLayer())
90         clearRepaintLayoutRects();
91     m_layer = nullptr;
92 }
93
94 void RenderLayerModelObject::createLayer()
95 {
96     ASSERT(!m_layer);
97     m_layer = std::make_unique<RenderLayer>(*this);
98     setHasLayer(true);
99     m_layer->insertOnlyThisLayer();
100 }
101
102 bool RenderLayerModelObject::hasSelfPaintingLayer() const
103 {
104     return m_layer && m_layer->isSelfPaintingLayer();
105 }
106
107 void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
108 {
109     s_wasFloating = isFloating();
110     s_hadLayer = hasLayer();
111     s_hadTransform = hasTransform();
112     if (s_hadLayer)
113         s_layerWasSelfPainting = layer()->isSelfPaintingLayer();
114
115     // If our z-index changes value or our visibility changes,
116     // we need to dirty our stacking context's z-order list.
117     const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
118     if (oldStyle) {
119         if (parent()) {
120             // Do a repaint with the old style first, e.g., for example if we go from
121             // having an outline to not having an outline.
122             if (diff == StyleDifference::RepaintLayer) {
123                 layer()->repaintIncludingDescendants();
124                 if (!(oldStyle->clip() == newStyle.clip()))
125                     layer()->clearClipRectsIncludingDescendants();
126             } else if (diff == StyleDifference::Repaint || newStyle.outlineSize() < oldStyle->outlineSize())
127                 repaint();
128         }
129
130         if (diff == StyleDifference::Layout || diff == StyleDifference::SimplifiedLayout) {
131             // When a layout hint happens, we do a repaint of the layer, since the layer could end up being destroyed.
132             if (hasLayer()) {
133                 if (oldStyle->position() != newStyle.position()
134                     || oldStyle->zIndex() != newStyle.zIndex()
135                     || oldStyle->hasAutoZIndex() != newStyle.hasAutoZIndex()
136                     || !(oldStyle->clip() == newStyle.clip())
137                     || oldStyle->hasClip() != newStyle.hasClip()
138                     || oldStyle->opacity() != newStyle.opacity()
139                     || oldStyle->transform() != newStyle.transform()
140                     || oldStyle->filter() != newStyle.filter()
141                     )
142                 layer()->repaintIncludingDescendants();
143             } else if (newStyle.hasTransform() || newStyle.opacity() < 1 || newStyle.hasFilter() || newStyle.hasBackdropFilter()) {
144                 // If we don't have a layer yet, but we are going to get one because of transform or opacity,
145                 //  then we need to repaint the old position of the object.
146                 repaint();
147             }
148         }
149     }
150
151     RenderElement::styleWillChange(diff, newStyle);
152 }
153
154 #if ENABLE(CSS_SCROLL_SNAP)
155 static bool scrollSnapContainerRequiresUpdateForStyleUpdate(const RenderStyle& oldStyle, const RenderStyle& newStyle)
156 {
157     return oldStyle.scrollSnapPort() != newStyle.scrollSnapPort();
158 }
159 #endif
160
161 void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
162 {
163     RenderElement::styleDidChange(diff, oldStyle);
164     updateFromStyle();
165
166     if (requiresLayer()) {
167         if (!layer() && layerCreationAllowedForSubtree()) {
168             if (s_wasFloating && isFloating())
169                 setChildNeedsLayout();
170             createLayer();
171             if (parent() && !needsLayout() && containingBlock()) {
172                 layer()->setRepaintStatus(NeedsFullRepaint);
173                 // There is only one layer to update, it is not worth using |cachedOffset| since
174                 // we are not sure the value will be used.
175                 layer()->updateLayerPositions(0);
176             }
177         }
178     } else if (layer() && layer()->parent()) {
179 #if ENABLE(CSS_COMPOSITING)
180         if (oldStyle->hasBlendMode())
181             layer()->parent()->dirtyAncestorChainHasBlendingDescendants();
182 #endif
183         setHasTransformRelatedProperty(false); // All transform-related propeties force layers, so we know we don't have one or the object doesn't support them.
184         setHasReflection(false);
185         // Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
186         if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && hasRepaintLayoutRects())
187             repaintUsingContainer(containerForRepaint(), repaintLayoutRects().m_repaintRect);
188         layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
189         if (s_wasFloating && isFloating())
190             setChildNeedsLayout();
191         if (s_hadTransform)
192             setNeedsLayoutAndPrefWidthsRecalc();
193     }
194
195     if (layer()) {
196         layer()->styleChanged(diff, oldStyle);
197         if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting)
198             setChildNeedsLayout();
199     }
200
201     bool newStyleIsViewportConstrained = style().hasViewportConstrainedPosition();
202     bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition();
203     if (newStyleIsViewportConstrained != oldStyleIsViewportConstrained) {
204         if (newStyleIsViewportConstrained && layer())
205             view().frameView().addViewportConstrainedObject(this);
206         else
207             view().frameView().removeViewportConstrainedObject(this);
208     }
209
210 #if ENABLE(CSS_SCROLL_SNAP)
211     const RenderStyle& newStyle = style();
212     if (oldStyle && scrollSnapContainerRequiresUpdateForStyleUpdate(*oldStyle, newStyle)) {
213         if (RenderLayer* renderLayer = layer()) {
214             renderLayer->updateSnapOffsets();
215             renderLayer->updateScrollSnapState();
216         } else if (isBody() || isDocumentElementRenderer()) {
217             FrameView& frameView = view().frameView();
218             frameView.updateSnapOffsets();
219             frameView.updateScrollSnapState();
220             frameView.updateScrollingCoordinatorScrollSnapProperties();
221         }
222     }
223     if (oldStyle && oldStyle->scrollSnapArea() != newStyle.scrollSnapArea()) {
224         const RenderBox* scrollSnapBox = enclosingBox().findEnclosingScrollableContainer();
225         if (scrollSnapBox && scrollSnapBox->layer()) {
226             const RenderStyle& style = scrollSnapBox->style();
227             if (style.scrollSnapType().strictness != ScrollSnapStrictness::None) {
228                 scrollSnapBox->layer()->updateSnapOffsets();
229                 scrollSnapBox->layer()->updateScrollSnapState();
230                 if (scrollSnapBox->isBody() || scrollSnapBox->isDocumentElementRenderer())
231                     scrollSnapBox->view().frameView().updateScrollingCoordinatorScrollSnapProperties();
232             }
233         }
234     }
235 #endif
236 }
237
238 bool RenderLayerModelObject::shouldPlaceBlockDirectionScrollbarOnLeft() const
239 {
240 // RTL Scrollbars require some system support, and this system support does not exist on certain versions of OS X. iOS uses a separate mechanism.
241 #if PLATFORM(IOS)
242     return false;
243 #else
244     switch (settings().userInterfaceDirectionPolicy()) {
245     case UserInterfaceDirectionPolicy::Content:
246         return style().shouldPlaceBlockDirectionScrollbarOnLeft();
247     case UserInterfaceDirectionPolicy::System:
248         return settings().systemLayoutDirection() == TextDirection::RTL;
249     }
250     ASSERT_NOT_REACHED();
251     return style().shouldPlaceBlockDirectionScrollbarOnLeft();
252 #endif
253 }
254
255 bool RenderLayerModelObject::hasRepaintLayoutRects() const
256 {
257     return gRepaintLayoutRectsMap && gRepaintLayoutRectsMap->contains(this);
258 }
259
260 void RenderLayerModelObject::setRepaintLayoutRects(const RepaintLayoutRects& rects)
261 {
262     if (!gRepaintLayoutRectsMap)
263         gRepaintLayoutRectsMap = new RepaintLayoutRectsMap();
264     gRepaintLayoutRectsMap->set(this, rects);
265 }
266
267 void RenderLayerModelObject::clearRepaintLayoutRects()
268 {
269     if (gRepaintLayoutRectsMap)
270         gRepaintLayoutRectsMap->remove(this);
271 }
272
273 RepaintLayoutRects RenderLayerModelObject::repaintLayoutRects() const
274 {
275     if (!hasRepaintLayoutRects())
276         return RepaintLayoutRects();
277     return gRepaintLayoutRectsMap->get(this);
278 }
279
280 void RenderLayerModelObject::computeRepaintLayoutRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
281 {
282     if (!m_layer || !m_layer->isSelfPaintingLayer())
283         clearRepaintLayoutRects();
284     else
285         setRepaintLayoutRects(RepaintLayoutRects(*this, repaintContainer, geometryMap));
286 }
287
288 } // namespace WebCore
289