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