source: webkit/trunk/Source/WebCore/rendering/RenderLayer.cpp

Last change on this file was 295556, checked in by Alan Bujtas, 3 years ago

REGRESSION (r289443): Page contents disappear after entering a letter in the username field of bmoharris.com
https://bugs.webkit.org/show_bug.cgi?id=241625
<rdar://93516876>

Reviewed by Simon Fraser.

overflow: clip forbids scrolling entirely, through any mechanism (https://drafts.csswg.org/css-overflow/#propdef-overflow)

  • LayoutTests/fast/scrolling/scrollIntoView-with-overflow-clip-expected.html: Added.
  • LayoutTests/fast/scrolling/scrollIntoView-with-overflow-clip.html: Added.
  • LayoutTests/fast/scrolling/selection-reveal-with-overflow-clip-expected.html: Added.
  • LayoutTests/fast/scrolling/selection-reveal-with-overflow-clip.html: Added.
  • Source/WebCore/rendering/RenderLayer.cpp:

(WebCore::RenderLayer::allowsCurrentScroll const): Make sure the content is not scrollable when overflow: clip is set on the renderer.

Canonical link: https://commits.webkit.org/251561@main

  • Property svn:eol-style set to native
File size: 264.5 KB
Line 
1/*
2 * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
3 * Copyright (C) 2019 Adobe. All rights reserved.
4 * Copyright (c) 2020, 2021, 2022 Igalia S.L.
5 *
6 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
7 *
8 * Other contributors:
9 * Robert O'Callahan <[email protected]>
10 * David Baron <[email protected]>
11 * Christian Biesinger <[email protected]>
12 * Randall Jesup <[email protected]>
13 * Roland Mainz <[email protected]>
14 * Josh Soref <[email protected]>
15 * Boris Zbarsky <[email protected]>
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 *
31 * Alternatively, the contents of this file may be used under the terms
32 * of either the Mozilla Public License Version 1.1, found at
33 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
34 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
35 * (the "GPL"), in which case the provisions of the MPL or the GPL are
36 * applicable instead of those above. If you wish to allow use of your
37 * version of this file only under the terms of one of those two
38 * licenses (the MPL or the GPL) and not to allow others to use your
39 * version of this file under the LGPL, indicate your decision by
40 * deletingthe provisions above and replace them with the notice and
41 * other provisions required by the MPL or the GPL, as the case may be.
42 * If you do not delete the provisions above, a recipient may use your
43 * version of this file under any of the LGPL, the MPL or the GPL.
44 */
45
46#include "config.h"
47#include "RenderLayer.h"
48
49#include "BoxShape.h"
50#include "CSSFilter.h"
51#include "CSSPropertyNames.h"
52#include "Chrome.h"
53#include "DebugPageOverlays.h"
54#include "DeprecatedGlobalSettings.h"
55#include "Document.h"
56#include "DocumentMarkerController.h"
57#include "Editor.h"
58#include "Element.h"
59#include "ElementInlines.h"
60#include "EventHandler.h"
61#include "FEColorMatrix.h"
62#include "FEMerge.h"
63#include "FloatConversion.h"
64#include "FloatPoint3D.h"
65#include "FloatRect.h"
66#include "FloatRoundedRect.h"
67#include "FocusController.h"
68#include "Frame.h"
69#include "FrameLoader.h"
70#include "FrameLoaderClient.h"
71#include "FrameSelection.h"
72#include "FrameTree.h"
73#include "FrameView.h"
74#include "Gradient.h"
75#include "GraphicsContext.h"
76#include "HTMLFormControlElement.h"
77#include "HTMLFrameElement.h"
78#include "HTMLFrameOwnerElement.h"
79#include "HTMLIFrameElement.h"
80#include "HTMLNames.h"
81#include "HTMLParserIdioms.h"
82#include "HitTestRequest.h"
83#include "HitTestResult.h"
84#include "HitTestingTransformState.h"
85#include "LegacyRenderSVGRoot.h"
86#include "Logging.h"
87#include "OverflowEvent.h"
88#include "OverlapTestRequestClient.h"
89#include "Page.h"
90#include "PlatformMouseEvent.h"
91#include "ReferencedSVGResources.h"
92#include "RenderAncestorIterator.h"
93#include "RenderFlexibleBox.h"
94#include "RenderFragmentContainer.h"
95#include "RenderFragmentedFlow.h"
96#include "RenderGeometryMap.h"
97#include "RenderImage.h"
98#include "RenderInline.h"
99#include "RenderIterator.h"
100#include "RenderLayerBacking.h"
101#include "RenderLayerCompositor.h"
102#include "RenderLayerFilters.h"
103#include "RenderLayerScrollableArea.h"
104#include "RenderMarquee.h"
105#include "RenderMultiColumnFlow.h"
106#include "RenderReplica.h"
107#include "RenderSVGContainer.h"
108#include "RenderSVGForeignObject.h"
109#include "RenderSVGInline.h"
110#include "RenderSVGModelObject.h"
111#include "RenderSVGResourceClipper.h"
112#include "RenderSVGRoot.h"
113#include "RenderSVGText.h"
114#include "RenderScrollbar.h"
115#include "RenderScrollbarPart.h"
116#include "RenderTableCell.h"
117#include "RenderTableRow.h"
118#include "RenderText.h"
119#include "RenderTheme.h"
120#include "RenderTreeAsText.h"
121#include "RenderTreeMutationDisallowedScope.h"
122#include "RenderView.h"
123#include "RuntimeEnabledFeatures.h"
124#include "SVGNames.h"
125#include "ScaleTransformOperation.h"
126#include "ScriptDisallowedScope.h"
127#include "ScrollAnimator.h"
128#include "ScrollSnapOffsetsInfo.h"
129#include "Scrollbar.h"
130#include "ScrollbarTheme.h"
131#include "ScrollingCoordinator.h"
132#include "Settings.h"
133#include "ShadowRoot.h"
134#include "SourceGraphic.h"
135#include "StyleProperties.h"
136#include "StyleResolver.h"
137#include "Styleable.h"
138#include "TransformationMatrix.h"
139#include "TranslateTransformOperation.h"
140#include "WheelEventTestMonitor.h"
141#include <stdio.h>
142#include <wtf/HexNumber.h>
143#include <wtf/MonotonicTime.h>
144#include <wtf/StdLibExtras.h>
145#include <wtf/text/CString.h>
146#include <wtf/text/TextStream.h>
147
148#define MIN_INTERSECT_FOR_REVEAL 32
149
150namespace WebCore {
151
152using namespace HTMLNames;
153
154class ClipRects : public RefCounted<ClipRects> {
155 WTF_MAKE_FAST_ALLOCATED;
156public:
157 static Ref<ClipRects> create()
158 {
159 return adoptRef(*new ClipRects);
160 }
161
162 static Ref<ClipRects> create(const ClipRects& other)
163 {
164 return adoptRef(*new ClipRects(other));
165 }
166
167 void reset()
168 {
169 m_overflowClipRect.reset();
170 m_fixedClipRect.reset();
171 m_posClipRect.reset();
172 m_fixed = false;
173 }
174
175 const ClipRect& overflowClipRect() const { return m_overflowClipRect; }
176 void setOverflowClipRect(const ClipRect& clipRect) { m_overflowClipRect = clipRect; }
177
178 const ClipRect& fixedClipRect() const { return m_fixedClipRect; }
179 void setFixedClipRect(const ClipRect& clipRect) { m_fixedClipRect = clipRect; }
180
181 const ClipRect& posClipRect() const { return m_posClipRect; }
182 void setPosClipRect(const ClipRect& clipRect) { m_posClipRect = clipRect; }
183
184 bool fixed() const { return m_fixed; }
185 void setFixed(bool fixed) { m_fixed = fixed; }
186
187 void setOverflowClipRectAffectedByRadius() { m_overflowClipRect.setAffectedByRadius(true); }
188
189 bool operator==(const ClipRects& other) const
190 {
191 return m_overflowClipRect == other.overflowClipRect()
192 && m_fixedClipRect == other.fixedClipRect()
193 && m_posClipRect == other.posClipRect()
194 && m_fixed == other.fixed();
195 }
196
197 ClipRects& operator=(const ClipRects& other)
198 {
199 m_overflowClipRect = other.overflowClipRect();
200 m_fixedClipRect = other.fixedClipRect();
201 m_posClipRect = other.posClipRect();
202 m_fixed = other.fixed();
203 return *this;
204 }
205
206private:
207 ClipRects() = default;
208
209 ClipRects(const LayoutRect& clipRect)
210 : m_overflowClipRect(clipRect)
211 , m_fixedClipRect(clipRect)
212 , m_posClipRect(clipRect)
213 {
214 }
215
216 ClipRects(const ClipRects& other)
217 : RefCounted()
218 , m_fixed(other.fixed())
219 , m_overflowClipRect(other.overflowClipRect())
220 , m_fixedClipRect(other.fixedClipRect())
221 , m_posClipRect(other.posClipRect())
222 {
223 }
224
225 bool m_fixed { false };
226 ClipRect m_overflowClipRect;
227 ClipRect m_fixedClipRect;
228 ClipRect m_posClipRect;
229};
230
231class ClipRectsCache {
232 WTF_MAKE_FAST_ALLOCATED;
233public:
234 ClipRectsCache()
235 {
236#if ASSERT_ENABLED
237 for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
238 m_clipRectsRoot[i] = 0;
239 m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
240 }
241#endif
242 }
243
244 ClipRects* getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
245 {
246 return m_clipRects[getIndex(clipRectsType, respectOverflow)].get();
247 }
248
249 void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, RefPtr<ClipRects>&& clipRects)
250 {
251 m_clipRects[getIndex(clipRectsType, respectOverflow)] = WTFMove(clipRects);
252 }
253
254#if ASSERT_ENABLED
255 const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
256 OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
257#endif
258
259private:
260 unsigned getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
261 {
262 unsigned index = static_cast<unsigned>(clipRectsType);
263 if (respectOverflow == RespectOverflowClip)
264 index += static_cast<unsigned>(NumCachedClipRectsTypes);
265 ASSERT_WITH_SECURITY_IMPLICATION(index < NumCachedClipRectsTypes * 2);
266 return index;
267 }
268
269 RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
270};
271
272void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
273{
274#if !ENABLE(3D_TRANSFORMS)
275 UNUSED_PARAM(has3DRendering);
276 matrix.makeAffine();
277#else
278 if (!has3DRendering)
279 matrix.makeAffine();
280#endif
281}
282
283#if !LOG_DISABLED
284static TextStream& operator<<(TextStream& ts, const ClipRects& clipRects)
285{
286 TextStream::GroupScope scope(ts);
287 ts << indent << "ClipRects\n";
288 ts << indent << " overflow : " << clipRects.overflowClipRect() << "\n";
289 ts << indent << " fixed : " << clipRects.fixedClipRect() << "\n";
290 ts << indent << " positioned: " << clipRects.posClipRect() << "\n";
291
292 return ts;
293}
294
295#endif
296
297static ScrollingScope nextScrollingScope()
298{
299 static ScrollingScope currentScope = 0;
300 return ++currentScope;
301}
302
303WTF_MAKE_ISO_ALLOCATED_IMPL(RenderLayer);
304
305RenderLayer::RenderLayer(RenderLayerModelObject& renderer)
306 : m_isRenderViewLayer(renderer.isRenderView())
307 , m_forcedStackingContext(renderer.isMedia())
308 , m_isNormalFlowOnly(false)
309 , m_isCSSStackingContext(false)
310 , m_isOpportunisticStackingContext(false)
311 , m_zOrderListsDirty(false)
312 , m_normalFlowListDirty(true)
313 , m_hadNegativeZOrderList(false)
314 , m_inResizeMode(false)
315 , m_hasSelfPaintingLayerDescendant(false)
316 , m_hasSelfPaintingLayerDescendantDirty(false)
317 , m_usedTransparency(false)
318 , m_paintingInsideReflection(false)
319 , m_repaintStatus(NeedsNormalRepaint)
320 , m_visibleContentStatusDirty(true)
321 , m_hasVisibleContent(false)
322 , m_visibleDescendantStatusDirty(false)
323 , m_hasVisibleDescendant(false)
324 , m_isFixedIntersectingViewport(false)
325 , m_behavesAsFixed(false)
326 , m_3DTransformedDescendantStatusDirty(true)
327 , m_has3DTransformedDescendant(false)
328 , m_hasCompositingDescendant(false)
329 , m_hasCompositedNonContainedDescendants(false)
330 , m_hasCompositedScrollingAncestor(false)
331 , m_hasTransformedAncestor(false)
332 , m_has3DTransformedAncestor(false)
333 , m_insideSVGForeignObject(false)
334 , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
335 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
336#if ASSERT_ENABLED
337 , m_layerListMutationAllowed(true)
338#endif
339#if ENABLE(CSS_COMPOSITING)
340 , m_blendMode(static_cast<unsigned>(BlendMode::Normal))
341 , m_hasNotIsolatedCompositedBlendingDescendants(false)
342 , m_hasNotIsolatedBlendingDescendants(false)
343 , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
344#endif
345 , m_repaintRectsValid(false)
346 , m_renderer(renderer)
347{
348 setIsNormalFlowOnly(shouldBeNormalFlowOnly());
349 setIsCSSStackingContext(shouldBeCSSStackingContext());
350
351 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
352
353 if (isRenderViewLayer())
354 m_boxScrollingScope = m_contentsScrollingScope = nextScrollingScope();
355
356 if (!renderer.firstChild()) {
357 m_visibleContentStatusDirty = false;
358 m_hasVisibleContent = renderer.style().visibility() == Visibility::Visible;
359 }
360}
361
362RenderLayer::~RenderLayer()
363{
364 if (inResizeMode())
365 renderer().frame().eventHandler().resizeLayerDestroyed();
366
367 if (m_reflection)
368 removeReflection();
369
370 clearLayerScrollableArea();
371 clearLayerFilters();
372
373 if (paintsIntoProvidedBacking()) {
374 auto* backingProviderLayer = this->backingProviderLayer();
375 if (backingProviderLayer->backing())
376 backingProviderLayer->backing()->removeBackingSharingLayer(*this);
377 }
378
379 // Child layers will be deleted by their corresponding render objects, so
380 // we don't need to delete them ourselves.
381
382 clearBacking(true);
383
384 // Layer and all its children should be removed from the tree before destruction.
385 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(renderer().renderTreeBeingDestroyed() || !parent());
386 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(renderer().renderTreeBeingDestroyed() || !firstChild());
387}
388
389void RenderLayer::addChild(RenderLayer& child, RenderLayer* beforeChild)
390{
391 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
392 if (prevSibling) {
393 child.setPreviousSibling(prevSibling);
394 prevSibling->setNextSibling(&child);
395 ASSERT(prevSibling != &child);
396 } else
397 setFirstChild(&child);
398
399 if (beforeChild) {
400 beforeChild->setPreviousSibling(&child);
401 child.setNextSibling(beforeChild);
402 ASSERT(beforeChild != &child);
403 } else
404 setLastChild(&child);
405
406 child.setParent(this);
407
408 dirtyPaintOrderListsOnChildChange(child);
409
410 child.updateAncestorDependentState();
411 child.updateDescendantDependentFlags();
412 if (child.m_hasVisibleContent || child.m_hasVisibleDescendant)
413 setAncestorChainHasVisibleDescendant();
414
415 if (child.isSelfPaintingLayer() || child.hasSelfPaintingLayerDescendant())
416 setAncestorChainHasSelfPaintingLayerDescendant();
417
418 if (compositor().hasContentCompositingLayers())
419 setDescendantsNeedCompositingRequirementsTraversal();
420
421 if (child.hasDescendantNeedingCompositingRequirementsTraversal() || child.needsCompositingRequirementsTraversal())
422 child.setAncestorsHaveCompositingDirtyFlag(Compositing::HasDescendantNeedingRequirementsTraversal);
423
424 if (child.hasDescendantNeedingUpdateBackingOrHierarchyTraversal() || child.needsUpdateBackingOrHierarchyTraversal())
425 child.setAncestorsHaveCompositingDirtyFlag(Compositing::HasDescendantNeedingBackingOrHierarchyTraversal);
426
427#if ENABLE(CSS_COMPOSITING)
428 if (child.hasBlendMode() || (child.hasNotIsolatedBlendingDescendants() && !child.isolatesBlending()))
429 updateAncestorChainHasBlendingDescendants(); // Why not just dirty?
430#endif
431
432 compositor().layerWasAdded(*this, child);
433}
434
435void RenderLayer::removeChild(RenderLayer& oldChild)
436{
437 if (!renderer().renderTreeBeingDestroyed())
438 compositor().layerWillBeRemoved(*this, oldChild);
439
440 // remove the child
441 if (oldChild.previousSibling())
442 oldChild.previousSibling()->setNextSibling(oldChild.nextSibling());
443 if (oldChild.nextSibling())
444 oldChild.nextSibling()->setPreviousSibling(oldChild.previousSibling());
445
446 if (m_first == &oldChild)
447 m_first = oldChild.nextSibling();
448 if (m_last == &oldChild)
449 m_last = oldChild.previousSibling();
450
451 dirtyPaintOrderListsOnChildChange(oldChild);
452
453 oldChild.setPreviousSibling(nullptr);
454 oldChild.setNextSibling(nullptr);
455 oldChild.setParent(nullptr);
456
457 oldChild.updateDescendantDependentFlags();
458 if (oldChild.m_hasVisibleContent || oldChild.m_hasVisibleDescendant)
459 dirtyAncestorChainVisibleDescendantStatus();
460
461 if (oldChild.isSelfPaintingLayer() || oldChild.hasSelfPaintingLayerDescendant())
462 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
463
464 if (compositor().hasContentCompositingLayers())
465 setDescendantsNeedCompositingRequirementsTraversal();
466
467#if ENABLE(CSS_COMPOSITING)
468 if (oldChild.hasBlendMode() || (oldChild.hasNotIsolatedBlendingDescendants() && !oldChild.isolatesBlending()))
469 dirtyAncestorChainHasBlendingDescendants();
470#endif
471}
472
473void RenderLayer::dirtyPaintOrderListsOnChildChange(RenderLayer& child)
474{
475 if (child.isNormalFlowOnly())
476 dirtyNormalFlowList();
477
478 if (!child.isNormalFlowOnly() || child.firstChild()) {
479 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
480 // case where we're building up generated content layers. This is ok, since the lists will start
481 // off dirty in that case anyway.
482 child.dirtyStackingContextZOrderLists();
483 }
484}
485
486void RenderLayer::insertOnlyThisLayer(LayerChangeTiming timing)
487{
488 if (!m_parent && renderer().parent()) {
489 // We need to connect ourselves when our renderer() has a parent.
490 // Find our enclosingLayer and add ourselves.
491 auto* parentLayer = renderer().layerParent();
492 if (!parentLayer)
493 return;
494
495 auto* beforeChild = parentLayer->reflectionLayer() != this ? renderer().layerNextSibling(*parentLayer) : nullptr;
496 parentLayer->addChild(*this, beforeChild);
497 }
498
499 // Remove all descendant layers from the hierarchy and add them to the new position.
500 for (auto& child : childrenOfType<RenderElement>(renderer()))
501 child.moveLayers(*this);
502
503 if (parent()) {
504 if (timing == LayerChangeTiming::StyleChange)
505 renderer().view().layerChildrenChangedDuringStyleChange(*parent());
506 }
507
508 // Clear out all the clip rects.
509 clearClipRectsIncludingDescendants();
510}
511
512void RenderLayer::removeOnlyThisLayer(LayerChangeTiming timing)
513{
514 if (!m_parent)
515 return;
516
517 if (timing == LayerChangeTiming::StyleChange)
518 renderer().view().layerChildrenChangedDuringStyleChange(*parent());
519
520 // Mark that we are about to lose our layer. This makes render tree
521 // walks ignore this layer while we're removing it.
522 renderer().setHasLayer(false);
523
524 compositor().layerWillBeRemoved(*m_parent, *this);
525
526 // Dirty the clip rects.
527 clearClipRectsIncludingDescendants();
528
529 RenderLayer* nextSib = nextSibling();
530
531 // Remove the child reflection layer before moving other child layers.
532 // The reflection layer should not be moved to the parent.
533 if (auto* reflectionLayer = this->reflectionLayer())
534 removeChild(*reflectionLayer);
535
536 // Now walk our kids and reattach them to our parent.
537 RenderLayer* current = m_first;
538 while (current) {
539 RenderLayer* next = current->nextSibling();
540 removeChild(*current);
541 m_parent->addChild(*current, nextSib);
542 current->setRepaintStatus(NeedsFullRepaint);
543 current = next;
544 }
545
546 // Remove us from the parent.
547 m_parent->removeChild(*this);
548 renderer().destroyLayer();
549}
550
551static bool canCreateStackingContext(const RenderLayer& layer)
552{
553 auto& renderer = layer.renderer();
554 return renderer.hasTransformRelatedProperty()
555 || renderer.hasClipPath()
556 || renderer.hasFilter()
557 || renderer.hasMask()
558 || renderer.hasBackdropFilter()
559#if ENABLE(CSS_COMPOSITING)
560 || renderer.hasBlendMode()
561#endif
562 || renderer.isTransparent()
563 || renderer.isPositioned() // Note that this only creates stacking context in conjunction with explicit z-index.
564 || renderer.hasReflection()
565 || renderer.style().hasIsolation()
566 || renderer.shouldApplyPaintContainment()
567 || !renderer.style().hasAutoUsedZIndex()
568 || (renderer.style().willChange() && renderer.style().willChange()->canCreateStackingContext())
569 || layer.establishesTopLayer();
570}
571
572static void expandScrollRectToVisibleTargetRectToIncludeScrollPadding(RenderBox* renderBox, const LayoutRect& viewRect, LayoutRect& targetRect)
573{
574 if (!renderBox)
575 return;
576 // scroll-padding applies to the scroll container, but expand the rectangle that we want to expose in order
577 // simulate padding the scroll container. This rectangle is passed up the tree of scrolling elements to
578 // ensure that the padding on this scroll container is maintained.
579 targetRect.expand(renderBox->scrollPaddingForViewportRect(viewRect));
580}
581
582bool RenderLayer::shouldBeNormalFlowOnly() const
583{
584 if (canCreateStackingContext(*this))
585 return false;
586
587 return renderer().hasNonVisibleOverflow()
588 || renderer().isCanvas()
589 || renderer().isVideo()
590 || renderer().isEmbeddedObject()
591 || renderer().isRenderIFrame()
592 || (renderer().style().specifiesColumns() && !isRenderViewLayer())
593 || renderer().isRenderFragmentedFlow();
594}
595
596bool RenderLayer::shouldBeCSSStackingContext() const
597{
598 return !renderer().style().hasAutoUsedZIndex() || renderer().shouldApplyPaintContainment() || isRenderViewLayer();
599}
600
601bool RenderLayer::setIsNormalFlowOnly(bool isNormalFlowOnly)
602{
603 if (isNormalFlowOnly == m_isNormalFlowOnly)
604 return false;
605
606 m_isNormalFlowOnly = isNormalFlowOnly;
607
608 if (auto* p = parent())
609 p->dirtyNormalFlowList();
610 dirtyStackingContextZOrderLists();
611 return true;
612}
613
614void RenderLayer::isStackingContextChanged()
615{
616 dirtyStackingContextZOrderLists();
617 if (isStackingContext())
618 dirtyZOrderLists();
619 else
620 clearZOrderLists();
621}
622
623bool RenderLayer::setIsOpportunisticStackingContext(bool isStacking)
624{
625 bool wasStacking = isStackingContext();
626 m_isOpportunisticStackingContext = isStacking;
627 if (wasStacking == isStackingContext())
628 return false;
629
630 isStackingContextChanged();
631 return true;
632}
633
634bool RenderLayer::setIsCSSStackingContext(bool isCSSStackingContext)
635{
636 bool wasStacking = isStackingContext();
637 m_isCSSStackingContext = isCSSStackingContext;
638 if (wasStacking == isStackingContext())
639 return false;
640
641 isStackingContextChanged();
642 return true;
643}
644
645void RenderLayer::setParent(RenderLayer* parent)
646{
647 if (parent == m_parent)
648 return;
649
650 if (m_parent && !renderer().renderTreeBeingDestroyed())
651 compositor().layerWillBeRemoved(*m_parent, *this);
652
653 m_parent = parent;
654
655 if (m_parent && !renderer().renderTreeBeingDestroyed())
656 compositor().layerWasAdded(*m_parent, *this);
657}
658
659RenderLayer* RenderLayer::stackingContext() const
660{
661 auto* layer = parent();
662 while (layer && !layer->isStackingContext())
663 layer = layer->parent();
664
665 ASSERT(!layer || layer->isStackingContext());
666 ASSERT_IMPLIES(establishesTopLayer(), !layer || layer == renderer().view().layer());
667 return layer;
668}
669
670void RenderLayer::dirtyZOrderLists()
671{
672 ASSERT(layerListMutationAllowed());
673 ASSERT(isStackingContext());
674
675 if (m_posZOrderList)
676 m_posZOrderList->clear();
677 if (m_negZOrderList)
678 m_negZOrderList->clear();
679 m_zOrderListsDirty = true;
680
681 // FIXME: Ideally, we'd only dirty if the lists changed.
682 if (hasCompositingDescendant())
683 setNeedsCompositingPaintOrderChildrenUpdate();
684}
685
686void RenderLayer::dirtyStackingContextZOrderLists()
687{
688 if (auto* sc = stackingContext())
689 sc->dirtyZOrderLists();
690}
691
692bool RenderLayer::willCompositeClipPath() const
693{
694 if (!isComposited())
695 return false;
696
697 auto* clipPath = renderer().style().clipPath();
698 if (!clipPath)
699 return false;
700
701 if (renderer().hasMask())
702 return false;
703
704 return (clipPath->type() != PathOperation::Shape || clipPath->type() == PathOperation::Shape) && GraphicsLayer::supportsLayerType(GraphicsLayer::Type::Shape);
705}
706
707void RenderLayer::dirtyNormalFlowList()
708{
709 ASSERT(layerListMutationAllowed());
710
711 if (m_normalFlowList)
712 m_normalFlowList->clear();
713 m_normalFlowListDirty = true;
714
715 if (hasCompositingDescendant())
716 setNeedsCompositingPaintOrderChildrenUpdate();
717}
718
719void RenderLayer::updateNormalFlowList()
720{
721 if (!m_normalFlowListDirty)
722 return;
723
724 ASSERT(layerListMutationAllowed());
725
726 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
727 // Ignore non-overflow layers and reflections.
728 if (child->isNormalFlowOnly() && !isReflectionLayer(*child)) {
729 if (!m_normalFlowList)
730 m_normalFlowList = makeUnique<Vector<RenderLayer*>>();
731 m_normalFlowList->append(child);
732 }
733 }
734
735 if (m_normalFlowList)
736 m_normalFlowList->shrinkToFit();
737
738 m_normalFlowListDirty = false;
739}
740
741void RenderLayer::rebuildZOrderLists()
742{
743 ASSERT(layerListMutationAllowed());
744 ASSERT(isDirtyStackingContext());
745
746 OptionSet<Compositing> childDirtyFlags;
747 rebuildZOrderLists(m_posZOrderList, m_negZOrderList, childDirtyFlags);
748 m_zOrderListsDirty = false;
749
750 bool hasNegativeZOrderList = m_negZOrderList && m_negZOrderList->size();
751 // Having negative z-order lists affect whether a compositing layer needs a foreground layer.
752 // Ideally we'd only trigger this when having z-order children changes, but we blow away the old z-order
753 // lists on dirtying so we don't know the old state.
754 if (hasNegativeZOrderList != m_hadNegativeZOrderList) {
755 m_hadNegativeZOrderList = hasNegativeZOrderList;
756 if (isComposited())
757 setNeedsCompositingConfigurationUpdate();
758 }
759
760 // Building lists may have added layers with dirty flags, so make sure we propagate dirty bits up the tree.
761 if (m_compositingDirtyBits.containsAll({ Compositing::DescendantsNeedRequirementsTraversal, Compositing::DescendantsNeedBackingAndHierarchyTraversal }))
762 return;
763
764 if (childDirtyFlags.containsAny(computeCompositingRequirementsFlags()))
765 setDescendantsNeedCompositingRequirementsTraversal();
766
767 if (childDirtyFlags.containsAny(updateBackingOrHierarchyFlags()))
768 setDescendantsNeedUpdateBackingAndHierarchyTraversal();
769}
770
771void RenderLayer::rebuildZOrderLists(std::unique_ptr<Vector<RenderLayer*>>& posZOrderList, std::unique_ptr<Vector<RenderLayer*>>& negZOrderList, OptionSet<Compositing>& accumulatedDirtyFlags)
772{
773 bool includeHiddenLayers = compositor().usesCompositing();
774 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
775 if (!isReflectionLayer(*child))
776 child->collectLayers(includeHiddenLayers, posZOrderList, negZOrderList, accumulatedDirtyFlags);
777 }
778
779 auto compareZIndex = [] (const RenderLayer* first, const RenderLayer* second) -> bool {
780 return first->zIndex() < second->zIndex();
781 };
782
783 // Sort the two lists.
784 if (posZOrderList) {
785 std::stable_sort(posZOrderList->begin(), posZOrderList->end(), compareZIndex);
786 posZOrderList->shrinkToFit();
787 }
788
789 if (negZOrderList) {
790 std::stable_sort(negZOrderList->begin(), negZOrderList->end(), compareZIndex);
791 negZOrderList->shrinkToFit();
792 }
793
794 if (isRenderViewLayer() && renderer().document().hasTopLayerElement()) {
795 auto topLayerLayers = topLayerRenderLayers(renderer().view());
796 if (topLayerLayers.size()) {
797 if (!posZOrderList)
798 posZOrderList = makeUnique<Vector<RenderLayer*>>();
799
800 posZOrderList->appendVector(topLayerLayers);
801 }
802 }
803}
804
805void RenderLayer::collectLayers(bool includeHiddenLayers, std::unique_ptr<Vector<RenderLayer*>>& positiveZOrderList, std::unique_ptr<Vector<RenderLayer*>>& negativeZOrderList, OptionSet<Compositing>& accumulatedDirtyFlags)
806{
807 updateDescendantDependentFlags();
808
809 if (establishesTopLayer())
810 return;
811
812 bool isStacking = isStackingContext();
813 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
814 bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStacking));
815 if (includeHiddenLayer && !isNormalFlowOnly()) {
816 auto& layerList = (zIndex() >= 0) ? positiveZOrderList : negativeZOrderList;
817 if (!layerList)
818 layerList = makeUnique<Vector<RenderLayer*>>();
819 layerList->append(this);
820 accumulatedDirtyFlags.add(m_compositingDirtyBits);
821 }
822
823 // Recur into our children to collect more layers, but only if we don't establish
824 // a stacking context/container.
825 if ((includeHiddenLayers || m_hasVisibleDescendant) && !isStacking) {
826 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
827 // Ignore reflections.
828 if (!isReflectionLayer(*child))
829 child->collectLayers(includeHiddenLayers, positiveZOrderList, negativeZOrderList, accumulatedDirtyFlags);
830 }
831 }
832}
833
834void RenderLayer::setAncestorsHaveCompositingDirtyFlag(Compositing flag)
835{
836 for (auto* layer = paintOrderParent(); layer; layer = layer->paintOrderParent()) {
837 if (layer->m_compositingDirtyBits.contains(flag))
838 break;
839 layer->m_compositingDirtyBits.add(flag);
840 }
841}
842
843void RenderLayer::updateLayerListsIfNeeded()
844{
845 updateZOrderLists();
846 updateNormalFlowList();
847
848 if (RenderLayer* reflectionLayer = this->reflectionLayer()) {
849 reflectionLayer->updateZOrderLists();
850 reflectionLayer->updateNormalFlowList();
851 }
852}
853
854String RenderLayer::name() const
855{
856 if (!isReflection())
857 return renderer().debugDescription();
858 return makeString(renderer().debugDescription(), " (reflection)");
859}
860
861RenderLayerCompositor& RenderLayer::compositor() const
862{
863 return renderer().view().compositor();
864}
865
866void RenderLayer::contentChanged(ContentChangeType changeType)
867{
868 if (changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ModelChanged || (isComposited() && changeType == ImageChanged)) {
869 setNeedsPostLayoutCompositingUpdate();
870 setNeedsCompositingConfigurationUpdate();
871 }
872
873 if (auto* backing = this->backing())
874 backing->contentChanged(changeType);
875}
876
877bool RenderLayer::canRender3DTransforms() const
878{
879 return compositor().canRender3DTransforms();
880}
881
882bool RenderLayer::paintsWithFilters() const
883{
884 if (!renderer().hasFilter())
885 return false;
886
887 if (!isComposited())
888 return true;
889
890 return !m_backing->canCompositeFilters();
891}
892
893bool RenderLayer::requiresFullLayerImageForFilters() const
894{
895 if (!paintsWithFilters())
896 return false;
897
898 return m_filters && m_filters->hasFilterThatMovesPixels();
899}
900
901OptionSet<RenderLayer::UpdateLayerPositionsFlag> RenderLayer::flagsForUpdateLayerPositions(RenderLayer& startingLayer)
902{
903 OptionSet<UpdateLayerPositionsFlag> flags = { CheckForRepaint };
904
905 if (auto* parent = startingLayer.parent()) {
906 if (parent->hasTransformedAncestor() || parent->transform())
907 flags.add(SeenTransformedLayer);
908
909 if (parent->has3DTransformedAncestor() || (parent->transform() && !parent->transform()->isAffine()))
910 flags.add(Seen3DTransformedLayer);
911
912 if (parent->behavesAsFixed() || (parent->renderer().isFixedPositioned() && !parent->hasTransformedAncestor()))
913 flags.add(SeenFixedLayer);
914
915 if (parent->hasCompositedScrollingAncestor() || parent->hasCompositedScrollableOverflow())
916 flags.add(SeenCompositedScrollingLayer);
917 }
918
919 return flags;
920}
921
922void RenderLayer::willUpdateLayerPositions()
923{
924 renderer().document().markers().invalidateRectsForAllMarkers();
925}
926
927void RenderLayer::updateLayerPositionsAfterStyleChange()
928{
929 willUpdateLayerPositions();
930 recursiveUpdateLayerPositions(nullptr, flagsForUpdateLayerPositions(*this));
931}
932
933void RenderLayer::updateLayerPositionsAfterLayout(bool isRelayoutingSubtree, bool didFullRepaint)
934{
935 auto updateLayerPositionFlags = [&](bool isRelayoutingSubtree, bool didFullRepaint) {
936 auto flags = flagsForUpdateLayerPositions(*this);
937 if (didFullRepaint) {
938 flags.remove(RenderLayer::CheckForRepaint);
939 flags.add(RenderLayer::NeedsFullRepaintInBacking);
940 }
941 if (isRelayoutingSubtree && enclosingPaginationLayer(RenderLayer::IncludeCompositedPaginatedLayers))
942 flags.add(RenderLayer::UpdatePagination);
943 return flags;
944 };
945
946 LOG(Compositing, "RenderLayer %p updateLayerPositionsAfterLayout", this);
947 willUpdateLayerPositions();
948
949 RenderGeometryMap geometryMap(UseTransforms);
950 if (!isRenderViewLayer())
951 geometryMap.pushMappingsToAncestor(parent(), nullptr);
952
953 recursiveUpdateLayerPositions(&geometryMap, updateLayerPositionFlags(isRelayoutingSubtree, didFullRepaint));
954}
955
956void RenderLayer::recursiveUpdateLayerPositions(RenderGeometryMap* geometryMap, OptionSet<UpdateLayerPositionsFlag> flags)
957{
958 updateLayerPosition(&flags);
959 if (m_scrollableArea)
960 m_scrollableArea->applyPostLayoutScrollPositionIfNeeded();
961
962 if (geometryMap)
963 geometryMap->pushMappingsToAncestor(this, parent());
964
965 // Clear our cached clip rect information.
966 clearClipRects();
967
968 if (m_scrollableArea && m_scrollableArea->hasOverflowControls()) {
969 LayoutSize offsetFromRoot;
970 if (geometryMap)
971 offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
972 else {
973 // FIXME: It looks suspicious to call convertToLayerCoords here
974 // as canUseOffsetFromAncestor may be true for an ancestor layer.
975 offsetFromRoot = offsetFromAncestor(root());
976 }
977 m_scrollableArea->positionOverflowControls(roundedIntSize(offsetFromRoot));
978 }
979
980 updateDescendantDependentFlags();
981
982 if (flags & UpdatePagination)
983 updatePagination();
984 else
985 m_enclosingPaginationLayer = nullptr;
986
987 if (m_hasVisibleContent) {
988 // FIXME: Paint offset cache does not work with RenderLayers as there is not a 1-to-1
989 // mapping between them and the RenderObjects. It would be neat to enable
990 // LayoutState outside the layout() phase and use it here.
991 ASSERT(!renderer().view().frameView().layoutContext().isPaintOffsetCacheEnabled());
992
993 auto* repaintContainer = renderer().containerForRepaint().renderer;
994
995 auto oldRects = repaintRects();
996 computeRepaintRects(repaintContainer, geometryMap);
997
998 auto newRects = repaintRects();
999
1000 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
1001 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
1002 if ((flags & CheckForRepaint) && newRects) {
1003 if (!renderer().view().printing()) {
1004 if (m_repaintStatus & NeedsFullRepaint) {
1005 if (oldRects)
1006 renderer().repaintUsingContainer(repaintContainer, oldRects->clippedOverflowRect);
1007
1008 if (!oldRects || newRects->clippedOverflowRect != oldRects->clippedOverflowRect)
1009 renderer().repaintUsingContainer(repaintContainer, newRects->clippedOverflowRect);
1010
1011 } else if (shouldRepaintAfterLayout()) {
1012 // FIXME: We will convert this to just take the old and new RepaintLayoutRects once
1013 // we change other callers to use RepaintLayoutRects.
1014 auto resolvedOldRects = valueOrDefault(oldRects);
1015 renderer().repaintAfterLayoutIfNeeded(repaintContainer, resolvedOldRects.clippedOverflowRect, resolvedOldRects.outlineBoundsRect,
1016 &newRects->clippedOverflowRect, &newRects->outlineBoundsRect);
1017 }
1018 }
1019 }
1020 } else
1021 clearRepaintRects();
1022
1023 m_repaintStatus = NeedsNormalRepaint;
1024 m_hasTransformedAncestor = flags.contains(SeenTransformedLayer);
1025 m_has3DTransformedAncestor = flags.contains(Seen3DTransformedLayer);
1026 m_behavesAsFixed = flags.contains(SeenFixedLayer);
1027 setHasCompositedScrollingAncestor(flags.contains(SeenCompositedScrollingLayer));
1028
1029 // Update the reflection's position and size.
1030 if (m_reflection)
1031 m_reflection->layout();
1032
1033 if (renderer().isRenderFragmentedFlow()) {
1034 updatePagination();
1035 flags.add(UpdatePagination);
1036 }
1037
1038 if (transform()) {
1039 flags.add(SeenTransformedLayer);
1040 if (!transform()->isAffine())
1041 flags.add(Seen3DTransformedLayer);
1042 }
1043
1044 // Fixed inside transform behaves like absolute (per spec).
1045 if (renderer().isFixedPositioned() && !m_hasTransformedAncestor) {
1046 m_behavesAsFixed = true;
1047 flags.add(SeenFixedLayer);
1048 }
1049
1050 if (hasCompositedScrollableOverflow())
1051 flags.add(SeenCompositedScrollingLayer);
1052
1053 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1054 child->recursiveUpdateLayerPositions(geometryMap, flags);
1055
1056 if (m_scrollableArea)
1057 m_scrollableArea->updateMarqueePosition();
1058
1059 if (renderer().isFixedPositioned() && renderer().settings().acceleratedCompositingForFixedPositionEnabled()) {
1060 bool intersectsViewport = compositor().fixedLayerIntersectsViewport(*this);
1061 if (intersectsViewport != m_isFixedIntersectingViewport) {
1062 m_isFixedIntersectingViewport = intersectsViewport;
1063 setNeedsPostLayoutCompositingUpdate();
1064 }
1065 }
1066
1067#if ENABLE(LAYER_BASED_SVG_ENGINE)
1068 if (renderer().isSVGLayerAwareRenderer() && renderer().document().settings().layerBasedSVGEngineEnabled()) {
1069 if (!is<RenderSVGRoot>(renderer()))
1070 ASSERT(!renderer().isFixedPositioned());
1071
1072 // Only the outermost <svg> and / <foreignObject> are potentially scrollable.
1073 if (is<RenderSVGModelObject>(renderer()) || is<RenderSVGText>(renderer()) || is<RenderSVGInline>(renderer()))
1074 ASSERT(!m_scrollableArea);
1075 }
1076#endif
1077
1078 if (isComposited())
1079 backing()->updateAfterLayout(flags.contains(ContainingClippingLayerChangedSize), flags.contains(NeedsFullRepaintInBacking));
1080
1081 if (geometryMap)
1082 geometryMap->popMappingsToAncestor(parent());
1083}
1084
1085LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
1086{
1087 LayoutRect repaintRect;
1088 if (m_repaintRectsValid)
1089 repaintRect = m_repaintRects.clippedOverflowRect;
1090 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1091 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
1092 if (child->isComposited())
1093 continue;
1094
1095 repaintRect.uniteIfNonZero(child->repaintRectIncludingNonCompositingDescendants());
1096 }
1097 return repaintRect;
1098}
1099
1100void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
1101{
1102 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1103 if (renderer().shouldApplyPaintContainment()) {
1104 m_hasSelfPaintingLayerDescendant = true;
1105 m_hasSelfPaintingLayerDescendantDirty = false;
1106 break;
1107 }
1108 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
1109 break;
1110
1111 layer->m_hasSelfPaintingLayerDescendantDirty = false;
1112 layer->m_hasSelfPaintingLayerDescendant = true;
1113 }
1114}
1115
1116void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
1117{
1118 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1119 layer->m_hasSelfPaintingLayerDescendantDirty = true;
1120 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
1121 // in this case, there is no need to dirty our ancestors further.
1122 if (layer->isSelfPaintingLayer()) {
1123 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
1124 break;
1125 }
1126 }
1127}
1128
1129void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
1130{
1131 ASSERT(!m_visibleContentStatusDirty);
1132
1133 if (!isSelfPaintingLayer())
1134 clearRepaintRects();
1135 else {
1136 setRepaintRects({
1137 renderer().clippedOverflowRectForRepaint(repaintContainer),
1138 renderer().outlineBoundsForRepaint(repaintContainer, geometryMap)
1139 });
1140 }
1141}
1142
1143void RenderLayer::computeRepaintRectsIncludingDescendants()
1144{
1145 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
1146 // We should make this more efficient.
1147 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
1148 computeRepaintRects(renderer().containerForRepaint().renderer);
1149
1150 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
1151 layer->computeRepaintRectsIncludingDescendants();
1152}
1153
1154void RenderLayer::setRepaintRects(const LayerRepaintRects& rects)
1155{
1156 m_repaintRects = rects;
1157 m_repaintRectsValid = true;
1158}
1159
1160void RenderLayer::clearRepaintRects()
1161{
1162 m_repaintRectsValid = false;
1163}
1164
1165void RenderLayer::updateLayerPositionsAfterOverflowScroll()
1166{
1167 RenderGeometryMap geometryMap(UseTransforms);
1168 if (!isRenderViewLayer())
1169 geometryMap.pushMappingsToAncestor(parent(), nullptr);
1170
1171 willUpdateLayerPositions();
1172
1173 // FIXME: why is it OK to not check the ancestors of this layer in order to
1174 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
1175 recursiveUpdateLayerPositionsAfterScroll(&geometryMap, RenderLayer::IsOverflowScroll);
1176}
1177
1178void RenderLayer::updateLayerPositionsAfterDocumentScroll()
1179{
1180 ASSERT(isRenderViewLayer());
1181 LOG(Scrolling, "RenderLayer::updateLayerPositionsAfterDocumentScroll");
1182
1183 willUpdateLayerPositions();
1184
1185 RenderGeometryMap geometryMap(UseTransforms);
1186 recursiveUpdateLayerPositionsAfterScroll(&geometryMap);
1187}
1188
1189void RenderLayer::recursiveUpdateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, OptionSet<UpdateLayerPositionsAfterScrollFlag> flags)
1190{
1191 // FIXME: This shouldn't be needed, but there are some corner cases where
1192 // these flags are still dirty. Update so that the check below is valid.
1193 updateDescendantDependentFlags();
1194
1195 // If we have no visible content and no visible descendants, there is no point recomputing
1196 // our rectangles as they will be empty. If our visibility changes, we are expected to
1197 // recompute all our positions anyway.
1198 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
1199 return;
1200
1201 bool positionChanged = updateLayerPosition();
1202 if (positionChanged)
1203 flags.add(HasChangedAncestor);
1204
1205 if (flags.containsAny({ HasChangedAncestor, HasSeenViewportConstrainedAncestor, IsOverflowScroll }))
1206 clearClipRects();
1207
1208 if (renderer().style().hasViewportConstrainedPosition())
1209 flags.add(HasSeenViewportConstrainedAncestor);
1210
1211 if (renderer().hasNonVisibleOverflow())
1212 flags.add(HasSeenAncestorWithOverflowClip);
1213
1214 bool shouldComputeRepaintRects = (flags.contains(HasSeenViewportConstrainedAncestor) || flags.containsAll({ IsOverflowScroll, HasSeenAncestorWithOverflowClip })) && isSelfPaintingLayer();
1215 bool isVisuallyEmpty = !isVisuallyNonEmpty();
1216 bool shouldPushAndPopMappings = geometryMap && ((shouldComputeRepaintRects && !isVisuallyEmpty) || firstChild());
1217 if (shouldPushAndPopMappings)
1218 geometryMap->pushMappingsToAncestor(this, parent());
1219
1220 if (shouldComputeRepaintRects) {
1221 // When scrolling, we don't compute repaint rects for visually non-empty layers.
1222 if (isVisuallyEmpty)
1223 clearRepaintRects();
1224 else // FIXME: We could track the repaint container as we walk down the tree.
1225 computeRepaintRects(renderer().containerForRepaint().renderer, geometryMap);
1226 } else if (!renderer().view().frameView().platformWidget()) {
1227 // When ScrollView's m_paintsEntireContents flag flips due to layer backing changes, the repaint area transitions from
1228 // visual to layout overflow. When this happens the cached repaint rects become invalid and they need to be recomputed (see webkit.org/b/188121).
1229 // Check that our cached rects are correct.
1230 ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.clippedOverflowRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint().renderer));
1231 ASSERT_IMPLIES(m_repaintRectsValid, m_repaintRects.outlineBoundsRect == renderer().outlineBoundsForRepaint(renderer().containerForRepaint().renderer));
1232 }
1233
1234 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1235 child->recursiveUpdateLayerPositionsAfterScroll(geometryMap, flags);
1236
1237 // We don't update our reflection as scrolling is a translation which does not change the size()
1238 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
1239 // updated above.
1240
1241 if (m_scrollableArea)
1242 m_scrollableArea->updateMarqueePosition();
1243
1244 if (shouldPushAndPopMappings)
1245 geometryMap->popMappingsToAncestor(parent());
1246}
1247
1248#if ENABLE(CSS_COMPOSITING)
1249
1250void RenderLayer::updateBlendMode()
1251{
1252 bool hadBlendMode = static_cast<BlendMode>(m_blendMode) != BlendMode::Normal;
1253 if (parent() && hadBlendMode != hasBlendMode()) {
1254 if (hasBlendMode())
1255 parent()->updateAncestorChainHasBlendingDescendants();
1256 else
1257 parent()->dirtyAncestorChainHasBlendingDescendants();
1258 }
1259
1260 BlendMode newBlendMode = renderer().style().blendMode();
1261 if (newBlendMode != static_cast<BlendMode>(m_blendMode))
1262 m_blendMode = static_cast<unsigned>(newBlendMode);
1263}
1264
1265void RenderLayer::willRemoveChildWithBlendMode()
1266{
1267 parent()->dirtyAncestorChainHasBlendingDescendants();
1268}
1269
1270void RenderLayer::updateAncestorChainHasBlendingDescendants()
1271{
1272 for (auto* layer = this; layer; layer = layer->parent()) {
1273 if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
1274 break;
1275 layer->m_hasNotIsolatedBlendingDescendants = true;
1276 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1277
1278 layer->updateSelfPaintingLayer();
1279
1280 if (layer->isCSSStackingContext())
1281 break;
1282 }
1283}
1284
1285void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
1286{
1287 for (auto* layer = this; layer; layer = layer->parent()) {
1288 if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
1289 break;
1290
1291 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
1292
1293 if (layer->isCSSStackingContext())
1294 break;
1295 }
1296}
1297#endif
1298
1299FloatRect RenderLayer::referenceBoxRectForClipPath(CSSBoxType boxType, const LayoutSize& offsetFromRoot, const LayoutRect& rootRelativeBounds) const
1300{
1301 // FIXME: [LBSE] Upstream clipping support for SVG.
1302
1303 // FIXME: Support different reference boxes for inline content.
1304 // https://bugs.webkit.org/show_bug.cgi?id=129047
1305 if (!renderer().isBox())
1306 return rootRelativeBounds;
1307
1308 auto referenceBoxRect = renderer().referenceBoxRect(boxType);
1309 referenceBoxRect.move(offsetFromRoot);
1310 return referenceBoxRect;
1311}
1312
1313void RenderLayer::updateTransformFromStyle(TransformationMatrix& transform, const RenderStyle& style, OptionSet<RenderStyle::TransformOperationOption> options) const
1314{
1315 auto referenceBoxRect = snapRectToDevicePixelsIfNeeded(renderer().transformReferenceBoxRect(style), renderer());
1316 renderer().applyTransform(transform, style, referenceBoxRect, options);
1317 makeMatrixRenderable(transform, canRender3DTransforms());
1318}
1319
1320void RenderLayer::setReferenceBoxForPathOperations()
1321{
1322 auto pathOperation = renderer().style().offsetPath();
1323 if (!pathOperation)
1324 return;
1325 if (is<BoxPathOperation>(pathOperation)) {
1326 auto& boxPathOperation = downcast<BoxPathOperation>(*pathOperation);
1327 auto pathReferenceBoxRect = snapRectToDevicePixelsIfNeeded(renderer().referenceBoxRect(boxPathOperation.referenceBox()), renderer());
1328 boxPathOperation.setPathForReferenceRect(FloatRoundedRect { pathReferenceBoxRect });
1329 } else if (is<RayPathOperation>(pathOperation)) {
1330 if (const auto* containingBlock = renderer().containingBlock()) {
1331 auto& rayPathOperation = downcast<RayPathOperation>(*pathOperation);
1332 auto pathReferenceBoxRect = snapRectToDevicePixelsIfNeeded(containingBlock->transformReferenceBoxRect(containingBlock->style()), renderer());
1333 if (!pathReferenceBoxRect.width())
1334 pathReferenceBoxRect.setWidth(pathReferenceBoxRect.height());
1335 if (!pathReferenceBoxRect.height())
1336 pathReferenceBoxRect.setHeight(pathReferenceBoxRect.width());
1337 rayPathOperation.setContainingBlockReferenceRect(pathReferenceBoxRect);
1338 auto left = renderer().style().left();
1339 auto top = renderer().style().top();
1340 rayPathOperation.setStartingPosition(FloatPoint(left.isPercent() ? left.value() / 100 * pathReferenceBoxRect.width() : left.value(), top.isPercent() ? top.value() / 100 * pathReferenceBoxRect.height() : top.value()));
1341 }
1342 }
1343}
1344
1345void RenderLayer::updateTransform()
1346{
1347 bool hasTransform = renderer().hasTransform();
1348 bool had3DTransform = has3DTransform();
1349
1350 bool hadTransform = !!m_transform;
1351 if (hasTransform != hadTransform) {
1352 if (hasTransform)
1353 m_transform = makeUnique<TransformationMatrix>();
1354 else
1355 m_transform = nullptr;
1356
1357 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
1358 clearClipRectsIncludingDescendants();
1359 }
1360
1361 if (hasTransform) {
1362 m_transform->makeIdentity();
1363 setReferenceBoxForPathOperations();
1364 updateTransformFromStyle(*m_transform, renderer().style(), RenderStyle::allTransformOperations);
1365 }
1366
1367 if (had3DTransform != has3DTransform()) {
1368 dirty3DTransformedDescendantStatus();
1369 // Having a 3D transform affects whether enclosing perspective and preserve-3d layers composite, so trigger an update.
1370 setNeedsPostLayoutCompositingUpdateOnAncestors();
1371 }
1372}
1373
1374TransformationMatrix RenderLayer::currentTransform(OptionSet<RenderStyle::TransformOperationOption> options) const
1375{
1376 if (!m_transform)
1377 return { };
1378
1379 // m_transform includes transform-origin and is affected by the choice of the transform-box.
1380 // Therefore we can only use the cached m_transform, if the animation doesn't alter transform-box or excludes transform-origin.
1381
1382 // Query the animatedStyle() to obtain the current transformation, when accelerated transform animations are running.
1383 auto styleable = Styleable::fromRenderer(renderer());
1384 if ((styleable && styleable->isRunningAcceleratedTransformAnimation()) || !options.contains(RenderStyle::TransformOperationOption::TransformOrigin)) {
1385 std::unique_ptr<RenderStyle> animatedStyle = renderer().animatedStyle();
1386
1387 TransformationMatrix transform;
1388 updateTransformFromStyle(transform, *animatedStyle, options);
1389 return transform;
1390 }
1391
1392 return *m_transform;
1393}
1394
1395TransformationMatrix RenderLayer::renderableTransform(OptionSet<PaintBehavior> paintBehavior) const
1396{
1397 if (!m_transform)
1398 return TransformationMatrix();
1399
1400 if (paintBehavior & PaintBehavior::FlattenCompositingLayers) {
1401 TransformationMatrix matrix = *m_transform;
1402 makeMatrixRenderable(matrix, false /* flatten 3d */);
1403 return matrix;
1404 }
1405
1406 return *m_transform;
1407}
1408
1409RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
1410{
1411 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
1412 while (layer) {
1413 if (layer->renderer().hasPotentiallyScrollableOverflow())
1414 return const_cast<RenderLayer*>(layer);
1415
1416 layer = layer->parent();
1417 }
1418 return nullptr;
1419}
1420
1421// FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
1422// painting of content inside paginated layers.
1423bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
1424{
1425 // No enclosing layer means no compositing in the chain.
1426 if (!m_enclosingPaginationLayer)
1427 return false;
1428
1429 // If the enclosing layer is composited, we don't have to check anything in between us and that
1430 // layer.
1431 if (m_enclosingPaginationLayer->isComposited())
1432 return true;
1433
1434 // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
1435 // previous check.
1436 if (m_enclosingPaginationLayer == this)
1437 return false;
1438
1439 // The enclosing paginated layer is our ancestor and is not composited, so we have to check
1440 // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
1441 if (isComposited())
1442 return true;
1443
1444 // For normal flow layers, we can recur up the layer tree.
1445 if (isNormalFlowOnly())
1446 return parent()->hasCompositedLayerInEnclosingPaginationChain();
1447
1448 // Otherwise we have to go up the containing block chain. Find the first enclosing
1449 // containing block layer ancestor, and check that.
1450 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1451 if (containingBlock->hasLayer())
1452 return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
1453 }
1454 return false;
1455}
1456
1457void RenderLayer::updatePagination()
1458{
1459 m_enclosingPaginationLayer = nullptr;
1460
1461 if (!parent())
1462 return;
1463
1464 // Each layer that is inside a multicolumn flow thread has to be checked individually and
1465 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
1466 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
1467 // to that layer easily.
1468 if (renderer().isRenderFragmentedFlow()) {
1469 m_enclosingPaginationLayer = *this;
1470 return;
1471 }
1472
1473 if (isNormalFlowOnly()) {
1474 // Content inside a transform is not considered to be paginated, since we simply
1475 // paint the transform multiple times in each column, so we don't have to use
1476 // fragments for the transformed content.
1477 if (parent()->hasTransform())
1478 m_enclosingPaginationLayer = nullptr;
1479 else
1480 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1481 return;
1482 }
1483
1484 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
1485 // we find one, then we just check its pagination status.
1486 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1487 if (containingBlock->hasLayer()) {
1488 // Content inside a transform is not considered to be paginated, since we simply
1489 // paint the transform multiple times in each column, so we don't have to use
1490 // fragments for the transformed content.
1491 if (containingBlock->layer()->hasTransform())
1492 m_enclosingPaginationLayer = nullptr;
1493 else
1494 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1495 return;
1496 }
1497 }
1498}
1499
1500void RenderLayer::setHasVisibleContent()
1501{
1502 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1503 ASSERT(!parent() || parent()->hasVisibleDescendant());
1504 return;
1505 }
1506
1507 m_visibleContentStatusDirty = false;
1508 m_hasVisibleContent = true;
1509 computeRepaintRects(renderer().containerForRepaint().renderer);
1510 if (!isNormalFlowOnly()) {
1511 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1512 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1513 // collected. FIXME: When compositing, we could skip this dirtying phase.
1514 for (auto* sc = stackingContext(); sc; sc = sc->stackingContext()) {
1515 sc->dirtyZOrderLists();
1516 if (sc->hasVisibleContent())
1517 break;
1518 }
1519 }
1520
1521 if (parent())
1522 parent()->setAncestorChainHasVisibleDescendant();
1523}
1524
1525void RenderLayer::dirtyVisibleContentStatus()
1526{
1527 m_visibleContentStatusDirty = true;
1528 if (parent())
1529 parent()->dirtyAncestorChainVisibleDescendantStatus();
1530}
1531
1532void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1533{
1534 for (auto* layer = this; layer; layer = layer->parent()) {
1535 if (layer->m_visibleDescendantStatusDirty)
1536 break;
1537
1538 layer->m_visibleDescendantStatusDirty = true;
1539 }
1540}
1541
1542void RenderLayer::setAncestorChainHasVisibleDescendant()
1543{
1544 for (auto* layer = this; layer; layer = layer->parent()) {
1545 if (renderer().shouldApplyPaintContainment()) {
1546 m_hasVisibleDescendant = true;
1547 m_visibleDescendantStatusDirty = false;
1548 break;
1549 }
1550 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1551 break;
1552
1553 layer->m_hasVisibleDescendant = true;
1554 layer->m_visibleDescendantStatusDirty = false;
1555 }
1556}
1557
1558void RenderLayer::updateAncestorDependentState()
1559{
1560 bool insideSVGForeignObject = renderer().document().mayHaveRenderedSVGForeignObjects() && ancestorsOfType<RenderSVGForeignObject>(renderer()).first();
1561 if (insideSVGForeignObject == m_insideSVGForeignObject)
1562 return;
1563
1564 m_insideSVGForeignObject = insideSVGForeignObject;
1565 updateSelfPaintingLayer();
1566}
1567
1568void RenderLayer::updateDescendantDependentFlags()
1569{
1570 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
1571 bool hasVisibleDescendant = false;
1572 bool hasSelfPaintingLayerDescendant = false;
1573#if ENABLE(CSS_COMPOSITING)
1574 bool hasNotIsolatedBlendingDescendants = false;
1575#endif
1576
1577 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1578 child->updateDescendantDependentFlags();
1579
1580 hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1581 hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1582#if ENABLE(CSS_COMPOSITING)
1583 hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
1584#endif
1585
1586 bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant;
1587#if ENABLE(CSS_COMPOSITING)
1588 allFlagsSet &= hasNotIsolatedBlendingDescendants;
1589#endif
1590 if (allFlagsSet)
1591 break;
1592 }
1593
1594 m_hasVisibleDescendant = hasVisibleDescendant;
1595 m_visibleDescendantStatusDirty = false;
1596 m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
1597 m_hasSelfPaintingLayerDescendantDirty = false;
1598
1599#if ENABLE(CSS_COMPOSITING)
1600 m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
1601 if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
1602 m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1603 updateSelfPaintingLayer();
1604 }
1605#endif
1606 }
1607
1608 if (m_visibleContentStatusDirty) {
1609 m_hasVisibleContent = computeHasVisibleContent();
1610 m_visibleContentStatusDirty = false;
1611 }
1612}
1613
1614bool RenderLayer::computeHasVisibleContent() const
1615{
1616 if (renderer().style().visibility() == Visibility::Visible)
1617 return true;
1618
1619 // Layer's renderer has visibility:hidden, but some non-layer child may have visibility:visible.
1620 RenderObject* r = renderer().firstChild();
1621 while (r) {
1622 if (r->style().visibility() == Visibility::Visible && !r->hasLayer())
1623 return true;
1624
1625 RenderObject* child = nullptr;
1626 if (!r->hasLayer() && (child = r->firstChildSlow()))
1627 r = child;
1628 else if (r->nextSibling())
1629 r = r->nextSibling();
1630 else {
1631 do {
1632 r = r->parent();
1633 if (r == &renderer())
1634 r = nullptr;
1635 } while (r && !r->nextSibling());
1636 if (r)
1637 r = r->nextSibling();
1638 }
1639 }
1640
1641 return false;
1642}
1643
1644void RenderLayer::dirty3DTransformedDescendantStatus()
1645{
1646 RenderLayer* curr = stackingContext();
1647 if (curr)
1648 curr->m_3DTransformedDescendantStatusDirty = true;
1649
1650 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1651 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1652 while (curr && curr->preserves3D()) {
1653 curr->m_3DTransformedDescendantStatusDirty = true;
1654 curr = curr->stackingContext();
1655 }
1656}
1657
1658// Return true if this layer or any preserve-3d descendants have 3d.
1659bool RenderLayer::update3DTransformedDescendantStatus()
1660{
1661 if (m_3DTransformedDescendantStatusDirty) {
1662 m_has3DTransformedDescendant = false;
1663
1664 updateZOrderLists();
1665
1666 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1667 // in the normal flow list, so we only need to check those.
1668 for (auto* layer : positiveZOrderLayers())
1669 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1670
1671 // Now check our negative z-index children.
1672 for (auto* layer : negativeZOrderLayers())
1673 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1674
1675 m_3DTransformedDescendantStatusDirty = false;
1676 }
1677
1678 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1679 // the m_has3DTransformedDescendant set.
1680 if (preserves3D())
1681 return has3DTransform() || m_has3DTransformedDescendant;
1682
1683 return has3DTransform();
1684}
1685
1686bool RenderLayer::updateLayerPosition(OptionSet<UpdateLayerPositionsFlag>* flags)
1687{
1688 LayoutPoint localPoint;
1689 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1690 if (renderer().isInline() && is<RenderInline>(renderer())) {
1691 auto& inlineFlow = downcast<RenderInline>(renderer());
1692 IntRect lineBox = inlineFlow.linesBoundingBox();
1693 setSize(lineBox.size());
1694 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1695 localPoint += inlineBoundingBoxOffset;
1696 } else if (RenderBox* box = renderBox()) {
1697 // FIXME: Is snapping the size really needed here for the RenderBox case?
1698 auto newSize = snappedIntRect(box->frameRect()).size();
1699 if (newSize != size()) {
1700 if (is<RenderWidget>(*box) && downcast<RenderWidget>(*box).requiresAcceleratedCompositing()) {
1701 // Trigger RenderLayerCompositor::requiresCompositingForFrame() which depends on the contentBoxRect size.
1702 setNeedsPostLayoutCompositingUpdate();
1703 }
1704
1705 if (flags && renderer().hasNonVisibleOverflow())
1706 flags->add(ContainingClippingLayerChangedSize);
1707
1708 setSize(newSize);
1709 }
1710
1711 box->applyTopLeftLocationOffset(localPoint);
1712#if ENABLE(LAYER_BASED_SVG_ENGINE)
1713 } else if (is<RenderSVGModelObject>(renderer())) {
1714 auto& svgRenderer = downcast<RenderSVGModelObject>(renderer());
1715 auto newSize = enclosingIntRect(svgRenderer.frameRectEquivalent()).size();
1716 if (newSize != size()) {
1717 if (flags && renderer().hasNonVisibleOverflow())
1718 flags->add(ContainingClippingLayerChangedSize);
1719
1720 setSize(newSize);
1721 }
1722
1723 svgRenderer.applyTopLeftLocationOffsetEquivalent(localPoint);
1724#endif
1725 }
1726
1727 if (!renderer().isOutOfFlowPositioned()) {
1728 auto* ancestor = renderer().parent();
1729 // We must adjust our position by walking up the render tree looking for the
1730 // nearest enclosing object with a layer.
1731 while (ancestor && !ancestor->hasLayer()) {
1732 if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
1733 // Rows and cells share the same coordinate space (that of the section).
1734 // Omit them when computing our xpos/ypos.
1735 localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1736 }
1737 ancestor = ancestor->parent();
1738 }
1739 if (is<RenderTableRow>(ancestor)) {
1740 // Put ourselves into the row coordinate space.
1741 localPoint -= downcast<RenderTableRow>(*ancestor).topLeftLocationOffset();
1742 }
1743 }
1744
1745 // Subtract our parent's scroll offset.
1746 RenderLayer* positionedParent;
1747 if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
1748 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1749 if (positionedParent->renderer().hasNonVisibleOverflow()) {
1750 if (auto* positionedParentScrollableArea = positionedParent->scrollableArea())
1751 localPoint -= toLayoutSize(positionedParentScrollableArea->scrollPosition());
1752 }
1753
1754 if (positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
1755 LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
1756 localPoint += offset;
1757 }
1758
1759 ASSERT(positionedParent->contentsScrollingScope());
1760 m_boxScrollingScope = positionedParent->contentsScrollingScope();
1761 } else if (auto* parentLayer = parent()) {
1762 if (parentLayer->renderer().hasNonVisibleOverflow()) {
1763 if (auto* parentLayerScrollableArea = parentLayer->scrollableArea())
1764 localPoint -= toLayoutSize(parentLayerScrollableArea->scrollPosition());
1765 }
1766
1767 ASSERT(parentLayer->contentsScrollingScope());
1768 m_boxScrollingScope = parentLayer->contentsScrollingScope();
1769 }
1770
1771 if (hasCompositedScrollableOverflow()) {
1772 if (!m_contentsScrollingScope || m_contentsScrollingScope == m_boxScrollingScope)
1773 m_contentsScrollingScope = nextScrollingScope();
1774 } else if (!m_contentsScrollingScope || m_contentsScrollingScope != m_boxScrollingScope)
1775 m_contentsScrollingScope = m_boxScrollingScope;
1776
1777 bool positionOrOffsetChanged = false;
1778 if (renderer().isInFlowPositioned()) {
1779 LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
1780 positionOrOffsetChanged = newOffset != m_offsetForPosition;
1781 m_offsetForPosition = newOffset;
1782 localPoint.move(m_offsetForPosition);
1783 }
1784
1785 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1786 localPoint -= inlineBoundingBoxOffset;
1787
1788 positionOrOffsetChanged |= location() != localPoint;
1789 setLocation(localPoint);
1790
1791 if (positionOrOffsetChanged && compositor().hasContentCompositingLayers()) {
1792 if (isComposited())
1793 setNeedsCompositingGeometryUpdate();
1794 // This layer's position can affect the location of a composited descendant (which may be a sibling in z-order),
1795 // so trigger a descendant walk from the paint-order parent.
1796 if (auto* paintParent = paintOrderParent())
1797 paintParent->setDescendantsNeedUpdateBackingAndHierarchyTraversal();
1798 }
1799
1800 return positionOrOffsetChanged;
1801}
1802
1803TransformationMatrix RenderLayer::perspectiveTransform() const
1804{
1805 if (!renderer().hasTransformRelatedProperty())
1806 return { };
1807
1808 const auto& style = renderer().style();
1809 if (!style.hasPerspective())
1810 return { };
1811
1812 auto transformReferenceBoxRect = snapRectToDevicePixelsIfNeeded(renderer().transformReferenceBoxRect(style), renderer());
1813 auto perspectiveOrigin = style.computePerspectiveOrigin(transformReferenceBoxRect);
1814
1815 // In the regular case of a non-clipped, non-scrolled GraphicsLayer, all transformations
1816 // (via CSS 'transform' / 'perspective') are applied with respect to a predefined anchor point,
1817 // which depends on the chosen CSS 'transform-box' / 'transform-origin' properties.
1818 //
1819 // A transformation given by the CSS 'transform' property is applied, by translating
1820 // to the 'transform origin', applying the transformation, and translating back.
1821 // When an element specifies a CSS 'perspective' property, the perspective transformation matrix
1822 // that's computed here is propagated to the GraphicsLayer by calling setChildrenTransform().
1823 //
1824 // However the GraphicsLayer platform implementations (e.g. CA on macOS) apply the children transform,
1825 // defined on the parent, with respect to the anchor point of the parent, when rendering child elements.
1826 // This is wrong, as the perspective transformation (applied to a child of the element defining the
1827 // 3d effect), must be independant of the chosen transform-origin (the parents transform origin
1828 // must not affect its children).
1829 //
1830 // To circumvent this, explicitely remove the transform-origin dependency in the perspective matrix.
1831 auto transformOrigin = transformOriginPixelSnappedIfNeeded();
1832
1833 TransformationMatrix transform;
1834 style.unapplyTransformOrigin(transform, transformOrigin);
1835 style.applyPerspective(transform, renderer(), perspectiveOrigin);
1836 style.applyTransformOrigin(transform, transformOrigin);
1837 return transform;
1838}
1839
1840FloatPoint3D RenderLayer::transformOriginPixelSnappedIfNeeded() const
1841{
1842 if (!renderer().hasTransformRelatedProperty())
1843 return { };
1844
1845 const auto& style = renderer().style();
1846 auto referenceBoxRect = renderer().transformReferenceBoxRect(style);
1847
1848 auto origin = style.computeTransformOrigin(referenceBoxRect);
1849 if (rendererNeedsPixelSnapping(renderer()))
1850 origin.setXY(roundPointToDevicePixels(LayoutPoint(origin.xy()), renderer().document().deviceScaleFactor()));
1851 return origin;
1852}
1853
1854FloatPoint RenderLayer::perspectiveOrigin() const
1855{
1856 if (!renderer().hasTransformRelatedProperty())
1857 return { };
1858 return floatPointForLengthPoint(renderer().style().perspectiveOrigin(), renderer().transformReferenceBoxRect(renderer().style()).size());
1859}
1860
1861static inline bool isContainerForPositioned(RenderLayer& layer, PositionType position, bool establishesTopLayer)
1862{
1863 if (establishesTopLayer)
1864 return layer.isRenderViewLayer();
1865
1866 switch (position) {
1867 case PositionType::Fixed:
1868 return layer.renderer().canContainFixedPositionObjects();
1869
1870 case PositionType::Absolute:
1871 return layer.renderer().canContainAbsolutelyPositionedObjects();
1872
1873 default:
1874 ASSERT_NOT_REACHED();
1875 return false;
1876 }
1877}
1878
1879bool RenderLayer::ancestorLayerIsInContainingBlockChain(const RenderLayer& ancestor, const RenderLayer* checkLimit) const
1880{
1881 if (&ancestor == this)
1882 return true;
1883
1884 for (const auto* currentBlock = renderer().containingBlock(); currentBlock && !is<RenderView>(*currentBlock); currentBlock = currentBlock->containingBlock()) {
1885 auto* currLayer = currentBlock->layer();
1886 if (currLayer == &ancestor)
1887 return true;
1888
1889 if (currLayer && currLayer == checkLimit)
1890 return false;
1891 }
1892
1893 return false;
1894}
1895
1896RenderLayer* RenderLayer::enclosingAncestorForPosition(PositionType position) const
1897{
1898 auto* curr = parent();
1899 while (curr && !isContainerForPositioned(*curr, position, establishesTopLayer()))
1900 curr = curr->parent();
1901
1902 ASSERT_IMPLIES(establishesTopLayer(), !curr || curr == renderer().view().layer());
1903 return curr;
1904}
1905
1906RenderLayer* RenderLayer::enclosingLayerInContainingBlockOrder() const
1907{
1908 for (const auto* currentBlock = renderer().containingBlock(); currentBlock; currentBlock = currentBlock->containingBlock()) {
1909 if (auto* layer = currentBlock->layer())
1910 return layer;
1911 }
1912
1913 return nullptr;
1914}
1915
1916RenderLayer* RenderLayer::enclosingFrameRenderLayer() const
1917{
1918 auto* ownerElement = renderer().document().ownerElement();
1919 if (!ownerElement)
1920 return nullptr;
1921
1922 auto* ownerRenderer = ownerElement->renderer();
1923 if (!ownerRenderer)
1924 return nullptr;
1925
1926 return ownerRenderer->enclosingLayer();
1927}
1928
1929RenderLayer* RenderLayer::enclosingContainingBlockLayer(CrossFrameBoundaries crossFrameBoundaries) const
1930{
1931 if (auto* ancestor = enclosingLayerInContainingBlockOrder())
1932 return ancestor;
1933
1934 if (crossFrameBoundaries == CrossFrameBoundaries::No)
1935 return nullptr;
1936
1937 return enclosingFrameRenderLayer();
1938}
1939
1940RenderLayer* RenderLayer::enclosingScrollableLayer(IncludeSelfOrNot includeSelf, CrossFrameBoundaries crossFrameBoundaries) const
1941{
1942 RenderTreeMutationDisallowedScope renderTreeMutationDisallowedScope;
1943
1944 auto isConsideredScrollable = [](const RenderLayer& layer) {
1945 return is<RenderBox>(layer.renderer()) && downcast<RenderBox>(layer.renderer()).canBeScrolledAndHasScrollableArea();
1946 };
1947
1948 if (includeSelf == IncludeSelfOrNot::IncludeSelf && isConsideredScrollable(*this))
1949 return const_cast<RenderLayer*>(this);
1950
1951 for (auto* nextLayer = enclosingContainingBlockLayer(crossFrameBoundaries); nextLayer; nextLayer = nextLayer->enclosingContainingBlockLayer(crossFrameBoundaries)) {
1952 if (isConsideredScrollable(*nextLayer))
1953 return nextLayer;
1954 }
1955
1956 return nullptr;
1957}
1958
1959RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1960{
1961 RenderLayer* curr = parent();
1962 while (curr && !curr->isRenderViewLayer() && !curr->transform())
1963 curr = curr->parent();
1964
1965 return curr;
1966}
1967
1968inline bool RenderLayer::shouldRepaintAfterLayout() const
1969{
1970#if ENABLE(LAYER_BASED_SVG_ENGINE)
1971 // The SVG containers themselves never trigger repaints, only their contents are allowed to.
1972 // SVG container sizes/positions are only ever determined by their children, so they will
1973 // change as a reaction on a re-position/re-sizing of the children - which already properly
1974 // trigger repaints.
1975 if (is<RenderSVGContainer>(renderer()) && !paintsWithFilters())
1976 return false;
1977#endif
1978
1979 if (m_repaintStatus == NeedsNormalRepaint)
1980 return true;
1981
1982 // Composited layers that were moved during a positioned movement only
1983 // layout, don't need to be repainted. They just need to be recomposited.
1984 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1985 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1986}
1987
1988void RenderLayer::setBackingProviderLayer(RenderLayer* backingProvider)
1989{
1990 if (backingProvider == m_backingProviderLayer)
1991 return;
1992
1993 if (!renderer().renderTreeBeingDestroyed())
1994 clearClipRectsIncludingDescendants();
1995
1996 m_backingProviderLayer = backingProvider;
1997}
1998
1999void RenderLayer::disconnectFromBackingProviderLayer()
2000{
2001 if (!m_backingProviderLayer)
2002 return;
2003
2004 ASSERT(m_backingProviderLayer->isComposited());
2005 if (m_backingProviderLayer->isComposited())
2006 m_backingProviderLayer->backing()->removeBackingSharingLayer(*this);
2007}
2008
2009bool compositedWithOwnBackingStore(const RenderLayer& layer)
2010{
2011 return layer.isComposited() && !layer.backing()->paintsIntoCompositedAncestor();
2012}
2013
2014RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
2015{
2016 if (includeSelf == IncludeSelf && isComposited())
2017 return const_cast<RenderLayer*>(this);
2018
2019 for (const RenderLayer* curr = paintOrderParent(); curr; curr = curr->paintOrderParent()) {
2020 if (curr->isComposited())
2021 return const_cast<RenderLayer*>(curr);
2022 }
2023
2024 return nullptr;
2025}
2026
2027RenderLayer::EnclosingCompositingLayerStatus RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
2028{
2029 auto repaintTargetForLayer = [](const RenderLayer& layer) -> RenderLayer* {
2030 if (compositedWithOwnBackingStore(layer))
2031 return const_cast<RenderLayer*>(&layer);
2032
2033 if (layer.paintsIntoProvidedBacking())
2034 return layer.backingProviderLayer();
2035
2036 return nullptr;
2037 };
2038 auto isEligibleForFullRepaintCheck = [&](const auto& layer) {
2039 return layer.isSelfPaintingLayer() && !layer.renderer().hasPotentiallyScrollableOverflow() && !is<RenderView>(layer.renderer());
2040 };
2041
2042 auto fullRepaintAlreadyScheduled = isEligibleForFullRepaintCheck(*this) && needsFullRepaint();
2043 RenderLayer* repaintTarget = nullptr;
2044 if (includeSelf == IncludeSelf && (repaintTarget = repaintTargetForLayer(*this)))
2045 return { fullRepaintAlreadyScheduled, repaintTarget };
2046
2047 for (const RenderLayer* curr = paintOrderParent(); curr; curr = curr->paintOrderParent()) {
2048 fullRepaintAlreadyScheduled = fullRepaintAlreadyScheduled || (isEligibleForFullRepaintCheck(*curr) && curr->needsFullRepaint());
2049 if ((repaintTarget = repaintTargetForLayer(*curr)))
2050 return { fullRepaintAlreadyScheduled, repaintTarget };
2051 }
2052
2053 return { };
2054}
2055
2056RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
2057{
2058 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
2059 for (; curr; curr = curr->parent()) {
2060 if (curr->requiresFullLayerImageForFilters())
2061 return const_cast<RenderLayer*>(curr);
2062 }
2063
2064 return nullptr;
2065}
2066
2067RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
2068{
2069 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
2070 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(*curr) || curr->isRenderViewLayer())
2071 return const_cast<RenderLayer*>(curr);
2072 }
2073 return nullptr;
2074}
2075
2076// FIXME: This needs a better name.
2077void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
2078{
2079 ASSERT(requiresFullLayerImageForFilters());
2080 ASSERT(m_filters);
2081
2082 if (rect.isEmpty())
2083 return;
2084
2085 LayoutRect rectForRepaint = rect;
2086 rectForRepaint.expand(toLayoutBoxExtent(filterOutsets()));
2087
2088 m_filters->expandDirtySourceRect(rectForRepaint);
2089
2090 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
2091 ASSERT(parentLayer);
2092 FloatQuad repaintQuad(rectForRepaint);
2093 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
2094
2095 if (parentLayer->isComposited()) {
2096 if (!parentLayer->backing()->paintsIntoWindow()) {
2097 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
2098 return;
2099 }
2100 // If the painting goes to window, redirect the painting to the parent RenderView.
2101 parentLayer = renderer().view().layer();
2102 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
2103 }
2104
2105 if (parentLayer->paintsWithFilters()) {
2106 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
2107 return;
2108 }
2109
2110 if (parentLayer->isRenderViewLayer()) {
2111 downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
2112 return;
2113 }
2114
2115 ASSERT_NOT_REACHED();
2116}
2117
2118bool RenderLayer::hasAncestorWithFilterOutsets() const
2119{
2120 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
2121 if (curr->hasFilterOutsets())
2122 return true;
2123 }
2124 return false;
2125}
2126
2127RenderLayer* RenderLayer::clippingRootForPainting() const
2128{
2129 if (isComposited())
2130 return const_cast<RenderLayer*>(this);
2131
2132 if (paintsIntoProvidedBacking())
2133 return backingProviderLayer();
2134
2135 const RenderLayer* current = this;
2136 while (current) {
2137 if (current->isRenderViewLayer())
2138 return const_cast<RenderLayer*>(current);
2139
2140 current = current->paintOrderParent();
2141 ASSERT(current);
2142 if (current->transform() || compositedWithOwnBackingStore(*current))
2143 return const_cast<RenderLayer*>(current);
2144
2145 if (current->paintsIntoProvidedBacking())
2146 return current->backingProviderLayer();
2147 }
2148
2149 ASSERT_NOT_REACHED();
2150 return nullptr;
2151}
2152
2153LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
2154{
2155 // We don't use convertToLayerCoords because it doesn't know about transforms
2156 return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
2157}
2158
2159bool RenderLayer::cannotBlitToWindow() const
2160{
2161 if (isTransparent() || hasReflection() || hasTransform())
2162 return true;
2163 if (!parent())
2164 return false;
2165 return parent()->cannotBlitToWindow();
2166}
2167
2168RenderLayer* RenderLayer::transparentPaintingAncestor()
2169{
2170 if (isComposited())
2171 return nullptr;
2172
2173 for (RenderLayer* curr = stackingContext(); curr; curr = curr->stackingContext()) {
2174 if (curr->isComposited())
2175 break;
2176 if (curr->isTransparent())
2177 return curr;
2178 }
2179 return nullptr;
2180}
2181
2182enum TransparencyClipBoxBehavior {
2183 PaintingTransparencyClipBox,
2184 HitTestingTransparencyClipBox
2185};
2186
2187enum TransparencyClipBoxMode {
2188 DescendantsOfTransparencyClipBox,
2189 RootOfTransparencyClipBox
2190};
2191
2192static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, OptionSet<PaintBehavior> = { });
2193
2194static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
2195 TransparencyClipBoxBehavior transparencyBehavior, OptionSet<PaintBehavior> paintBehavior)
2196{
2197 // If we have a mask, then the clip is limited to the border box area (and there is
2198 // no need to examine child layers).
2199 if (!layer.renderer().hasMask()) {
2200 // Note: we don't have to walk z-order lists since transparent elements always establish
2201 // a stacking container. This means we can just walk the layer tree directly.
2202 for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
2203 if (!layer.isReflectionLayer(*curr))
2204 clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
2205 }
2206 }
2207
2208 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
2209 // current transparencyClipBox to catch all child layers.
2210 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
2211 // size into the parent layer.
2212 if (layer.renderer().hasReflection()) {
2213 LayoutSize delta = layer.offsetFromAncestor(rootLayer);
2214 clipRect.move(-delta);
2215 clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
2216 clipRect.move(delta);
2217 }
2218}
2219
2220static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
2221 TransparencyClipBoxMode transparencyMode, OptionSet<PaintBehavior> paintBehavior)
2222{
2223 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
2224 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
2225 // would be better to respect clips.
2226
2227 if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
2228 || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
2229 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
2230 // the transformed layer and all of its children.
2231 RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
2232 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : nullptr;
2233 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
2234 LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
2235
2236 TransformationMatrix transform;
2237 transform.translate(delta.width(), delta.height());
2238 transform.multiply(*layer.transform());
2239
2240 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
2241 // paints unfragmented.
2242 LayoutRect clipRect = layer.boundingBox(&layer);
2243 expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
2244 clipRect.expand(toLayoutBoxExtent(layer.filterOutsets()));
2245 LayoutRect result = transform.mapRect(clipRect);
2246 if (!paginationLayer)
2247 return result;
2248
2249 // We have to break up the transformed extent across our columns.
2250 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
2251 // get our true bounding box.
2252 auto& enclosingFragmentedFlow = downcast<RenderFragmentedFlow>(paginationLayer->renderer());
2253 result = enclosingFragmentedFlow.fragmentsBoundingBox(result);
2254 result.move(paginationLayer->offsetFromAncestor(rootLayer));
2255 return result;
2256 }
2257
2258 LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
2259 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
2260 clipRect.expand(toLayoutBoxExtent(layer.filterOutsets()));
2261
2262 return clipRect;
2263}
2264
2265static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, OptionSet<PaintBehavior> paintBehavior)
2266{
2267 return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
2268}
2269
2270void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
2271{
2272 if (context.paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
2273 return;
2274
2275 RenderLayer* ancestor = transparentPaintingAncestor();
2276 if (ancestor)
2277 ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
2278
2279 if (paintsWithTransparency(paintingInfo.paintBehavior)) {
2280 ASSERT(isCSSStackingContext());
2281 m_usedTransparency = true;
2282 context.save();
2283 LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
2284 adjustedClipRect.move(paintingInfo.subpixelOffset);
2285 FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
2286 context.clip(pixelSnappedClipRect);
2287
2288#if ENABLE(CSS_COMPOSITING)
2289 bool usesCompositeOperation = hasBlendMode() && !(renderer().isLegacySVGRoot() && parent() && parent()->isRenderViewLayer());
2290 if (usesCompositeOperation)
2291 context.setCompositeOperation(context.compositeOperation(), blendMode());
2292#endif
2293
2294 context.beginTransparencyLayer(renderer().opacity());
2295
2296#if ENABLE(CSS_COMPOSITING)
2297 if (usesCompositeOperation)
2298 context.setCompositeOperation(context.compositeOperation(), BlendMode::Normal);
2299#endif
2300
2301#ifdef REVEAL_TRANSPARENCY_LAYERS
2302 context.setFillColor(SRGBA<uint8_t> { 0, 0, 128, 51 });
2303 context.fillRect(pixelSnappedClipRect);
2304#endif
2305 }
2306}
2307
2308#if PLATFORM(IOS_FAMILY)
2309void RenderLayer::willBeDestroyed()
2310{
2311 if (RenderLayerBacking* layerBacking = backing())
2312 layerBacking->layerWillBeDestroyed();
2313}
2314#endif
2315
2316bool RenderLayer::isDescendantOf(const RenderLayer& layer) const
2317{
2318 for (auto* ancestor = this; ancestor; ancestor = ancestor->parent()) {
2319 if (&layer == ancestor)
2320 return true;
2321 }
2322 return false;
2323}
2324
2325static RenderLayer* findCommonAncestor(const RenderLayer& firstLayer, const RenderLayer& secondLayer)
2326{
2327 if (&firstLayer == &secondLayer)
2328 return const_cast<RenderLayer*>(&firstLayer);
2329
2330 HashSet<const RenderLayer*> ancestorChain;
2331 for (auto* currLayer = &firstLayer; currLayer; currLayer = currLayer->parent())
2332 ancestorChain.add(currLayer);
2333
2334 for (auto* currLayer = &secondLayer; currLayer; currLayer = currLayer->parent()) {
2335 if (ancestorChain.contains(currLayer))
2336 return const_cast<RenderLayer*>(currLayer);
2337 }
2338 return nullptr;
2339}
2340
2341RenderLayer* RenderLayer::commonAncestorWithLayer(const RenderLayer& layer) const
2342{
2343 return findCommonAncestor(*this, layer);
2344}
2345
2346void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
2347{
2348 LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
2349 roundedLocation = roundedIntPoint(location);
2350}
2351
2352// Returns the layer reached on the walk up towards the ancestor.
2353static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
2354{
2355 ASSERT(ancestorLayer != layer);
2356
2357 const RenderLayerModelObject& renderer = layer->renderer();
2358 auto position = renderer.style().position();
2359
2360 // FIXME: Special casing RenderFragmentedFlow so much for fixed positioning here is not great.
2361 RenderFragmentedFlow* fixedFragmentedFlowContainer = position == PositionType::Fixed ? renderer.enclosingFragmentedFlow() : nullptr;
2362 if (fixedFragmentedFlowContainer && !fixedFragmentedFlowContainer->isOutOfFlowPositioned())
2363 fixedFragmentedFlowContainer = nullptr;
2364
2365 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFragmentedFlow
2366 // may need to be revisited in a future patch.
2367 // If the fixed renderer is inside a RenderFragmentedFlow, we should not compute location using localToAbsolute,
2368 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
2369 // positioned in a completely different place in the viewport (RenderView).
2370 if (position == PositionType::Fixed && !fixedFragmentedFlowContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
2371 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
2372 // localToAbsolute() on the RenderView.
2373 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
2374 location += LayoutSize(absPos.x(), absPos.y());
2375 return ancestorLayer;
2376 }
2377
2378 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
2379 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
2380 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
2381 if (position == PositionType::Fixed && !fixedFragmentedFlowContainer) {
2382 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
2383 // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
2384 // so we should always find the ancestor at or before we find the fixed position container.
2385 RenderLayer* fixedPositionContainerLayer = nullptr;
2386 bool foundAncestor = false;
2387 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
2388 if (currLayer == ancestorLayer)
2389 foundAncestor = true;
2390
2391 if (isContainerForPositioned(*currLayer, PositionType::Fixed, layer->establishesTopLayer())) {
2392 fixedPositionContainerLayer = currLayer;
2393 ASSERT_UNUSED(foundAncestor, foundAncestor);
2394 break;
2395 }
2396 }
2397
2398 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
2399
2400 if (fixedPositionContainerLayer != ancestorLayer) {
2401 LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
2402 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
2403 location += (fixedContainerCoords - ancestorCoords);
2404 return ancestorLayer;
2405 }
2406 }
2407
2408 if (position == PositionType::Fixed && fixedFragmentedFlowContainer) {
2409 ASSERT(ancestorLayer);
2410 if (ancestorLayer == renderer.view().layer()) {
2411 // Add location in flow thread coordinates.
2412 location += toLayoutSize(layer->location());
2413
2414 // Add flow thread offset in view coordinates since the view may be scrolled.
2415 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
2416 location += LayoutSize(absPos.x(), absPos.y());
2417 return ancestorLayer;
2418 }
2419 }
2420
2421 RenderLayer* parentLayer;
2422 if (position == PositionType::Absolute || position == PositionType::Fixed) {
2423 // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
2424 parentLayer = layer->parent();
2425 bool foundAncestorFirst = false;
2426 while (parentLayer) {
2427 // RenderFragmentedFlow is a positioned container, child of RenderView, positioned at (0,0).
2428 // This implies that, for out-of-flow positioned elements inside a RenderFragmentedFlow,
2429 // we are bailing out before reaching root layer.
2430 if (isContainerForPositioned(*parentLayer, position, layer->establishesTopLayer()))
2431 break;
2432
2433 if (parentLayer == ancestorLayer) {
2434 foundAncestorFirst = true;
2435 break;
2436 }
2437
2438 parentLayer = parentLayer->parent();
2439 }
2440
2441 // We should not reach RenderView layer past the RenderFragmentedFlow layer for any
2442 // children of the RenderFragmentedFlow.
2443 if (renderer.enclosingFragmentedFlow())
2444 ASSERT(parentLayer != renderer.view().layer());
2445
2446 if (foundAncestorFirst) {
2447 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
2448 // to enclosingAncestorForPosition and subtract.
2449 RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
2450 LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
2451 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
2452 location += (thisCoords - ancestorCoords);
2453 return ancestorLayer;
2454 }
2455 } else
2456 parentLayer = layer->parent();
2457
2458 if (!parentLayer)
2459 return nullptr;
2460
2461 location += toLayoutSize(layer->location());
2462
2463 if (adjustForColumns == RenderLayer::AdjustForColumns) {
2464 auto* parentLayer = layer->parent();
2465 if (parentLayer && parentLayer != ancestorLayer) {
2466 if (is<RenderMultiColumnFlow>(parentLayer->renderer())) {
2467 if (auto* fragment = downcast<RenderMultiColumnFlow>(parentLayer->renderer()).physicalTranslationFromFlowToFragment(location))
2468 location.moveBy(fragment->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2469 }
2470 }
2471 }
2472
2473 return parentLayer;
2474}
2475
2476LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2477{
2478 if (ancestorLayer == this)
2479 return location;
2480
2481 const RenderLayer* currLayer = this;
2482 LayoutPoint locationInLayerCoords = location;
2483 while (currLayer && currLayer != ancestorLayer)
2484 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
2485 return locationInLayerCoords;
2486}
2487
2488LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer, ColumnOffsetAdjustment adjustForColumns) const
2489{
2490 return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint(), adjustForColumns));
2491}
2492
2493static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)
2494{
2495 // If scrollbars aren't explicitly forbidden, permit scrolling.
2496 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarMode::AlwaysOff)
2497 return true;
2498
2499 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2500 if (frameView.wasScrolledByUser())
2501 return false;
2502
2503 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2504 // like navigation to an anchor.
2505 return !frameView.frame().eventHandler().autoscrollInProgress();
2506}
2507
2508bool RenderLayer::allowsCurrentScroll() const
2509{
2510 if (!renderer().hasNonVisibleOverflow())
2511 return false;
2512
2513 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2514 // FIXME: Is this still needed? It used to be relevant for Safari RSS.
2515 if (renderer().parent() && !renderer().parent()->style().lineClamp().isNone())
2516 return false;
2517
2518 // Only boxes can have overflowClip set.
2519 auto& box = *renderBox();
2520
2521 if (box.frame().eventHandler().autoscrollInProgress()) {
2522 // The "programmatically" here is misleading; this asks whether the box has scrollable overflow,
2523 // or is a special case like a form control.
2524 return box.canBeProgramaticallyScrolled();
2525 }
2526
2527 // Programmatic scrolls can scroll overflow: hidden but not overflow: clip.
2528 return box.hasPotentiallyScrollableOverflow() && (box.hasHorizontalOverflow() || box.hasVerticalOverflow());
2529}
2530
2531void RenderLayer::scrollRectToVisible(const LayoutRect& absoluteRect, bool insideFixed, const ScrollRectToVisibleOptions& options)
2532{
2533 LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << absoluteRect);
2534
2535 LayoutRect newRect = absoluteRect;
2536 FrameView& frameView = renderer().view().frameView();
2537 auto* parentLayer = enclosingContainingBlockLayer(CrossFrameBoundaries::No);
2538
2539 auto scrollPositionChangeOptionsForElement = [this, options](Element* element)
2540 {
2541 auto scrollPositionOptions = ScrollPositionChangeOptions::createProgrammatic();
2542 if (!renderer().frame().eventHandler().autoscrollInProgress() && element && useSmoothScrolling(options.behavior, element))
2543 scrollPositionOptions.animated = ScrollIsAnimated::Yes;
2544 return scrollPositionOptions;
2545 };
2546
2547 if (allowsCurrentScroll()) {
2548 auto* scrollableArea = ensureLayerScrollableArea();
2549
2550 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2551 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2552 RenderBox* box = renderBox();
2553 ASSERT(box);
2554 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
2555
2556 // localExposedRect is now the absolute rect in local coordinates, but relative to the
2557 // border edge. Make the rectangle relative to the scrollable area.
2558 localExposeRect.moveBy(-LayoutPoint(box->borderLeft(), box->borderTop()));
2559
2560 if (box->shouldPlaceVerticalScrollbarOnLeft()) {
2561 // For `direction: rtl; writing-mode: horizontal-{tb,bt}` and `writing-mode: vertical-rl`
2562 // boxes, the scroll bar is on the left side. The visible rect starts from the right side
2563 // of the scroll bar. So the x of localExposeRect should start from the same position too.
2564 localExposeRect.moveBy(LayoutPoint(-scrollableArea->verticalScrollbarWidth(), 0));
2565 }
2566 LayoutRect layerBounds(0_lu, 0_lu, box->clientWidth(), box->clientHeight());
2567 expandScrollRectToVisibleTargetRectToIncludeScrollPadding(box, layerBounds, localExposeRect);
2568 LayoutRect revealRect = getRectToExpose(layerBounds, localExposeRect, insideFixed, options.alignX, options.alignY);
2569
2570 if (auto result = scrollableArea->updateScrollPosition(scrollPositionChangeOptionsForElement(box->element()), revealRect, localExposeRect))
2571 newRect = result.value();
2572 } else if (!parentLayer) {
2573 HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
2574
2575 if (ownerElement && ownerElement->renderer()) {
2576 HTMLFrameElementBase* frameElementBase = nullptr;
2577
2578 if (is<HTMLFrameElementBase>(*ownerElement))
2579 frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
2580
2581 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
2582 // If this assertion fires we need to protect the ownerElement from being destroyed.
2583 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
2584
2585 LayoutRect viewRect = frameView.visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
2586
2587 auto* element = ownerElement->contentDocument() ? ownerElement->contentDocument()->documentElement() : nullptr;
2588 RenderBox* renderer = element ? element->renderBox() : nullptr;
2589 expandScrollRectToVisibleTargetRectToIncludeScrollPadding(renderer, viewRect, newRect);
2590
2591 LayoutRect exposeRect = getRectToExpose(viewRect, newRect, insideFixed, options.alignX, options.alignY);
2592 auto scrollPosition = roundedIntPoint(exposeRect.location());
2593
2594 scrollPosition = frameView.constrainedScrollPosition(scrollPosition);
2595
2596 // FIXME: Should we use contentDocument()->scrollingElement()?
2597 // See https://bugs.webkit.org/show_bug.cgi?id=205059
2598 frameView.setScrollPosition(scrollPosition, scrollPositionChangeOptionsForElement(element));
2599
2600 if (options.shouldAllowCrossOriginScrolling == ShouldAllowCrossOriginScrolling::Yes || frameView.safeToPropagateScrollToParent()) {
2601 if (auto* enclosingLayer = ownerElement->renderer()->enclosingLayer())
2602 parentLayer = enclosingLayer->enclosingScrollableLayer(IncludeSelfOrNot::IncludeSelf, CrossFrameBoundaries::No);
2603 // Convert the rect into the coordinate space of the parent frame's document.
2604 newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
2605 insideFixed = false; // FIXME: ideally need to determine if this <iframe> is inside position:fixed.
2606 } else
2607 parentLayer = nullptr;
2608 }
2609 } else {
2610 if (options.revealMode == SelectionRevealMode::RevealUpToMainFrame && frameView.frame().isMainFrame())
2611 return;
2612
2613 if (options.revealMode == SelectionRevealMode::DelegateMainFrameScroll && frameView.frame().isMainFrame()) {
2614 page().chrome().scrollMainFrameToRevealRect(snappedIntRect(absoluteRect));
2615 return;
2616 }
2617
2618 auto minScrollPosition = frameView.minimumScrollPosition();
2619 auto maxScrollPosition = frameView.maximumScrollPosition();
2620
2621#if !PLATFORM(IOS_FAMILY)
2622 LayoutRect viewRect = frameView.visibleContentRect();
2623#else
2624 // FIXME: ContentInsets should be taken care of in UI process side. webkit.org/b/199682
2625 // To do that, getRectToExpose needs to return the additional scrolling to do beyond content rect.
2626 LayoutRect viewRect = frameView.viewRectExpandedByContentInsets();
2627
2628 // FIXME: webkit.org/b/199683 FrameView::visibleContentRect is wrong when content insets are present
2629 maxScrollPosition = frameView.scrollPositionFromOffset(ScrollPosition(frameView.totalContentsSize() - flooredIntSize(viewRect.size())));
2630
2631 auto contentInsets = page().contentInsets();
2632 minScrollPosition.move(-contentInsets.left(), -contentInsets.top());
2633 maxScrollPosition.move(contentInsets.right(), contentInsets.bottom());
2634#endif
2635 // Move the target rect into "scrollView contents" coordinates.
2636 LayoutRect targetRect = absoluteRect;
2637 targetRect.move(0, frameView.headerHeight());
2638
2639 auto* element = frameView.frame().document() ? frameView.frame().document()->documentElement() : nullptr;
2640 RenderBox* renderer = element ? element->renderBox() : nullptr;
2641 expandScrollRectToVisibleTargetRectToIncludeScrollPadding(renderer, viewRect, targetRect);
2642
2643 LayoutRect revealRect = getRectToExpose(viewRect, targetRect, insideFixed, options.alignX, options.alignY);
2644 // Avoid scrolling to the rounded value of revealRect.location() if we don't actually need to scroll
2645 if (revealRect != viewRect) {
2646 // FIXME: Should we use document()->scrollingElement()?
2647 // See https://bugs.webkit.org/show_bug.cgi?id=205059
2648 ScrollOffset clampedScrollPosition = roundedIntPoint(revealRect.location()).constrainedBetween(minScrollPosition, maxScrollPosition);
2649 frameView.setScrollPosition(clampedScrollPosition, scrollPositionChangeOptionsForElement(element));
2650 }
2651
2652 // This is the outermost view of a web page, so after scrolling this view we
2653 // scroll its container by calling Page::scrollMainFrameToRevealRect.
2654 // This only has an effect on the Mac platform in applications
2655 // that put web views into scrolling containers, such as Mac OS X Mail.
2656 // The canAutoscroll function in EventHandler also knows about this.
2657 page().chrome().scrollContainingScrollViewsToRevealRect(snappedIntRect(absoluteRect));
2658 }
2659 }
2660
2661 if (parentLayer)
2662 parentLayer->scrollRectToVisible(newRect, insideFixed, options);
2663}
2664
2665LayoutRect RenderLayer::getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY) const
2666{
2667 FrameView& frameView = renderer().view().frameView();
2668 if (renderer().isRenderView() && insideFixed) {
2669 // If the element is inside position:fixed and we're not scaled, no amount of scrolling is going to move things around.
2670 if (frameView.frameScaleFactor() == 1)
2671 return visibleRect;
2672
2673 if (renderer().settings().visualViewportEnabled()) {
2674 // exposeRect is in absolute coords, affected by page scale. Unscale it.
2675 LayoutRect unscaledExposeRect = exposeRect;
2676 unscaledExposeRect.scale(1 / frameView.frameScaleFactor());
2677 unscaledExposeRect.move(0, -frameView.headerHeight());
2678
2679 // These are both in unscaled coordinates.
2680 LayoutRect layoutViewport = frameView.layoutViewportRect();
2681 LayoutRect visualViewport = frameView.visualViewportRect();
2682
2683 // The rect to expose may be partially offscreen, which we can't do anything about with position:fixed.
2684 unscaledExposeRect.intersect(layoutViewport);
2685 // Make sure it's not larger than the visual viewport; if so, we'll just move to the top left.
2686 unscaledExposeRect.setSize(unscaledExposeRect.size().shrunkTo(visualViewport.size()));
2687
2688 // Compute how much we have to move the visualViewport to reveal the part of the layoutViewport that contains exposeRect.
2689 LayoutRect requiredVisualViewport = getRectToExpose(visualViewport, unscaledExposeRect, false, alignX, alignY);
2690 // Scale it back up.
2691 requiredVisualViewport.scale(frameView.frameScaleFactor());
2692 requiredVisualViewport.move(0, frameView.headerHeight());
2693 return requiredVisualViewport;
2694 }
2695 }
2696
2697 ScrollAlignment::Behavior scrollX = alignX.getHiddenBehavior();
2698 bool intersectsInX = exposeRect.maxX() >= visibleRect.x() && exposeRect.x() <= visibleRect.maxX();
2699
2700 // Determine the appropriate X behavior.
2701 if (intersectsInX) {
2702 LayoutUnit intersectWidth = std::max(LayoutUnit(), std::min(visibleRect.maxX(), exposeRect.maxX()) - std::max(visibleRect.x(), exposeRect.x()));
2703 if (intersectWidth == exposeRect.width() || (alignX.legacyHorizontalVisibilityThresholdEnabled() && intersectWidth >= MIN_INTERSECT_FOR_REVEAL)) {
2704 // If the rectangle is fully visible, use the specified visible behavior.
2705 // If the rectangle is partially visible, but over a certain threshold,
2706 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2707 scrollX = alignX.getVisibleBehavior();
2708 } else if (intersectWidth == visibleRect.width()) {
2709 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2710 scrollX = alignX.getVisibleBehavior();
2711 if (scrollX == ScrollAlignment::Behavior::AlignCenter)
2712 scrollX = ScrollAlignment::Behavior::NoScroll;
2713 } else if (intersectWidth > 0) {
2714 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2715 scrollX = alignX.getPartialBehavior();
2716 }
2717 }
2718 // If we're trying to align to the closest edge, and the exposeRect is further right
2719 // than the visibleRect, and not bigger than the visible area, then align with the right.
2720 if (scrollX == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2721 scrollX = ScrollAlignment::Behavior::AlignRight;
2722
2723 // Given the X behavior, compute the X coordinate.
2724 LayoutUnit x;
2725 if (scrollX == ScrollAlignment::Behavior::NoScroll)
2726 x = visibleRect.x();
2727 else if (scrollX == ScrollAlignment::Behavior::AlignRight)
2728 x = exposeRect.maxX() - visibleRect.width();
2729 else if (scrollX == ScrollAlignment::Behavior::AlignCenter)
2730 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2731 else
2732 x = exposeRect.x();
2733
2734 ScrollAlignment::Behavior scrollY = alignY.getHiddenBehavior();
2735 bool intersectsInY = exposeRect.maxY() >= visibleRect.y() && exposeRect.y() <= visibleRect.maxY();
2736
2737 // Determine the appropriate Y behavior.
2738 if (intersectsInY) {
2739 LayoutUnit intersectHeight = std::max(LayoutUnit(), std::min(visibleRect.maxY(), exposeRect.maxY()) - std::max(visibleRect.y(), exposeRect.y()));
2740 if (intersectHeight == exposeRect.height()) {
2741 // If the rectangle is fully visible, use the specified visible behavior.
2742 scrollY = alignY.getVisibleBehavior();
2743 } else if (intersectHeight == visibleRect.height()) {
2744 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2745 scrollY = alignY.getVisibleBehavior();
2746 if (scrollY == ScrollAlignment::Behavior::AlignCenter)
2747 scrollY = ScrollAlignment::Behavior::NoScroll;
2748 } else if (intersectHeight > 0) {
2749 // If the rectangle is partially visible, use the specified partial behavior
2750 scrollY = alignY.getPartialBehavior();
2751 }
2752 }
2753 // If we're trying to align to the closest edge, and the exposeRect is further down
2754 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2755 if (scrollY == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2756 scrollY = ScrollAlignment::Behavior::AlignBottom;
2757
2758 // Given the Y behavior, compute the Y coordinate.
2759 LayoutUnit y;
2760 if (scrollY == ScrollAlignment::Behavior::NoScroll)
2761 y = visibleRect.y();
2762 else if (scrollY == ScrollAlignment::Behavior::AlignBottom)
2763 y = exposeRect.maxY() - visibleRect.height();
2764 else if (scrollY == ScrollAlignment::Behavior::AlignCenter)
2765 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2766 else
2767 y = exposeRect.y();
2768
2769 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2770}
2771
2772void RenderLayer::autoscroll(const IntPoint& positionInWindow)
2773{
2774 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(positionInWindow);
2775 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, { SelectionRevealMode::Reveal, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded, ShouldAllowCrossOriginScrolling::Yes });
2776}
2777
2778bool RenderLayer::canResize() const
2779{
2780 // We need a special case for <iframe> because they never have
2781 // hasNonVisibleOverflow(). However, they do "implicitly" clip their contents, so
2782 // we want to allow resizing them also.
2783 return (renderer().hasNonVisibleOverflow() || renderer().isRenderIFrame()) && renderer().style().resize() != Resize::None;
2784}
2785
2786LayoutSize RenderLayer::minimumSizeForResizing(float zoomFactor) const
2787{
2788 // Use the resizer size as the strict minimum size
2789 auto resizerRect = overflowControlsRects().resizer;
2790 LayoutUnit minWidth = minimumValueForLength(renderer().style().minWidth(), renderer().containingBlock()->width());
2791 LayoutUnit minHeight = minimumValueForLength(renderer().style().minHeight(), renderer().containingBlock()->height());
2792 minWidth = std::max(LayoutUnit(minWidth / zoomFactor), LayoutUnit(resizerRect.width()));
2793 minHeight = std::max(LayoutUnit(minHeight / zoomFactor), LayoutUnit(resizerRect.height()));
2794 return LayoutSize(minWidth, minHeight);
2795}
2796
2797void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2798{
2799 // FIXME: This should be possible on generated content but is not right now.
2800 if (!inResizeMode() || !canResize() || !renderer().element())
2801 return;
2802
2803 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2804 // If they do it would still be better to deal with them explicitly.
2805 Element* element = renderer().element();
2806 auto* renderer = downcast<RenderBox>(element->renderer());
2807
2808 Document& document = element->document();
2809 if (!document.frame()->eventHandler().mousePressed())
2810 return;
2811
2812 float zoomFactor = renderer->style().effectiveZoom();
2813
2814 auto absolutePoint = document.view()->windowToContents(evt.position());
2815 auto localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
2816
2817 LayoutSize newOffset = offsetFromResizeCorner(localPoint);
2818 newOffset.setWidth(newOffset.width() / zoomFactor);
2819 newOffset.setHeight(newOffset.height() / zoomFactor);
2820
2821 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2822
2823 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2824 if (renderer->shouldPlaceVerticalScrollbarOnLeft()) {
2825 newOffset.setWidth(-newOffset.width());
2826 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2827 }
2828
2829 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSizeForResizing(zoomFactor)) - currentSize;
2830
2831 StyledElement* styledElement = downcast<StyledElement>(element);
2832 bool isBoxSizingBorder = renderer->style().boxSizing() == BoxSizing::BorderBox;
2833
2834 Resize resize = renderer->style().resize();
2835 bool canResizeWidth = resize == Resize::Horizontal || resize == Resize::Both
2836 || (renderer->isHorizontalWritingMode() ? resize == Resize::Inline : resize == Resize::Block);
2837 if (canResizeWidth && difference.width()) {
2838 if (is<HTMLFormControlElement>(*element)) {
2839 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2840 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSUnitType::CSS_PX);
2841 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSUnitType::CSS_PX);
2842 }
2843 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? 0_lu : renderer->horizontalBorderAndPaddingExtent());
2844 baseWidth = baseWidth / zoomFactor;
2845 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSUnitType::CSS_PX);
2846 }
2847
2848 bool canResizeHeight = resize == Resize::Vertical || resize == Resize::Both
2849 || (renderer->isHorizontalWritingMode() ? resize == Resize::Block : resize == Resize::Inline);
2850 if (canResizeHeight && difference.height()) {
2851 if (is<HTMLFormControlElement>(*element)) {
2852 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2853 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSUnitType::CSS_PX);
2854 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSUnitType::CSS_PX);
2855 }
2856 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? 0_lu : renderer->verticalBorderAndPaddingExtent());
2857 baseHeight = baseHeight / zoomFactor;
2858 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSUnitType::CSS_PX);
2859 }
2860
2861 document.updateLayout();
2862
2863 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2864}
2865
2866IntSize RenderLayer::visibleSize() const
2867{
2868 RenderBox* box = renderBox();
2869 if (!box)
2870 return IntSize();
2871
2872 return IntSize(roundToInt(box->clientWidth()), roundToInt(box->clientHeight()));
2873}
2874
2875RenderLayer::OverflowControlRects RenderLayer::overflowControlsRects() const
2876{
2877 if (m_scrollableArea)
2878 return m_scrollableArea->overflowControlsRects();
2879
2880 ASSERT(is<RenderBox>(renderer()));
2881 auto& renderBox = downcast<RenderBox>(renderer());
2882 // Scrollbars sit inside the border box.
2883 auto overflowControlsPositioningRect = snappedIntRect(renderBox.paddingBoxRectIncludingScrollbar());
2884
2885 bool placeVerticalScrollbarOnTheLeft = renderBox.shouldPlaceVerticalScrollbarOnLeft();
2886 bool haveResizer = renderer().style().resize() != Resize::None;
2887
2888 OverflowControlRects result;
2889 auto cornerRect = [&](IntSize cornerSize) {
2890 if (placeVerticalScrollbarOnTheLeft) {
2891 auto bottomLeftCorner = overflowControlsPositioningRect.minXMaxYCorner();
2892 return IntRect { { bottomLeftCorner.x(), bottomLeftCorner.y() - cornerSize.height(), }, cornerSize };
2893 }
2894 return IntRect { overflowControlsPositioningRect.maxXMaxYCorner() - cornerSize, cornerSize };
2895 };
2896
2897 if (haveResizer) {
2898 auto scrollbarThickness = ScrollbarTheme::theme().scrollbarThickness();
2899 result.resizer = cornerRect({ scrollbarThickness, scrollbarThickness });
2900 }
2901
2902 return result;
2903}
2904
2905String RenderLayer::debugDescription() const
2906{
2907 String compositedDescription;
2908 if (isComposited()) {
2909 TextStream stream;
2910 stream << " " << *backing();
2911 compositedDescription = stream.release();
2912 }
2913
2914 return makeString("RenderLayer 0x", hex(reinterpret_cast<uintptr_t>(this), Lowercase),
2915 ' ', size().width(), 'x', size().height(),
2916 transform() ? " has transform" : "",
2917 hasFilter() ? " has filter" : "",
2918 hasBackdropFilter() ? " has backdrop filter" : "",
2919 hasBlendMode() ? " has blend mode" : "",
2920 isolatesBlending() ? " isolates blending" : "",
2921 compositedDescription);
2922}
2923
2924IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& localPoint) const
2925{
2926 auto resizerRect = overflowControlsRects().resizer;
2927 auto resizeCorner = renderer().shouldPlaceVerticalScrollbarOnLeft() ? resizerRect.minXMaxYCorner() : resizerRect.maxXMaxYCorner();
2928 return localPoint - resizeCorner;
2929}
2930
2931int RenderLayer::scrollWidth() const
2932{
2933 if (m_scrollableArea)
2934 return m_scrollableArea->scrollWidth();
2935
2936 RenderBox* box = renderBox();
2937 ASSERT(box);
2938 LayoutRect overflowRect(box->layoutOverflowRect());
2939 box->flipForWritingMode(overflowRect);
2940 return roundToInt(overflowRect.maxX() - overflowRect.x());
2941}
2942
2943int RenderLayer::scrollHeight() const
2944{
2945 if (m_scrollableArea)
2946 return m_scrollableArea->scrollHeight();
2947
2948 RenderBox* box = renderBox();
2949 ASSERT(box);
2950 LayoutRect overflowRect(box->layoutOverflowRect());
2951 box->flipForWritingMode(overflowRect);
2952 return roundToInt(overflowRect.maxY() - overflowRect.y());
2953}
2954
2955void RenderLayer::updateScrollInfoAfterLayout()
2956{
2957 updateLayerScrollableArea();
2958 if (m_scrollableArea)
2959 m_scrollableArea->updateScrollInfoAfterLayout();
2960}
2961
2962void RenderLayer::updateScrollbarSteps()
2963{
2964 if (m_scrollableArea)
2965 m_scrollableArea->updateScrollbarSteps();
2966}
2967
2968bool RenderLayer::canUseCompositedScrolling() const
2969{
2970 if (m_scrollableArea)
2971 return m_scrollableArea->canUseCompositedScrolling();
2972 return false;
2973}
2974
2975bool RenderLayer::hasCompositedScrollableOverflow() const
2976{
2977 if (m_scrollableArea)
2978 return m_scrollableArea->hasCompositedScrollableOverflow();
2979 return false;
2980}
2981
2982bool RenderLayer::hasOverlayScrollbars() const
2983{
2984 if (m_scrollableArea)
2985 return m_scrollableArea->hasOverlayScrollbars();
2986 return false;
2987}
2988
2989bool RenderLayer::usesCompositedScrolling() const
2990{
2991 if (m_scrollableArea)
2992 return m_scrollableArea->usesCompositedScrolling();
2993 return false;
2994}
2995
2996bool RenderLayer::isPointInResizeControl(IntPoint localPoint) const
2997{
2998 if (!canResize())
2999 return false;
3000
3001 return overflowControlsRects().resizer.contains(localPoint);
3002}
3003
3004void RenderLayer::paint(GraphicsContext& context, const LayoutRect& damageRect, const LayoutSize& subpixelOffset, OptionSet<PaintBehavior> paintBehavior, RenderObject* subtreePaintRoot, OptionSet<PaintLayerFlag> paintFlags, SecurityOriginPaintPolicy paintPolicy, EventRegionContext* eventRegionContext)
3005{
3006 OverlapTestRequestMap overlapTestRequests;
3007
3008 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, subpixelOffset, subtreePaintRoot, &overlapTestRequests, paintPolicy == SecurityOriginPaintPolicy::AccessibleOriginOnly);
3009 if (eventRegionContext) {
3010 paintingInfo.eventRegionContext = eventRegionContext;
3011 paintFlags.add(RenderLayer::PaintLayerFlag::CollectingEventRegion);
3012 }
3013 paintLayer(context, paintingInfo, paintFlags);
3014
3015 for (auto& widget : overlapTestRequests.keys())
3016 widget->setOverlapTestResult(false);
3017}
3018
3019void RenderLayer::clipToRect(GraphicsContext& context, GraphicsContextStateSaver& stateSaver, EventRegionContextStateSaver& eventRegionStateSaver, const LayerPaintingInfo& paintingInfo, OptionSet<PaintBehavior> paintBehavior, const ClipRect& clipRect, BorderRadiusClippingRule rule)
3020{
3021 float deviceScaleFactor = renderer().document().deviceScaleFactor();
3022 bool needsClipping = !clipRect.isInfinite() && clipRect.rect() != paintingInfo.paintDirtyRect;
3023 if (needsClipping || clipRect.affectedByRadius())
3024 stateSaver.save();
3025
3026 if (needsClipping) {
3027 LayoutRect adjustedClipRect = clipRect.rect();
3028 adjustedClipRect.move(paintingInfo.subpixelOffset);
3029 auto snappedClipRect = snapRectToDevicePixels(adjustedClipRect, deviceScaleFactor);
3030 context.clip(snappedClipRect);
3031 eventRegionStateSaver.pushClip(enclosingIntRect(snappedClipRect));
3032 }
3033
3034 if (clipRect.affectedByRadius()) {
3035 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
3036 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
3037 // containing block chain so we check that also.
3038 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
3039 if (paintBehavior.contains(PaintBehavior::CompositedOverflowScrollContent) && layer->usesCompositedScrolling())
3040 break;
3041
3042 if (layer->renderer().hasNonVisibleOverflow() && layer->renderer().style().hasBorderRadius() && ancestorLayerIsInContainingBlockChain(*layer)) {
3043 LayoutRect adjustedClipRect = LayoutRect(toLayoutPoint(layer->offsetFromAncestor(paintingInfo.rootLayer, AdjustForColumns)), layer->size());
3044 adjustedClipRect.move(paintingInfo.subpixelOffset);
3045 FloatRoundedRect roundedRect = layer->renderer().style().getRoundedInnerBorderFor(adjustedClipRect).pixelSnappedRoundedRectForPainting(deviceScaleFactor);
3046 if (roundedRect.intersectionIsRectangular(paintingInfo.paintDirtyRect))
3047 context.clip(snapRectToDevicePixels(intersection(paintingInfo.paintDirtyRect, adjustedClipRect), deviceScaleFactor));
3048 else
3049 context.clipRoundedRect(roundedRect);
3050 }
3051
3052 if (layer == paintingInfo.rootLayer)
3053 break;
3054 }
3055 }
3056}
3057
3058static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
3059{
3060 if (overlapTestRequests.isEmpty())
3061 return;
3062
3063 Vector<OverlapTestRequestClient*> overlappedRequestClients;
3064 LayoutRect boundingBox = layer->boundingBox(rootLayer, layer->offsetFromAncestor(rootLayer));
3065 for (auto& request : overlapTestRequests) {
3066 if (!boundingBox.intersects(request.value))
3067 continue;
3068
3069 request.key->setOverlapTestResult(true);
3070 overlappedRequestClients.append(request.key);
3071 }
3072 for (auto* client : overlappedRequestClients)
3073 overlapTestRequests.remove(client);
3074}
3075
3076static inline bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
3077{
3078 return paintingReflection && !layer->has3DTransform();
3079}
3080
3081static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
3082{
3083 if (layer->renderer().style().isNotFinal() && !layer->isRenderViewLayer() && !layer->renderer().isDocumentElementRenderer())
3084 return true;
3085
3086 // Avoid painting all layers if the document is in a state where visual updates aren't allowed.
3087 // A full repaint will occur in Document::setVisualUpdatesAllowed(bool) if painting is suppressed here.
3088 if (!layer->renderer().document().visualUpdatesAllowed())
3089 return true;
3090
3091 return false;
3092}
3093
3094static inline bool paintForFixedRootBackground(const RenderLayer* layer, OptionSet<RenderLayer::PaintLayerFlag> paintFlags)
3095{
3096 return layer->renderer().isDocumentElementRenderer() && (paintFlags & RenderLayer::PaintLayerFlag::PaintingRootBackgroundOnly);
3097}
3098
3099void RenderLayer::paintLayer(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3100{
3101 auto shouldContinuePaint = [&] () {
3102 return backing()->paintsIntoWindow()
3103 || backing()->paintsIntoCompositedAncestor()
3104 || shouldDoSoftwarePaint(this, paintFlags.contains(PaintLayerFlag::PaintingReflection))
3105 || paintForFixedRootBackground(this, paintFlags);
3106 };
3107
3108 auto paintsIntoDifferentCompositedDestination = [&]() {
3109 if (paintsIntoProvidedBacking())
3110 return true;
3111
3112 if (isComposited() && !shouldContinuePaint())
3113 return true;
3114
3115 return false;
3116 };
3117
3118 if (paintsIntoDifferentCompositedDestination()) {
3119 if (!context.performingPaintInvalidation() && !(paintingInfo.paintBehavior & PaintBehavior::FlattenCompositingLayers))
3120 return;
3121
3122 paintFlags.add(PaintLayerFlag::TemporaryClipRects);
3123 }
3124
3125 if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) {
3126 // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible
3127 // unless their position or viewport size is changed.
3128 ASSERT(renderer().isFixedPositioned());
3129 return;
3130 }
3131
3132 paintLayerWithEffects(context, paintingInfo, paintFlags);
3133}
3134
3135void RenderLayer::paintLayerWithEffects(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3136{
3137 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
3138 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
3139 return;
3140
3141 if (shouldSuppressPaintingLayer(this))
3142 return;
3143
3144 // If this layer is totally invisible then there is nothing to paint.
3145 if (!renderer().opacity())
3146 return;
3147
3148 if (paintsWithTransparency(paintingInfo.paintBehavior))
3149 paintFlags.add(PaintLayerFlag::HaveTransparency);
3150
3151 // PaintLayerFlag::AppliedTransform is used in RenderReplica, to avoid applying the transform twice.
3152 if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerFlag::AppliedTransform)) {
3153 TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
3154 // If the transform can't be inverted, then don't paint anything.
3155 if (!layerTransform.isInvertible())
3156 return;
3157
3158 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
3159 // layer from the parent now, assuming there is a parent
3160 if (paintFlags & PaintLayerFlag::HaveTransparency) {
3161 if (parent())
3162 parent()->beginTransparencyLayers(context, paintingInfo, paintingInfo.paintDirtyRect);
3163 else
3164 beginTransparencyLayers(context, paintingInfo, paintingInfo.paintDirtyRect);
3165 }
3166
3167 if (enclosingPaginationLayer(ExcludeCompositedPaginatedLayers)) {
3168 paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags);
3169 return;
3170 }
3171
3172 // Make sure the parent's clip rects have been calculated.
3173 ClipRect clipRect = paintingInfo.paintDirtyRect;
3174 GraphicsContextStateSaver stateSaver(context, false);
3175 EventRegionContextStateSaver eventRegionStateSaver(paintingInfo.eventRegionContext);
3176 if (parent()) {
3177 ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerFlag::TemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
3178 IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerFlag::PaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
3179 clipRect = backgroundClipRect(clipRectsContext);
3180 clipRect.intersect(paintingInfo.paintDirtyRect);
3181
3182 OptionSet<PaintBehavior> paintBehavior = PaintBehavior::Normal;
3183 if (paintFlags.contains(PaintLayerFlag::PaintingOverflowContents))
3184 paintBehavior.add(PaintBehavior::CompositedOverflowScrollContent);
3185
3186#if ENABLE(LAYER_BASED_SVG_ENGINE)
3187 // Always apply SVG viewport clipping in coordinate system before the SVG viewBox transformation is applied.
3188 if (is<RenderSVGRoot>(renderer())) {
3189 auto& svgRoot = downcast<RenderSVGRoot>(renderer());
3190 if (svgRoot.shouldApplyViewportClip()) {
3191 auto newRect = svgRoot.borderBoxRect();
3192
3193 auto offsetFromParent = offsetFromAncestor(clipRectsContext.rootLayer);
3194 auto offsetForThisLayer = offsetFromParent + paintingInfo.subpixelOffset;
3195 auto devicePixelSnappedOffsetForThisLayer = toFloatSize(roundPointToDevicePixels(toLayoutPoint(offsetForThisLayer), renderer().document().deviceScaleFactor()));
3196 newRect.move(devicePixelSnappedOffsetForThisLayer.width(), devicePixelSnappedOffsetForThisLayer.height());
3197
3198 clipRect.intersect(newRect);
3199 }
3200 }
3201#endif
3202
3203 // Push the parent coordinate space's clip.
3204 parent()->clipToRect(context, stateSaver, eventRegionStateSaver, paintingInfo, paintBehavior, clipRect);
3205 }
3206
3207 paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
3208 return;
3209 }
3210
3211 paintLayerContentsAndReflection(context, paintingInfo, paintFlags);
3212}
3213
3214void RenderLayer::paintLayerContentsAndReflection(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3215{
3216 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
3217
3218 auto localPaintFlags = paintFlags - PaintLayerFlag::AppliedTransform;
3219
3220 // Paint the reflection first if we have one.
3221 if (m_reflection && !m_paintingInsideReflection) {
3222 // Mark that we are now inside replica painting.
3223 m_paintingInsideReflection = true;
3224 reflectionLayer()->paintLayer(context, paintingInfo, localPaintFlags | PaintLayerFlag::PaintingReflection);
3225 m_paintingInsideReflection = false;
3226 }
3227
3228 localPaintFlags.add(paintLayerPaintingCompositingAllPhasesFlags());
3229 paintLayerContents(context, paintingInfo, localPaintFlags);
3230}
3231
3232bool RenderLayer::setupFontSubpixelQuantization(GraphicsContext& context, bool& didQuantizeFonts)
3233{
3234 if (context.paintingDisabled())
3235 return false;
3236
3237 bool scrollingOnMainThread = true;
3238#if ENABLE(ASYNC_SCROLLING)
3239 if (auto* scrollingCoordinator = page().scrollingCoordinator())
3240 scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(renderer().view().frameView());
3241#endif
3242
3243 // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
3244 // things on the scrolling thread.
3245 bool contentsScrollByPainting = (renderer().hasNonVisibleOverflow() && !usesCompositedScrolling()) || (renderer().frame().ownerElement());
3246 bool isZooming = !page().chrome().client().hasStablePageScaleFactor();
3247 if (scrollingOnMainThread || contentsScrollByPainting || isZooming) {
3248 didQuantizeFonts = context.shouldSubpixelQuantizeFonts();
3249 context.setShouldSubpixelQuantizeFonts(false);
3250 return true;
3251 }
3252 return false;
3253}
3254
3255std::pair<Path, WindRule> RenderLayer::computeClipPath(const LayoutSize& offsetFromRoot, const LayoutRect& rootRelativeBoundsForNonBoxes) const
3256{
3257 const RenderStyle& style = renderer().style();
3258
3259 if (is<ShapePathOperation>(*style.clipPath())) {
3260 auto& clipPath = downcast<ShapePathOperation>(*style.clipPath());
3261 auto referenceBoxRect = referenceBoxRectForClipPath(clipPath.referenceBox(), offsetFromRoot, rootRelativeBoundsForNonBoxes);
3262 auto snappedReferenceBoxRect = snapRectToDevicePixelsIfNeeded(referenceBoxRect, renderer());
3263 return { clipPath.pathForReferenceRect(snappedReferenceBoxRect), clipPath.windRule() };
3264 }
3265
3266 if (is<BoxPathOperation>(*style.clipPath()) && is<RenderBox>(renderer())) {
3267 auto& clipPath = downcast<BoxPathOperation>(*style.clipPath());
3268
3269 auto shapeRect = computeRoundedRectForBoxShape(clipPath.referenceBox(), downcast<RenderBox>(renderer())).pixelSnappedRoundedRectForPainting(renderer().document().deviceScaleFactor());
3270 shapeRect.move(offsetFromRoot);
3271
3272 return { clipPath.pathForReferenceRect(shapeRect), WindRule::NonZero };
3273 }
3274
3275 return { Path(), WindRule::NonZero };
3276}
3277
3278void RenderLayer::setupClipPath(GraphicsContext& context, GraphicsContextStateSaver& stateSaver, const LayerPaintingInfo& paintingInfo, const LayoutSize& offsetFromRoot)
3279{
3280 if (!renderer().hasClipPath() || context.paintingDisabled() || paintingInfo.paintDirtyRect.isEmpty())
3281 return;
3282
3283 // SVG elements get clipped in SVG code.
3284 if (is<LegacyRenderSVGRoot>(renderer()))
3285 return;
3286
3287 auto clippedContentBounds = calculateLayerBounds(paintingInfo.rootLayer, offsetFromRoot, { UseLocalClipRectIfPossible });
3288
3289 auto& style = renderer().style();
3290 LayoutSize paintingOffsetFromRoot = LayoutSize(snapSizeToDevicePixel(offsetFromRoot + paintingInfo.subpixelOffset, LayoutPoint(), renderer().document().deviceScaleFactor()));
3291 ASSERT(style.clipPath());
3292 if (is<ShapePathOperation>(*style.clipPath()) || (is<BoxPathOperation>(*style.clipPath()) && is<RenderBox>(renderer()))) {
3293 // clippedContentBounds is used as the reference box for inlines, which is also poorly specified: https://github.com/w3c/csswg-drafts/issues/6383.
3294 auto [path, windRule] = computeClipPath(paintingOffsetFromRoot, clippedContentBounds);
3295 stateSaver.save();
3296 context.clipPath(path, windRule);
3297 }
3298
3299 if (is<ReferencePathOperation>(style.clipPath())) {
3300 auto& referenceClipPathOperation = downcast<ReferencePathOperation>(*style.clipPath());
3301 if (auto* clipperRenderer = renderer().ensureReferencedSVGResources().referencedClipperRenderer(renderer().document(), referenceClipPathOperation)) {
3302 // Use the border box as the reference box, even though this is not clearly specified: https://github.com/w3c/csswg-drafts/issues/5786.
3303 // clippedContentBounds is used as the reference box for inlines, which is also poorly specified: https://github.com/w3c/csswg-drafts/issues/6383.
3304 auto referenceBox = referenceBoxRectForClipPath(CSSBoxType::BorderBox, offsetFromRoot, clippedContentBounds);
3305 auto snappedReferenceBox = snapRectToDevicePixelsIfNeeded(referenceBox, renderer());
3306 auto offset = snappedReferenceBox.location();
3307
3308 auto snappedClippingBounds = snapRectToDevicePixelsIfNeeded(clippedContentBounds, renderer());
3309 snappedClippingBounds.moveBy(-offset);
3310
3311 stateSaver.save();
3312 context.translate(offset);
3313 clipperRenderer->applyClippingToContext(context, renderer(), { { }, referenceBox.size() }, snappedClippingBounds, renderer().style().effectiveZoom());
3314 context.translate(-offset);
3315 }
3316 }
3317}
3318
3319RenderLayerFilters* RenderLayer::filtersForPainting(GraphicsContext& context, OptionSet<PaintLayerFlag> paintFlags) const
3320{
3321 if (context.paintingDisabled())
3322 return nullptr;
3323
3324 if (paintFlags & PaintLayerFlag::PaintingOverlayScrollbars)
3325 return nullptr;
3326
3327 if (!paintsWithFilters())
3328 return nullptr;
3329
3330 if (m_filters)
3331 return m_filters.get();
3332
3333 return nullptr;
3334}
3335
3336GraphicsContext* RenderLayer::setupFilters(GraphicsContext& destinationContext, LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags, const LayoutSize& offsetFromRoot)
3337{
3338 auto* paintingFilters = filtersForPainting(destinationContext, paintFlags);
3339 if (!paintingFilters)
3340 return nullptr;
3341
3342 LayoutRect filterRepaintRect = paintingFilters->dirtySourceRect();
3343 filterRepaintRect.move(offsetFromRoot);
3344
3345 auto rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, offsetFromRoot, { });
3346
3347 GraphicsContext* filterContext = paintingFilters->beginFilterEffect(renderer(), destinationContext, enclosingIntRect(rootRelativeBounds), enclosingIntRect(paintingInfo.paintDirtyRect), enclosingIntRect(filterRepaintRect));
3348 if (!filterContext)
3349 return nullptr;
3350
3351 paintingInfo.paintDirtyRect = paintingFilters->repaintRect();
3352
3353 // If the filter needs the full source image, we need to avoid using the clip rectangles.
3354 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
3355 // Note that we will still apply the clipping on the final rendering of the filter.
3356 paintingInfo.clipToDirtyRect = !paintingFilters->hasFilterThatMovesPixels();
3357
3358 paintingInfo.requireSecurityOriginAccessForWidgets = paintingFilters->hasFilterThatShouldBeRestrictedBySecurityOrigin();
3359
3360 return filterContext;
3361}
3362
3363void RenderLayer::applyFilters(GraphicsContext& originalContext, const LayerPaintingInfo& paintingInfo, OptionSet<PaintBehavior> behavior, const LayerFragments& layerFragments)
3364{
3365 // FIXME: Handle more than one fragment.
3366 ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
3367
3368 GraphicsContextStateSaver stateSaver(originalContext, false);
3369 EventRegionContextStateSaver eventRegionStateSaver(paintingInfo.eventRegionContext);
3370
3371 clipToRect(originalContext, stateSaver, eventRegionStateSaver, paintingInfo, behavior, backgroundRect);
3372 m_filters->applyFilterEffect(originalContext);
3373}
3374
3375void RenderLayer::paintLayerContents(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3376{
3377 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
3378
3379 if (context.detectingContentfulPaint() && context.contenfulPaintDetected())
3380 return;
3381
3382 auto localPaintFlags = paintFlags - PaintLayerFlag::AppliedTransform;
3383
3384 bool haveTransparency = localPaintFlags.contains(PaintLayerFlag::HaveTransparency);
3385 bool isPaintingOverlayScrollbars = localPaintFlags.contains(PaintLayerFlag::PaintingOverlayScrollbars);
3386 bool isPaintingScrollingContent = localPaintFlags.contains(PaintLayerFlag::PaintingCompositingScrollingPhase);
3387 bool isPaintingCompositedForeground = localPaintFlags.contains(PaintLayerFlag::PaintingCompositingForegroundPhase);
3388 bool isPaintingCompositedBackground = localPaintFlags.contains(PaintLayerFlag::PaintingCompositingBackgroundPhase);
3389 bool isPaintingOverflowContents = localPaintFlags.contains(PaintLayerFlag::PaintingOverflowContents);
3390 bool isCollectingEventRegion = localPaintFlags.contains(PaintLayerFlag::CollectingEventRegion);
3391
3392 bool isSelfPaintingLayer = this->isSelfPaintingLayer();
3393
3394 // Outline always needs to be painted even if we have no visible content. Also,
3395 // the outline is painted in the background phase during composited scrolling.
3396 // If it were painted in the foreground phase, it would move with the scrolled
3397 // content. When not composited scrolling, the outline is painted in the
3398 // foreground phase. Since scrolled contents are moved by repainting in this
3399 // case, the outline won't get 'dragged along'.
3400 bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars && !isCollectingEventRegion
3401 && (renderer().view().printing() || renderer().view().hasRenderersWithOutline())
3402 && ((isPaintingScrollingContent && isPaintingCompositedBackground)
3403 || (!isPaintingScrollingContent && isPaintingCompositedForeground));
3404 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars && !isCollectingEventRegion;
3405
3406 if (localPaintFlags.contains(PaintLayerFlag::PaintingRootBackgroundOnly) && !renderer().isRenderView() && !renderer().isDocumentElementRenderer()) {
3407 // If beginTransparencyLayers was called prior to this, ensure the transparency state is cleaned up before returning.
3408 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
3409 context.endTransparencyLayer();
3410 context.restore();
3411 m_usedTransparency = false;
3412 }
3413
3414 return;
3415 }
3416
3417 updateLayerListsIfNeeded();
3418
3419 LayoutSize offsetFromRoot = offsetFromAncestor(paintingInfo.rootLayer);
3420
3421 // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
3422 // things on the scrolling thread.
3423 bool didQuantizeFonts = true;
3424 bool needToAdjustSubpixelQuantization = setupFontSubpixelQuantization(context, didQuantizeFonts);
3425
3426 // Apply clip-path to context.
3427 LayoutSize columnAwareOffsetFromRoot = offsetFromRoot;
3428 if (renderer().enclosingFragmentedFlow() && (renderer().hasClipPath() || filtersForPainting(context, paintFlags)))
3429 columnAwareOffsetFromRoot = toLayoutSize(convertToLayerCoords(paintingInfo.rootLayer, LayoutPoint(), AdjustForColumns));
3430
3431 GraphicsContextStateSaver stateSaver(context, false);
3432 if (shouldApplyClipPath(paintingInfo.paintBehavior, localPaintFlags))
3433 setupClipPath(context, stateSaver, paintingInfo, columnAwareOffsetFromRoot);
3434
3435 bool selectionAndBackgroundsOnly = paintingInfo.paintBehavior.contains(PaintBehavior::SelectionAndBackgroundsOnly);
3436 bool selectionOnly = paintingInfo.paintBehavior.contains(PaintBehavior::SelectionOnly);
3437
3438 SinglePaintFrequencyTracking singlePaintFrequencyTracking(m_paintFrequencyTracker, page().lastRenderingUpdateTimestamp());
3439
3440 LayerFragments layerFragments;
3441 RenderObject* subtreePaintRootForRenderer = nullptr;
3442
3443 auto paintBehavior = [&]() {
3444 constexpr OptionSet<PaintBehavior> flagsToCopy = { PaintBehavior::FlattenCompositingLayers, PaintBehavior::Snapshotting, PaintBehavior::ExcludeSelection };
3445 OptionSet<PaintBehavior> paintBehavior = paintingInfo.paintBehavior & flagsToCopy;
3446
3447 if (localPaintFlags.contains(PaintLayerFlag::PaintingSkipRootBackground))
3448 paintBehavior.add(PaintBehavior::SkipRootBackground);
3449 else if (localPaintFlags.contains(PaintLayerFlag::PaintingRootBackgroundOnly))
3450 paintBehavior.add(PaintBehavior::RootBackgroundOnly);
3451
3452 // FIXME: This seems wrong. We should retain the TileFirstPaint flag for all RenderLayers painted into the root tile cache.
3453 if ((paintingInfo.paintBehavior & PaintBehavior::TileFirstPaint) && isRenderViewLayer())
3454 paintBehavior.add(PaintBehavior::TileFirstPaint);
3455
3456 if (isPaintingOverflowContents)
3457 paintBehavior.add(PaintBehavior::CompositedOverflowScrollContent);
3458
3459 if (isCollectingEventRegion) {
3460 paintBehavior = paintBehavior & PaintBehavior::CompositedOverflowScrollContent;
3461 if (isPaintingCompositedForeground)
3462 paintBehavior.add(PaintBehavior::EventRegionIncludeForeground);
3463 if (isPaintingCompositedBackground)
3464 paintBehavior.add(PaintBehavior::EventRegionIncludeBackground);
3465 }
3466
3467 return paintBehavior;
3468 }();
3469
3470 { // Scope for filter-related state changes.
3471 LayerPaintingInfo localPaintingInfo(paintingInfo);
3472 GraphicsContext* filterContext = setupFilters(context, localPaintingInfo, paintFlags, columnAwareOffsetFromRoot);
3473 if (filterContext && haveTransparency) {
3474 // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
3475 beginTransparencyLayers(context, localPaintingInfo, paintingInfo.paintDirtyRect);
3476 }
3477 GraphicsContext& currentContext = filterContext ? *filterContext : context;
3478
3479 // If this layer's renderer is a child of the subtreePaintRoot, we render unconditionally, which
3480 // is done by passing a nil subtreePaintRoot down to our renderer (as if no subtreePaintRoot was ever set).
3481 // Otherwise, our renderer tree may or may not contain the subtreePaintRoot root, so we pass that root along
3482 // so it will be tested against as we descend through the renderers.
3483 if (localPaintingInfo.subtreePaintRoot && !renderer().isDescendantOf(localPaintingInfo.subtreePaintRoot))
3484 subtreePaintRootForRenderer = localPaintingInfo.subtreePaintRoot;
3485
3486 if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
3487 performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
3488
3489 LayoutRect paintDirtyRect = localPaintingInfo.paintDirtyRect;
3490 if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars || isCollectingEventRegion) {
3491 // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
3492 // fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
3493 // use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
3494 if (!localPaintingInfo.clipToDirtyRect && renderer().hasNonVisibleOverflow()) {
3495 // We can turn clipping back by requesting full repaint for the overflow area.
3496 localPaintingInfo.clipToDirtyRect = true;
3497 paintDirtyRect = clipRectRelativeToAncestor(localPaintingInfo.rootLayer, offsetFromRoot, LayoutRect::infiniteRect());
3498 }
3499 collectFragments(layerFragments, localPaintingInfo.rootLayer, paintDirtyRect, ExcludeCompositedPaginatedLayers,
3500 (localPaintFlags & PaintLayerFlag::TemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
3501 (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
3502 updatePaintingInfoForFragments(layerFragments, localPaintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
3503 }
3504
3505 if (isPaintingCompositedBackground) {
3506 // Paint only the backgrounds for all of the fragments of the layer.
3507 if (shouldPaintContent && !selectionOnly) {
3508 paintBackgroundForFragments(layerFragments, currentContext, context, paintingInfo.paintDirtyRect, haveTransparency,
3509 localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
3510 }
3511 }
3512
3513 // Now walk the sorted list of children with negative z-indices.
3514 if ((isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground))
3515 paintList(negativeZOrderLayers(), currentContext, localPaintingInfo, localPaintFlags);
3516
3517 if (isPaintingCompositedForeground) {
3518 if (shouldPaintContent) {
3519 paintForegroundForFragments(layerFragments, currentContext, context, paintingInfo.paintDirtyRect, haveTransparency,
3520 localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
3521 }
3522 }
3523
3524 if (isCollectingEventRegion)
3525 collectEventRegionForFragments(layerFragments, currentContext, localPaintingInfo, paintBehavior);
3526
3527 if (shouldPaintOutline)
3528 paintOutlineForFragments(layerFragments, currentContext, localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
3529
3530 if (isPaintingCompositedForeground) {
3531 // Paint any child layers that have overflow.
3532 paintList(normalFlowLayers(), currentContext, localPaintingInfo, localPaintFlags);
3533
3534 // Now walk the sorted list of children with positive z-indices.
3535 paintList(positiveZOrderLayers(), currentContext, localPaintingInfo, localPaintFlags);
3536 }
3537
3538 if (m_scrollableArea) {
3539 if (isPaintingOverlayScrollbars && m_scrollableArea->hasScrollbars())
3540 paintOverflowControlsForFragments(layerFragments, currentContext, localPaintingInfo);
3541 }
3542
3543 if (filterContext) {
3544 // When we called collectFragments() last time, paintDirtyRect was reset to represent the filter bounds.
3545 // Now we need to compute the backgroundRect uncontaminated by filters, in order to clip the filtered result.
3546 // Note that we also use paintingInfo here, not localPaintingInfo which filters also contaminated.
3547 LayerFragments layerFragments;
3548 collectFragments(layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
3549 (localPaintFlags & PaintLayerFlag::TemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
3550 (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
3551 updatePaintingInfoForFragments(layerFragments, paintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
3552
3553 applyFilters(context, paintingInfo, paintBehavior, layerFragments);
3554 }
3555 }
3556
3557 if (shouldPaintContent && !(selectionOnly || selectionAndBackgroundsOnly)) {
3558 if (shouldPaintMask(paintingInfo.paintBehavior, localPaintFlags)) {
3559 // Paint the mask for the fragments.
3560 paintMaskForFragments(layerFragments, context, paintingInfo, paintBehavior, subtreePaintRootForRenderer);
3561 }
3562
3563 if (!(paintFlags & PaintLayerFlag::PaintingCompositingMaskPhase) && (paintFlags & PaintLayerFlag::PaintingCompositingClipPathPhase)) {
3564 // Re-use paintChildClippingMaskForFragments to paint black for the compositing clipping mask.
3565 paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, paintBehavior, subtreePaintRootForRenderer);
3566 }
3567
3568 if (localPaintFlags & PaintLayerFlag::PaintingChildClippingMaskPhase) {
3569 // Paint the border radius mask for the fragments.
3570 paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, paintBehavior, subtreePaintRootForRenderer);
3571 }
3572 }
3573
3574 // End our transparency layer
3575 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
3576 context.endTransparencyLayer();
3577 context.restore();
3578 m_usedTransparency = false;
3579 }
3580
3581 // Re-set this to whatever it was before we painted the layer.
3582 if (needToAdjustSubpixelQuantization)
3583 context.setShouldSubpixelQuantizeFonts(didQuantizeFonts);
3584}
3585
3586void RenderLayer::paintLayerByApplyingTransform(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags, const LayoutSize& translationOffset)
3587{
3588 auto usesSVGSubtreeTransformRules = [](const RenderLayerModelObject& renderer) {
3589#if ENABLE(LAYER_BASED_SVG_ENGINE)
3590 return renderer.document().settings().layerBasedSVGEngineEnabled() && renderer.isSVGLayerAwareRenderer() && !renderer.isSVGRoot();
3591#else
3592 UNUSED_PARAM(renderer);
3593#endif
3594 return false;
3595 };
3596
3597 // This involves subtracting out the position of the layer in our current coordinate space, but preserving
3598 // the accumulated error for sub-pixel layout.
3599 // Note: The pixel-snapping logic is disabled for the whole SVG render tree, except the outermost <svg>.
3600 float deviceScaleFactor = renderer().document().deviceScaleFactor();
3601 LayoutSize offsetFromParent = offsetFromAncestor(paintingInfo.rootLayer);
3602 offsetFromParent += translationOffset;
3603 TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
3604 // Add the subpixel accumulation to the current layer's offset so that we can always snap the translateRight value to where the renderer() is supposed to be painting.
3605 LayoutSize offsetForThisLayer = offsetFromParent + paintingInfo.subpixelOffset;
3606 FloatSize alignedOffsetForThisLayer = usesSVGSubtreeTransformRules(renderer()) ? offsetForThisLayer : toFloatSize(roundPointToDevicePixels(toLayoutPoint(offsetForThisLayer), deviceScaleFactor));
3607 // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
3608 // all we need to do is add the delta to the accumulated pixels coming from ancestor layers.
3609 // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
3610 transform.translateRight(alignedOffsetForThisLayer.width(), alignedOffsetForThisLayer.height());
3611 // Apply the transform.
3612 auto oldTransform = context.getCTM();
3613 auto affineTransform = transform.toAffineTransform();
3614 context.concatCTM(affineTransform);
3615
3616 if (paintingInfo.eventRegionContext)
3617 paintingInfo.eventRegionContext->pushTransform(affineTransform);
3618
3619 // Now do a paint with the root layer shifted to be us.
3620 LayoutSize adjustedSubpixelOffset;
3621 if (!usesSVGSubtreeTransformRules(renderer()) && !renderer().isSVGRoot())
3622 adjustedSubpixelOffset = offsetForThisLayer - LayoutSize(alignedOffsetForThisLayer);
3623
3624 LayerPaintingInfo transformedPaintingInfo(paintingInfo);
3625 transformedPaintingInfo.rootLayer = this;
3626 transformedPaintingInfo.paintDirtyRect = LayoutRect(encloseRectToDevicePixels(valueOrDefault(transform.inverse()).mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor));
3627 transformedPaintingInfo.subpixelOffset = adjustedSubpixelOffset;
3628 paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
3629
3630 if (paintingInfo.eventRegionContext)
3631 paintingInfo.eventRegionContext->popTransform();
3632
3633 context.setCTM(oldTransform);
3634}
3635
3636void RenderLayer::paintList(LayerList layerIterator, GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3637{
3638 if (layerIterator.begin() == layerIterator.end())
3639 return;
3640
3641 if (!hasSelfPaintingLayerDescendant())
3642 return;
3643
3644#if ASSERT_ENABLED
3645 LayerListMutationDetector mutationChecker(*this);
3646#endif
3647
3648 for (auto* childLayer : layerIterator)
3649 childLayer->paintLayer(context, paintingInfo, paintFlags);
3650}
3651
3652RenderLayer* RenderLayer::enclosingPaginationLayerInSubtree(const RenderLayer* rootLayer, PaginationInclusionMode mode) const
3653{
3654 // If we don't have an enclosing layer, or if the root layer is the same as the enclosing layer,
3655 // then just return the enclosing pagination layer (it will be 0 in the former case and the rootLayer in the latter case).
3656 RenderLayer* paginationLayer = enclosingPaginationLayer(mode);
3657 if (!paginationLayer || rootLayer == paginationLayer)
3658 return paginationLayer;
3659
3660 // Walk up the layer tree and see which layer we hit first. If it's the root, then the enclosing pagination
3661 // layer isn't in our subtree and we return nullptr. If we hit the enclosing pagination layer first, then
3662 // we can return it.
3663 for (const RenderLayer* layer = this; layer; layer = layer->parent()) {
3664 if (layer == rootLayer)
3665 return nullptr;
3666 if (layer == paginationLayer)
3667 return paginationLayer;
3668 }
3669
3670 // This should never be reached, since an enclosing layer should always either be the rootLayer or be
3671 // our enclosing pagination layer.
3672 ASSERT_NOT_REACHED();
3673 return nullptr;
3674}
3675
3676void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect, PaginationInclusionMode inclusionMode,
3677 ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutSize& offsetFromRoot,
3678 const LayoutRect* layerBoundingBox, ShouldApplyRootOffsetToFragments applyRootOffsetToFragments)
3679{
3680 RenderLayer* paginationLayer = enclosingPaginationLayerInSubtree(rootLayer, inclusionMode);
3681 if (!paginationLayer || hasTransform()) {
3682 // For unpaginated layers, there is only one fragment.
3683 LayerFragment fragment;
3684 ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
3685 calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, offsetFromRoot);
3686 fragments.append(fragment);
3687 return;
3688 }
3689
3690 // Compute our offset within the enclosing pagination layer.
3691 LayoutSize offsetWithinPaginatedLayer = offsetFromAncestor(paginationLayer);
3692
3693 // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
3694 // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
3695 ClipRectsContext paginationClipRectsContext(paginationLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
3696 LayoutRect layerBoundsInFragmentedFlow;
3697 ClipRect backgroundRectInFragmentedFlow;
3698 ClipRect foregroundRectInFragmentedFlow;
3699 calculateRects(paginationClipRectsContext, LayoutRect::infiniteRect(), layerBoundsInFragmentedFlow, backgroundRectInFragmentedFlow, foregroundRectInFragmentedFlow,
3700 offsetWithinPaginatedLayer);
3701
3702 // Take our bounding box within the flow thread and clip it.
3703 LayoutRect layerBoundingBoxInFragmentedFlow = layerBoundingBox ? *layerBoundingBox : boundingBox(paginationLayer, offsetWithinPaginatedLayer);
3704 layerBoundingBoxInFragmentedFlow.intersect(backgroundRectInFragmentedFlow.rect());
3705
3706 auto& enclosingFragmentedFlow = downcast<RenderFragmentedFlow>(paginationLayer->renderer());
3707 RenderLayer* parentPaginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(rootLayer, inclusionMode);
3708 LayerFragments ancestorFragments;
3709 if (parentPaginationLayer) {
3710 // Compute a bounding box accounting for fragments.
3711 LayoutRect layerFragmentBoundingBoxInParentPaginationLayer = enclosingFragmentedFlow.fragmentsBoundingBox(layerBoundingBoxInFragmentedFlow);
3712
3713 // Convert to be in the ancestor pagination context's coordinate space.
3714 LayoutSize offsetWithinParentPaginatedLayer = paginationLayer->offsetFromAncestor(parentPaginationLayer);
3715 layerFragmentBoundingBoxInParentPaginationLayer.move(offsetWithinParentPaginatedLayer);
3716
3717 // Now collect ancestor fragments.
3718 parentPaginationLayer->collectFragments(ancestorFragments, rootLayer, dirtyRect, inclusionMode, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip,
3719 offsetFromAncestor(rootLayer), &layerFragmentBoundingBoxInParentPaginationLayer, ApplyRootOffsetToFragments);
3720
3721 if (ancestorFragments.isEmpty())
3722 return;
3723
3724 for (auto& ancestorFragment : ancestorFragments) {
3725 // Shift the dirty rect into flow thread coordinates.
3726 LayoutRect dirtyRectInFragmentedFlow(dirtyRect);
3727 dirtyRectInFragmentedFlow.move(-offsetWithinParentPaginatedLayer - ancestorFragment.paginationOffset);
3728
3729 size_t oldSize = fragments.size();
3730
3731 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
3732 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
3733 enclosingFragmentedFlow.collectLayerFragments(fragments, layerBoundingBoxInFragmentedFlow, dirtyRectInFragmentedFlow);
3734
3735 size_t newSize = fragments.size();
3736
3737 if (oldSize == newSize)
3738 continue;
3739
3740 for (size_t i = oldSize; i < newSize; ++i) {
3741 LayerFragment& fragment = fragments.at(i);
3742
3743 // Set our four rects with all clipping applied that was internal to the flow thread.
3744 fragment.setRects(layerBoundsInFragmentedFlow, backgroundRectInFragmentedFlow, foregroundRectInFragmentedFlow, layerBoundingBoxInFragmentedFlow);
3745
3746 // Shift to the root-relative physical position used when painting the flow thread in this fragment.
3747 fragment.moveBy(toLayoutPoint(ancestorFragment.paginationOffset + fragment.paginationOffset + offsetWithinParentPaginatedLayer));
3748
3749 // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
3750 // properly clipped by the overflow.
3751 fragment.intersect(ancestorFragment.paginationClip);
3752
3753 // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
3754 // clip, so the column clip ends up being all we apply.
3755 fragment.intersect(fragment.paginationClip);
3756
3757 if (applyRootOffsetToFragments == ApplyRootOffsetToFragments)
3758 fragment.paginationOffset = fragment.paginationOffset + offsetWithinParentPaginatedLayer;
3759 }
3760 }
3761
3762 return;
3763 }
3764
3765 // Shift the dirty rect into flow thread coordinates.
3766 LayoutSize offsetOfPaginationLayerFromRoot = enclosingPaginationLayer(inclusionMode)->offsetFromAncestor(rootLayer);
3767 LayoutRect dirtyRectInFragmentedFlow(dirtyRect);
3768 dirtyRectInFragmentedFlow.move(-offsetOfPaginationLayerFromRoot);
3769
3770 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
3771 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
3772 enclosingFragmentedFlow.collectLayerFragments(fragments, layerBoundingBoxInFragmentedFlow, dirtyRectInFragmentedFlow);
3773
3774 if (fragments.isEmpty())
3775 return;
3776
3777 // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
3778 ClipRect ancestorClipRect = dirtyRect;
3779 if (paginationLayer->parent()) {
3780 ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
3781 ancestorClipRect = paginationLayer->backgroundClipRect(clipRectsContext);
3782 ancestorClipRect.intersect(dirtyRect);
3783 }
3784
3785 for (auto& fragment : fragments) {
3786 // Set our four rects with all clipping applied that was internal to the flow thread.
3787 fragment.setRects(layerBoundsInFragmentedFlow, backgroundRectInFragmentedFlow, foregroundRectInFragmentedFlow, layerBoundingBoxInFragmentedFlow);
3788
3789 // Shift to the root-relative physical position used when painting the flow thread in this fragment.
3790 fragment.moveBy(toLayoutPoint(fragment.paginationOffset + offsetOfPaginationLayerFromRoot));
3791
3792 // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
3793 // properly clipped by the overflow.
3794 fragment.intersect(ancestorClipRect);
3795
3796 // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
3797 // clip, so the column clip ends up being all we apply.
3798 fragment.intersect(fragment.paginationClip);
3799
3800 if (applyRootOffsetToFragments == ApplyRootOffsetToFragments)
3801 fragment.paginationOffset = fragment.paginationOffset + offsetOfPaginationLayerFromRoot;
3802 }
3803}
3804
3805void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintLayerFlag> localPaintFlags,
3806 bool shouldPaintContent, const LayoutSize& offsetFromRoot)
3807{
3808 for (auto& fragment : fragments) {
3809 fragment.shouldPaintContent = shouldPaintContent;
3810 if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerFlag::PaintingOverflowContents)) {
3811 LayoutSize newOffsetFromRoot = offsetFromRoot + fragment.paginationOffset;
3812 fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, newOffsetFromRoot, fragment.boundingBox);
3813 }
3814 }
3815}
3816
3817void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, OptionSet<PaintLayerFlag> paintFlags)
3818{
3819 LayerFragments enclosingPaginationFragments;
3820 LayoutSize offsetOfPaginationLayerFromRoot;
3821 RenderLayer* paginatedLayer = enclosingPaginationLayer(ExcludeCompositedPaginatedLayers);
3822 LayoutRect transformedExtent = transparencyClipBox(*this, paginatedLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
3823 paginatedLayer->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
3824 (paintFlags & PaintLayerFlag::TemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
3825 (paintFlags & PaintLayerFlag::PaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetOfPaginationLayerFromRoot, &transformedExtent);
3826
3827 for (const auto& fragment : enclosingPaginationFragments) {
3828 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
3829 // the enclosing pagination layer.
3830 LayoutRect clipRect = fragment.backgroundRect.rect();
3831
3832 // Now compute the clips within a given fragment
3833 if (parent() != paginatedLayer) {
3834 offsetOfPaginationLayerFromRoot = toLayoutSize(paginatedLayer->convertToLayerCoords(paintingInfo.rootLayer, toLayoutPoint(offsetOfPaginationLayerFromRoot)));
3835
3836 ClipRectsContext clipRectsContext(paginatedLayer, (paintFlags & PaintLayerFlag::TemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
3837 IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerFlag::PaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
3838 LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
3839 parentClipRect.move(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
3840 clipRect.intersect(parentClipRect);
3841 }
3842
3843 OptionSet<PaintBehavior> paintBehavior = PaintBehavior::Normal;
3844 if (paintFlags.contains(PaintLayerFlag::PaintingOverflowContents))
3845 paintBehavior.add(PaintBehavior::CompositedOverflowScrollContent);
3846
3847 GraphicsContextStateSaver stateSaver(context, false);
3848 EventRegionContextStateSaver eventRegionStateSaver(paintingInfo.eventRegionContext);
3849
3850 parent()->clipToRect(context, stateSaver, eventRegionStateSaver, paintingInfo, paintBehavior, clipRect);
3851 paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
3852 }
3853}
3854
3855void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext& context, GraphicsContext& contextForTransparencyLayer,
3856 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintBehavior> paintBehavior,
3857 RenderObject* subtreePaintRootForRenderer)
3858{
3859 for (const auto& fragment : layerFragments) {
3860 if (!fragment.shouldPaintContent)
3861 continue;
3862
3863 // Begin transparency layers lazily now that we know we have to paint something.
3864 if (haveTransparency)
3865 beginTransparencyLayers(contextForTransparencyLayer, localPaintingInfo, transparencyPaintDirtyRect);
3866
3867 GraphicsContextStateSaver stateSaver(context, false);
3868 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
3869
3870 if (localPaintingInfo.clipToDirtyRect) {
3871 // Paint our background first, before painting any child layers.
3872 // Establish the clip used to paint our background.
3873 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, paintBehavior, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
3874 }
3875
3876 // Paint the background.
3877 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
3878 PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhase::BlockBackground, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), this);
3879 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
3880 }
3881}
3882
3883void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext& context, GraphicsContext& contextForTransparencyLayer,
3884 const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintBehavior> paintBehavior,
3885 RenderObject* subtreePaintRootForRenderer)
3886{
3887 // Begin transparency if we have something to paint.
3888 if (haveTransparency) {
3889 for (const auto& fragment : layerFragments) {
3890 if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
3891 beginTransparencyLayers(contextForTransparencyLayer, localPaintingInfo, transparencyPaintDirtyRect);
3892 break;
3893 }
3894 }
3895 }
3896
3897 OptionSet<PaintBehavior> localPaintBehavior;
3898 if (localPaintingInfo.paintBehavior & PaintBehavior::ForceBlackText)
3899 localPaintBehavior = PaintBehavior::ForceBlackText;
3900 else if (localPaintingInfo.paintBehavior & PaintBehavior::ForceWhiteText)
3901 localPaintBehavior = PaintBehavior::ForceWhiteText;
3902 else
3903 localPaintBehavior = paintBehavior;
3904
3905 // FIXME: It's unclear if this flag copying is necessary.
3906 if (localPaintingInfo.paintBehavior & PaintBehavior::ExcludeSelection)
3907 localPaintBehavior.add(PaintBehavior::ExcludeSelection);
3908
3909 if (localPaintingInfo.paintBehavior & PaintBehavior::Snapshotting)
3910 localPaintBehavior.add(PaintBehavior::Snapshotting);
3911
3912 if (localPaintingInfo.paintBehavior & PaintBehavior::TileFirstPaint)
3913 localPaintBehavior.add(PaintBehavior::TileFirstPaint);
3914
3915 if (localPaintingInfo.paintBehavior & PaintBehavior::CompositedOverflowScrollContent)
3916 localPaintBehavior.add(PaintBehavior::CompositedOverflowScrollContent);
3917
3918 GraphicsContextStateSaver stateSaver(context, false);
3919 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
3920
3921 // Optimize clipping for the single fragment case.
3922 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
3923 if (shouldClip)
3924 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, localPaintBehavior, layerFragments[0].foregroundRect);
3925
3926 // We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for
3927 // interleaving of the fragments to work properly.
3928 bool selectionOnly = localPaintingInfo.paintBehavior.contains(PaintBehavior::SelectionOnly);
3929 bool selectionAndBackgroundsOnly = localPaintingInfo.paintBehavior.contains(PaintBehavior::SelectionAndBackgroundsOnly);
3930
3931#if ENABLE(LAYER_BASED_SVG_ENGINE)
3932 if (is<RenderSVGModelObject>(renderer()) && !is<RenderSVGContainer>(renderer())) {
3933 // SVG containers need to propagate paint phases. This could be saved if we remember somewhere if a SVG subtree
3934 // contains e.g. RenderSVGForeignObject objects that do need the individual paint phases. For SVG shapes & SVG images
3935 // we can avoid the multiple paintForegroundForFragmentsWithPhase() calls.
3936 if (selectionOnly || selectionAndBackgroundsOnly)
3937 return;
3938
3939 paintForegroundForFragmentsWithPhase(PaintPhase::Foreground, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3940 return;
3941 }
3942#endif
3943
3944 if (!selectionOnly)
3945 paintForegroundForFragmentsWithPhase(PaintPhase::ChildBlockBackgrounds, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3946
3947 if (selectionOnly || selectionAndBackgroundsOnly)
3948 paintForegroundForFragmentsWithPhase(PaintPhase::Selection, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3949 else {
3950 paintForegroundForFragmentsWithPhase(PaintPhase::Float, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3951 paintForegroundForFragmentsWithPhase(PaintPhase::Foreground, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3952 paintForegroundForFragmentsWithPhase(PaintPhase::ChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
3953 }
3954}
3955
3956void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext& context,
3957 const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintBehavior> paintBehavior, RenderObject* subtreePaintRootForRenderer)
3958{
3959 bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
3960
3961 for (const auto& fragment : layerFragments) {
3962 if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty())
3963 continue;
3964
3965 GraphicsContextStateSaver stateSaver(context, false);
3966 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
3967
3968 if (shouldClip)
3969 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, paintBehavior, fragment.foregroundRect);
3970
3971 PaintInfo paintInfo(context, fragment.foregroundRect.rect(), phase, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), this, localPaintingInfo.requireSecurityOriginAccessForWidgets);
3972 if (phase == PaintPhase::Foreground)
3973 paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
3974 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
3975 }
3976}
3977
3978void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo,
3979 OptionSet<PaintBehavior> paintBehavior, RenderObject* subtreePaintRootForRenderer)
3980{
3981 for (const auto& fragment : layerFragments) {
3982 if (fragment.backgroundRect.isEmpty())
3983 continue;
3984
3985 // Paint our own outline
3986 PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhase::SelfOutline, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), this);
3987
3988 GraphicsContextStateSaver stateSaver(context, false);
3989 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
3990
3991 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, paintBehavior, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius);
3992 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
3993 }
3994}
3995
3996void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo,
3997 OptionSet<PaintBehavior> paintBehavior, RenderObject* subtreePaintRootForRenderer)
3998{
3999 for (const auto& fragment : layerFragments) {
4000 if (!fragment.shouldPaintContent)
4001 continue;
4002
4003 GraphicsContextStateSaver stateSaver(context, false);
4004 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
4005
4006 if (localPaintingInfo.clipToDirtyRect)
4007 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, paintBehavior, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
4008
4009 // Paint the mask.
4010 // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
4011 PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhase::Mask, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), this);
4012 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
4013 }
4014}
4015
4016void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintBehavior> paintBehavior, RenderObject* subtreePaintRootForRenderer)
4017{
4018 for (const auto& fragment : layerFragments) {
4019 if (!fragment.shouldPaintContent)
4020 continue;
4021
4022 GraphicsContextStateSaver stateSaver(context, false);
4023 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
4024
4025 if (localPaintingInfo.clipToDirtyRect)
4026 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, paintBehavior, fragment.foregroundRect, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self.
4027
4028 // Paint the clipped mask.
4029 PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhase::ClippingMask, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), this);
4030 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
4031 }
4032}
4033
4034void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo)
4035{
4036 ASSERT(m_scrollableArea);
4037
4038 for (const auto& fragment : layerFragments) {
4039 if (fragment.backgroundRect.isEmpty())
4040 continue;
4041
4042 GraphicsContextStateSaver stateSaver(context, false);
4043 EventRegionContextStateSaver eventRegionStateSaver(localPaintingInfo.eventRegionContext);
4044
4045 clipToRect(context, stateSaver, eventRegionStateSaver, localPaintingInfo, { }, fragment.backgroundRect);
4046 m_scrollableArea->paintOverflowControls(context, roundedIntPoint(paintOffsetForRenderer(fragment, localPaintingInfo)), snappedIntRect(fragment.backgroundRect.rect()), true);
4047 }
4048}
4049
4050void RenderLayer::collectEventRegionForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo, OptionSet<PaintBehavior> paintBehavior)
4051{
4052 ASSERT(localPaintingInfo.eventRegionContext);
4053
4054 for (const auto& fragment : layerFragments) {
4055 PaintInfo paintInfo(context, fragment.foregroundRect.rect(), PaintPhase::EventRegion, paintBehavior);
4056 paintInfo.eventRegionContext = localPaintingInfo.eventRegionContext;
4057 renderer().paint(paintInfo, paintOffsetForRenderer(fragment, localPaintingInfo));
4058 }
4059}
4060
4061bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
4062{
4063 return hitTest(request, result.hitTestLocation(), result);
4064}
4065
4066bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result)
4067{
4068 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
4069 ASSERT(!renderer().view().needsLayout());
4070
4071 ASSERT(!isRenderFragmentedFlow());
4072 LayoutRect hitTestArea = renderer().view().documentRect();
4073 if (!request.ignoreClipping()) {
4074 const auto& settings = renderer().settings();
4075 if (settings.visualViewportEnabled() && settings.clientCoordinatesRelativeToLayoutViewport()) {
4076 auto& frameView = renderer().view().frameView();
4077 LayoutRect absoluteLayoutViewportRect = frameView.layoutViewportRect();
4078 auto scaleFactor = frameView.frame().frameScaleFactor();
4079 if (scaleFactor > 1)
4080 absoluteLayoutViewportRect.scale(scaleFactor);
4081 hitTestArea.intersect(absoluteLayoutViewportRect);
4082 } else
4083 hitTestArea.intersect(renderer().view().frameView().visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect));
4084 }
4085
4086 RenderLayer* insideLayer = hitTestLayer(this, nullptr, request, result, hitTestArea, hitTestLocation, false);
4087 if (!insideLayer) {
4088 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
4089 // return ourselves. We do this so mouse events continue getting delivered after a drag has
4090 // exited the WebView, and so hit testing over a scrollbar hits the content document.
4091 if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRenderViewLayer()) {
4092 renderer().updateHitTestResult(result, downcast<RenderView>(renderer()).flipForWritingMode(hitTestLocation.point()));
4093 insideLayer = this;
4094 }
4095 }
4096
4097 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
4098 Node* node = result.innerNode();
4099 if (node && !result.URLElement())
4100 result.setURLElement(node->enclosingLinkEventParentOrSelf());
4101
4102 // Now return whether we were inside this layer (this will always be true for the root
4103 // layer).
4104 return insideLayer;
4105}
4106
4107Element* RenderLayer::enclosingElement() const
4108{
4109 for (RenderElement* r = &renderer(); r; r = r->parent()) {
4110 if (Element* e = r->element())
4111 return e;
4112 }
4113 return nullptr;
4114}
4115
4116Vector<RenderLayer*> RenderLayer::topLayerRenderLayers(RenderView& renderView)
4117{
4118 Vector<RenderLayer*> layers;
4119 auto topLayerElements = renderView.document().topLayerElements();
4120 for (auto& element : topLayerElements) {
4121 auto* renderer = element->renderer();
4122 if (!renderer)
4123 continue;
4124
4125 auto backdropRenderer = renderer->backdropRenderer();
4126 if (backdropRenderer && backdropRenderer->hasLayer())
4127 layers.append(backdropRenderer->layer());
4128
4129 if (renderer->hasLayer())
4130 layers.append(downcast<RenderLayerModelObject>(*renderer).layer());
4131 }
4132 return layers;
4133}
4134
4135bool RenderLayer::establishesTopLayer() const
4136{
4137 return isInTopLayerOrBackdrop(renderer().style(), renderer().element());
4138}
4139
4140void RenderLayer::establishesTopLayerWillChange()
4141{
4142 if (auto* parentLayer = parent())
4143 parentLayer->removeChild(*this);
4144}
4145
4146void RenderLayer::establishesTopLayerDidChange()
4147{
4148 if (auto* parentLayer = renderer().layerParent())
4149 parentLayer->addChild(*this);
4150}
4151
4152RenderLayer* RenderLayer::enclosingFragmentedFlowAncestor() const
4153{
4154 RenderLayer* curr = parent();
4155 for (; curr && !curr->isRenderFragmentedFlow(); curr = curr->parent()) {
4156 if (curr->isStackingContext() && curr->isComposited()) {
4157 // We only adjust the position of the first level of layers.
4158 return nullptr;
4159 }
4160 }
4161 return curr;
4162}
4163
4164// Compute the z-offset of the point in the transformState.
4165// This is effectively projecting a ray normal to the plane of ancestor, finding where that
4166// ray intersects target, and computing the z delta between those two points.
4167static double computeZOffset(const HitTestingTransformState& transformState)
4168{
4169 // We got an affine transform, so no z-offset
4170 if (transformState.m_accumulatedTransform.isAffine())
4171 return 0;
4172
4173 // Flatten the point into the target plane
4174 FloatPoint targetPoint = transformState.mappedPoint();
4175
4176 // Now map the point back through the transform, which computes Z.
4177 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
4178 return backmappedPoint.z();
4179}
4180
4181Ref<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
4182 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
4183 const HitTestingTransformState* containerTransformState,
4184 const LayoutSize& translationOffset) const
4185{
4186 RefPtr<HitTestingTransformState> transformState;
4187 LayoutSize offset;
4188 if (containerTransformState) {
4189 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
4190 transformState = HitTestingTransformState::create(*containerTransformState);
4191 offset = offsetFromAncestor(containerLayer);
4192 } else {
4193 // If this is the first time we need to make transform state, then base it off of hitTestLocation,
4194 // which is relative to rootLayer.
4195 transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
4196 offset = offsetFromAncestor(rootLayer);
4197 }
4198 offset += translationOffset;
4199
4200 RenderObject* containerRenderer = containerLayer ? &containerLayer->renderer() : nullptr;
4201 if (renderer().shouldUseTransformFromContainer(containerRenderer)) {
4202 TransformationMatrix containerTransform;
4203 renderer().getTransformFromContainer(containerRenderer, offset, containerTransform);
4204 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
4205 } else {
4206 transformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
4207 }
4208
4209 return transformState.releaseNonNull();
4210}
4211
4212
4213static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
4214{
4215 if (!hitLayer)
4216 return false;
4217
4218 // The hit layer is depth-sorting with other layers, so just say that it was hit.
4219 if (canDepthSort)
4220 return true;
4221
4222 // We need to look at z-depth to decide if this layer was hit.
4223 if (zOffset) {
4224 ASSERT(transformState);
4225 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
4226 double childZOffset = computeZOffset(*transformState);
4227 if (childZOffset > *zOffset) {
4228 *zOffset = childZOffset;
4229 return true;
4230 }
4231 return false;
4232 }
4233
4234 return true;
4235}
4236
4237// hitTestLocation and hitTestRect are relative to rootLayer.
4238// A 'flattening' layer is one preserves3D() == false.
4239// transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
4240// transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer.
4241// transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
4242//
4243// If zOffset is non-null (which indicates that the caller wants z offset information),
4244// *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
4245RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
4246 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
4247 const HitTestingTransformState* transformState, double* zOffset)
4248{
4249 updateLayerListsIfNeeded();
4250
4251 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
4252 return nullptr;
4253
4254 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
4255
4256 // Apply a transform if we have one.
4257 if (transform() && !appliedTransform) {
4258 if (enclosingPaginationLayer(IncludeCompositedPaginatedLayers))
4259 return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
4260
4261 // Make sure the parent's clip rects have been calculated.
4262 if (parent()) {
4263 ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
4264 ClipRect clipRect = backgroundClipRect(clipRectsContext);
4265 // Test the enclosing clip now.
4266 if (!clipRect.intersects(hitTestLocation))
4267 return nullptr;
4268 }
4269
4270 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
4271 }
4272
4273 // Ensure our lists and 3d status are up-to-date.
4274 update3DTransformedDescendantStatus();
4275
4276 RefPtr<HitTestingTransformState> localTransformState;
4277 if (appliedTransform) {
4278 // We computed the correct state in the caller (above code), so just reference it.
4279 ASSERT(transformState);
4280 localTransformState = const_cast<HitTestingTransformState*>(transformState);
4281 } else if (transformState || has3DTransformedDescendant() || preserves3D()) {
4282 // We need transform state for the first time, or to offset the container state, so create it here.
4283 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
4284 }
4285
4286 // Check for hit test on backface if backface-visibility is 'hidden'
4287 if (localTransformState && renderer().style().backfaceVisibility() == BackfaceVisibility::Hidden) {
4288 std::optional<TransformationMatrix> invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
4289 // If the z-vector of the matrix is negative, the back is facing towards the viewer.
4290 if (invertedMatrix && invertedMatrix.value().m33() < 0)
4291 return nullptr;
4292 }
4293
4294 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
4295 if (localTransformState && !preserves3D()) {
4296 // Keep a copy of the pre-flattening state, for computing z-offsets for the container
4297 unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
4298 // This layer is flattening, so flatten the state passed to descendants.
4299 localTransformState->flatten();
4300 }
4301
4302 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
4303 // descendants.
4304 double localZOffset = -std::numeric_limits<double>::infinity();
4305 double* zOffsetForDescendantsPtr = nullptr;
4306 double* zOffsetForContentsPtr = nullptr;
4307
4308 bool depthSortDescendants = false;
4309 if (preserves3D()) {
4310 depthSortDescendants = true;
4311 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
4312 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
4313 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
4314 } else if (zOffset) {
4315 zOffsetForDescendantsPtr = nullptr;
4316 // Container needs us to give back a z offset for the hit layer.
4317 zOffsetForContentsPtr = zOffset;
4318 }
4319
4320 // This variable tracks which layer the mouse ends up being inside.
4321 RenderLayer* candidateLayer = nullptr;
4322#if ASSERT_ENABLED
4323 LayerListMutationDetector mutationChecker(*this);
4324#endif
4325
4326 auto offsetFromRoot = offsetFromAncestor(rootLayer);
4327 // FIXME: We need to correctly hit test the clip-path when we have a RenderInline too.
4328 if (auto* rendererBox = this->renderBox(); rendererBox && !rendererBox->hitTestClipPath(hitTestLocation, toLayoutPoint(offsetFromRoot - toLayoutSize(rendererLocation()))))
4329 return nullptr;
4330
4331 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
4332 auto* hitLayer = hitTestList(positiveZOrderLayers(), rootLayer, request, result, hitTestRect, hitTestLocation,
4333 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
4334 if (hitLayer) {
4335 if (!depthSortDescendants)
4336 return hitLayer;
4337 candidateLayer = hitLayer;
4338 }
4339
4340 // Now check our overflow objects.
4341 hitLayer = hitTestList(normalFlowLayers(), rootLayer, request, result, hitTestRect, hitTestLocation,
4342 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
4343 if (hitLayer) {
4344 if (!depthSortDescendants)
4345 return hitLayer;
4346 candidateLayer = hitLayer;
4347 }
4348
4349 // Collect the fragments. This will compute the clip rectangles for each layer fragment.
4350 LayerFragments layerFragments;
4351 collectFragments(layerFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers, RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, offsetFromRoot);
4352
4353 LayoutPoint localPoint;
4354 if (canResize() && m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation, localPoint)) {
4355 renderer().updateHitTestResult(result, localPoint);
4356 return this;
4357 }
4358
4359 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check
4360 // every fragment in reverse order.
4361 if (isSelfPaintingLayer()) {
4362 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
4363 HitTestResult tempResult(result.hitTestLocation());
4364 bool insideFragmentForegroundRect = false;
4365 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect)
4366 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
4367 if (request.resultIsElementList())
4368 result.append(tempResult, request);
4369 else
4370 result = tempResult;
4371 if (!depthSortDescendants)
4372 return this;
4373 // Foreground can depth-sort with descendant layers, so keep this as a candidate.
4374 candidateLayer = this;
4375 } else if (insideFragmentForegroundRect && request.resultIsElementList())
4376 result.append(tempResult, request);
4377 }
4378
4379 // Now check our negative z-index children.
4380 hitLayer = hitTestList(negativeZOrderLayers(), rootLayer, request, result, hitTestRect, hitTestLocation,
4381 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
4382 if (hitLayer) {
4383 if (!depthSortDescendants)
4384 return hitLayer;
4385 candidateLayer = hitLayer;
4386 }
4387
4388 // If we found a layer, return. Child layers, and foreground always render in front of background.
4389 if (candidateLayer)
4390 return candidateLayer;
4391
4392 if (isSelfPaintingLayer()) {
4393 HitTestResult tempResult(result.hitTestLocation());
4394 bool insideFragmentBackgroundRect = false;
4395 if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect)
4396 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
4397 if (request.resultIsElementList())
4398 result.append(tempResult, request);
4399 else
4400 result = tempResult;
4401 return this;
4402 }
4403 if (insideFragmentBackgroundRect && request.resultIsElementList())
4404 result.append(tempResult, request);
4405 }
4406
4407 return nullptr;
4408}
4409
4410bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result,
4411 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& insideClipRect) const
4412{
4413 if (layerFragments.isEmpty())
4414 return false;
4415
4416 for (int i = layerFragments.size() - 1; i >= 0; --i) {
4417 const LayerFragment& fragment = layerFragments.at(i);
4418 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects(hitTestLocation))
4419 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.intersects(hitTestLocation)))
4420 continue;
4421 insideClipRect = true;
4422 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocation, hitTestFilter))
4423 return true;
4424 }
4425
4426 return false;
4427}
4428
4429RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
4430 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
4431{
4432 LayerFragments enclosingPaginationFragments;
4433 LayoutSize offsetOfPaginationLayerFromRoot;
4434 RenderLayer* paginatedLayer = enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
4435 LayoutRect transformedExtent = transparencyClipBox(*this, paginatedLayer, HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
4436 paginatedLayer->collectFragments(enclosingPaginationFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers,
4437 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, offsetOfPaginationLayerFromRoot, &transformedExtent);
4438
4439 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
4440 const LayerFragment& fragment = enclosingPaginationFragments.at(i);
4441
4442 // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
4443 // the enclosing pagination layer.
4444 LayoutRect clipRect = fragment.backgroundRect.rect();
4445
4446 // Now compute the clips within a given fragment
4447 if (parent() != paginatedLayer) {
4448 offsetOfPaginationLayerFromRoot = toLayoutSize(paginatedLayer->convertToLayerCoords(rootLayer, toLayoutPoint(offsetOfPaginationLayerFromRoot)));
4449
4450 ClipRectsContext clipRectsContext(paginatedLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
4451 LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
4452 parentClipRect.move(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
4453 clipRect.intersect(parentClipRect);
4454 }
4455
4456 if (!hitTestLocation.intersects(clipRect))
4457 continue;
4458
4459 RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation,
4460 transformState, zOffset, fragment.paginationOffset);
4461 if (hitLayer)
4462 return hitLayer;
4463 }
4464
4465 return nullptr;
4466}
4467
4468RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
4469 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
4470 const LayoutSize& translationOffset)
4471{
4472 // Create a transform state to accumulate this transform.
4473 Ref<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
4474
4475 // If the transform can't be inverted, then don't hit test this layer at all.
4476 if (!newTransformState->m_accumulatedTransform.isInvertible())
4477 return nullptr;
4478
4479 // Compute the point and the hit test rect in the coords of this layer by using the values
4480 // from the transformState, which store the point and quad in the coords of the last flattened
4481 // layer, and the accumulated transform which lets up map through preserve-3d layers.
4482 //
4483 // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
4484 // by our container.
4485 FloatPoint localPoint = newTransformState->mappedPoint();
4486 FloatQuad localPointQuad = newTransformState->mappedQuad();
4487 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
4488 HitTestLocation newHitTestLocation;
4489 if (hitTestLocation.isRectBasedTest())
4490 newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
4491 else
4492 newHitTestLocation = HitTestLocation(flooredLayoutPoint(localPoint));
4493
4494 // Now do a hit test with the root layer shifted to be us.
4495 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.ptr(), zOffset);
4496}
4497
4498bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const
4499{
4500 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
4501
4502 if (!renderer().hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - rendererLocation()), hitTestFilter)) {
4503 // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
4504 // a rect-based test.
4505 ASSERT(!result.innerNode() || (request.resultIsElementList() && result.listBasedTestResult().size()));
4506 return false;
4507 }
4508
4509 // For positioned generated content, we might still not have a
4510 // node by the time we get to the layer level, since none of
4511 // the content in the layer has an element. So just walk up
4512 // the tree.
4513 if (!result.innerNode() || !result.innerNonSharedNode()) {
4514 Element* e = enclosingElement();
4515 if (!result.innerNode())
4516 result.setInnerNode(e);
4517 if (!result.innerNonSharedNode())
4518 result.setInnerNonSharedNode(e);
4519 }
4520
4521 return true;
4522}
4523
4524RenderLayer* RenderLayer::hitTestList(LayerList layerIterator, RenderLayer* rootLayer,
4525 const HitTestRequest& request, HitTestResult& result,
4526 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
4527 const HitTestingTransformState* transformState,
4528 double* zOffsetForDescendants, double* zOffset,
4529 const HitTestingTransformState* unflattenedTransformState,
4530 bool depthSortDescendants)
4531{
4532 if (layerIterator.begin() == layerIterator.end())
4533 return nullptr;
4534
4535 if (!hasSelfPaintingLayerDescendant())
4536 return nullptr;
4537
4538 RenderLayer* resultLayer = nullptr;
4539
4540 for (auto iter = layerIterator.rbegin(); iter != layerIterator.rend(); ++iter) {
4541 auto* childLayer = *iter;
4542
4543 HitTestResult tempResult(result.hitTestLocation());
4544 auto* hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
4545
4546 // If it is a list-based test, we can safely append the temporary result since it might had hit
4547 // nodes but not necessarily had hitLayer set.
4548 ASSERT(!result.isRectBasedTest() || request.resultIsElementList());
4549 if (request.resultIsElementList())
4550 result.append(tempResult, request);
4551
4552 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
4553 resultLayer = hitLayer;
4554 if (!request.resultIsElementList())
4555 result = tempResult;
4556 if (!depthSortDescendants)
4557 break;
4558 }
4559 }
4560
4561 return resultLayer;
4562}
4563
4564Ref<ClipRects> RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
4565{
4566 ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
4567 ASSERT(clipRectsType < NumCachedClipRectsTypes);
4568 if (m_clipRectsCache) {
4569 if (auto* clipRects = m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) {
4570 ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
4571 ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
4572
4573#ifdef CHECK_CACHED_CLIP_RECTS
4574 // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
4575 ClipRectsContext tempContext(clipRectsContext);
4576 tempContext.clipRectsType = TemporaryClipRects;
4577 Ref<ClipRects> tempClipRects = ClipRects::create();
4578 calculateClipRects(tempContext, tempClipRects);
4579 ASSERT(tempClipRects.get() == *clipRects);
4580#endif
4581 return *clipRects; // We have the correct cached value.
4582 }
4583 }
4584
4585 if (!m_clipRectsCache)
4586 m_clipRectsCache = makeUnique<ClipRectsCache>();
4587#if ASSERT_ENABLED
4588 m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer;
4589 m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy;
4590#endif
4591
4592 RefPtr<ClipRects> parentClipRects;
4593 // For transformed layers, the root layer was shifted to be us, so there is no need to
4594 // examine the parent. We want to cache clip rects with us as the root.
4595 if (clipRectsContext.rootLayer != this && parent())
4596 parentClipRects = this->parentClipRects(clipRectsContext);
4597
4598 auto clipRects = ClipRects::create();
4599 calculateClipRects(clipRectsContext, clipRects);
4600
4601 if (parentClipRects && *parentClipRects == clipRects) {
4602 m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentClipRects.copyRef());
4603 return parentClipRects.releaseNonNull();
4604 }
4605 m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, clipRects.copyRef());
4606 return clipRects;
4607}
4608
4609ClipRects* RenderLayer::clipRects(const ClipRectsContext& context) const
4610{
4611 ASSERT(context.clipRectsType < NumCachedClipRectsTypes);
4612 if (!m_clipRectsCache)
4613 return nullptr;
4614 return m_clipRectsCache->getClipRects(context.clipRectsType, context.respectOverflowClip);
4615}
4616
4617bool RenderLayer::clipCrossesPaintingBoundary() const
4618{
4619 return parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers) != enclosingPaginationLayer(IncludeCompositedPaginatedLayers)
4620 || parent()->enclosingCompositingLayerForRepaint().layer != enclosingCompositingLayerForRepaint().layer;
4621}
4622
4623void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
4624{
4625 if (!parent()) {
4626 // The root layer's clip rect is always infinite.
4627 clipRects.reset();
4628 return;
4629 }
4630
4631 ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
4632 bool useCached = clipRectsType != TemporaryClipRects;
4633
4634 // For transformed layers, the root layer was shifted to be us, so there is no need to
4635 // examine the parent. We want to cache clip rects with us as the root.
4636 RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : nullptr;
4637
4638 // Ensure that our parent's clip has been calculated so that we can examine the values.
4639 if (parentLayer) {
4640 if (useCached && parentLayer->clipRects(clipRectsContext))
4641 clipRects = *parentLayer->clipRects(clipRectsContext);
4642 else {
4643 ClipRectsContext parentContext(clipRectsContext);
4644 parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why?
4645
4646 if ((parentContext.clipRectsType != TemporaryClipRects && parentContext.clipRectsType != AbsoluteClipRects) && clipCrossesPaintingBoundary())
4647 parentContext.clipRectsType = TemporaryClipRects;
4648
4649 parentLayer->calculateClipRects(parentContext, clipRects);
4650 }
4651 } else
4652 clipRects.reset();
4653
4654 // A fixed object is essentially the root of its containing block hierarchy, so when
4655 // we encounter such an object, we reset our clip rects to the fixedClipRect.
4656 if (renderer().isFixedPositioned()) {
4657 clipRects.setPosClipRect(clipRects.fixedClipRect());
4658 clipRects.setOverflowClipRect(clipRects.fixedClipRect());
4659 clipRects.setFixed(true);
4660 } else if (renderer().isInFlowPositioned())
4661 clipRects.setPosClipRect(clipRects.overflowClipRect());
4662 else if (renderer().isAbsolutelyPositioned())
4663 clipRects.setOverflowClipRect(clipRects.posClipRect());
4664
4665 // Update the clip rects that will be passed to child layers.
4666#if PLATFORM(IOS_FAMILY)
4667 if (renderer().hasClipOrNonVisibleOverflow() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || this != clipRectsContext.rootLayer)) {
4668#else
4669 if ((renderer().hasNonVisibleOverflow() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || this != clipRectsContext.rootLayer)) || renderer().hasClip()) {
4670#endif
4671 // This layer establishes a clip of some kind.
4672 LayoutPoint offset;
4673 if (!m_hasTransformedAncestor && canUseOffsetFromAncestor())
4674 offset = toLayoutPoint(offsetFromAncestor(clipRectsContext.rootLayer, AdjustForColumns));
4675 else
4676 offset = LayoutPoint(renderer().localToContainerPoint(FloatPoint(), &clipRectsContext.rootLayer->renderer()));
4677
4678 if (clipRects.fixed() && &clipRectsContext.rootLayer->renderer() == &renderer().view())
4679 offset -= toLayoutSize(renderer().view().frameView().scrollPositionForFixedPosition());
4680
4681 if (renderer().hasNonVisibleOverflow()) {
4682 ClipRect newOverflowClip;
4683 if (is<RenderBox>(renderer()))
4684 newOverflowClip = downcast<RenderBox>(renderer()).overflowClipRectForChildLayers(offset, nullptr, clipRectsContext.overlayScrollbarSizeRelevancy);
4685#if ENABLE(LAYER_BASED_SVG_ENGINE)
4686 else if (is<RenderSVGModelObject>(renderer()))
4687 newOverflowClip = downcast<RenderSVGModelObject>(renderer()).overflowClipRectForChildLayers(offset, nullptr, clipRectsContext.overlayScrollbarSizeRelevancy);
4688#endif
4689 else {
4690 ASSERT_NOT_REACHED();
4691 return;
4692 }
4693
4694 newOverflowClip.setAffectedByRadius(renderer().style().hasBorderRadius());
4695 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
4696 if (renderer().isPositioned())
4697 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
4698 if (renderer().shouldApplyPaintContainment()) {
4699 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
4700 clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect()));
4701 }
4702 }
4703 if (renderer().hasClip() && is<RenderBox>(renderer())) {
4704 LayoutRect newPosClip = downcast<RenderBox>(renderer()).clipRect(offset, nullptr);
4705 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
4706 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
4707 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
4708 }
4709 } else if (renderer().hasNonVisibleOverflow() && transform() && renderer().style().hasBorderRadius())
4710 clipRects.setOverflowClipRectAffectedByRadius();
4711
4712 LOG_WITH_STREAM(ClipRects, stream << "RenderLayer " << this << " calculateClipRects " << clipRectsContext << " computed " << clipRects);
4713}
4714
4715Ref<ClipRects> RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext) const
4716{
4717 ASSERT(parent());
4718
4719 auto containerLayer = parent();
4720 auto temporaryParentClipRects = [&](const ClipRectsContext& clipContext) {
4721 auto parentClipRects = ClipRects::create();
4722 containerLayer->calculateClipRects(clipContext, parentClipRects);
4723 return parentClipRects;
4724 };
4725
4726 if (clipRectsContext.clipRectsType == TemporaryClipRects)
4727 return temporaryParentClipRects(clipRectsContext);
4728
4729 if (clipRectsContext.clipRectsType != AbsoluteClipRects && clipCrossesPaintingBoundary()) {
4730 ClipRectsContext tempClipRectsContext(clipRectsContext);
4731 tempClipRectsContext.clipRectsType = TemporaryClipRects;
4732 return temporaryParentClipRects(tempClipRectsContext);
4733 }
4734
4735 return containerLayer->updateClipRects(clipRectsContext);
4736}
4737
4738static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, PositionType position)
4739{
4740 if (position == PositionType::Fixed)
4741 return parentRects.fixedClipRect();
4742
4743 if (position == PositionType::Absolute)
4744 return parentRects.posClipRect();
4745
4746 return parentRects.overflowClipRect();
4747}
4748
4749ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const
4750{
4751 ASSERT(parent());
4752 auto parentRects = parentClipRects(clipRectsContext);
4753 ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer().style().position());
4754 RenderView& view = renderer().view();
4755 // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
4756 if (parentRects->fixed() && &clipRectsContext.rootLayer->renderer() == &view && !backgroundClipRect.isInfinite())
4757 backgroundClipRect.moveBy(view.frameView().scrollPositionForFixedPosition());
4758
4759 LOG_WITH_STREAM(ClipRects, stream << "RenderLayer " << this << " backgroundClipRect with context " << clipRectsContext << " returning " << backgroundClipRect);
4760 return backgroundClipRect;
4761}
4762
4763void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
4764 ClipRect& backgroundRect, ClipRect& foregroundRect, const LayoutSize& offsetFromRoot) const
4765{
4766 if (clipRectsContext.rootLayer != this && parent()) {
4767 backgroundRect = backgroundClipRect(clipRectsContext);
4768 backgroundRect.intersect(paintDirtyRect);
4769 } else
4770 backgroundRect = paintDirtyRect;
4771
4772 LayoutSize offsetFromRootLocal = offsetFromRoot;
4773
4774 layerBounds = LayoutRect(toLayoutPoint(offsetFromRootLocal), size());
4775
4776 foregroundRect = backgroundRect;
4777
4778 // Update the clip rects that will be passed to child layers.
4779 if (renderer().hasClipOrNonVisibleOverflow()) {
4780 // This layer establishes a clip of some kind.
4781 if (renderer().hasNonVisibleOverflow()) {
4782 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) {
4783 LayoutRect overflowClipRect;
4784
4785 if (is<RenderBox>(renderer()))
4786 overflowClipRect = downcast<RenderBox>(renderer()).overflowClipRect(toLayoutPoint(offsetFromRootLocal), nullptr, clipRectsContext.overlayScrollbarSizeRelevancy);
4787#if ENABLE(LAYER_BASED_SVG_ENGINE)
4788 else if (is<RenderSVGModelObject>(renderer()))
4789 overflowClipRect = downcast<RenderSVGModelObject>(renderer()).overflowClipRect(toLayoutPoint(offsetFromRootLocal), nullptr, clipRectsContext.overlayScrollbarSizeRelevancy);
4790#endif
4791 else {
4792 ASSERT_NOT_REACHED();
4793 return;
4794 }
4795
4796 foregroundRect.intersect(overflowClipRect);
4797 foregroundRect.setAffectedByRadius(true);
4798 } else if (transform() && renderer().style().hasBorderRadius())
4799 foregroundRect.setAffectedByRadius(true);
4800 }
4801
4802 if (renderer().hasClip() && is<RenderBox>(renderer())) {
4803 // Clip applies to *us* as well, so update the damageRect.
4804 LayoutRect newPosClip = downcast<RenderBox>(renderer()).clipRect(toLayoutPoint(offsetFromRootLocal), nullptr);
4805 backgroundRect.intersect(newPosClip);
4806 foregroundRect.intersect(newPosClip);
4807 }
4808
4809 // If we establish a clip at all, then make sure our background rect is intersected with our layer's bounds including our visual overflow,
4810 // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden.
4811 if (renderBox() && renderBox()->hasVisualOverflow()) {
4812 // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the
4813 // individual region boxes as overflow.
4814 LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect();
4815 renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped.
4816 layerBoundsWithVisualOverflow.move(offsetFromRootLocal);
4817 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
4818 backgroundRect.intersect(layerBoundsWithVisualOverflow);
4819 } else {
4820 // Shift the bounds to be for our region only.
4821 LayoutRect bounds = renderBox()->borderBoxRectInFragment(nullptr);
4822
4823 bounds.move(offsetFromRootLocal);
4824 if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
4825 backgroundRect.intersect(bounds);
4826 }
4827 }
4828}
4829
4830LayoutRect RenderLayer::childrenClipRect() const
4831{
4832 // FIXME: border-radius not accounted for.
4833 // FIXME: Regions not accounted for.
4834 RenderLayer* clippingRootLayer = clippingRootForPainting();
4835 LayoutRect layerBounds;
4836 ClipRect backgroundRect;
4837 ClipRect foregroundRect;
4838 ClipRectsContext clipRectsContext(clippingRootLayer, TemporaryClipRects);
4839 // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
4840 calculateRects(clipRectsContext, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, offsetFromAncestor(clipRectsContext.rootLayer));
4841 if (foregroundRect.rect().isInfinite())
4842 return renderer().view().unscaledDocumentRect();
4843
4844 auto absoluteClippingRect = clippingRootLayer->renderer().localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
4845 return intersection(absoluteClippingRect, renderer().view().unscaledDocumentRect());
4846}
4847
4848LayoutRect RenderLayer::clipRectRelativeToAncestor(RenderLayer* ancestor, LayoutSize offsetFromAncestor, const LayoutRect& constrainingRect) const
4849{
4850 LayoutRect layerBounds;
4851 ClipRect backgroundRect;
4852 ClipRect foregroundRect;
4853 auto clipRectType = !m_enclosingPaginationLayer || m_enclosingPaginationLayer == ancestor ? PaintingClipRects : TemporaryClipRects;
4854 ClipRectsContext clipRectsContext(ancestor, clipRectType);
4855 calculateRects(clipRectsContext, constrainingRect, layerBounds, backgroundRect, foregroundRect, offsetFromAncestor);
4856 return backgroundRect.rect();
4857}
4858
4859LayoutRect RenderLayer::selfClipRect() const
4860{
4861 // FIXME: border-radius not accounted for.
4862 // FIXME: Regions not accounted for.
4863 RenderLayer* clippingRootLayer = clippingRootForPainting();
4864 LayoutRect clipRect = clipRectRelativeToAncestor(clippingRootLayer, offsetFromAncestor(clippingRootLayer), renderer().view().documentRect());
4865 return clippingRootLayer->renderer().localToAbsoluteQuad(FloatQuad(clipRect)).enclosingBoundingBox();
4866}
4867
4868LayoutRect RenderLayer::localClipRect(bool& clipExceedsBounds) const
4869{
4870 clipExceedsBounds = false;
4871 // FIXME: border-radius not accounted for.
4872 // FIXME: Regions not accounted for.
4873 RenderLayer* clippingRootLayer = clippingRootForPainting();
4874 LayoutSize offsetFromRoot = offsetFromAncestor(clippingRootLayer);
4875 LayoutRect clipRect = clipRectRelativeToAncestor(clippingRootLayer, offsetFromRoot, LayoutRect::infiniteRect());
4876 if (clipRect.isInfinite())
4877 return clipRect;
4878
4879 if (renderer().hasClip() && is<RenderBox>(renderer())) {
4880 // CSS clip may be larger than our border box.
4881 LayoutRect cssClipRect = downcast<RenderBox>(renderer()).clipRect({ }, nullptr);
4882 clipExceedsBounds = !cssClipRect.isEmpty() && (clipRect.width() < cssClipRect.width() || clipRect.height() < cssClipRect.height());
4883 }
4884
4885 clipRect.move(-offsetFromRoot);
4886 return clipRect;
4887}
4888
4889void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds)
4890{
4891 m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds));
4892}
4893
4894void RenderLayer::clearBlockSelectionGapsBounds()
4895{
4896 m_blockSelectionGapsBounds = IntRect();
4897 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
4898 child->clearBlockSelectionGapsBounds();
4899}
4900
4901void RenderLayer::repaintBlockSelectionGaps()
4902{
4903 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
4904 child->repaintBlockSelectionGaps();
4905
4906 if (m_blockSelectionGapsBounds.isEmpty())
4907 return;
4908
4909 LayoutRect rect = m_blockSelectionGapsBounds;
4910 if (m_scrollableArea)
4911 rect.moveBy(-m_scrollableArea->scrollPosition());
4912 if (renderer().hasNonVisibleOverflow() && !usesCompositedScrolling())
4913 rect.intersect(downcast<RenderBox>(renderer()).overflowClipRect(LayoutPoint(), nullptr)); // FIXME: Regions not accounted for.
4914 if (renderer().hasClip())
4915 rect.intersect(downcast<RenderBox>(renderer()).clipRect(LayoutPoint(), nullptr)); // FIXME: Regions not accounted for.
4916 if (!rect.isEmpty())
4917 renderer().repaintRectangle(rect);
4918}
4919
4920bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutSize& offsetFromRoot, const std::optional<LayoutRect>& cachedBoundingBox) const
4921{
4922 // Always examine the canvas and the root.
4923 // FIXME: Could eliminate the isDocumentElementRenderer() check if we fix background painting so that the RenderView
4924 // paints the root's background.
4925 if (isRenderViewLayer() || renderer().isDocumentElementRenderer())
4926 return true;
4927
4928 if (damageRect.isInfinite())
4929 return true;
4930
4931 if (damageRect.isEmpty())
4932 return false;
4933
4934 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we can return true.
4935 if (!renderer().isRenderInline() && layerBounds.intersects(damageRect))
4936 return true;
4937
4938 // Otherwise we need to compute the bounding box of this single layer and see if it intersects
4939 // the damage rect. It's possible the fragment computed the bounding box already, in which case we
4940 // can use the cached value.
4941 if (cachedBoundingBox)
4942 return cachedBoundingBox->intersects(damageRect);
4943
4944 return boundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
4945}
4946
4947LayoutRect RenderLayer::localBoundingBox(OptionSet<CalculateLayerBoundsFlag> flags) const
4948{
4949 // There are three special cases we need to consider.
4950 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
4951 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
4952 // line boxes of all three lines (including overflow on those lines).
4953 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
4954 // overflow, we have to create a bounding box that will extend to include this overflow.
4955 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
4956 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
4957 // floats.
4958 LayoutRect result;
4959 if (renderer().isInline() && is<RenderInline>(renderer()))
4960 result = downcast<RenderInline>(renderer()).linesVisualOverflowBoundingBox();
4961#if ENABLE(LAYER_BASED_SVG_ENGINE)
4962 else if (is<RenderSVGModelObject>(renderer()))
4963 result = downcast<RenderSVGModelObject>(renderer()).visualOverflowRectEquivalent();
4964#endif
4965 else if (is<RenderTableRow>(renderer())) {
4966 auto& tableRow = downcast<RenderTableRow>(renderer());
4967 // Our bounding box is just the union of all of our cells' border/overflow rects.
4968 for (RenderTableCell* cell = tableRow.firstCell(); cell; cell = cell->nextCell()) {
4969 LayoutRect bbox = cell->borderBoxRect();
4970 result.unite(bbox);
4971 LayoutRect overflowRect = tableRow.visualOverflowRect();
4972 if (bbox != overflowRect)
4973 result.unite(overflowRect);
4974 }
4975 } else {
4976 RenderBox* box = renderBox();
4977 ASSERT(box);
4978 if (!(flags & DontConstrainForMask) && box->hasMask()) {
4979 result = box->maskClipRect(LayoutPoint());
4980 box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not.
4981 } else
4982 result = box->visualOverflowRect();
4983 }
4984 return result;
4985}
4986
4987LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, OptionSet<CalculateLayerBoundsFlag> flags) const
4988{
4989 LayoutRect result = localBoundingBox(flags);
4990 if (renderer().view().frameView().hasFlippedBlockRenderers()) {
4991 if (renderer().isBox())
4992 renderBox()->flipForWritingMode(result);
4993 else
4994 renderer().containingBlock()->flipForWritingMode(result);
4995 }
4996
4997 PaginationInclusionMode inclusionMode = ExcludeCompositedPaginatedLayers;
4998 if (flags & UseFragmentBoxesIncludingCompositing)
4999 inclusionMode = IncludeCompositedPaginatedLayers;
5000
5001 const RenderLayer* paginationLayer = nullptr;
5002 if (flags.containsAny({ UseFragmentBoxesExcludingCompositing, UseFragmentBoxesIncludingCompositing }))
5003 paginationLayer = enclosingPaginationLayerInSubtree(ancestorLayer, inclusionMode);
5004
5005 const RenderLayer* childLayer = this;
5006 bool isPaginated = paginationLayer;
5007 while (paginationLayer) {
5008 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
5009 // get our true bounding box.
5010 result.move(childLayer->offsetFromAncestor(paginationLayer));
5011
5012 auto& enclosingFragmentedFlow = downcast<RenderFragmentedFlow>(paginationLayer->renderer());
5013 result = enclosingFragmentedFlow.fragmentsBoundingBox(result);
5014
5015 childLayer = paginationLayer;
5016 paginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(ancestorLayer, inclusionMode);
5017 }
5018
5019 if (isPaginated) {
5020 result.move(childLayer->offsetFromAncestor(ancestorLayer));
5021 return result;
5022 }
5023
5024 result.move(offsetFromRoot);
5025 return result;
5026}
5027
5028bool RenderLayer::getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(LayoutRect& bounds, OptionSet<CalculateLayerBoundsFlag> additionalFlags) const
5029{
5030 // The animation will override the display transform, so don't include it.
5031 auto boundsFlags = additionalFlags | (defaultCalculateLayerBoundsFlags() - IncludeSelfTransform);
5032
5033 bounds = calculateLayerBounds(this, LayoutSize(), boundsFlags);
5034
5035 LayoutRect animatedBounds = bounds;
5036 if (auto styleable = Styleable::fromRenderer(renderer())) {
5037 if (styleable->computeAnimationExtent(animatedBounds)) {
5038 bounds = animatedBounds;
5039 return true;
5040 }
5041 }
5042
5043 return false;
5044}
5045
5046IntRect RenderLayer::absoluteBoundingBox() const
5047{
5048 const RenderLayer* rootLayer = root();
5049 return snappedIntRect(boundingBox(rootLayer, offsetFromAncestor(rootLayer)));
5050}
5051
5052FloatRect RenderLayer::absoluteBoundingBoxForPainting() const
5053{
5054 const RenderLayer* rootLayer = root();
5055 return snapRectToDevicePixels(boundingBox(rootLayer, offsetFromAncestor(rootLayer)), renderer().document().deviceScaleFactor());
5056}
5057
5058LayoutRect RenderLayer::overlapBounds() const
5059{
5060 if (overlapBoundsIncludeChildren())
5061 return calculateLayerBounds(this, { }, defaultCalculateLayerBoundsFlags() | IncludeFilterOutsets);
5062
5063 return localBoundingBox();
5064}
5065
5066LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, OptionSet<CalculateLayerBoundsFlag> flags) const
5067{
5068 if (!isSelfPaintingLayer())
5069 return LayoutRect();
5070
5071 // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
5072 if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
5073 return LayoutRect();
5074
5075 if (isRenderViewLayer()) {
5076 // The root layer is always just the size of the document.
5077 return renderer().view().unscaledDocumentRect();
5078 }
5079
5080 LayoutRect boundingBoxRect = localBoundingBox(flags);
5081 if (renderer().view().frameView().hasFlippedBlockRenderers()) {
5082 if (is<RenderBox>(renderer()))
5083 downcast<RenderBox>(renderer()).flipForWritingMode(boundingBoxRect);
5084 else
5085 renderer().containingBlock()->flipForWritingMode(boundingBoxRect);
5086 }
5087
5088 if (renderer().isDocumentElementRenderer()) {
5089 // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited),
5090 // then it has to be big enough to cover the viewport in order to display the background. This is akin
5091 // to the code in RenderBox::paintRootBoxFillLayers().
5092 const FrameView& frameView = renderer().view().frameView();
5093 boundingBoxRect.setWidth(std::max(boundingBoxRect.width(), frameView.contentsWidth() - boundingBoxRect.x()));
5094 boundingBoxRect.setHeight(std::max(boundingBoxRect.height(), frameView.contentsHeight() - boundingBoxRect.y()));
5095 }
5096
5097 LayoutRect unionBounds = boundingBoxRect;
5098
5099 if (flags & UseLocalClipRectIfPossible) {
5100 bool clipExceedsBounds = false;
5101 LayoutRect localClipRect = this->localClipRect(clipExceedsBounds);
5102 if (!localClipRect.isInfinite() && !clipExceedsBounds) {
5103 if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehavior::Normal))
5104 localClipRect = transform()->mapRect(localClipRect);
5105
5106 localClipRect.move(offsetFromAncestor(ancestorLayer));
5107 return localClipRect;
5108 }
5109 }
5110
5111 // FIXME: should probably just pass 'flags' down to descendants.
5112 auto descendantFlags = defaultCalculateLayerBoundsFlags() | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants);
5113
5114 const_cast<RenderLayer*>(this)->updateLayerListsIfNeeded();
5115
5116 if (RenderLayer* reflection = reflectionLayer()) {
5117 if (!reflection->isComposited()) {
5118 LayoutRect childUnionBounds = reflection->calculateLayerBounds(this, reflection->offsetFromAncestor(this), descendantFlags);
5119 unionBounds.unite(childUnionBounds);
5120 }
5121 }
5122
5123 ASSERT(isStackingContext() || !positiveZOrderLayers().size());
5124
5125#if ASSERT_ENABLED
5126 LayerListMutationDetector mutationChecker(const_cast<RenderLayer&>(*this));
5127#endif
5128
5129 auto computeLayersUnion = [this, &unionBounds, flags, descendantFlags] (const RenderLayer& childLayer) {
5130 if (!(flags & IncludeCompositedDescendants) && (childLayer.isComposited() || childLayer.paintsIntoProvidedBacking()))
5131 return;
5132 LayoutRect childBounds = childLayer.calculateLayerBounds(this, childLayer.offsetFromAncestor(this), descendantFlags);
5133 // Ignore child layer (and behave as if we had overflow: hidden) when it is positioned off the parent layer so much
5134 // that we hit the max LayoutUnit value.
5135 unionBounds.checkedUnite(childBounds);
5136 };
5137
5138 for (auto* childLayer : negativeZOrderLayers())
5139 computeLayersUnion(*childLayer);
5140
5141 for (auto* childLayer : positiveZOrderLayers())
5142 computeLayersUnion(*childLayer);
5143
5144 for (auto* childLayer : normalFlowLayers())
5145 computeLayersUnion(*childLayer);
5146
5147 if (flags.contains(IncludeFilterOutsets) || (flags.contains(IncludePaintedFilterOutsets) && paintsWithFilters()))
5148 unionBounds.expand(toLayoutBoxExtent(filterOutsets()));
5149
5150 if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehavior::Normal)) {
5151 TransformationMatrix* affineTrans = transform();
5152 boundingBoxRect = affineTrans->mapRect(boundingBoxRect);
5153 unionBounds = affineTrans->mapRect(unionBounds);
5154 }
5155 unionBounds.move(offsetFromRoot);
5156 return unionBounds;
5157}
5158
5159void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear)
5160{
5161 // FIXME: it's not clear how this layer not having clip rects guarantees that no descendants have any.
5162 if (!m_clipRectsCache)
5163 return;
5164
5165 clearClipRects(typeToClear);
5166
5167 for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
5168 l->clearClipRectsIncludingDescendants(typeToClear);
5169}
5170
5171void RenderLayer::clearClipRects(ClipRectsType typeToClear)
5172{
5173 if (typeToClear == AllClipRectTypes)
5174 m_clipRectsCache = nullptr;
5175 else {
5176 ASSERT(typeToClear < NumCachedClipRectsTypes);
5177 m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, nullptr);
5178 m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, nullptr);
5179 }
5180}
5181
5182RenderLayerBacking* RenderLayer::ensureBacking()
5183{
5184 if (!m_backing) {
5185 m_backing = makeUnique<RenderLayerBacking>(*this);
5186 compositor().layerBecameComposited(*this);
5187
5188 updateFilterPaintingStrategy();
5189 }
5190 return m_backing.get();
5191}
5192
5193void RenderLayer::clearBacking(bool layerBeingDestroyed)
5194{
5195 if (!m_backing)
5196 return;
5197
5198 if (!renderer().renderTreeBeingDestroyed())
5199 compositor().layerBecameNonComposited(*this);
5200
5201 m_backing->willBeDestroyed();
5202 m_backing = nullptr;
5203
5204 if (!layerBeingDestroyed)
5205 updateFilterPaintingStrategy();
5206}
5207
5208bool RenderLayer::hasCompositedMask() const
5209{
5210 return m_backing && m_backing->hasMaskLayer();
5211}
5212
5213bool RenderLayer::paintsWithTransform(OptionSet<PaintBehavior> paintBehavior) const
5214{
5215 bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
5216 return transform() && ((paintBehavior & PaintBehavior::FlattenCompositingLayers) || paintsToWindow);
5217}
5218
5219bool RenderLayer::shouldPaintMask(OptionSet<PaintBehavior> paintBehavior, OptionSet<PaintLayerFlag> paintFlags) const
5220{
5221 if (!renderer().hasMask())
5222 return false;
5223
5224 bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
5225 if (paintsToWindow || (paintBehavior & PaintBehavior::FlattenCompositingLayers))
5226 return true;
5227
5228 return paintFlags.contains(PaintLayerFlag::PaintingCompositingMaskPhase);
5229}
5230
5231bool RenderLayer::shouldApplyClipPath(OptionSet<PaintBehavior> paintBehavior, OptionSet<PaintLayerFlag> paintFlags) const
5232{
5233 if (!renderer().hasClipPath())
5234 return false;
5235
5236 bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
5237 if (paintsToWindow || (paintBehavior & PaintBehavior::FlattenCompositingLayers))
5238 return true;
5239
5240 return paintFlags.contains(PaintLayerFlag::PaintingCompositingClipPathPhase);
5241}
5242
5243bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
5244{
5245 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
5246 return false;
5247
5248 if (paintsWithTransparency(PaintBehavior::Normal))
5249 return false;
5250
5251 if (renderer().isDocumentElementRenderer()) {
5252 // Normally the document element doens't have a layer. If it does have a layer, its background propagates to the RenderView
5253 // so this layer doesn't draw it.
5254 return false;
5255 }
5256
5257 // We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child
5258 // is visible and that child doesn't cover the entire rect.
5259 if (renderer().style().visibility() != Visibility::Visible)
5260 return false;
5261
5262 if (paintsWithFilters() && renderer().style().filter().hasFilterThatAffectsOpacity())
5263 return false;
5264
5265 // FIXME: Handle simple transforms.
5266 if (paintsWithTransform(PaintBehavior::Normal))
5267 return false;
5268
5269 // FIXME: Remove this check.
5270 // This function should not be called when layer-lists are dirty.
5271 // It is somehow getting triggered during style update.
5272 if (zOrderListsDirty() || normalFlowListDirty())
5273 return false;
5274
5275 // Table painting is special; a table paints its sections.
5276 if (renderer().isTablePart())
5277 return false;
5278
5279 // A fieldset with a legend will have an irregular shape, so can't be treated as opaque.
5280 if (renderer().isFieldset())
5281 return false;
5282
5283 // FIXME: We currently only check the immediate renderer,
5284 // which will miss many cases.
5285 if (renderer().backgroundIsKnownToBeOpaqueInRect(localRect))
5286 return true;
5287
5288 // We can't consult child layers if we clip, since they might cover
5289 // parts of the rect that are clipped out.
5290 if (renderer().hasNonVisibleOverflow())
5291 return false;
5292
5293 return listBackgroundIsKnownToBeOpaqueInRect(positiveZOrderLayers(), localRect)
5294 || listBackgroundIsKnownToBeOpaqueInRect(negativeZOrderLayers(), localRect)
5295 || listBackgroundIsKnownToBeOpaqueInRect(normalFlowLayers(), localRect);
5296}
5297
5298bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const LayerList& list, const LayoutRect& localRect) const
5299{
5300 if (list.begin() == list.end())
5301 return false;
5302
5303 for (auto iter = list.rbegin(); iter != list.rend(); ++iter) {
5304 const auto* childLayer = *iter;
5305 if (childLayer->isComposited())
5306 continue;
5307
5308 if (!childLayer->canUseOffsetFromAncestor())
5309 continue;
5310
5311 LayoutRect childLocalRect(localRect);
5312 childLocalRect.move(-childLayer->offsetFromAncestor(this));
5313
5314 if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
5315 return true;
5316 }
5317 return false;
5318}
5319
5320void RenderLayer::repaintIncludingDescendants()
5321{
5322 renderer().repaint();
5323 for (RenderLayer* current = firstChild(); current; current = current->nextSibling())
5324 current->repaintIncludingDescendants();
5325}
5326
5327void RenderLayer::setBackingNeedsRepaint(GraphicsLayer::ShouldClipToLayer shouldClip)
5328{
5329 ASSERT(isComposited());
5330 if (backing()->paintsIntoWindow()) {
5331 // If we're trying to repaint the placeholder document layer, propagate the
5332 // repaint to the native view system.
5333 renderer().view().repaintViewRectangle(absoluteBoundingBox());
5334 } else
5335 backing()->setContentsNeedDisplay(shouldClip);
5336}
5337
5338void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r, GraphicsLayer::ShouldClipToLayer shouldClip)
5339{
5340 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here,
5341 // so assert but check that the layer is composited.
5342 ASSERT(isComposited());
5343 if (!isComposited() || backing()->paintsIntoWindow()) {
5344 // If we're trying to repaint the placeholder document layer, propagate the
5345 // repaint to the native view system.
5346 LayoutRect absRect(r);
5347 absRect.move(offsetFromAncestor(root()));
5348
5349 renderer().view().repaintViewRectangle(absRect);
5350 } else
5351 backing()->setContentsNeedDisplayInRect(r, shouldClip);
5352}
5353
5354// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
5355void RenderLayer::repaintIncludingNonCompositingDescendants(const RenderLayerModelObject* repaintContainer)
5356{
5357 auto clippedOverflowRect = m_repaintRectsValid ? m_repaintRects.clippedOverflowRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
5358 renderer().repaintUsingContainer(repaintContainer, clippedOverflowRect);
5359
5360 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
5361 if (!curr->isComposited())
5362 curr->repaintIncludingNonCompositingDescendants(repaintContainer);
5363 }
5364}
5365
5366bool RenderLayer::shouldBeSelfPaintingLayer() const
5367{
5368 if (!isNormalFlowOnly())
5369 return true;
5370
5371 return hasOverlayScrollbars()
5372 || hasCompositedScrollableOverflow()
5373 || renderer().isTableRow()
5374 || renderer().isCanvas()
5375 || renderer().isVideo()
5376 || renderer().isEmbeddedObject()
5377 || renderer().isRenderIFrame()
5378 || renderer().isRenderFragmentedFlow();
5379}
5380
5381void RenderLayer::updateSelfPaintingLayer()
5382{
5383 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer();
5384 if (m_isSelfPaintingLayer == isSelfPaintingLayer)
5385 return;
5386
5387 m_isSelfPaintingLayer = isSelfPaintingLayer;
5388 if (!parent())
5389 return;
5390
5391 if (isSelfPaintingLayer)
5392 parent()->setAncestorChainHasSelfPaintingLayerDescendant();
5393 else {
5394 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
5395 clearRepaintRects();
5396 }
5397}
5398
5399static bool hasVisibleBoxDecorationsOrBackground(const RenderElement& renderer)
5400{
5401 return renderer.hasVisibleBoxDecorations() || renderer.style().hasOutline();
5402}
5403
5404static bool styleHasSmoothingTextMode(const RenderStyle& style)
5405{
5406 FontSmoothingMode smoothingMode = style.fontDescription().fontSmoothing();
5407 return smoothingMode == FontSmoothingMode::AutoSmoothing || smoothingMode == FontSmoothingMode::SubpixelAntialiased;
5408}
5409
5410// Constrain the depth and breadth of the search for performance.
5411static const unsigned maxRendererTraversalCount = 200;
5412
5413static void determineNonLayerDescendantsPaintedContent(const RenderElement& renderer, unsigned& renderersTraversed, RenderLayer::PaintedContentRequest& request)
5414{
5415 for (const auto& child : childrenOfType<RenderObject>(renderer)) {
5416 if (++renderersTraversed > maxRendererTraversalCount) {
5417 request.makeStatesUndetermined();
5418 return;
5419 }
5420
5421 if (is<RenderText>(child)) {
5422 const auto& renderText = downcast<RenderText>(child);
5423 if (!renderText.hasRenderedText())
5424 continue;
5425
5426 if (renderer.style().effectiveUserSelect() != UserSelect::None)
5427 request.setHasPaintedContent();
5428
5429 if (!renderText.text().isAllSpecialCharacters<isHTMLSpace>()) {
5430 request.setHasPaintedContent();
5431
5432 if (request.needToDetermineSubpixelAntialiasedTextState() && styleHasSmoothingTextMode(child.style()))
5433 request.setHasSubpixelAntialiasedText();
5434 }
5435
5436 if (request.isSatisfied())
5437 return;
5438 }
5439
5440 if (!is<RenderElement>(child))
5441 continue;
5442
5443 const RenderElement& renderElementChild = downcast<RenderElement>(child);
5444
5445 if (is<RenderLayerModelObject>(renderElementChild) && downcast<RenderLayerModelObject>(renderElementChild).hasSelfPaintingLayer())
5446 continue;
5447
5448 if (hasVisibleBoxDecorationsOrBackground(renderElementChild)) {
5449 request.setHasPaintedContent();
5450 if (request.isSatisfied())
5451 return;
5452 }
5453
5454 if (is<RenderReplaced>(renderElementChild)) {
5455 request.setHasPaintedContent();
5456
5457 if (is<RenderImage>(renderElementChild) && request.needToDetermineSubpixelAntialiasedTextState()) {
5458 auto& imageRenderer = downcast<RenderImage>(renderElementChild);
5459 // May draw text if showing alt text, or image is an SVG image or PDF image.
5460 if ((imageRenderer.isShowingAltText() || imageRenderer.hasNonBitmapImage()) && styleHasSmoothingTextMode(child.style()))
5461 request.setHasSubpixelAntialiasedText();
5462 }
5463
5464 if (request.isSatisfied())
5465 return;
5466 }
5467
5468 determineNonLayerDescendantsPaintedContent(renderElementChild, renderersTraversed, request);
5469 if (request.isSatisfied())
5470 return;
5471 }
5472}
5473
5474bool RenderLayer::hasNonEmptyChildRenderers(PaintedContentRequest& request) const
5475{
5476 unsigned renderersTraversed = 0;
5477 determineNonLayerDescendantsPaintedContent(renderer(), renderersTraversed, request);
5478 return request.probablyHasPaintedContent();
5479}
5480
5481bool RenderLayer::hasVisibleBoxDecorationsOrBackground() const
5482{
5483 return WebCore::hasVisibleBoxDecorationsOrBackground(renderer());
5484}
5485
5486bool RenderLayer::hasVisibleBoxDecorations() const
5487{
5488 if (!hasVisibleContent())
5489 return false;
5490
5491 return hasVisibleBoxDecorationsOrBackground() || (m_scrollableArea && m_scrollableArea->hasOverflowControls());
5492}
5493
5494bool RenderLayer::isVisuallyNonEmpty(PaintedContentRequest* request) const
5495{
5496 ASSERT(!m_visibleDescendantStatusDirty);
5497
5498 if (!hasVisibleContent() || !renderer().style().opacity())
5499 return false;
5500
5501 if (renderer().isRenderReplaced() || (m_scrollableArea && m_scrollableArea->hasOverflowControls())) {
5502 if (!request)
5503 return true;
5504
5505 request->setHasPaintedContent();
5506 if (request->isSatisfied())
5507 return true;
5508 }
5509
5510 if (hasVisibleBoxDecorationsOrBackground()) {
5511 if (!request)
5512 return true;
5513
5514 request->setHasPaintedContent();
5515 if (request->isSatisfied())
5516 return true;
5517 }
5518
5519 PaintedContentRequest localRequest;
5520 if (!request)
5521 request = &localRequest;
5522
5523 return hasNonEmptyChildRenderers(*request);
5524}
5525
5526void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
5527{
5528 setIsNormalFlowOnly(shouldBeNormalFlowOnly());
5529
5530 if (setIsCSSStackingContext(shouldBeCSSStackingContext())) {
5531#if ENABLE(CSS_COMPOSITING)
5532 if (parent()) {
5533 if (isCSSStackingContext()) {
5534 if (!hasNotIsolatedBlendingDescendantsStatusDirty() && hasNotIsolatedBlendingDescendants())
5535 parent()->dirtyAncestorChainHasBlendingDescendants();
5536 } else {
5537 if (hasNotIsolatedBlendingDescendantsStatusDirty())
5538 parent()->dirtyAncestorChainHasBlendingDescendants();
5539 else if (hasNotIsolatedBlendingDescendants())
5540 parent()->updateAncestorChainHasBlendingDescendants();
5541 }
5542 }
5543#endif
5544 }
5545
5546 updateLayerScrollableArea();
5547
5548 // FIXME: RenderLayer already handles visibility changes through our visibility dirty bits. This logic could
5549 // likely be folded along with the rest.
5550 if (oldStyle) {
5551 bool visibilityChanged = oldStyle->visibility() != renderer().style().visibility();
5552 if (oldStyle->usedZIndex() != renderer().style().usedZIndex() || visibilityChanged) {
5553 dirtyStackingContextZOrderLists();
5554 if (isStackingContext())
5555 dirtyZOrderLists();
5556 }
5557
5558 // Visibility is input to canUseCompositedScrolling().
5559 if (visibilityChanged && m_scrollableArea)
5560 m_scrollableArea->computeHasCompositedScrollableOverflow();
5561 }
5562
5563 if (m_scrollableArea) {
5564 m_scrollableArea->createOrDestroyMarquee();
5565 m_scrollableArea->updateScrollbarsAfterStyleChange(oldStyle);
5566 }
5567 // Overlay scrollbars can make this layer self-painting so we need
5568 // to recompute the bit once scrollbars have been updated.
5569 updateSelfPaintingLayer();
5570
5571 if (!hasReflection() && m_reflection)
5572 removeReflection();
5573 else if (hasReflection()) {
5574 if (!m_reflection)
5575 createReflection();
5576 else
5577 m_reflection->setStyle(createReflectionStyle());
5578 }
5579
5580 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
5581 if (m_scrollableArea)
5582 m_scrollableArea->updateAllScrollbarRelatedStyle();
5583
5584 updateDescendantDependentFlags();
5585 updateTransform();
5586#if ENABLE(CSS_COMPOSITING)
5587 updateBlendMode();
5588#endif
5589 updateFiltersAfterStyleChange();
5590
5591 compositor().layerStyleChanged(diff, *this, oldStyle);
5592
5593 updateFilterPaintingStrategy();
5594
5595#if PLATFORM(IOS_FAMILY) && ENABLE(TOUCH_EVENTS)
5596 if (diff == StyleDifference::RecompositeLayer || diff >= StyleDifference::LayoutPositionedMovementOnly)
5597 renderer().document().invalidateRenderingDependentRegions();
5598#else
5599 UNUSED_PARAM(diff);
5600#endif
5601}
5602
5603RenderLayer* RenderLayer::reflectionLayer() const
5604{
5605 return m_reflection ? m_reflection->layer() : nullptr;
5606}
5607
5608bool RenderLayer::isReflectionLayer(const RenderLayer& layer) const
5609{
5610 return m_reflection ? &layer == m_reflection->layer() : false;
5611}
5612
5613void RenderLayer::createReflection()
5614{
5615 ASSERT(!m_reflection);
5616 m_reflection = createRenderer<RenderReplica>(renderer().document(), createReflectionStyle());
5617 // FIXME: A renderer should be a child of its parent!
5618 m_reflection->setParent(&renderer()); // We create a 1-way connection.
5619 m_reflection->initializeStyle();
5620}
5621
5622void RenderLayer::removeReflection()
5623{
5624 if (!m_reflection->renderTreeBeingDestroyed()) {
5625 if (auto* layer = m_reflection->layer())
5626 removeChild(*layer);
5627 }
5628
5629 m_reflection->setParent(nullptr);
5630 m_reflection = nullptr;
5631}
5632
5633RenderStyle RenderLayer::createReflectionStyle()
5634{
5635 auto newStyle = RenderStyle::create();
5636 newStyle.inheritFrom(renderer().style());
5637
5638 // Map in our transform.
5639 TransformOperations transform;
5640 switch (renderer().style().boxReflect()->direction()) {
5641 case ReflectionDirection::Below:
5642 transform.operations().append(TranslateTransformOperation::create(Length(0, LengthType::Fixed), Length(100., LengthType::Percent), TransformOperation::TRANSLATE));
5643 transform.operations().append(TranslateTransformOperation::create(Length(0, LengthType::Fixed), renderer().style().boxReflect()->offset(), TransformOperation::TRANSLATE));
5644 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
5645 break;
5646 case ReflectionDirection::Above:
5647 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
5648 transform.operations().append(TranslateTransformOperation::create(Length(0, LengthType::Fixed), Length(100., LengthType::Percent), TransformOperation::TRANSLATE));
5649 transform.operations().append(TranslateTransformOperation::create(Length(0, LengthType::Fixed), renderer().style().boxReflect()->offset(), TransformOperation::TRANSLATE));
5650 break;
5651 case ReflectionDirection::Right:
5652 transform.operations().append(TranslateTransformOperation::create(Length(100., LengthType::Percent), Length(0, LengthType::Fixed), TransformOperation::TRANSLATE));
5653 transform.operations().append(TranslateTransformOperation::create(renderer().style().boxReflect()->offset(), Length(0, LengthType::Fixed), TransformOperation::TRANSLATE));
5654 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
5655 break;
5656 case ReflectionDirection::Left:
5657 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
5658 transform.operations().append(TranslateTransformOperation::create(Length(100., LengthType::Percent), Length(0, LengthType::Fixed), TransformOperation::TRANSLATE));
5659 transform.operations().append(TranslateTransformOperation::create(renderer().style().boxReflect()->offset(), Length(0, LengthType::Fixed), TransformOperation::TRANSLATE));
5660 break;
5661 }
5662 newStyle.setTransform(transform);
5663
5664 // Map in our mask.
5665 newStyle.setMaskBoxImage(renderer().style().boxReflect()->mask());
5666
5667 // Style has transform and mask, so needs to be stacking context.
5668 newStyle.setUsedZIndex(0);
5669
5670 return newStyle;
5671}
5672
5673void RenderLayer::ensureLayerFilters()
5674{
5675 if (m_filters)
5676 return;
5677
5678 m_filters = makeUnique<RenderLayerFilters>(*this);
5679}
5680
5681void RenderLayer::clearLayerFilters()
5682{
5683 m_filters = nullptr;
5684}
5685
5686RenderLayerScrollableArea* RenderLayer::ensureLayerScrollableArea()
5687{
5688 bool hadScrollableArea = scrollableArea();
5689
5690 if (!m_scrollableArea)
5691 m_scrollableArea = makeUnique<RenderLayerScrollableArea>(*this);
5692
5693 if (!hadScrollableArea) {
5694 if (renderer().settings().asyncOverflowScrollingEnabled())
5695 setNeedsCompositingConfigurationUpdate();
5696
5697 m_scrollableArea->restoreScrollPosition();
5698 }
5699
5700 return m_scrollableArea.get();
5701}
5702
5703void RenderLayer::clearLayerScrollableArea()
5704{
5705 if (m_scrollableArea) {
5706 m_scrollableArea->clear();
5707 m_scrollableArea = nullptr;
5708 }
5709}
5710
5711void RenderLayer::updateFiltersAfterStyleChange()
5712{
5713 if (!hasFilter()) {
5714 clearLayerFilters();
5715 return;
5716 }
5717
5718 // Add the filter as a client to this renderer, unless we are a RenderLayer accommodating
5719 // an SVG. In that case it takes care of its own resource management for filters.
5720 if (renderer().style().filter().hasReferenceFilter() && !renderer().isSVGRootOrLegacySVGRoot()) {
5721 ensureLayerFilters();
5722 m_filters->updateReferenceFilterClients(renderer().style().filter());
5723 } else if (m_filters)
5724 m_filters->removeReferenceFilterClients();
5725}
5726
5727void RenderLayer::updateLayerScrollableArea()
5728{
5729 if (!is<RenderBox>(renderer()) || !downcast<RenderBox>(renderer()).requiresLayerWithScrollableArea()) {
5730 bool hadScrollableArea = scrollableArea();
5731 clearLayerScrollableArea();
5732
5733 if (hadScrollableArea && renderer().settings().asyncOverflowScrollingEnabled())
5734 setNeedsCompositingConfigurationUpdate();
5735 return;
5736 }
5737
5738 ensureLayerScrollableArea();
5739}
5740
5741void RenderLayer::updateFilterPaintingStrategy()
5742{
5743 // RenderLayerFilters is only used to render the filters in software mode,
5744 // so we always need to run updateFilterPaintingStrategy() after the composited
5745 // mode might have changed for this layer.
5746 if (!paintsWithFilters()) {
5747 // Don't delete the whole filter info here, because we might use it
5748 // for loading SVG reference filter files.
5749 if (m_filters)
5750 m_filters->clearFilter();
5751
5752 // Early-return only if we *don't* have reference filters.
5753 // For reference filters, we still want the FilterEffect graph built
5754 // for us, even if we're composited.
5755 if (!renderer().style().filter().hasReferenceFilter())
5756 return;
5757 }
5758
5759 ensureLayerFilters();
5760 m_filters->setRenderingMode(renderer().page().acceleratedFiltersEnabled() ? RenderingMode::Accelerated : RenderingMode::Unaccelerated);
5761 m_filters->setFilterScale({ page().deviceScaleFactor(), page().deviceScaleFactor() });
5762}
5763
5764IntOutsets RenderLayer::filterOutsets() const
5765{
5766 if (m_filters)
5767 return m_filters->calculateOutsets(renderer(), localBoundingBox());
5768 return renderer().style().filterOutsets();
5769}
5770
5771static RenderLayer* parentLayerCrossFrame(const RenderLayer& layer)
5772{
5773 if (auto* parent = layer.parent())
5774 return parent;
5775
5776 return layer.enclosingFrameRenderLayer();
5777}
5778
5779bool RenderLayer::isTransparentRespectingParentFrames() const
5780{
5781 static const double minimumVisibleOpacity = 0.01;
5782
5783 float currentOpacity = 1;
5784 for (auto* layer = this; layer; layer = parentLayerCrossFrame(*layer)) {
5785 currentOpacity *= layer->renderer().style().opacity();
5786 if (currentOpacity < minimumVisibleOpacity)
5787 return true;
5788 }
5789
5790 return false;
5791}
5792
5793void RenderLayer::simulateFrequentPaint()
5794{
5795 SinglePaintFrequencyTracking { m_paintFrequencyTracker, page().lastRenderingUpdateTimestamp() };
5796}
5797
5798RenderLayerScrollableArea* RenderLayer::scrollableArea() const
5799{
5800 return m_scrollableArea.get();
5801}
5802
5803#if !LOG_DISABLED
5804static TextStream& operator<<(TextStream& ts, RenderLayer::EventRegionInvalidationReason reason)
5805{
5806 switch (reason) {
5807 case RenderLayer::EventRegionInvalidationReason::Paint: ts << "Paint"; break;
5808 case RenderLayer::EventRegionInvalidationReason::SettingDidChange: ts << "SettingDidChange"; break;
5809 case RenderLayer::EventRegionInvalidationReason::Style: ts << "Style"; break;
5810 case RenderLayer::EventRegionInvalidationReason::NonCompositedFrame: ts << "NonCompositedFrame"; break;
5811 }
5812 return ts;
5813}
5814#endif // !LOG_DISABLED
5815
5816bool RenderLayer::invalidateEventRegion(EventRegionInvalidationReason reason)
5817{
5818#if ENABLE(ASYNC_SCROLLING)
5819 auto* compositingLayer = enclosingCompositingLayerForRepaint().layer;
5820
5821 auto shouldInvalidate = [&] {
5822 if (!compositingLayer)
5823 return false;
5824
5825 if (reason == EventRegionInvalidationReason::NonCompositedFrame)
5826 return true;
5827
5828 return compositingLayer->backing()->maintainsEventRegion();
5829 };
5830
5831 if (!shouldInvalidate())
5832 return false;
5833
5834 LOG_WITH_STREAM(EventRegions, stream << this << " invalidateEventRegion for reason " << reason << " invalidating in compositing layer " << compositingLayer);
5835
5836 compositingLayer->backing()->setNeedsEventRegionUpdate();
5837
5838 if (reason == EventRegionInvalidationReason::NonCompositedFrame) {
5839 auto& view = renderer().view();
5840 LOG_WITH_STREAM(EventRegions, stream << " calling setNeedsEventRegionUpdateForNonCompositedFrame on " << view);
5841 view.setNeedsEventRegionUpdateForNonCompositedFrame();
5842 auto visibleDebugOverlayRegions = OptionSet<DebugOverlayRegions>::fromRaw(renderer().settings().visibleDebugOverlayRegions());
5843 if (visibleDebugOverlayRegions.containsAny({ DebugOverlayRegions::TouchActionRegion, DebugOverlayRegions::EditableElementRegion, DebugOverlayRegions::WheelEventHandlerRegion }))
5844 view.setNeedsRepaintHackAfterCompositingLayerUpdateForDebugOverlaysOnly();
5845 view.compositor().scheduleCompositingLayerUpdate();
5846 }
5847 return true;
5848#else
5849 UNUSED_PARAM(reason);
5850 return false;
5851#endif
5852}
5853
5854TextStream& operator<<(WTF::TextStream& ts, ClipRectsType clipRectsType)
5855{
5856 switch (clipRectsType) {
5857 case PaintingClipRects: ts << "painting"; break;
5858 case RootRelativeClipRects: ts << "root-relative"; break;
5859 case AbsoluteClipRects: ts << "absolute"; break;
5860 case TemporaryClipRects: ts << "temporary"; break;
5861 case NumCachedClipRectsTypes:
5862 case AllClipRectTypes:
5863 ts << "?";
5864 break;
5865 }
5866 return ts;
5867}
5868
5869TextStream& operator<<(TextStream& ts, const RenderLayer& layer)
5870{
5871 ts << layer.debugDescription();
5872 return ts;
5873}
5874
5875TextStream& operator<<(TextStream& ts, const RenderLayer::ClipRectsContext& context)
5876{
5877 ts.dumpProperty("root layer:", context.rootLayer);
5878 ts.dumpProperty("type:", context.clipRectsType);
5879 ts.dumpProperty("overflow-clip:", context.respectOverflowClip == IgnoreOverflowClip ? "ignore" : "respect");
5880
5881 return ts;
5882}
5883
5884TextStream& operator<<(TextStream& ts, IndirectCompositingReason reason)
5885{
5886 switch (reason) {
5887 case IndirectCompositingReason::None: ts << "none"; break;
5888 case IndirectCompositingReason::Clipping: ts << "clipping"; break;
5889 case IndirectCompositingReason::Stacking: ts << "stacking"; break;
5890 case IndirectCompositingReason::OverflowScrollPositioning: ts << "overflow positioning"; break;
5891 case IndirectCompositingReason::Overlap: ts << "overlap"; break;
5892 case IndirectCompositingReason::BackgroundLayer: ts << "background layer"; break;
5893 case IndirectCompositingReason::GraphicalEffect: ts << "graphical effect"; break;
5894 case IndirectCompositingReason::Perspective: ts << "perspective"; break;
5895 case IndirectCompositingReason::Preserve3D: ts << "preserve-3d"; break;
5896 }
5897
5898 return ts;
5899}
5900
5901TextStream& operator<<(TextStream& ts, PaintBehavior behavior)
5902{
5903 switch (behavior) {
5904 case PaintBehavior::Normal: ts << "Normal"; break;
5905 case PaintBehavior::SelectionOnly: ts << "SelectionOnly"; break;
5906 case PaintBehavior::SkipSelectionHighlight: ts << "SkipSelectionHighlight"; break;
5907 case PaintBehavior::ForceBlackText: ts << "ForceBlackText"; break;
5908 case PaintBehavior::ForceWhiteText: ts << "ForceWhiteText"; break;
5909 case PaintBehavior::RenderingSVGMask: ts << "RenderingSVGMask"; break;
5910 case PaintBehavior::SkipRootBackground: ts << "SkipRootBackground"; break;
5911 case PaintBehavior::RootBackgroundOnly: ts << "RootBackgroundOnly"; break;
5912 case PaintBehavior::SelectionAndBackgroundsOnly: ts << "SelectionAndBackgroundsOnly"; break;
5913 case PaintBehavior::ExcludeSelection: ts << "ExcludeSelection"; break;
5914 case PaintBehavior::FlattenCompositingLayers: ts << "FlattenCompositingLayers"; break;
5915 case PaintBehavior::Snapshotting: ts << "Snapshotting"; break;
5916 case PaintBehavior::TileFirstPaint: ts << "TileFirstPaint"; break;
5917 case PaintBehavior::CompositedOverflowScrollContent: ts << "CompositedOverflowScrollContent"; break;
5918 case PaintBehavior::AnnotateLinks: ts << "AnnotateLinks"; break;
5919 case PaintBehavior::EventRegionIncludeForeground: ts << "EventRegionIncludeForeground"; break;
5920 case PaintBehavior::EventRegionIncludeBackground: ts << "EventRegionIncludeBackground"; break;
5921 }
5922
5923 return ts;
5924}
5925
5926} // namespace WebCore
5927
5928#if ENABLE(TREE_DEBUGGING)
5929
5930void showLayerTree(const WebCore::RenderLayer* layer)
5931{
5932 if (!layer)
5933 return;
5934
5935 String output = externalRepresentation(&layer->renderer().frame(), {
5936 WebCore::RenderAsTextFlag::ShowAllLayers,
5937 WebCore::RenderAsTextFlag::ShowLayerNesting,
5938 WebCore::RenderAsTextFlag::ShowCompositedLayers,
5939 WebCore::RenderAsTextFlag::ShowOverflow,
5940 WebCore::RenderAsTextFlag::ShowSVGGeometry,
5941 WebCore::RenderAsTextFlag::ShowLayerFragments,
5942 WebCore::RenderAsTextFlag::ShowAddresses,
5943 WebCore::RenderAsTextFlag::ShowIDAndClass,
5944 WebCore::RenderAsTextFlag::DontUpdateLayout,
5945 WebCore::RenderAsTextFlag::ShowLayoutState,
5946 });
5947 fprintf(stderr, "\n%s\n", output.utf8().data());
5948}
5949
5950void showLayerTree(const WebCore::RenderObject* renderer)
5951{
5952 if (!renderer)
5953 return;
5954 showLayerTree(renderer->enclosingLayer());
5955}
5956
5957static void outputPaintOrderTreeLegend(TextStream& stream)
5958{
5959 stream.nextLine();
5960 stream << "(S)tacking Context/(F)orced SC/O(P)portunistic SC, (N)ormal flow only, (O)verflow clip, (A)lpha (opacity or mask), has (B)lend mode, (I)solates blending, (T)ransform-ish, (F)ilter, Fi(X)ed position, Behaves as fi(x)ed, (C)omposited, (P)rovides backing/uses (p)rovided backing/paints to (a)ncestor, (c)omposited descendant, (s)scrolling ancestor, (t)transformed ancestor\n"
5961 "Dirty (z)-lists, Dirty (n)ormal flow lists\n"
5962 "Traversal needs: requirements (t)raversal on descendants, (b)acking or hierarchy traversal on descendants, (r)equirements traversal on all descendants, requirements traversal on all (s)ubsequent layers, (h)ierarchy traversal on all descendants, update of paint (o)rder children\n"
5963 "Update needs: post-(l)ayout requirements, (g)eometry, (k)ids geometry, (c)onfig, layer conne(x)ion, (s)crolling tree\n"
5964 "Scrolling scope: box contents\n";
5965 stream.nextLine();
5966}
5967
5968static void outputIdent(TextStream& stream, unsigned depth)
5969{
5970 unsigned i = 0;
5971 while (++i <= depth * 2)
5972 stream << " ";
5973}
5974
5975static void outputPaintOrderTreeRecursive(TextStream& stream, const WebCore::RenderLayer& layer, const char* prefix, unsigned depth = 0)
5976{
5977 stream << (layer.isCSSStackingContext() ? "S" : (layer.isForcedStackingContext() ? "F" : (layer.isOpportunisticStackingContext() ? "P" : "-")));
5978 stream << (layer.isNormalFlowOnly() ? "N" : "-");
5979 stream << (layer.renderer().hasNonVisibleOverflow() ? "O" : "-");
5980 stream << (layer.isTransparent() ? "A" : "-");
5981 stream << (layer.hasBlendMode() ? "B" : "-");
5982 stream << (layer.isolatesBlending() ? "I" : "-");
5983 stream << (layer.renderer().hasTransformRelatedProperty() ? "T" : "-");
5984 stream << (layer.hasFilter() ? "F" : "-");
5985 stream << (layer.renderer().isFixedPositioned() ? "X" : "-");
5986 stream << (layer.behavesAsFixed() ? "x" : "-");
5987 stream << (layer.isComposited() ? "C" : "-");
5988
5989 auto compositedPaintingDestinationString = [&layer]() {
5990 if (layer.paintsIntoProvidedBacking())
5991 return "p";
5992
5993 if (!layer.isComposited())
5994 return "-";
5995
5996 if (layer.backing()->hasBackingSharingLayers())
5997 return "P";
5998
5999 if (layer.backing()->paintsIntoCompositedAncestor())
6000 return "a";
6001
6002 return "-";
6003 };
6004
6005 stream << compositedPaintingDestinationString();
6006 stream << (layer.hasCompositingDescendant() ? "c" : "-");
6007 stream << (layer.hasCompositedScrollingAncestor() ? "s" : "-");
6008 stream << (layer.hasTransformedAncestor() ? "t" : "-");
6009
6010 stream << " ";
6011
6012 stream << (layer.zOrderListsDirty() ? "z" : "-");
6013 stream << (layer.normalFlowListDirty() ? "n" : "-");
6014
6015 stream << " ";
6016
6017 stream << (layer.hasDescendantNeedingCompositingRequirementsTraversal() ? "t" : "-");
6018 stream << (layer.hasDescendantNeedingUpdateBackingOrHierarchyTraversal() ? "b" : "-");
6019 stream << (layer.descendantsNeedCompositingRequirementsTraversal() ? "r" : "-");
6020 stream << (layer.subsequentLayersNeedCompositingRequirementsTraversal() ? "s" : "-");
6021 stream << (layer.descendantsNeedUpdateBackingAndHierarchyTraversal() ? "h" : "-");
6022 stream << (layer.needsCompositingPaintOrderChildrenUpdate() ? "o" : "-");
6023
6024 stream << " ";
6025
6026 stream << (layer.needsPostLayoutCompositingUpdate() ? "l" : "-");
6027 stream << (layer.needsCompositingGeometryUpdate() ? "g" : "-");
6028 stream << (layer.childrenNeedCompositingGeometryUpdate() ? "k" : "-");
6029 stream << (layer.needsCompositingConfigurationUpdate() ? "c" : "-");
6030 stream << (layer.needsCompositingLayerConnection() ? "x" : "-");
6031 stream << (layer.needsScrollingTreeUpdate() ? "s" : "-");
6032
6033 stream << " ";
6034
6035 stream << layer.boxScrollingScope();
6036 stream << " ";
6037 stream << layer.contentsScrollingScope();
6038
6039 stream << " ";
6040
6041 outputIdent(stream, depth);
6042
6043 stream << prefix;
6044
6045 auto layerRect = layer.rect();
6046
6047 stream << &layer << " " << layerRect;
6048
6049 if (auto* scrollableArea = layer.scrollableArea())
6050 stream << " [SA " << scrollableArea << "]";
6051
6052 if (layer.isComposited()) {
6053 auto& backing = *layer.backing();
6054 stream << " (layerID " << backing.graphicsLayer()->primaryLayerID() << ")";
6055
6056 if (layer.indirectCompositingReason() != WebCore::IndirectCompositingReason::None)
6057 stream << " " << layer.indirectCompositingReason();
6058
6059 auto scrollingNodeID = backing.scrollingNodeIDForRole(WebCore::ScrollCoordinationRole::Scrolling);
6060 auto frameHostingNodeID = backing.scrollingNodeIDForRole(WebCore::ScrollCoordinationRole::FrameHosting);
6061 auto viewportConstrainedNodeID = backing.scrollingNodeIDForRole(WebCore::ScrollCoordinationRole::ViewportConstrained);
6062 auto positionedNodeID = backing.scrollingNodeIDForRole(WebCore::ScrollCoordinationRole::Positioning);
6063
6064 if (scrollingNodeID || frameHostingNodeID || viewportConstrainedNodeID || positionedNodeID) {
6065 stream << " {";
6066 bool first = true;
6067 if (scrollingNodeID) {
6068 stream << "sc " << scrollingNodeID;
6069 first = false;
6070 }
6071
6072 if (frameHostingNodeID) {
6073 if (!first)
6074 stream << ", ";
6075 stream << "fh " << frameHostingNodeID;
6076 first = false;
6077 }
6078
6079 if (viewportConstrainedNodeID) {
6080 if (!first)
6081 stream << ", ";
6082 stream << "vc " << viewportConstrainedNodeID;
6083 first = false;
6084 }
6085
6086 if (positionedNodeID) {
6087 if (!first)
6088 stream << ", ";
6089 stream << "pos " << positionedNodeID;
6090 }
6091
6092 stream << "}";
6093 }
6094 }
6095 stream << " " << layer.name();
6096 stream.nextLine();
6097
6098 const_cast<WebCore::RenderLayer&>(layer).updateLayerListsIfNeeded();
6099
6100 for (auto* child : layer.negativeZOrderLayers())
6101 outputPaintOrderTreeRecursive(stream, *child, "- ", depth + 1);
6102
6103 for (auto* child : layer.normalFlowLayers())
6104 outputPaintOrderTreeRecursive(stream, *child, "n ", depth + 1);
6105
6106 for (auto* child : layer.positiveZOrderLayers())
6107 outputPaintOrderTreeRecursive(stream, *child, "+ ", depth + 1);
6108}
6109
6110void showPaintOrderTree(const WebCore::RenderLayer* layer)
6111{
6112 TextStream stream;
6113 outputPaintOrderTreeLegend(stream);
6114 if (layer)
6115 outputPaintOrderTreeRecursive(stream, *layer, "");
6116
6117 WTFLogAlways("%s", stream.release().utf8().data());
6118}
6119
6120#endif
Note: See TracBrowser for help on using the repository browser.