1 | /*
|
---|
2 | * Copyright (C) 1999 Lars Knoll ([email protected])
|
---|
3 | * (C) 1999 Antti Koivisto ([email protected])
|
---|
4 | * (C) 2005 Allan Sandfeld Jensen ([email protected])
|
---|
5 | * (C) 2005, 2006 Samuel Weinig ([email protected])
|
---|
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 "RenderLayerBacking.h"
|
---|
30 | #include "RenderLayerCompositor.h"
|
---|
31 | #include "RenderLayerScrollableArea.h"
|
---|
32 | #include "RenderSVGBlock.h"
|
---|
33 | #include "RenderSVGModelObject.h"
|
---|
34 | #include "RenderView.h"
|
---|
35 | #include "SVGGraphicsElement.h"
|
---|
36 | #include "Settings.h"
|
---|
37 | #include "StyleScrollSnapPoints.h"
|
---|
38 | #include "TransformState.h"
|
---|
39 | #include <wtf/IsoMallocInlines.h>
|
---|
40 |
|
---|
41 | namespace WebCore {
|
---|
42 |
|
---|
43 | WTF_MAKE_ISO_ALLOCATED_IMPL(RenderLayerModelObject);
|
---|
44 |
|
---|
45 | bool RenderLayerModelObject::s_wasFloating = false;
|
---|
46 | bool RenderLayerModelObject::s_hadLayer = false;
|
---|
47 | bool RenderLayerModelObject::s_hadTransform = false;
|
---|
48 | bool RenderLayerModelObject::s_layerWasSelfPainting = false;
|
---|
49 |
|
---|
50 | RenderLayerModelObject::RenderLayerModelObject(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
|
---|
51 | : RenderElement(element, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
|
---|
52 | {
|
---|
53 | }
|
---|
54 |
|
---|
55 | RenderLayerModelObject::RenderLayerModelObject(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
|
---|
56 | : RenderElement(document, WTFMove(style), baseTypeFlags | RenderLayerModelObjectFlag)
|
---|
57 | {
|
---|
58 | }
|
---|
59 |
|
---|
60 | RenderLayerModelObject::~RenderLayerModelObject()
|
---|
61 | {
|
---|
62 | // Do not add any code here. Add it to willBeDestroyed() instead.
|
---|
63 | }
|
---|
64 |
|
---|
65 | void RenderLayerModelObject::willBeDestroyed()
|
---|
66 | {
|
---|
67 | if (isPositioned()) {
|
---|
68 | if (style().hasViewportConstrainedPosition())
|
---|
69 | view().frameView().removeViewportConstrainedObject(*this);
|
---|
70 | }
|
---|
71 |
|
---|
72 | if (hasLayer()) {
|
---|
73 | setHasLayer(false);
|
---|
74 | destroyLayer();
|
---|
75 | }
|
---|
76 |
|
---|
77 | RenderElement::willBeDestroyed();
|
---|
78 | }
|
---|
79 |
|
---|
80 | void RenderLayerModelObject::willBeRemovedFromTree(IsInternalMove isInternalMove)
|
---|
81 | {
|
---|
82 | if (auto* layer = this->layer(); layer && layer->needsFullRepaint() && isInternalMove == IsInternalMove::No)
|
---|
83 | issueRepaint(std::nullopt, ClipRepaintToLayer::No, ForceRepaint::Yes);
|
---|
84 |
|
---|
85 | RenderElement::willBeRemovedFromTree(isInternalMove);
|
---|
86 | }
|
---|
87 |
|
---|
88 | void RenderLayerModelObject::destroyLayer()
|
---|
89 | {
|
---|
90 | ASSERT(!hasLayer());
|
---|
91 | ASSERT(m_layer);
|
---|
92 | m_layer = nullptr;
|
---|
93 | }
|
---|
94 |
|
---|
95 | void RenderLayerModelObject::createLayer()
|
---|
96 | {
|
---|
97 | ASSERT(!m_layer);
|
---|
98 | m_layer = makeUnique<RenderLayer>(*this);
|
---|
99 | setHasLayer(true);
|
---|
100 | m_layer->insertOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange);
|
---|
101 | }
|
---|
102 |
|
---|
103 | bool RenderLayerModelObject::hasSelfPaintingLayer() const
|
---|
104 | {
|
---|
105 | return m_layer && m_layer->isSelfPaintingLayer();
|
---|
106 | }
|
---|
107 |
|
---|
108 | void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
|
---|
109 | {
|
---|
110 | s_wasFloating = isFloating();
|
---|
111 | s_hadLayer = hasLayer();
|
---|
112 | s_hadTransform = hasTransform();
|
---|
113 | if (s_hadLayer)
|
---|
114 | s_layerWasSelfPainting = layer()->isSelfPaintingLayer();
|
---|
115 |
|
---|
116 | auto* oldStyle = hasInitializedStyle() ? &style() : nullptr;
|
---|
117 | if (diff == StyleDifference::RepaintLayer && parent() && oldStyle && oldStyle->clip() != newStyle.clip())
|
---|
118 | layer()->clearClipRectsIncludingDescendants();
|
---|
119 | RenderElement::styleWillChange(diff, newStyle);
|
---|
120 | }
|
---|
121 |
|
---|
122 | void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
|
---|
123 | {
|
---|
124 | RenderElement::styleDidChange(diff, oldStyle);
|
---|
125 | updateFromStyle();
|
---|
126 |
|
---|
127 | if (requiresLayer()) {
|
---|
128 | if (!layer() && layerCreationAllowedForSubtree()) {
|
---|
129 | if (s_wasFloating && isFloating())
|
---|
130 | setChildNeedsLayout();
|
---|
131 | createLayer();
|
---|
132 | if (parent() && !needsLayout() && containingBlock())
|
---|
133 | layer()->setRepaintStatus(NeedsFullRepaint);
|
---|
134 | }
|
---|
135 | } else if (layer() && layer()->parent()) {
|
---|
136 | #if ENABLE(CSS_COMPOSITING)
|
---|
137 | if (oldStyle && oldStyle->hasBlendMode())
|
---|
138 | layer()->willRemoveChildWithBlendMode();
|
---|
139 | #endif
|
---|
140 | setHasTransformRelatedProperty(false); // All transform-related properties force layers, so we know we don't have one or the object doesn't support them.
|
---|
141 | #if ENABLE(LAYER_BASED_SVG_ENGINE)
|
---|
142 | setHasSVGTransform(false); // Same reason as for setHasTransformRelatedProperty().
|
---|
143 | #endif
|
---|
144 | setHasReflection(false);
|
---|
145 |
|
---|
146 | // Repaint the about to be destroyed self-painting layer when style change also triggers repaint.
|
---|
147 | if (layer()->isSelfPaintingLayer() && layer()->repaintStatus() == NeedsFullRepaint && layer()->repaintRects())
|
---|
148 | repaintUsingContainer(containerForRepaint().renderer, layer()->repaintRects()->clippedOverflowRect);
|
---|
149 |
|
---|
150 | layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::StyleChange); // calls destroyLayer() which clears m_layer
|
---|
151 | if (s_wasFloating && isFloating())
|
---|
152 | setChildNeedsLayout();
|
---|
153 | if (s_hadTransform)
|
---|
154 | setNeedsLayoutAndPrefWidthsRecalc();
|
---|
155 | }
|
---|
156 |
|
---|
157 | if (layer()) {
|
---|
158 | layer()->styleChanged(diff, oldStyle);
|
---|
159 | if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting)
|
---|
160 | setChildNeedsLayout();
|
---|
161 | }
|
---|
162 |
|
---|
163 | bool newStyleIsViewportConstrained = style().hasViewportConstrainedPosition();
|
---|
164 | bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition();
|
---|
165 | if (newStyleIsViewportConstrained != oldStyleIsViewportConstrained) {
|
---|
166 | if (newStyleIsViewportConstrained && layer())
|
---|
167 | view().frameView().addViewportConstrainedObject(*this);
|
---|
168 | else
|
---|
169 | view().frameView().removeViewportConstrainedObject(*this);
|
---|
170 | }
|
---|
171 |
|
---|
172 | const RenderStyle& newStyle = style();
|
---|
173 | if (oldStyle && oldStyle->scrollPadding() != newStyle.scrollPadding()) {
|
---|
174 | if (isDocumentElementRenderer()) {
|
---|
175 | FrameView& frameView = view().frameView();
|
---|
176 | frameView.updateScrollbarSteps();
|
---|
177 | } else if (RenderLayer* renderLayer = layer())
|
---|
178 | renderLayer->updateScrollbarSteps();
|
---|
179 | }
|
---|
180 |
|
---|
181 | bool scrollMarginChanged = oldStyle && oldStyle->scrollMargin() != newStyle.scrollMargin();
|
---|
182 | bool scrollAlignChanged = oldStyle && oldStyle->scrollSnapAlign() != newStyle.scrollSnapAlign();
|
---|
183 | bool scrollSnapStopChanged = oldStyle && oldStyle->scrollSnapStop() != newStyle.scrollSnapStop();
|
---|
184 | if (scrollMarginChanged || scrollAlignChanged || scrollSnapStopChanged) {
|
---|
185 | if (auto* scrollSnapBox = enclosingScrollableContainerForSnapping())
|
---|
186 | scrollSnapBox->setNeedsLayout();
|
---|
187 | }
|
---|
188 | }
|
---|
189 |
|
---|
190 | bool RenderLayerModelObject::shouldPlaceVerticalScrollbarOnLeft() const
|
---|
191 | {
|
---|
192 | // RTL Scrollbars require some system support, and this system support does not exist on certain versions of OS X. iOS uses a separate mechanism.
|
---|
193 | #if PLATFORM(IOS_FAMILY)
|
---|
194 | return false;
|
---|
195 | #else
|
---|
196 | switch (settings().userInterfaceDirectionPolicy()) {
|
---|
197 | case UserInterfaceDirectionPolicy::Content:
|
---|
198 | return style().shouldPlaceVerticalScrollbarOnLeft();
|
---|
199 | case UserInterfaceDirectionPolicy::System:
|
---|
200 | return settings().systemLayoutDirection() == TextDirection::RTL;
|
---|
201 | }
|
---|
202 | ASSERT_NOT_REACHED();
|
---|
203 | return style().shouldPlaceVerticalScrollbarOnLeft();
|
---|
204 | #endif
|
---|
205 | }
|
---|
206 |
|
---|
207 | std::optional<LayerRepaintRects> RenderLayerModelObject::layerRepaintRects() const
|
---|
208 | {
|
---|
209 | return hasLayer() ? layer()->repaintRects() : std::nullopt;
|
---|
210 | }
|
---|
211 |
|
---|
212 | bool RenderLayerModelObject::startAnimation(double timeOffset, const Animation& animation, const KeyframeList& keyframes)
|
---|
213 | {
|
---|
214 | if (!layer() || !layer()->backing())
|
---|
215 | return false;
|
---|
216 | return layer()->backing()->startAnimation(timeOffset, animation, keyframes);
|
---|
217 | }
|
---|
218 |
|
---|
219 | void RenderLayerModelObject::animationPaused(double timeOffset, const String& name)
|
---|
220 | {
|
---|
221 | if (!layer() || !layer()->backing())
|
---|
222 | return;
|
---|
223 | layer()->backing()->animationPaused(timeOffset, name);
|
---|
224 | }
|
---|
225 |
|
---|
226 | void RenderLayerModelObject::animationFinished(const String& name)
|
---|
227 | {
|
---|
228 | if (!layer() || !layer()->backing())
|
---|
229 | return;
|
---|
230 | layer()->backing()->animationFinished(name);
|
---|
231 | }
|
---|
232 |
|
---|
233 | void RenderLayerModelObject::transformRelatedPropertyDidChange()
|
---|
234 | {
|
---|
235 | if (!layer() || !layer()->backing())
|
---|
236 | return;
|
---|
237 | layer()->backing()->transformRelatedPropertyDidChange();
|
---|
238 | }
|
---|
239 |
|
---|
240 | void RenderLayerModelObject::suspendAnimations(MonotonicTime time)
|
---|
241 | {
|
---|
242 | if (!layer() || !layer()->backing())
|
---|
243 | return;
|
---|
244 | layer()->backing()->suspendAnimations(time);
|
---|
245 | }
|
---|
246 |
|
---|
247 | void RenderLayerModelObject::updateLayerTransform()
|
---|
248 | {
|
---|
249 | // Transform-origin depends on box size, so we need to update the layer transform after layout.
|
---|
250 | if (hasLayer())
|
---|
251 | layer()->updateTransform();
|
---|
252 | }
|
---|
253 |
|
---|
254 | #if ENABLE(LAYER_BASED_SVG_ENGINE)
|
---|
255 | std::optional<LayoutRect> RenderLayerModelObject::computeVisibleRectInSVGContainer(const LayoutRect& rect, const RenderLayerModelObject* container, RenderObject::VisibleRectContext context) const
|
---|
256 | {
|
---|
257 | ASSERT(is<RenderSVGModelObject>(this) || is<RenderSVGBlock>(this));
|
---|
258 | ASSERT(!style().hasInFlowPosition());
|
---|
259 | ASSERT(!view().frameView().layoutContext().isPaintOffsetCacheEnabled());
|
---|
260 |
|
---|
261 | if (container == this)
|
---|
262 | return rect;
|
---|
263 |
|
---|
264 | bool containerIsSkipped;
|
---|
265 | auto* localContainer = this->container(container, containerIsSkipped);
|
---|
266 | if (!localContainer)
|
---|
267 | return rect;
|
---|
268 |
|
---|
269 | ASSERT_UNUSED(containerIsSkipped, !containerIsSkipped);
|
---|
270 |
|
---|
271 | LayoutRect adjustedRect = rect;
|
---|
272 |
|
---|
273 | // FIXME: [LBSE] Upstream RenderSVGForeignObject changes
|
---|
274 | // Move to origin of local coordinate system, if this is the first call to computeVisibleRectInContainer() originating
|
---|
275 | // from a SVG renderer (RenderSVGModelObject / RenderSVGBlock) or if we cross the boundary from HTML -> SVG via RenderSVGForeignObject.
|
---|
276 | // bool moveToOrigin = is<RenderSVGForeignObject>(renderer);
|
---|
277 | bool moveToOrigin = false;
|
---|
278 |
|
---|
279 | /* FIXME: [LBSE] Upstream RenderObject changes
|
---|
280 | if (context.options.contains(RenderObject::VisibleRectContextOption::TranslateToSVGRendererOrigin)) {
|
---|
281 | context.options.remove(RenderObject::VisibleRectContextOption::TranslateToSVGRendererOrigin);
|
---|
282 | moveToOrigin = true;
|
---|
283 | }
|
---|
284 | */
|
---|
285 |
|
---|
286 | if (moveToOrigin)
|
---|
287 | adjustedRect.moveBy(nominalSVGLayoutLocation());
|
---|
288 |
|
---|
289 | if (auto* transform = layer()->transform())
|
---|
290 | adjustedRect = transform->mapRect(adjustedRect);
|
---|
291 |
|
---|
292 | return localContainer->computeVisibleRectInContainer(adjustedRect, container, context);
|
---|
293 | }
|
---|
294 |
|
---|
295 | void RenderLayerModelObject::mapLocalToSVGContainer(const RenderLayerModelObject* ancestorContainer, TransformState& transformState, OptionSet<MapCoordinatesMode> mode, bool* wasFixed) const
|
---|
296 | {
|
---|
297 | // FIXME: [LBSE] Upstream RenderSVGBlock changes
|
---|
298 | // ASSERT(is<RenderSVGModelObject>(this) || is<RenderSVGBlock>(this));
|
---|
299 | ASSERT(is<RenderSVGModelObject>(this));
|
---|
300 | ASSERT(style().position() == PositionType::Static);
|
---|
301 |
|
---|
302 | if (ancestorContainer == this)
|
---|
303 | return;
|
---|
304 |
|
---|
305 | ASSERT(!view().frameView().layoutContext().isPaintOffsetCacheEnabled());
|
---|
306 |
|
---|
307 | bool ancestorSkipped;
|
---|
308 | auto* container = this->container(ancestorContainer, ancestorSkipped);
|
---|
309 | if (!container)
|
---|
310 | return;
|
---|
311 |
|
---|
312 | ASSERT_UNUSED(ancestorSkipped, !ancestorSkipped);
|
---|
313 |
|
---|
314 | // If this box has a transform, it acts as a fixed position container for fixed descendants,
|
---|
315 | // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
|
---|
316 | if (hasTransform())
|
---|
317 | mode.remove(IsFixed);
|
---|
318 |
|
---|
319 | if (wasFixed)
|
---|
320 | *wasFixed = mode.contains(IsFixed);
|
---|
321 |
|
---|
322 | auto containerOffset = offsetFromContainer(*container, LayoutPoint(transformState.mappedPoint()));
|
---|
323 |
|
---|
324 | bool preserve3D = mode & UseTransforms && (container->style().preserves3D() || style().preserves3D());
|
---|
325 | if (mode & UseTransforms && shouldUseTransformFromContainer(container)) {
|
---|
326 | TransformationMatrix t;
|
---|
327 | getTransformFromContainer(container, containerOffset, t);
|
---|
328 | transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
|
---|
329 | } else
|
---|
330 | transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
|
---|
331 |
|
---|
332 | mode.remove(ApplyContainerFlip);
|
---|
333 |
|
---|
334 | container->mapLocalToContainer(ancestorContainer, transformState, mode, wasFixed);
|
---|
335 | }
|
---|
336 |
|
---|
337 | void RenderLayerModelObject::applySVGTransform(TransformationMatrix& transform, SVGGraphicsElement& graphicsElement, const RenderStyle& style, const FloatRect& boundingBox, OptionSet<RenderStyle::TransformOperationOption> options) const
|
---|
338 | {
|
---|
339 | // This check does not use style.hasTransformRelatedProperty() on purpose -- we only want to know if either the 'transform' property, an
|
---|
340 | // offset path, or the individual transform operations are set (perspective / transform-style: preserve-3d are not relevant here).
|
---|
341 | bool hasCSSTransform = style.hasTransform() || style.rotate() || style.translate() || style.scale();
|
---|
342 |
|
---|
343 | bool affectedByTransformOrigin = false;
|
---|
344 | std::optional<AffineTransform> svgTransform;
|
---|
345 |
|
---|
346 | if (hasCSSTransform)
|
---|
347 | affectedByTransformOrigin = style.affectedByTransformOrigin();
|
---|
348 | else if (auto affineTransform = graphicsElement.animatedLocalTransform(); !affineTransform.isIdentity()) {
|
---|
349 | svgTransform = affineTransform;
|
---|
350 | affectedByTransformOrigin = affineTransform.a() != 1 || affineTransform.b() || affineTransform.c() || affineTransform.d() != 1;
|
---|
351 | }
|
---|
352 |
|
---|
353 | if (!hasCSSTransform && !svgTransform.has_value())
|
---|
354 | return;
|
---|
355 |
|
---|
356 | FloatPoint3D originTranslate;
|
---|
357 | if (options.contains(RenderStyle::TransformOperationOption::TransformOrigin) && affectedByTransformOrigin)
|
---|
358 | originTranslate = style.computeTransformOrigin(boundingBox);
|
---|
359 |
|
---|
360 | style.applyTransformOrigin(transform, originTranslate);
|
---|
361 |
|
---|
362 | // CSS transforms take precedence over SVG transforms.
|
---|
363 | if (hasCSSTransform)
|
---|
364 | style.applyCSSTransform(transform, boundingBox, options);
|
---|
365 | else
|
---|
366 | transform.multiplyAffineTransform(svgTransform.value());
|
---|
367 |
|
---|
368 | style.unapplyTransformOrigin(transform, originTranslate);
|
---|
369 | }
|
---|
370 |
|
---|
371 | void RenderLayerModelObject::updateHasSVGTransformFlags(const SVGGraphicsElement& graphicsElement)
|
---|
372 | {
|
---|
373 | bool hasSVGTransform = !graphicsElement.animatedLocalTransform().isIdentity();
|
---|
374 | setHasTransformRelatedProperty(style().hasTransformRelatedProperty() || hasSVGTransform);
|
---|
375 | setHasSVGTransform(hasSVGTransform);
|
---|
376 | }
|
---|
377 | #endif
|
---|
378 |
|
---|
379 | bool rendererNeedsPixelSnapping(const RenderLayerModelObject& renderer)
|
---|
380 | {
|
---|
381 | #if ENABLE(LAYER_BASED_SVG_ENGINE)
|
---|
382 | if (renderer.document().settings().layerBasedSVGEngineEnabled() && renderer.isSVGLayerAwareRenderer() && !renderer.isSVGRoot())
|
---|
383 | return false;
|
---|
384 | #else
|
---|
385 | UNUSED_PARAM(renderer);
|
---|
386 | #endif
|
---|
387 |
|
---|
388 | return true;
|
---|
389 | }
|
---|
390 |
|
---|
391 | FloatRect snapRectToDevicePixelsIfNeeded(const LayoutRect& rect, const RenderLayerModelObject& renderer)
|
---|
392 | {
|
---|
393 | if (!rendererNeedsPixelSnapping(renderer))
|
---|
394 | return rect;
|
---|
395 | return snapRectToDevicePixels(rect, renderer.document().deviceScaleFactor());
|
---|
396 | }
|
---|
397 |
|
---|
398 | FloatRect snapRectToDevicePixelsIfNeeded(const FloatRect& rect, const RenderLayerModelObject& renderer)
|
---|
399 | {
|
---|
400 | if (!rendererNeedsPixelSnapping(renderer))
|
---|
401 | return rect;
|
---|
402 | return snapRectToDevicePixels(LayoutRect { rect }, renderer.document().deviceScaleFactor());
|
---|
403 | }
|
---|
404 |
|
---|
405 | } // namespace WebCore
|
---|
406 |
|
---|