2 * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
4 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
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>
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.
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.
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
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.
45 #include "RenderLayer.h"
48 #include "CSSAnimationController.h"
49 #include "CSSPropertyNames.h"
51 #include "DebugPageOverlays.h"
52 #include "DeprecatedGlobalSettings.h"
54 #include "DocumentEventQueue.h"
55 #include "DocumentMarkerController.h"
57 #include "EventHandler.h"
58 #include "FEColorMatrix.h"
60 #include "FilterEffectRenderer.h"
61 #include "FloatConversion.h"
62 #include "FloatPoint3D.h"
63 #include "FloatRect.h"
64 #include "FloatRoundedRect.h"
65 #include "FocusController.h"
67 #include "FrameLoader.h"
68 #include "FrameLoaderClient.h"
69 #include "FrameSelection.h"
70 #include "FrameTree.h"
71 #include "FrameView.h"
73 #include "GraphicsContext.h"
74 #include "HTMLFormControlElement.h"
75 #include "HTMLFrameElement.h"
76 #include "HTMLFrameOwnerElement.h"
77 #include "HTMLIFrameElement.h"
78 #include "HTMLNames.h"
79 #include "HitTestRequest.h"
80 #include "HitTestResult.h"
81 #include "HitTestingTransformState.h"
83 #include "MainFrame.h"
84 #include "NoEventDispatchAssertion.h"
85 #include "OverflowEvent.h"
86 #include "OverlapTestRequestClient.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 "RenderLayerFilterInfo.h"
99 #include "RenderMarquee.h"
100 #include "RenderMultiColumnFlow.h"
101 #include "RenderReplica.h"
102 #include "RenderSVGResourceClipper.h"
103 #include "RenderScrollbar.h"
104 #include "RenderScrollbarPart.h"
105 #include "RenderTableCell.h"
106 #include "RenderTableRow.h"
107 #include "RenderText.h"
108 #include "RenderTheme.h"
109 #include "RenderTreeAsText.h"
110 #include "RenderView.h"
111 #include "SVGNames.h"
112 #include "ScaleTransformOperation.h"
113 #include "ScrollAnimator.h"
114 #include "Scrollbar.h"
115 #include "ScrollbarTheme.h"
116 #include "ScrollingCoordinator.h"
117 #include "Settings.h"
118 #include "ShadowRoot.h"
119 #include "SourceGraphic.h"
120 #include "StyleProperties.h"
121 #include "StyleResolver.h"
122 #include "TransformationMatrix.h"
123 #include "TranslateTransformOperation.h"
124 #include "WheelEventTestTrigger.h"
126 #include <wtf/MonotonicTime.h>
127 #include <wtf/StdLibExtras.h>
128 #include <wtf/text/CString.h>
129 #include <wtf/text/TextStream.h>
131 #if ENABLE(CSS_SCROLL_SNAP)
132 #include "AxisScrollSnapOffsets.h"
135 #define MIN_INTERSECT_FOR_REVEAL 32
137 const Seconds paintFrequencyTimePerFrameThreshold = 32_ms;
138 const Seconds paintFrequencySecondsIdleThreshold = 5_s;
142 using namespace HTMLNames;
144 // This class is used to detect when we are painting frequently so that - even in a painting model
145 // without display lists - we can build and cache portions of display lists and reuse them only when
146 // animating. Once we transition fully to display lists, we can probably just pull from the previous
147 // paint's display list if it is still around and get rid of this code.
148 class PaintFrequencyInfo {
149 WTF_MAKE_FAST_ALLOCATED;
152 PaintFrequencyInfo(MonotonicTime now)
153 : m_firstPaintTime(now)
154 , m_lastPaintTime(now)
157 enum PaintFrequency { Idle, Low, High };
158 PaintFrequency updatePaintFrequency();
160 void paintingCacheableResource(MonotonicTime);
161 void setPaintedCacheableResource(bool painted) { m_paintedCacheableResource = painted; }
163 bool paintingFrequently() const { return m_paintingFrequently; }
166 MonotonicTime m_firstPaintTime;
167 MonotonicTime m_lastPaintTime;
168 unsigned m_totalPaints { 1 };
169 bool m_paintedCacheableResource { false };
170 bool m_paintingFrequently { false };
173 PaintFrequencyInfo::PaintFrequency PaintFrequencyInfo::updatePaintFrequency()
175 MonotonicTime now = MonotonicTime::now(); // FIXME: Should have a single time for the paint of the whole frame.
176 if ((now - m_lastPaintTime) > paintFrequencySecondsIdleThreshold)
178 if (m_totalPaints && ((now - m_firstPaintTime) / m_totalPaints) <= paintFrequencyTimePerFrameThreshold) {
179 m_paintingFrequently = true;
182 m_paintingFrequently = false;
186 void PaintFrequencyInfo::paintingCacheableResource(MonotonicTime now)
188 if (m_paintedCacheableResource)
191 m_paintedCacheableResource = true;
192 m_lastPaintTime = now;
196 class ClipRects : public RefCounted<ClipRects> {
197 WTF_MAKE_FAST_ALLOCATED;
199 static Ref<ClipRects> create()
201 return adoptRef(*new ClipRects);
204 static Ref<ClipRects> create(const ClipRects& other)
206 return adoptRef(*new ClipRects(other));
211 m_overflowClipRect.reset();
212 m_fixedClipRect.reset();
213 m_posClipRect.reset();
217 const ClipRect& overflowClipRect() const { return m_overflowClipRect; }
218 void setOverflowClipRect(const ClipRect& clipRect) { m_overflowClipRect = clipRect; }
220 const ClipRect& fixedClipRect() const { return m_fixedClipRect; }
221 void setFixedClipRect(const ClipRect& clipRect) { m_fixedClipRect = clipRect; }
223 const ClipRect& posClipRect() const { return m_posClipRect; }
224 void setPosClipRect(const ClipRect& clipRect) { m_posClipRect = clipRect; }
226 bool fixed() const { return m_fixed; }
227 void setFixed(bool fixed) { m_fixed = fixed; }
229 bool operator==(const ClipRects& other) const
231 return m_overflowClipRect == other.overflowClipRect()
232 && m_fixedClipRect == other.fixedClipRect()
233 && m_posClipRect == other.posClipRect()
234 && m_fixed == other.fixed();
237 ClipRects& operator=(const ClipRects& other)
239 m_overflowClipRect = other.overflowClipRect();
240 m_fixedClipRect = other.fixedClipRect();
241 m_posClipRect = other.posClipRect();
242 m_fixed = other.fixed();
247 ClipRects() = default;
249 ClipRects(const LayoutRect& clipRect)
250 : m_overflowClipRect(clipRect)
251 , m_fixedClipRect(clipRect)
252 , m_posClipRect(clipRect)
256 ClipRects(const ClipRects& other)
258 , m_fixed(other.fixed())
259 , m_overflowClipRect(other.overflowClipRect())
260 , m_fixedClipRect(other.fixedClipRect())
261 , m_posClipRect(other.posClipRect())
265 bool m_fixed { false };
266 ClipRect m_overflowClipRect;
267 ClipRect m_fixedClipRect;
268 ClipRect m_posClipRect;
271 class ClipRectsCache {
272 WTF_MAKE_FAST_ALLOCATED;
277 for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
278 m_clipRectsRoot[i] = 0;
279 m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
284 ClipRects* getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
286 return m_clipRects[getIndex(clipRectsType, respectOverflow)].get();
289 void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, RefPtr<ClipRects>&& clipRects)
291 m_clipRects[getIndex(clipRectsType, respectOverflow)] = WTFMove(clipRects);
295 const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
296 OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
300 unsigned getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
302 unsigned index = static_cast<unsigned>(clipRectsType);
303 if (respectOverflow == RespectOverflowClip)
304 index += static_cast<unsigned>(NumCachedClipRectsTypes);
305 ASSERT_WITH_SECURITY_IMPLICATION(index < NumCachedClipRectsTypes * 2);
309 RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
312 void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
314 #if !ENABLE(3D_TRANSFORMS)
315 UNUSED_PARAM(has3DRendering);
323 RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
324 : m_isRenderViewLayer(rendererLayerModelObject.isRenderView())
325 , m_forcedStackingContext(rendererLayerModelObject.isMedia())
326 , m_inResizeMode(false)
327 , m_scrollDimensionsDirty(true)
328 , m_normalFlowListDirty(true)
329 , m_hasSelfPaintingLayerDescendant(false)
330 , m_hasSelfPaintingLayerDescendantDirty(false)
331 , m_hasOutOfFlowPositionedDescendant(false)
332 , m_hasOutOfFlowPositionedDescendantDirty(true)
333 , m_needsCompositedScrolling(false)
334 , m_descendantsAreContiguousInStackingOrder(false)
335 , m_usedTransparency(false)
336 , m_paintingInsideReflection(false)
337 , m_inOverflowRelayout(false)
338 , m_repaintStatus(NeedsNormalRepaint)
339 , m_visibleContentStatusDirty(true)
340 , m_hasVisibleContent(false)
341 , m_visibleDescendantStatusDirty(false)
342 , m_hasVisibleDescendant(false)
343 , m_registeredScrollableArea(false)
344 , m_3DTransformedDescendantStatusDirty(true)
345 , m_has3DTransformedDescendant(false)
346 , m_hasCompositingDescendant(false)
347 , m_hasTransformedAncestor(false)
348 , m_has3DTransformedAncestor(false)
349 , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
350 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
352 , m_adjustForIOSCaretWhenScrolling(false)
355 #if ENABLE(IOS_TOUCH_EVENTS)
356 , m_registeredAsTouchEventListenerForScrolling(false)
358 , m_inUserScroll(false)
359 , m_requiresScrollBoundsOriginUpdate(false)
361 , m_containsDirtyOverlayScrollbars(false)
362 , m_updatingMarqueePosition(false)
364 , m_layerListMutationAllowed(true)
366 , m_hasFilterInfo(false)
367 #if ENABLE(CSS_COMPOSITING)
368 , m_blendMode(BlendModeNormal)
369 , m_hasNotIsolatedCompositedBlendingDescendants(false)
370 , m_hasNotIsolatedBlendingDescendants(false)
371 , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
373 , m_renderer(rendererLayerModelObject)
375 , m_previous(nullptr)
379 , m_staticInlinePosition(0)
380 , m_staticBlockPosition(0)
381 , m_enclosingPaginationLayer(nullptr)
383 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
384 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
386 // Non-stacking containers should have empty z-order lists. As this is already the case,
387 // there is no need to dirty / recompute these lists.
388 m_zOrderListsDirty = isStackingContainer();
390 if (!renderer().firstChild()) {
391 m_visibleContentStatusDirty = false;
392 m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
395 if (Element* element = renderer().element()) {
396 // We save and restore only the scrollOffset as the other scroll values are recalculated.
397 m_scrollPosition = element->savedLayerScrollPosition();
398 if (!m_scrollPosition.isZero())
399 scrollAnimator().setCurrentPosition(m_scrollPosition);
400 element->setSavedLayerScrollPosition(IntPoint());
404 RenderLayer::~RenderLayer()
407 renderer().frame().eventHandler().resizeLayerDestroyed();
409 ASSERT(m_registeredScrollableArea == renderer().view().frameView().containsScrollableArea(this));
411 if (m_registeredScrollableArea)
412 renderer().view().frameView().removeScrollableArea(this);
414 #if ENABLE(IOS_TOUCH_EVENTS)
415 unregisterAsTouchEventListenerForScrolling();
417 if (Element* element = renderer().element())
418 element->setSavedLayerScrollPosition(m_scrollPosition);
420 destroyScrollbar(HorizontalScrollbar);
421 destroyScrollbar(VerticalScrollbar);
423 if (auto* scrollingCoordinator = renderer().page().scrollingCoordinator())
424 scrollingCoordinator->willDestroyScrollableArea(*this);
432 FilterInfo::remove(*this);
434 // Child layers will be deleted by their corresponding render objects, so
435 // we don't need to delete them ourselves.
440 String RenderLayer::name() const
444 if (Element* element = renderer().element()) {
446 name.append(element->tagName().convertToLowercaseWithoutLocale());
449 if (element->hasID()) {
450 name.appendLiteral(" id=\'");
451 name.append(element->getIdAttribute());
455 if (element->hasClass()) {
456 name.appendLiteral(" class=\'");
457 size_t classNamesToDump = element->classNames().size();
458 const size_t maxNumClassNames = 7;
459 bool addEllipsis = false;
460 if (classNamesToDump > maxNumClassNames) {
461 classNamesToDump = maxNumClassNames;
465 for (size_t i = 0; i < classNamesToDump; ++i) {
468 name.append(element->classNames()[i]);
475 name.append(renderer().renderName());
478 name.appendLiteral(" (reflection)");
480 return name.toString();
483 RenderLayerCompositor& RenderLayer::compositor() const
485 return renderer().view().compositor();
488 void RenderLayer::contentChanged(ContentChangeType changeType)
490 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ImageChanged) && compositor().updateLayerCompositingState(*this))
491 compositor().setCompositingLayersNeedRebuild();
494 m_backing->contentChanged(changeType);
497 bool RenderLayer::canRender3DTransforms() const
499 return compositor().canRender3DTransforms();
502 bool RenderLayer::paintsWithFilters() const
504 if (!renderer().hasFilter())
510 if (!m_backing || !m_backing->canCompositeFilters())
516 bool RenderLayer::requiresFullLayerImageForFilters() const
518 if (!paintsWithFilters())
520 auto* renderer = filterRenderer();
521 return renderer && renderer->hasFilterThatMovesPixels();
524 FilterEffectRenderer* RenderLayer::filterRenderer() const
526 auto* filterInfo = FilterInfo::getIfExists(*this);
527 return filterInfo ? filterInfo->renderer() : nullptr;
530 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
532 LOG(Compositing, "RenderLayer %p updateLayerPositionsAfterLayout", this);
533 RenderGeometryMap geometryMap(UseTransforms);
534 if (this != rootLayer)
535 geometryMap.pushMappingsToAncestor(parent(), nullptr);
536 updateLayerPositions(&geometryMap, flags);
539 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
541 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
542 // we need to keep in sync, since we may have shifted relative
543 // to our parent layer.
545 applyPostLayoutScrollPositionIfNeeded();
548 geometryMap->pushMappingsToAncestor(this, parent());
550 // Clear our cached clip rect information.
553 if (hasOverflowControls()) {
554 LayoutSize offsetFromRoot;
556 offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
558 // FIXME: It looks suspicious to call convertToLayerCoords here
559 // as canUseConvertToLayerCoords may be true for an ancestor layer.
560 offsetFromRoot = offsetFromAncestor(root());
562 positionOverflowControls(roundedIntSize(offsetFromRoot));
565 updateDescendantDependentFlags();
567 if (flags & UpdatePagination)
570 m_enclosingPaginationLayer = nullptr;
572 if (m_hasVisibleContent) {
573 // FIXME: Paint offset cache does not work with RenderLayers as there is not a 1-to-1
574 // mapping between them and the RenderObjects. It would be neat to enable
575 // LayoutState outside the layout() phase and use it here.
576 ASSERT(!renderer().view().frameView().layoutContext().isPaintOffsetCacheEnabled());
578 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
580 auto hadRepaintLayoutRects = renderer().hasRepaintLayoutRects();
581 RepaintLayoutRects oldRects = hadRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects();
582 computeRepaintRects(repaintContainer, geometryMap);
584 auto hasRepaintLayoutRects = renderer().hasRepaintLayoutRects();
585 RepaintLayoutRects newRects = hasRepaintLayoutRects ? renderer().repaintLayoutRects() : RepaintLayoutRects();
586 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
587 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
588 if ((flags & CheckForRepaint) && hasRepaintLayoutRects) {
589 if (!renderer().view().printing()) {
590 if (m_repaintStatus & NeedsFullRepaint) {
591 if (hadRepaintLayoutRects)
592 renderer().repaintUsingContainer(repaintContainer, oldRects.m_repaintRect);
593 if (!hadRepaintLayoutRects || newRects.m_repaintRect != oldRects.m_repaintRect)
594 renderer().repaintUsingContainer(repaintContainer, newRects.m_repaintRect);
595 } else if (shouldRepaintAfterLayout()) {
596 // FIXME: We will convert this to just take the old and new RepaintLayoutRects once
597 // we change other callers to use RepaintLayoutRects.
598 renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRects.m_repaintRect, oldRects.m_outlineBox, &newRects.m_repaintRect, &newRects.m_outlineBox);
605 m_repaintStatus = NeedsNormalRepaint;
606 m_hasTransformedAncestor = flags & SeenTransformedLayer;
607 m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
609 // Update the reflection's position and size.
611 m_reflection->layout();
613 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
614 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
616 flags &= ~IsCompositingUpdateRoot;
618 if (renderer().isInFlowRenderFragmentedFlow()) {
620 flags |= UpdatePagination;
624 flags |= SeenTransformedLayer;
625 if (!transform()->isAffine())
626 flags |= Seen3DTransformedLayer;
629 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
630 child->updateLayerPositions(geometryMap, flags);
632 if ((flags & UpdateCompositingLayers) && isComposited()) {
633 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
634 if (flags & NeedsFullRepaintInBacking)
635 updateFlags |= RenderLayerBacking::NeedsFullRepaint;
637 updateFlags |= RenderLayerBacking::IsUpdateRoot;
638 backing()->updateAfterLayout(updateFlags);
641 // With all our children positioned, now update our marquee if we need to.
643 // FIXME: would like to use SetForScope<> but it doesn't work with bitfields.
644 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
645 m_updatingMarqueePosition = true;
646 m_marquee->updateMarqueePosition();
647 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
651 geometryMap->popMappingsToAncestor(parent());
653 renderer().document().markers().invalidateRectsForAllMarkers();
656 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
658 LayoutRect repaintRect = renderer().repaintLayoutRects().m_repaintRect;
659 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
660 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
661 if (child->isComposited())
664 repaintRect.uniteIfNonZero(child->repaintRectIncludingNonCompositingDescendants());
669 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
671 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
672 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
675 layer->m_hasSelfPaintingLayerDescendantDirty = false;
676 layer->m_hasSelfPaintingLayerDescendant = true;
680 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
682 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
683 layer->m_hasSelfPaintingLayerDescendantDirty = true;
684 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
685 // in this case, there is no need to dirty our ancestors further.
686 if (layer->isSelfPaintingLayer()) {
687 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
693 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
695 return renderer().settings().acceleratedCompositingForOverflowScrollEnabled();
698 // If we are a stacking container, then this function will determine if our
699 // descendants for a contiguous block in stacking order. This is required in
700 // order for an element to be safely promoted to a stacking container. It is safe
701 // to become a stacking container if this change would not alter the stacking
702 // order of layers on the page. That can only happen if a non-descendant appear
703 // between us and our descendants in stacking order. Here's an example:
713 // I've labeled our normal flow descendants A, B, C, and D, our stacking
714 // container descendants with their z indices, and us with 'this' (we're a
715 // stacking container and our zIndex doesn't matter here). These nodes appear in
716 // three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
717 // flow layers don't overlap). So if we arrange these lists in order we get our
720 // [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
722 // Neg z-order. <-+ +--> Normal flow descendants.
724 // We can then assign new, 'stacking' order indices to these elements as follows:
726 // [-8], [A-D], [0, 2, 5, 7]
727 // 'Stacking' indices: -1 0 1 2 3 4
729 // Note that the normal flow descendants can share an index because they don't
730 // stack/overlap. Now our problem becomes very simple: a layer can safely become
731 // a stacking container if the stacking-order indices of it and its descendants
732 // appear in a contiguous block in the list of stacking indices. This problem
733 // can be solved very efficiently by calculating the min/max stacking indices in
734 // the subtree, and the number stacking container descendants. Once we have this
735 // information, we know that the subtree's indices form a contiguous block if:
737 // maxStackIndex - minStackIndex == numSCDescendants
739 // So for node A in the example above we would have:
741 // minStackIndex = -1
742 // numSCDecendants = 2
745 // maxStackIndex - minStackIndex == numSCDescendants
746 // ===> 1 - (-1) == 2
749 // Since this is true, A can safely become a stacking container.
750 // Now, for node C we have:
753 // minStackIndex = 0 <-- because C has stacking index 0.
754 // numSCDecendants = 2
757 // maxStackIndex - minStackIndex == numSCDescendants
761 // Since this is false, C cannot be safely promoted to a stacking container. This
762 // happened because of the elements with z-index 5 and 0. Now if 5 had been a
763 // child of C rather than D, and A had no child with Z index 0, we would have had:
766 // minStackIndex = 0 <-- because C has stacking index 0.
767 // numSCDecendants = 3
770 // maxStackIndex - minStackIndex == numSCDescendants
774 // And we would conclude that C could be promoted.
775 void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
777 if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
780 ASSERT(!m_normalFlowListDirty);
781 ASSERT(!m_zOrderListsDirty);
783 std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
784 std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
785 rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
787 // Create a reverse lookup.
788 HashMap<const RenderLayer*, int> lookup;
791 int stackingOrderIndex = -1;
792 size_t listSize = negZOrderList->size();
793 for (size_t i = 0; i < listSize; ++i) {
794 RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
795 if (!currentLayer->isStackingContext())
797 lookup.set(currentLayer, stackingOrderIndex--);
802 size_t listSize = posZOrderList->size();
803 int stackingOrderIndex = 1;
804 for (size_t i = 0; i < listSize; ++i) {
805 RenderLayer* currentLayer = posZOrderList->at(i);
806 if (!currentLayer->isStackingContext())
808 lookup.set(currentLayer, stackingOrderIndex++);
815 bool firstIteration = true;
816 updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
819 void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
821 if (isStackingContext() && !firstIteration) {
822 if (lookup.contains(this)) {
823 minIndex = std::min(minIndex, lookup.get(this));
824 maxIndex = std::max(maxIndex, lookup.get(this));
830 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
831 int childMinIndex = 0;
832 int childMaxIndex = 0;
834 child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
837 minIndex = std::min(minIndex, childMinIndex);
838 maxIndex = std::max(maxIndex, childMaxIndex);
842 if (!isStackingContext()) {
843 bool newValue = maxIndex - minIndex == count;
844 bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
845 m_descendantsAreContiguousInStackingOrder = newValue;
847 updateNeedsCompositedScrolling();
851 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
853 ASSERT(!m_visibleContentStatusDirty);
854 renderer().computeRepaintLayoutRects(repaintContainer, geometryMap);
857 void RenderLayer::computeRepaintRectsIncludingDescendants()
859 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
860 // We should make this more efficient.
861 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
862 computeRepaintRects(renderer().containerForRepaint());
864 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
865 layer->computeRepaintRectsIncludingDescendants();
868 void RenderLayer::clearRepaintRects()
870 ASSERT(!m_visibleContentStatusDirty);
872 renderer().clearRepaintLayoutRects();
875 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
877 ASSERT(this == renderer().view().layer());
879 LOG(Scrolling, "RenderLayer::updateLayerPositionsAfterDocumentScroll");
881 RenderGeometryMap geometryMap(UseTransforms);
882 updateLayerPositionsAfterScroll(&geometryMap);
885 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
887 RenderGeometryMap geometryMap(UseTransforms);
888 if (this != renderer().view().layer())
889 geometryMap.pushMappingsToAncestor(parent(), nullptr);
891 // FIXME: why is it OK to not check the ancestors of this layer in order to
892 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
893 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
896 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
898 // FIXME: This shouldn't be needed, but there are some corner cases where
899 // these flags are still dirty. Update so that the check below is valid.
900 updateDescendantDependentFlags();
902 // If we have no visible content and no visible descendants, there is no point recomputing
903 // our rectangles as they will be empty. If our visibility changes, we are expected to
904 // recompute all our positions anyway.
905 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
908 bool positionChanged = updateLayerPosition();
910 flags |= HasChangedAncestor;
912 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
915 if (renderer().style().hasViewportConstrainedPosition())
916 flags |= HasSeenViewportConstrainedAncestor;
918 if (renderer().hasOverflowClip())
919 flags |= HasSeenAncestorWithOverflowClip;
921 bool shouldComputeRepaintRects = (flags & HasSeenViewportConstrainedAncestor || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) && isSelfPaintingLayer();
922 bool isVisuallyEmpty = !isVisuallyNonEmpty();
923 bool shouldPushAndPopMappings = geometryMap && ((shouldComputeRepaintRects && !isVisuallyEmpty) || firstChild());
924 if (shouldPushAndPopMappings)
925 geometryMap->pushMappingsToAncestor(this, parent());
927 if (shouldComputeRepaintRects) {
928 // When scrolling, we don't compute repaint rects for visually non-empty layers.
931 else // FIXME: We could track the repaint container as we walk down the tree.
932 computeRepaintRects(renderer().containerForRepaint(), geometryMap);
934 // Check that our cached rects are correct.
935 ASSERT(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
936 ASSERT(!renderer().hasRepaintLayoutRects() || renderer().repaintLayoutRects().m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
939 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
940 child->updateLayerPositionsAfterScroll(geometryMap, flags);
942 // We don't update our reflection as scrolling is a translation which does not change the size()
943 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
947 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
948 m_updatingMarqueePosition = true;
949 m_marquee->updateMarqueePosition();
950 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
953 if (shouldPushAndPopMappings)
954 geometryMap->popMappingsToAncestor(parent());
956 renderer().document().markers().invalidateRectsForAllMarkers();
959 void RenderLayer::positionNewlyCreatedOverflowControls()
961 if (!backing()->hasUnpositionedOverflowControlsLayers())
964 RenderGeometryMap geometryMap(UseTransforms);
965 if (this != renderer().view().layer() && parent())
966 geometryMap.pushMappingsToAncestor(parent(), nullptr);
968 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
969 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
972 #if ENABLE(CSS_COMPOSITING)
974 void RenderLayer::updateBlendMode()
976 bool hadBlendMode = m_blendMode != BlendModeNormal;
977 if (parent() && hadBlendMode != hasBlendMode()) {
979 parent()->updateAncestorChainHasBlendingDescendants();
981 parent()->dirtyAncestorChainHasBlendingDescendants();
984 BlendMode newBlendMode = renderer().style().blendMode();
985 if (newBlendMode != m_blendMode)
986 m_blendMode = newBlendMode;
989 void RenderLayer::updateAncestorChainHasBlendingDescendants()
991 for (auto* layer = this; layer; layer = layer->parent()) {
992 if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
994 layer->m_hasNotIsolatedBlendingDescendants = true;
995 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
997 layer->updateSelfPaintingLayer();
999 if (layer->isStackingContext())
1004 void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
1006 for (auto* layer = this; layer; layer = layer->parent()) {
1007 if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
1010 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
1012 if (layer->isStackingContext())
1018 void RenderLayer::updateTransform()
1020 bool hasTransform = renderer().hasTransform();
1021 bool had3DTransform = has3DTransform();
1023 bool hadTransform = !!m_transform;
1024 if (hasTransform != hadTransform) {
1026 m_transform = std::make_unique<TransformationMatrix>();
1028 m_transform = nullptr;
1030 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
1031 clearClipRectsIncludingDescendants();
1035 RenderBox* box = renderBox();
1037 m_transform->makeIdentity();
1038 box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
1039 makeMatrixRenderable(*m_transform, canRender3DTransforms());
1042 if (had3DTransform != has3DTransform())
1043 dirty3DTransformedDescendantStatus();
1046 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
1049 return TransformationMatrix();
1051 RenderBox* box = renderBox();
1053 if (renderer().animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyTransform, AnimationBase::Running | AnimationBase::Paused)) {
1054 TransformationMatrix currTransform;
1055 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1056 std::unique_ptr<RenderStyle> style = renderer().animation().animatedStyleForRenderer(renderer());
1057 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
1058 makeMatrixRenderable(currTransform, canRender3DTransforms());
1059 return currTransform;
1062 // m_transform includes transform-origin, so we need to recompute the transform here.
1063 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
1064 TransformationMatrix currTransform;
1065 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1066 box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
1067 makeMatrixRenderable(currTransform, canRender3DTransforms());
1068 return currTransform;
1071 return *m_transform;
1074 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
1077 return TransformationMatrix();
1079 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
1080 TransformationMatrix matrix = *m_transform;
1081 makeMatrixRenderable(matrix, false /* flatten 3d */);
1085 return *m_transform;
1088 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
1090 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
1092 if (layer->renderer().hasOverflowClip())
1093 return const_cast<RenderLayer*>(layer);
1095 layer = layer->parent();
1100 // FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
1101 // painting of content inside paginated layers.
1102 bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
1104 // No enclosing layer means no compositing in the chain.
1105 if (!m_enclosingPaginationLayer)
1108 // If the enclosing layer is composited, we don't have to check anything in between us and that
1110 if (m_enclosingPaginationLayer->isComposited())
1113 // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
1115 if (m_enclosingPaginationLayer == this)
1118 // The enclosing paginated layer is our ancestor and is not composited, so we have to check
1119 // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
1123 // For normal flow layers, we can recur up the layer tree.
1124 if (isNormalFlowOnly())
1125 return parent()->hasCompositedLayerInEnclosingPaginationChain();
1127 // Otherwise we have to go up the containing block chain. Find the first enclosing
1128 // containing block layer ancestor, and check that.
1129 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1130 if (containingBlock->hasLayer())
1131 return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
1136 void RenderLayer::updatePagination()
1138 m_enclosingPaginationLayer = nullptr;
1143 // Each layer that is inside a multicolumn flow thread has to be checked individually and
1144 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
1145 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
1146 // to that layer easily.
1147 if (renderer().isInFlowRenderFragmentedFlow()) {
1148 m_enclosingPaginationLayer = this;
1152 if (isNormalFlowOnly()) {
1153 // Content inside a transform is not considered to be paginated, since we simply
1154 // paint the transform multiple times in each column, so we don't have to use
1155 // fragments for the transformed content.
1156 if (parent()->hasTransform())
1157 m_enclosingPaginationLayer = nullptr;
1159 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1163 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
1164 // we find one, then we just check its pagination status.
1165 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1166 if (containingBlock->hasLayer()) {
1167 // Content inside a transform is not considered to be paginated, since we simply
1168 // paint the transform multiple times in each column, so we don't have to use
1169 // fragments for the transformed content.
1170 if (containingBlock->layer()->hasTransform())
1171 m_enclosingPaginationLayer = nullptr;
1173 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1179 bool RenderLayer::canBeStackingContainer() const
1181 if (isStackingContext() || !stackingContainer())
1184 return m_descendantsAreContiguousInStackingOrder;
1187 void RenderLayer::setHasVisibleContent()
1189 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1190 ASSERT(!parent() || parent()->hasVisibleDescendant());
1194 m_visibleContentStatusDirty = false;
1195 m_hasVisibleContent = true;
1196 computeRepaintRects(renderer().containerForRepaint());
1197 if (!isNormalFlowOnly()) {
1198 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1199 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1200 // collected. FIXME: When compositing, we could skip this dirtying phase.
1201 for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
1202 sc->dirtyZOrderLists();
1203 if (sc->hasVisibleContent())
1209 parent()->setAncestorChainHasVisibleDescendant();
1212 void RenderLayer::dirtyVisibleContentStatus()
1214 m_visibleContentStatusDirty = true;
1216 parent()->dirtyAncestorChainVisibleDescendantStatus();
1219 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1221 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1222 if (layer->m_visibleDescendantStatusDirty)
1225 layer->m_visibleDescendantStatusDirty = true;
1229 void RenderLayer::setAncestorChainHasVisibleDescendant()
1231 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1232 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1235 layer->m_hasVisibleDescendant = true;
1236 layer->m_visibleDescendantStatusDirty = false;
1240 void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
1242 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
1243 bool hasVisibleDescendant = false;
1244 bool hasSelfPaintingLayerDescendant = false;
1245 bool hasOutOfFlowPositionedDescendant = false;
1246 #if ENABLE(CSS_COMPOSITING)
1247 bool hasNotIsolatedBlendingDescendants = false;
1250 HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
1251 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1252 childOutOfFlowDescendantContainingBlocks.clear();
1253 child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
1255 bool childIsOutOfFlowPositioned = child->renderer().isOutOfFlowPositioned();
1256 if (childIsOutOfFlowPositioned)
1257 childOutOfFlowDescendantContainingBlocks.add(child->renderer().containingBlock());
1259 if (outOfFlowDescendantContainingBlocks) {
1260 HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
1261 for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
1262 outOfFlowDescendantContainingBlocks->add(*it);
1265 hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1266 hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1267 hasOutOfFlowPositionedDescendant |= !childOutOfFlowDescendantContainingBlocks.isEmpty();
1268 #if ENABLE(CSS_COMPOSITING)
1269 hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
1272 bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant;
1273 #if ENABLE(CSS_COMPOSITING)
1274 allFlagsSet &= hasNotIsolatedBlendingDescendants;
1280 if (outOfFlowDescendantContainingBlocks)
1281 outOfFlowDescendantContainingBlocks->remove(&renderer());
1283 m_hasVisibleDescendant = hasVisibleDescendant;
1284 m_visibleDescendantStatusDirty = false;
1285 m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
1286 m_hasSelfPaintingLayerDescendantDirty = false;
1288 m_hasOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant;
1289 if (m_hasOutOfFlowPositionedDescendantDirty)
1290 updateNeedsCompositedScrolling();
1292 m_hasOutOfFlowPositionedDescendantDirty = false;
1293 #if ENABLE(CSS_COMPOSITING)
1294 m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
1295 if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
1296 m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1297 updateSelfPaintingLayer();
1302 if (m_visibleContentStatusDirty) {
1303 if (renderer().style().visibility() == VISIBLE)
1304 m_hasVisibleContent = true;
1306 // layer may be hidden but still have some visible content, check for this
1307 m_hasVisibleContent = false;
1308 RenderObject* r = renderer().firstChild();
1310 if (r->style().visibility() == VISIBLE && !r->hasLayer()) {
1311 m_hasVisibleContent = true;
1314 RenderObject* child = nullptr;
1315 if (!r->hasLayer() && (child = r->firstChildSlow()))
1317 else if (r->nextSibling())
1318 r = r->nextSibling();
1322 if (r == &renderer())
1324 } while (r && !r->nextSibling());
1326 r = r->nextSibling();
1330 m_visibleContentStatusDirty = false;
1334 void RenderLayer::dirty3DTransformedDescendantStatus()
1336 RenderLayer* curr = stackingContainer();
1338 curr->m_3DTransformedDescendantStatusDirty = true;
1340 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1341 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1342 while (curr && curr->preserves3D()) {
1343 curr->m_3DTransformedDescendantStatusDirty = true;
1344 curr = curr->stackingContainer();
1348 // Return true if this layer or any preserve-3d descendants have 3d.
1349 bool RenderLayer::update3DTransformedDescendantStatus()
1351 if (m_3DTransformedDescendantStatusDirty) {
1352 m_has3DTransformedDescendant = false;
1354 updateZOrderLists();
1356 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1357 // in the normal flow list, so we only need to check those.
1358 if (auto* positiveZOrderList = posZOrderList()) {
1359 for (auto* layer : *positiveZOrderList)
1360 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1363 // Now check our negative z-index children.
1364 if (auto* negativeZOrderList = negZOrderList()) {
1365 for (auto* layer : *negativeZOrderList)
1366 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1369 m_3DTransformedDescendantStatusDirty = false;
1372 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1373 // the m_has3DTransformedDescendant set.
1375 return has3DTransform() || m_has3DTransformedDescendant;
1377 return has3DTransform();
1380 bool RenderLayer::updateLayerPosition()
1382 LayoutPoint localPoint;
1383 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1384 if (renderer().isInline() && is<RenderInline>(renderer())) {
1385 auto& inlineFlow = downcast<RenderInline>(renderer());
1386 IntRect lineBox = inlineFlow.linesBoundingBox();
1387 setSize(lineBox.size());
1388 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1389 localPoint += inlineBoundingBoxOffset;
1390 } else if (RenderBox* box = renderBox()) {
1391 // FIXME: Is snapping the size really needed here for the RenderBox case?
1392 setSize(snappedIntRect(box->frameRect()).size());
1393 box->applyTopLeftLocationOffset(localPoint);
1396 if (!renderer().isOutOfFlowPositioned()) {
1397 auto* ancestor = renderer().parent();
1398 // We must adjust our position by walking up the render tree looking for the
1399 // nearest enclosing object with a layer.
1400 while (ancestor && !ancestor->hasLayer()) {
1401 if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
1402 // Rows and cells share the same coordinate space (that of the section).
1403 // Omit them when computing our xpos/ypos.
1404 localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1406 ancestor = ancestor->parent();
1408 if (is<RenderTableRow>(ancestor)) {
1409 // Put ourselves into the row coordinate space.
1410 localPoint -= downcast<RenderTableRow>(*ancestor).topLeftLocationOffset();
1414 // Subtract our parent's scroll offset.
1415 RenderLayer* positionedParent;
1416 if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
1417 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1418 if (positionedParent->renderer().hasOverflowClip())
1419 localPoint -= toLayoutSize(positionedParent->scrollPosition());
1421 if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
1422 LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
1423 localPoint += offset;
1425 } else if (parent()) {
1426 if (parent()->renderer().hasOverflowClip())
1427 localPoint -= toLayoutSize(parent()->scrollPosition());
1430 bool positionOrOffsetChanged = false;
1431 if (renderer().isInFlowPositioned()) {
1432 LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
1433 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
1434 m_offsetForInFlowPosition = newOffset;
1435 localPoint.move(m_offsetForInFlowPosition);
1437 m_offsetForInFlowPosition = LayoutSize();
1440 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1441 localPoint -= inlineBoundingBoxOffset;
1443 positionOrOffsetChanged |= location() != localPoint;
1444 setLocation(localPoint);
1445 return positionOrOffsetChanged;
1448 TransformationMatrix RenderLayer::perspectiveTransform() const
1450 RenderBox* box = renderBox();
1452 return TransformationMatrix();
1454 if (!box->hasTransformRelatedProperty())
1455 return TransformationMatrix();
1457 const RenderStyle& style = box->style();
1458 if (!style.hasPerspective())
1459 return TransformationMatrix();
1461 // Maybe fetch the perspective from the backing?
1462 const FloatRect borderBox = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1463 float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), borderBox.width());
1464 float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), borderBox.height());
1466 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
1467 // We want it to be in the top-left, so subtract half the height and width.
1468 perspectiveOriginX -= borderBox.width() / 2.0f;
1469 perspectiveOriginY -= borderBox.height() / 2.0f;
1471 TransformationMatrix t;
1472 t.translate(perspectiveOriginX, perspectiveOriginY);
1473 t.applyPerspective(style.perspective());
1474 t.translate(-perspectiveOriginX, -perspectiveOriginY);
1479 FloatPoint RenderLayer::perspectiveOrigin() const
1481 if (!renderer().hasTransformRelatedProperty())
1482 return FloatPoint();
1484 const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
1485 const RenderStyle& style = renderer().style();
1487 return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
1488 floatValueForLength(style.perspectiveOriginY(), borderBox.height()));
1491 RenderLayer* RenderLayer::stackingContainer() const
1493 RenderLayer* layer = parent();
1494 while (layer && !layer->isStackingContainer())
1495 layer = layer->parent();
1497 ASSERT(!layer || layer->isStackingContainer());
1501 static inline bool isContainerForPositioned(RenderLayer& layer, EPosition position)
1505 return layer.renderer().canContainFixedPositionObjects();
1507 case AbsolutePosition:
1508 return layer.renderer().canContainAbsolutelyPositionedObjects();
1511 ASSERT_NOT_REACHED();
1516 RenderLayer* RenderLayer::enclosingAncestorForPosition(EPosition position) const
1518 RenderLayer* curr = parent();
1519 while (curr && !isContainerForPositioned(*curr, position))
1520 curr = curr->parent();
1525 static RenderLayer* parentLayerCrossFrame(const RenderLayer& layer)
1528 return layer.parent();
1530 HTMLFrameOwnerElement* ownerElement = layer.renderer().document().ownerElement();
1534 RenderElement* ownerRenderer = ownerElement->renderer();
1538 return ownerRenderer->enclosingLayer();
1541 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1543 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
1544 if (is<RenderBox>(nextLayer->renderer()) && downcast<RenderBox>(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
1551 IntRect RenderLayer::scrollableAreaBoundingBox(bool* isInsideFixed) const
1553 return renderer().absoluteBoundingBoxRect(/* useTransforms */ true, isInsideFixed);
1556 bool RenderLayer::isRubberBandInProgress() const
1558 #if ENABLE(RUBBER_BANDING)
1559 if (!scrollsOverflow())
1562 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1563 return scrollAnimator->isRubberBandInProgress();
1569 bool RenderLayer::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
1571 return renderer().settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
1574 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1576 RenderLayer* curr = parent();
1577 while (curr && !curr->isRenderViewLayer() && !curr->transform())
1578 curr = curr->parent();
1583 static inline const RenderLayer* compositingContainer(const RenderLayer& layer)
1585 return layer.isNormalFlowOnly() ? layer.parent() : layer.stackingContainer();
1588 inline bool RenderLayer::shouldRepaintAfterLayout() const
1590 if (m_repaintStatus == NeedsNormalRepaint)
1593 // Composited layers that were moved during a positioned movement only
1594 // layout, don't need to be repainted. They just need to be recomposited.
1595 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1596 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1599 bool compositedWithOwnBackingStore(const RenderLayer& layer)
1601 return layer.isComposited() && !layer.backing()->paintsIntoCompositedAncestor();
1604 RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
1606 if (includeSelf == IncludeSelf && isComposited())
1607 return const_cast<RenderLayer*>(this);
1609 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1610 if (curr->isComposited())
1611 return const_cast<RenderLayer*>(curr);
1617 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
1619 if (includeSelf == IncludeSelf && compositedWithOwnBackingStore(*this))
1620 return const_cast<RenderLayer*>(this);
1622 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1623 if (compositedWithOwnBackingStore(*curr))
1624 return const_cast<RenderLayer*>(curr);
1630 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
1632 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
1633 for (; curr; curr = curr->parent()) {
1634 if (curr->requiresFullLayerImageForFilters())
1635 return const_cast<RenderLayer*>(curr);
1641 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1643 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1644 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(*curr) || curr->isRenderViewLayer())
1645 return const_cast<RenderLayer*>(curr);
1650 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
1655 LayoutRect rectForRepaint = rect;
1656 renderer().style().filterOutsets().expandRect(rectForRepaint);
1658 FilterInfo& filterInfo = FilterInfo::get(*this);
1659 filterInfo.expandDirtySourceRect(rectForRepaint);
1661 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1662 ASSERT(parentLayer);
1663 FloatQuad repaintQuad(rectForRepaint);
1664 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1666 if (parentLayer->isComposited()) {
1667 if (!parentLayer->backing()->paintsIntoWindow()) {
1668 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1671 // If the painting goes to window, redirect the painting to the parent RenderView.
1672 parentLayer = renderer().view().layer();
1673 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1676 if (parentLayer->paintsWithFilters()) {
1677 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
1681 if (parentLayer->isRenderViewLayer()) {
1682 downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
1686 ASSERT_NOT_REACHED();
1689 bool RenderLayer::hasAncestorWithFilterOutsets() const
1691 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1692 if (curr->renderer().style().hasFilterOutsets())
1698 RenderLayer* RenderLayer::clippingRootForPainting() const
1701 return const_cast<RenderLayer*>(this);
1703 const RenderLayer* current = this;
1705 if (current->isRenderViewLayer())
1706 return const_cast<RenderLayer*>(current);
1708 current = compositingContainer(*current);
1710 if (current->transform() || compositedWithOwnBackingStore(*current))
1711 return const_cast<RenderLayer*>(current);
1714 ASSERT_NOT_REACHED();
1718 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1720 // We don't use convertToLayerCoords because it doesn't know about transforms
1721 return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
1724 bool RenderLayer::cannotBlitToWindow() const
1726 if (isTransparent() || hasReflection() || hasTransform())
1730 return parent()->cannotBlitToWindow();
1733 RenderLayer* RenderLayer::transparentPaintingAncestor()
1738 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1739 if (curr->isComposited())
1741 if (curr->isTransparent())
1747 enum TransparencyClipBoxBehavior {
1748 PaintingTransparencyClipBox,
1749 HitTestingTransparencyClipBox
1752 enum TransparencyClipBoxMode {
1753 DescendantsOfTransparencyClipBox,
1754 RootOfTransparencyClipBox
1757 static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
1759 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1760 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1762 // If we have a mask, then the clip is limited to the border box area (and there is
1763 // no need to examine child layers).
1764 if (!layer.renderer().hasMask()) {
1765 // Note: we don't have to walk z-order lists since transparent elements always establish
1766 // a stacking container. This means we can just walk the layer tree directly.
1767 for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
1768 if (!layer.reflection() || layer.reflectionLayer() != curr)
1769 clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
1773 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1774 // current transparencyClipBox to catch all child layers.
1775 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1776 // size into the parent layer.
1777 if (layer.renderer().hasReflection()) {
1778 LayoutSize delta = layer.offsetFromAncestor(rootLayer);
1779 clipRect.move(-delta);
1780 clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
1781 clipRect.move(delta);
1785 static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1786 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
1788 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1789 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1790 // would be better to respect clips.
1792 if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
1793 || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
1794 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1795 // the transformed layer and all of its children.
1796 RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
1797 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : nullptr;
1798 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1799 LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
1801 TransformationMatrix transform;
1802 transform.translate(delta.width(), delta.height());
1803 transform.multiply(*layer.transform());
1805 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1806 // paints unfragmented.
1807 LayoutRect clipRect = layer.boundingBox(&layer);
1808 expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
1809 layer.renderer().style().filterOutsets().expandRect(clipRect);
1810 LayoutRect result = transform.mapRect(clipRect);
1811 if (!paginationLayer)
1814 // We have to break up the transformed extent across our columns.
1815 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1816 // get our true bounding box.
1817 auto& enclosingFragmentedFlow = downcast<RenderFragmentedFlow>(paginationLayer->renderer());
1818 result = enclosingFragmentedFlow.fragmentsBoundingBox(result);
1819 result.move(paginationLayer->offsetFromAncestor(rootLayer));
1823 LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
1824 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1825 layer.renderer().style().filterOutsets().expandRect(clipRect);
1830 static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1832 return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
1835 void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
1837 if (context.paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
1840 RenderLayer* ancestor = transparentPaintingAncestor();
1842 ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
1844 if (paintsWithTransparency(paintingInfo.paintBehavior)) {
1845 ASSERT(isStackingContext());
1846 m_usedTransparency = true;
1848 LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
1849 adjustedClipRect.move(paintingInfo.subpixelOffset);
1850 FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
1851 context.clip(pixelSnappedClipRect);
1853 #if ENABLE(CSS_COMPOSITING)
1854 bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRenderViewLayer());
1855 if (usesCompositeOperation)
1856 context.setCompositeOperation(context.compositeOperation(), blendMode());
1859 context.beginTransparencyLayer(renderer().opacity());
1861 #if ENABLE(CSS_COMPOSITING)
1862 if (usesCompositeOperation)
1863 context.setCompositeOperation(context.compositeOperation(), BlendModeNormal);
1866 #ifdef REVEAL_TRANSPARENCY_LAYERS
1867 context.setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
1868 context.fillRect(pixelSnappedClipRect);
1874 void RenderLayer::willBeDestroyed()
1876 if (RenderLayerBacking* layerBacking = backing())
1877 layerBacking->layerWillBeDestroyed();
1881 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1883 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1885 child->setPreviousSibling(prevSibling);
1886 prevSibling->setNextSibling(child);
1887 ASSERT(prevSibling != child);
1889 setFirstChild(child);
1892 beforeChild->setPreviousSibling(child);
1893 child->setNextSibling(beforeChild);
1894 ASSERT(beforeChild != child);
1896 setLastChild(child);
1898 child->setParent(this);
1900 if (child->isNormalFlowOnly())
1901 dirtyNormalFlowList();
1903 if (!child->isNormalFlowOnly() || child->firstChild()) {
1904 // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
1905 // case where we're building up generated content layers. This is ok, since the lists will start
1906 // off dirty in that case anyway.
1907 child->dirtyStackingContainerZOrderLists();
1910 child->updateDescendantDependentFlags();
1911 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1912 setAncestorChainHasVisibleDescendant();
1914 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1915 setAncestorChainHasSelfPaintingLayerDescendant();
1917 if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
1918 setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
1920 #if ENABLE(CSS_COMPOSITING)
1921 if (child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending()))
1922 updateAncestorChainHasBlendingDescendants();
1925 compositor().layerWasAdded(*this, *child);
1928 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1930 if (!renderer().renderTreeBeingDestroyed())
1931 compositor().layerWillBeRemoved(*this, *oldChild);
1934 if (oldChild->previousSibling())
1935 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1936 if (oldChild->nextSibling())
1937 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1939 if (m_first == oldChild)
1940 m_first = oldChild->nextSibling();
1941 if (m_last == oldChild)
1942 m_last = oldChild->previousSibling();
1944 if (oldChild->isNormalFlowOnly())
1945 dirtyNormalFlowList();
1946 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1947 // Dirty the z-order list in which we are contained. When called via the
1948 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1949 // from the main layer tree, so we need to null-check the |stackingContainer| value.
1950 oldChild->dirtyStackingContainerZOrderLists();
1953 if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
1954 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
1956 oldChild->setPreviousSibling(nullptr);
1957 oldChild->setNextSibling(nullptr);
1958 oldChild->setParent(nullptr);
1960 oldChild->updateDescendantDependentFlags();
1961 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1962 dirtyAncestorChainVisibleDescendantStatus();
1964 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1965 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1967 #if ENABLE(CSS_COMPOSITING)
1968 if (oldChild->hasBlendMode() || (oldChild->hasNotIsolatedBlendingDescendants() && !oldChild->isolatesBlending()))
1969 dirtyAncestorChainHasBlendingDescendants();
1975 void RenderLayer::removeOnlyThisLayer()
1980 // Mark that we are about to lose our layer. This makes render tree
1981 // walks ignore this layer while we're removing it.
1982 renderer().setHasLayer(false);
1984 compositor().layerWillBeRemoved(*m_parent, *this);
1986 // Dirty the clip rects.
1987 clearClipRectsIncludingDescendants();
1989 RenderLayer* nextSib = nextSibling();
1991 // Remove the child reflection layer before moving other child layers.
1992 // The reflection layer should not be moved to the parent.
1994 removeChild(reflectionLayer());
1996 // Now walk our kids and reattach them to our parent.
1997 RenderLayer* current = m_first;
1999 RenderLayer* next = current->nextSibling();
2000 removeChild(current);
2001 m_parent->addChild(current, nextSib);
2002 current->setRepaintStatus(NeedsFullRepaint);
2003 // updateLayerPositions depends on hasLayer() already being false for proper layout.
2004 ASSERT(!renderer().hasLayer());
2005 current->updateLayerPositions(); // FIXME: use geometry map.
2009 // Remove us from the parent.
2010 m_parent->removeChild(this);
2011 renderer().destroyLayer();
2014 void RenderLayer::insertOnlyThisLayer()
2016 if (!m_parent && renderer().parent()) {
2017 // We need to connect ourselves when our renderer() has a parent.
2018 // Find our enclosingLayer and add ourselves.
2019 RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
2020 ASSERT(parentLayer);
2021 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : nullptr;
2022 parentLayer->addChild(this, beforeChild);
2025 // Remove all descendant layers from the hierarchy and add them to the new position.
2026 for (auto& child : childrenOfType<RenderElement>(renderer()))
2027 child.moveLayers(m_parent, this);
2029 // Clear out all the clip rects.
2030 clearClipRectsIncludingDescendants();
2033 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
2035 LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
2036 roundedLocation = roundedIntPoint(location);
2039 // Returns the layer reached on the walk up towards the ancestor.
2040 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
2042 ASSERT(ancestorLayer != layer);
2044 const RenderLayerModelObject& renderer = layer->renderer();
2045 EPosition position = renderer.style().position();
2047 // FIXME: Special casing RenderFragmentedFlow so much for fixed positioning here is not great.
2048 RenderFragmentedFlow* fixedFragmentedFlowContainer = position == FixedPosition ? renderer.enclosingFragmentedFlow() : nullptr;
2049 if (fixedFragmentedFlowContainer && !fixedFragmentedFlowContainer->isOutOfFlowPositioned())
2050 fixedFragmentedFlowContainer = nullptr;
2052 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFragmentedFlow
2053 // may need to be revisited in a future patch.
2054 // If the fixed renderer is inside a RenderFragmentedFlow, we should not compute location using localToAbsolute,
2055 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
2056 // positioned in a completely different place in the viewport (RenderView).
2057 if (position == FixedPosition && !fixedFragmentedFlowContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
2058 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
2059 // localToAbsolute() on the RenderView.
2060 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
2061 location += LayoutSize(absPos.x(), absPos.y());
2062 return ancestorLayer;
2065 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
2066 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
2067 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
2068 if (position == FixedPosition && !fixedFragmentedFlowContainer) {
2069 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
2070 // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
2071 // so we should always find the ancestor at or before we find the fixed position container.
2072 RenderLayer* fixedPositionContainerLayer = nullptr;
2073 bool foundAncestor = false;
2074 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
2075 if (currLayer == ancestorLayer)
2076 foundAncestor = true;
2078 if (isContainerForPositioned(*currLayer, FixedPosition)) {
2079 fixedPositionContainerLayer = currLayer;
2080 ASSERT_UNUSED(foundAncestor, foundAncestor);
2085 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
2087 if (fixedPositionContainerLayer != ancestorLayer) {
2088 LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
2089 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
2090 location += (fixedContainerCoords - ancestorCoords);
2091 return ancestorLayer;
2095 if (position == FixedPosition && fixedFragmentedFlowContainer) {
2096 ASSERT(ancestorLayer);
2097 if (ancestorLayer->isOutOfFlowRenderFragmentedFlow()) {
2098 location += toLayoutSize(layer->location());
2099 return ancestorLayer;
2102 if (ancestorLayer == renderer.view().layer()) {
2103 // Add location in flow thread coordinates.
2104 location += toLayoutSize(layer->location());
2106 // Add flow thread offset in view coordinates since the view may be scrolled.
2107 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
2108 location += LayoutSize(absPos.x(), absPos.y());
2109 return ancestorLayer;
2113 RenderLayer* parentLayer;
2114 if (position == AbsolutePosition || position == FixedPosition) {
2115 // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
2116 parentLayer = layer->parent();
2117 bool foundAncestorFirst = false;
2118 while (parentLayer) {
2119 // RenderFragmentedFlow is a positioned container, child of RenderView, positioned at (0,0).
2120 // This implies that, for out-of-flow positioned elements inside a RenderFragmentedFlow,
2121 // we are bailing out before reaching root layer.
2122 if (isContainerForPositioned(*parentLayer, position))
2125 if (parentLayer == ancestorLayer) {
2126 foundAncestorFirst = true;
2130 parentLayer = parentLayer->parent();
2133 // We should not reach RenderView layer past the RenderFragmentedFlow layer for any
2134 // children of the RenderFragmentedFlow.
2135 if (renderer.enclosingFragmentedFlow() && !layer->isOutOfFlowRenderFragmentedFlow())
2136 ASSERT(parentLayer != renderer.view().layer());
2138 if (foundAncestorFirst) {
2139 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
2140 // to enclosingAncestorForPosition and subtract.
2141 RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
2142 LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
2143 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
2144 location += (thisCoords - ancestorCoords);
2145 return ancestorLayer;
2148 parentLayer = layer->parent();
2153 location += toLayoutSize(layer->location());
2155 if (adjustForColumns == RenderLayer::AdjustForColumns) {
2156 if (RenderLayer* parentLayer = layer->parent()) {
2157 if (is<RenderMultiColumnFlow>(parentLayer->renderer())) {
2158 RenderFragmentContainer* fragment = downcast<RenderMultiColumnFlow>(parentLayer->renderer()).physicalTranslationFromFlowToFragment(location);
2160 location.moveBy(fragment->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2168 LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2170 if (ancestorLayer == this)
2173 const RenderLayer* currLayer = this;
2174 LayoutPoint locationInLayerCoords = location;
2175 while (currLayer && currLayer != ancestorLayer)
2176 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
2177 return locationInLayerCoords;
2180 LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer, ColumnOffsetAdjustment adjustForColumns) const
2182 return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint(), adjustForColumns));
2186 bool RenderLayer::hasAcceleratedTouchScrolling() const
2188 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2189 if (!scrollsOverflow())
2191 return renderer().style().useTouchOverflowScrolling() || renderer().settings().alwaysUseAcceleratedOverflowScroll();
2197 bool RenderLayer::hasTouchScrollableOverflow() const
2199 return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2202 #if ENABLE(TOUCH_EVENTS)
2203 bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
2205 // If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
2206 if (usesAcceleratedScrolling())
2209 return ScrollableArea::handleTouchEvent(touchEvent);
2212 #endif // PLATFORM(IOS)
2214 bool RenderLayer::usesAcceleratedScrolling() const
2217 return hasTouchScrollableOverflow();
2219 return needsCompositedScrolling();
2223 #if ENABLE(IOS_TOUCH_EVENTS)
2224 void RenderLayer::registerAsTouchEventListenerForScrolling()
2226 if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
2229 renderer().document().addTouchEventHandler(*renderer().element());
2230 m_registeredAsTouchEventListenerForScrolling = true;
2233 void RenderLayer::unregisterAsTouchEventListenerForScrolling()
2235 if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
2238 renderer().document().removeTouchEventHandler(*renderer().element());
2239 m_registeredAsTouchEventListenerForScrolling = false;
2241 #endif // ENABLE(IOS_TOUCH_EVENTS)
2243 bool RenderLayer::usesCompositedScrolling() const
2245 return isComposited() && backing()->hasScrollingLayer();
2248 bool RenderLayer::usesAsyncScrolling() const
2250 return hasAcceleratedTouchScrolling() && usesCompositedScrolling();
2253 bool RenderLayer::needsCompositedScrolling() const
2255 return m_needsCompositedScrolling;
2258 void RenderLayer::updateNeedsCompositedScrolling()
2260 bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
2262 if (!renderer().view().frameView().containsScrollableArea(this))
2263 m_needsCompositedScrolling = false;
2265 bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
2266 && canBeStackingContainer()
2267 && !hasOutOfFlowPositionedDescendant();
2269 #if !PLATFORM(IOS) && ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2270 m_needsCompositedScrolling = forceUseCompositedScrolling || renderer().style().useTouchOverflowScrolling();
2272 // On iOS we don't want to opt into accelerated composited scrolling, which creates scroll bar
2273 // layers in WebCore, because we use UIKit to composite our scroll bars.
2274 m_needsCompositedScrolling = forceUseCompositedScrolling;
2278 if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
2279 updateSelfPaintingLayer();
2280 if (isStackingContainer())
2285 dirtyStackingContainerZOrderLists();
2287 compositor().setShouldReevaluateCompositingAfterLayout();
2288 compositor().setCompositingLayersNeedRebuild();
2292 static inline int adjustedScrollDelta(int beginningDelta) {
2293 // This implemention matches Firefox's.
2294 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
2295 const int speedReducer = 12;
2297 int adjustedDelta = beginningDelta / speedReducer;
2298 if (adjustedDelta > 1)
2299 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
2300 else if (adjustedDelta < -1)
2301 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
2303 return adjustedDelta;
2306 static inline IntSize adjustedScrollDelta(const IntSize& delta)
2308 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
2311 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
2313 IntPoint lastKnownMousePosition = renderer().frame().eventHandler().lastKnownMousePosition();
2315 // 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
2316 static IntPoint previousMousePosition;
2317 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
2318 lastKnownMousePosition = previousMousePosition;
2320 previousMousePosition = lastKnownMousePosition;
2322 IntSize delta = lastKnownMousePosition - sourcePoint;
2324 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
2326 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
2329 scrollByRecursively(adjustedScrollDelta(delta));
2332 // FIXME: unify with the scrollRectToVisible() code below.
2333 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollableArea** scrolledArea)
2338 bool restrictedByLineClamp = false;
2339 if (renderer().parent())
2340 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2342 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2343 ScrollOffset newScrollOffset = scrollOffset() + delta;
2344 scrollToOffset(newScrollOffset);
2346 *scrolledArea = this;
2348 // If this layer can't do the scroll we ask the next layer up that can scroll to try
2349 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
2350 if (!remainingScrollOffset.isZero() && renderer().parent()) {
2351 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2352 scrollableLayer->scrollByRecursively(remainingScrollOffset, scrolledArea);
2354 renderer().frame().eventHandler().updateAutoscrollRenderer();
2357 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
2358 // have an overflow clip. Which means that it is a document node that can be scrolled.
2359 renderer().view().frameView().scrollBy(delta);
2361 *scrolledArea = &renderer().view().frameView();
2363 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
2364 // https://bugs.webkit.org/show_bug.cgi?id=28237
2368 void RenderLayer::setPostLayoutScrollPosition(std::optional<ScrollPosition> position)
2370 m_postLayoutScrollPosition = position;
2373 void RenderLayer::applyPostLayoutScrollPositionIfNeeded()
2375 if (!m_postLayoutScrollPosition)
2378 scrollToOffset(scrollOffsetFromPosition(m_postLayoutScrollPosition.value()));
2379 m_postLayoutScrollPosition = std::nullopt;
2382 void RenderLayer::scrollToXPosition(int x, ScrollClamping clamping)
2384 ScrollPosition position(x, m_scrollPosition.y());
2385 scrollToOffset(scrollOffsetFromPosition(position), clamping);
2388 void RenderLayer::scrollToYPosition(int y, ScrollClamping clamping)
2390 ScrollPosition position(m_scrollPosition.x(), y);
2391 scrollToOffset(scrollOffsetFromPosition(position), clamping);
2394 ScrollOffset RenderLayer::clampScrollOffset(const ScrollOffset& scrollOffset) const
2396 return scrollOffset.constrainedBetween(IntPoint(), maximumScrollOffset());
2399 void RenderLayer::scrollToOffset(const ScrollOffset& scrollOffset, ScrollClamping clamping)
2401 ScrollOffset newScrollOffset = clamping == ScrollClamping::Clamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2402 if (newScrollOffset != this->scrollOffset())
2403 scrollToOffsetWithoutAnimation(newScrollOffset, clamping);
2406 void RenderLayer::scrollTo(const ScrollPosition& position)
2408 RenderBox* box = renderBox();
2412 LOG_WITH_STREAM(Scrolling, stream << "RenderLayer::scrollTo " << position);
2414 ScrollPosition newPosition = position;
2415 if (!box->isHTMLMarquee()) {
2416 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
2417 if (m_scrollDimensionsDirty)
2418 computeScrollDimensions();
2420 if (adjustForIOSCaretWhenScrolling()) {
2421 // FIXME: It's not clear what this code is trying to do. Behavior seems reasonable with it removed.
2422 int maxOffset = scrollWidth() - roundToInt(box->clientWidth());
2423 ScrollOffset newOffset = scrollOffsetFromPosition(newPosition);
2424 int scrollXOffset = newOffset.x();
2425 if (scrollXOffset > maxOffset - caretWidth) {
2426 scrollXOffset += caretWidth;
2427 if (scrollXOffset <= caretWidth)
2429 } else if (scrollXOffset < m_scrollPosition.x() - caretWidth)
2430 scrollXOffset -= caretWidth;
2432 newOffset.setX(scrollXOffset);
2433 newPosition = scrollPositionFromOffset(newOffset);
2438 if (m_scrollPosition == newPosition) {
2440 if (m_requiresScrollBoundsOriginUpdate)
2441 updateCompositingLayersAfterScroll();
2446 m_scrollPosition = newPosition;
2448 RenderView& view = renderer().view();
2450 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
2451 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
2452 if (!view.frameView().layoutContext().isInRenderTreeLayout()) {
2453 // If we're in the middle of layout, we'll just update layers once layout has finished.
2454 updateLayerPositionsAfterOverflowScroll();
2455 // Update regions, scrolling may change the clip of a particular region.
2456 #if ENABLE(DASHBOARD_SUPPORT)
2457 view.frameView().updateAnnotatedRegions();
2459 view.frameView().updateWidgetPositions();
2461 if (!m_updatingMarqueePosition) {
2462 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
2463 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
2464 // in this case we're still updating their positions; we'll update compositing layers later
2465 // when that completes.
2466 updateCompositingLayersAfterScroll();
2469 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
2470 renderer().document().setTouchEventRegionsNeedUpdate();
2472 DebugPageOverlays::didLayout(renderer().frame());
2475 Frame& frame = renderer().frame();
2476 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
2477 // The caret rect needs to be invalidated after scrolling
2478 frame.selection().setCaretRectNeedsUpdate();
2480 LayoutRect rectForRepaint = renderer().hasRepaintLayoutRects() ? renderer().repaintLayoutRects().m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
2482 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
2483 if (repaintContainer)
2484 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
2485 frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
2487 bool requiresRepaint = true;
2488 if (compositor().inCompositingMode() && usesCompositedScrolling())
2489 requiresRepaint = false;
2491 // Just schedule a full repaint of our object.
2492 if (requiresRepaint)
2493 renderer().repaintUsingContainer(repaintContainer, rectForRepaint);
2495 // Schedule the scroll and scroll-related DOM events.
2496 if (Element* element = renderer().element())
2497 element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
2499 if (scrollsOverflow())
2500 view.frameView().didChangeScrollOffset();
2502 view.frameView().viewportContentsChanged();
2505 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)
2507 // If scrollbars aren't explicitly forbidden, permit scrolling.
2508 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
2511 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2512 if (frameView.wasScrolledByUser())
2515 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2516 // like navigation to an anchor.
2517 return !frameView.frame().eventHandler().autoscrollInProgress();
2520 bool RenderLayer::allowsCurrentScroll() const
2522 if (!renderer().hasOverflowClip())
2525 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2526 // FIXME: Is this still needed? It used to be relevant for Safari RSS.
2527 if (renderer().parent() && !renderer().parent()->style().lineClamp().isNone())
2530 RenderBox* box = renderBox();
2531 ASSERT(box); // Only boxes can have overflowClip set.
2533 if (renderer().frame().eventHandler().autoscrollInProgress()) {
2534 // The "programmatically" here is misleading; this asks whether the box has scrollable overflow,
2535 // or is a special case like a form control.
2536 return box->canBeProgramaticallyScrolled();
2539 // Programmatic scrolls can scroll overflow:hidden.
2540 return box->hasHorizontalOverflow() || box->hasVerticalOverflow();
2543 void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2545 LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << absoluteRect);
2547 RenderLayer* parentLayer = nullptr;
2548 LayoutRect newRect = absoluteRect;
2550 // We may end up propagating a scroll event. It is important that we suspend events until
2551 // the end of the function since they could delete the layer or the layer's renderer().
2552 FrameView& frameView = renderer().view().frameView();
2554 if (renderer().parent())
2555 parentLayer = renderer().parent()->enclosingLayer();
2557 if (allowsCurrentScroll()) {
2558 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2559 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2560 RenderBox* box = renderBox();
2562 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
2563 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
2564 LayoutRect revealRect = getRectToExpose(layerBounds, localExposeRect, insideFixed, alignX, alignY);
2566 ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(revealRect).location()));
2567 if (clampedScrollOffset != scrollOffset()) {
2568 ScrollOffset oldScrollOffset = scrollOffset();
2569 scrollToOffset(clampedScrollOffset);
2570 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
2571 localExposeRect.move(-scrollOffsetDifference);
2572 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
2574 } else if (!parentLayer && renderer().isRenderView()) {
2575 HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
2577 if (ownerElement && ownerElement->renderer()) {
2578 HTMLFrameElementBase* frameElementBase = nullptr;
2580 if (is<HTMLFrameElementBase>(*ownerElement))
2581 frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
2583 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
2584 // If this assertion fires we need to protect the ownerElement from being destroyed.
2585 NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
2587 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
2588 LayoutRect exposeRect = getRectToExpose(viewRect, absoluteRect, insideFixed, alignX, alignY);
2590 IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
2591 // Adjust offsets if they're outside of the allowable range.
2592 scrollOffset = scrollOffset.constrainedBetween(IntPoint(), IntPoint(frameView.contentsSize()));
2593 frameView.setScrollPosition(scrollOffset);
2595 if (frameView.safeToPropagateScrollToParent()) {
2596 parentLayer = ownerElement->renderer()->enclosingLayer();
2597 // Convert the rect into the coordinate space of the parent frame's document.
2598 newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
2599 insideFixed = false; // FIXME: ideally need to determine if this <iframe> is inside position:fixed.
2601 parentLayer = nullptr;
2604 if (revealMode == SelectionRevealMode::RevealUpToMainFrame && frameView.frame().isMainFrame())
2608 LayoutRect viewRect = frameView.visibleContentRect();
2610 LayoutRect viewRect = frameView.unobscuredContentRect();
2612 // Move the target rect into "scrollView contents" coordinates.
2613 LayoutRect targetRect = absoluteRect;
2614 targetRect.move(0, frameView.headerHeight());
2616 LayoutRect revealRect = getRectToExpose(viewRect, targetRect, insideFixed, alignX, alignY);
2618 frameView.setScrollPosition(roundedIntPoint(revealRect.location()));
2620 // This is the outermost view of a web page, so after scrolling this view we
2621 // scroll its container by calling Page::scrollRectIntoView.
2622 // This only has an effect on the Mac platform in applications
2623 // that put web views into scrolling containers, such as Mac OS X Mail.
2624 // The canAutoscroll function in EventHandler also knows about this.
2625 page().chrome().scrollRectIntoView(snappedIntRect(absoluteRect));
2630 parentLayer->scrollRectToVisible(revealMode, newRect, insideFixed, alignX, alignY);
2633 void RenderLayer::updateCompositingLayersAfterScroll()
2635 if (compositor().inCompositingMode()) {
2636 // Our stacking container is guaranteed to contain all of our descendants that may need
2637 // repositioning, so update compositing layers from there.
2638 if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
2639 if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
2640 compositor().updateCompositingLayers(CompositingUpdateType::OnCompositedScroll, compositingAncestor);
2642 compositor().updateCompositingLayers(CompositingUpdateType::OnScroll, compositingAncestor);
2647 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY) const
2649 FrameView& frameView = renderer().view().frameView();
2650 if (renderer().isRenderView() && insideFixed) {
2651 // If the element is inside position:fixed and we're not scaled, no amount of scrolling is going to move things around.
2652 if (frameView.frameScaleFactor() == 1)
2655 if (renderer().settings().visualViewportEnabled()) {
2656 // exposeRect is in absolute coords, affected by page scale. Unscale it.
2657 LayoutRect unscaledExposeRect = exposeRect;
2658 unscaledExposeRect.scale(1 / frameView.frameScaleFactor());
2659 unscaledExposeRect.move(0, -frameView.headerHeight());
2661 // These are both in unscaled coordinates.
2662 LayoutRect layoutViewport = frameView.layoutViewportRect();
2663 LayoutRect visualViewport = frameView.visualViewportRect();
2665 // The rect to expose may be partially offscreen, which we can't do anything about with position:fixed.
2666 unscaledExposeRect.intersect(layoutViewport);
2667 // Make sure it's not larger than the visual viewport; if so, we'll just move to the top left.
2668 unscaledExposeRect.setSize(unscaledExposeRect.size().shrunkTo(visualViewport.size()));
2670 // Compute how much we have to move the visualViewport to reveal the part of the layoutViewport that contains exposeRect.
2671 LayoutRect requiredVisualViewport = getRectToExpose(visualViewport, unscaledExposeRect, false, alignX, alignY);
2672 // Scale it back up.
2673 requiredVisualViewport.scale(frameView.frameScaleFactor());
2674 requiredVisualViewport.move(0, frameView.headerHeight());
2675 return requiredVisualViewport;
2679 // Determine the appropriate X behavior.
2680 ScrollAlignment::Behavior scrollX;
2681 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
2682 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
2683 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
2684 // If the rectangle is fully visible, use the specified visible behavior.
2685 // If the rectangle is partially visible, but over a certain threshold,
2686 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2687 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2688 else if (intersectWidth == visibleRect.width()) {
2689 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2690 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2691 if (scrollX == ScrollAlignment::Behavior::AlignCenter)
2692 scrollX = ScrollAlignment::Behavior::NoScroll;
2693 } else if (intersectWidth > 0)
2694 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2695 scrollX = ScrollAlignment::getPartialBehavior(alignX);
2697 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
2698 // If we're trying to align to the closest edge, and the exposeRect is further right
2699 // than the visibleRect, and not bigger than the visible area, then align with the right.
2700 if (scrollX == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2701 scrollX = ScrollAlignment::Behavior::AlignRight;
2703 // Given the X behavior, compute the X coordinate.
2705 if (scrollX == ScrollAlignment::Behavior::NoScroll)
2706 x = visibleRect.x();
2707 else if (scrollX == ScrollAlignment::Behavior::AlignRight)
2708 x = exposeRect.maxX() - visibleRect.width();
2709 else if (scrollX == ScrollAlignment::Behavior::AlignCenter)
2710 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2714 // Determine the appropriate Y behavior.
2715 ScrollAlignment::Behavior scrollY;
2716 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
2717 LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
2718 if (intersectHeight == exposeRect.height())
2719 // If the rectangle is fully visible, use the specified visible behavior.
2720 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2721 else if (intersectHeight == visibleRect.height()) {
2722 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2723 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2724 if (scrollY == ScrollAlignment::Behavior::AlignCenter)
2725 scrollY = ScrollAlignment::Behavior::NoScroll;
2726 } else if (intersectHeight > 0)
2727 // If the rectangle is partially visible, use the specified partial behavior
2728 scrollY = ScrollAlignment::getPartialBehavior(alignY);
2730 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
2731 // If we're trying to align to the closest edge, and the exposeRect is further down
2732 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2733 if (scrollY == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2734 scrollY = ScrollAlignment::Behavior::AlignBottom;
2736 // Given the Y behavior, compute the Y coordinate.
2738 if (scrollY == ScrollAlignment::Behavior::NoScroll)
2739 y = visibleRect.y();
2740 else if (scrollY == ScrollAlignment::Behavior::AlignBottom)
2741 y = exposeRect.maxY() - visibleRect.height();
2742 else if (scrollY == ScrollAlignment::Behavior::AlignCenter)
2743 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2747 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2750 void RenderLayer::autoscroll(const IntPoint& position)
2752 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
2753 scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2756 bool RenderLayer::canResize() const
2758 // We need a special case for <iframe> because they never have
2759 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
2760 // we want to allow resizing them also.
2761 return (renderer().hasOverflowClip() || renderer().isRenderIFrame()) && renderer().style().resize() != RESIZE_NONE;
2764 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2766 // FIXME: This should be possible on generated content but is not right now.
2767 if (!inResizeMode() || !canResize() || !renderer().element())
2770 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2771 // If they do it would still be better to deal with them explicitly.
2772 Element* element = renderer().element();
2773 auto* renderer = downcast<RenderBox>(element->renderer());
2775 Document& document = element->document();
2776 if (!document.frame()->eventHandler().mousePressed())
2779 float zoomFactor = renderer->style().effectiveZoom();
2781 LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(evt.position()));
2782 newOffset.setWidth(newOffset.width() / zoomFactor);
2783 newOffset.setHeight(newOffset.height() / zoomFactor);
2785 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2786 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2787 element->setMinimumSizeForResizing(minimumSize);
2789 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2790 if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
2791 newOffset.setWidth(-newOffset.width());
2792 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2795 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2797 StyledElement* styledElement = downcast<StyledElement>(element);
2798 bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
2800 EResize resize = renderer->style().resize();
2801 if (resize != RESIZE_VERTICAL && difference.width()) {
2802 if (is<HTMLFormControlElement>(*element)) {
2803 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2804 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2805 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2807 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
2808 baseWidth = baseWidth / zoomFactor;
2809 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
2812 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2813 if (is<HTMLFormControlElement>(*element)) {
2814 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2815 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2816 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2818 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
2819 baseHeight = baseHeight / zoomFactor;
2820 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
2823 document.updateLayout();
2825 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2828 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2830 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2831 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2834 void RenderLayer::setScrollOffset(const ScrollOffset& offset)
2836 scrollTo(scrollPositionFromOffset(offset));
2839 int RenderLayer::scrollOffset(ScrollbarOrientation orientation) const
2841 if (orientation == HorizontalScrollbar)
2842 return scrollOffset().x();
2844 if (orientation == VerticalScrollbar)
2845 return scrollOffset().y();
2850 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
2852 IntSize scrollbarSpace;
2853 if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars)
2854 scrollbarSpace = scrollbarIntrusion();
2856 // FIXME: This seems wrong: m_layerSize includes borders. Can we just use the ScrollableArea implementation?
2857 return IntRect(scrollPosition(), IntSize(std::max(0, m_layerSize.width() - scrollbarSpace.width()), std::max(0, m_layerSize.height() - scrollbarSpace.height())));
2860 IntSize RenderLayer::overhangAmount() const
2862 #if ENABLE(RUBBER_BANDING)
2863 if (!renderer().settings().rubberBandingForSubScrollableRegionsEnabled())
2868 // FIXME: use maximumScrollOffset(), or just move this to ScrollableArea.
2869 ScrollOffset scrollOffset = scrollOffsetFromPosition(scrollPosition());
2870 if (scrollOffset.y() < 0)
2871 stretch.setHeight(scrollOffset.y());
2872 else if (scrollableContentsSize().height() && scrollOffset.y() > scrollableContentsSize().height() - visibleHeight())
2873 stretch.setHeight(scrollOffset.y() - (scrollableContentsSize().height() - visibleHeight()));
2875 if (scrollOffset.x() < 0)
2876 stretch.setWidth(scrollOffset.x());
2877 else if (scrollableContentsSize().width() && scrollOffset.x() > scrollableContentsSize().width() - visibleWidth())
2878 stretch.setWidth(scrollOffset.x() - (scrollableContentsSize().width() - visibleWidth()));
2886 bool RenderLayer::isActive() const
2888 return page().focusController().isActive();
2891 static int cornerStart(const RenderLayer& layer, int minX, int maxX, int thickness)
2893 if (layer.shouldPlaceBlockDirectionScrollbarOnLeft())
2894 return minX + layer.renderer().style().borderLeftWidth();
2895 return maxX - thickness - layer.renderer().style().borderRightWidth();
2898 static LayoutRect cornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2900 int horizontalThickness;
2901 int verticalThickness;
2902 if (!layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2903 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2904 // even when they don't exist in order to set the resizer square size properly.
2905 horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
2906 verticalThickness = horizontalThickness;
2907 } else if (layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2908 horizontalThickness = layer.verticalScrollbar()->width();
2909 verticalThickness = horizontalThickness;
2910 } else if (layer.horizontalScrollbar() && !layer.verticalScrollbar()) {
2911 verticalThickness = layer.horizontalScrollbar()->height();
2912 horizontalThickness = verticalThickness;
2914 horizontalThickness = layer.verticalScrollbar()->width();
2915 verticalThickness = layer.horizontalScrollbar()->height();
2917 return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2918 bounds.maxY() - verticalThickness - layer.renderer().style().borderBottomWidth(),
2919 horizontalThickness, verticalThickness);
2922 IntRect RenderLayer::scrollCornerRect() const
2924 // We have a scrollbar corner when a non overlay scrollbar is visible and not filling the entire length of the box.
2925 // This happens when:
2926 // (a) A resizer is present and at least one non overlay scrollbar is present
2927 // (b) Both non overlay scrollbars are present.
2928 // Overlay scrollbars always fill the entire length of the box so we never have scroll corner in that case.
2929 bool hasHorizontalBar = m_hBar && !m_hBar->isOverlayScrollbar();
2930 bool hasVerticalBar = m_vBar && !m_vBar->isOverlayScrollbar();
2931 bool hasResizer = renderer().style().resize() != RESIZE_NONE;
2932 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2933 return snappedIntRect(cornerRect(*this, renderBox()->borderBoxRect()));
2937 static LayoutRect resizerCornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2939 ASSERT(layer.renderer().isBox());
2940 if (layer.renderer().style().resize() == RESIZE_NONE)
2941 return LayoutRect();
2942 return cornerRect(layer, bounds);
2945 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
2947 RenderBox* box = renderBox();
2949 return LayoutRect();
2950 LayoutRect scrollCornerAndResizer = scrollCornerRect();
2951 if (scrollCornerAndResizer.isEmpty())
2952 scrollCornerAndResizer = resizerCornerRect(*this, box->borderBoxRect());
2953 return scrollCornerAndResizer;
2956 bool RenderLayer::isScrollCornerVisible() const
2958 ASSERT(renderer().isBox());
2959 return !scrollCornerRect().isEmpty();
2962 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
2964 IntRect rect = scrollbarRect;
2965 rect.move(scrollbarOffset(scrollbar));
2967 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), rect);
2970 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
2972 IntRect rect = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentRect);
2973 rect.move(-scrollbarOffset(scrollbar));
2977 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
2979 IntPoint point = scrollbarPoint;
2980 point.move(scrollbarOffset(scrollbar));
2981 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), point);
2984 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
2986 IntPoint point = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentPoint);
2987 point.move(-scrollbarOffset(scrollbar));
2991 IntSize RenderLayer::visibleSize() const
2993 RenderBox* box = renderBox();
2997 return IntSize(roundToInt(box->clientWidth()), roundToInt(box->clientHeight()));
3000 IntSize RenderLayer::contentsSize() const
3002 return IntSize(scrollWidth(), scrollHeight());
3005 IntSize RenderLayer::scrollableContentsSize() const
3007 IntSize contentsSize = this->contentsSize();
3009 if (!hasScrollableHorizontalOverflow())
3010 contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
3012 if (!hasScrollableVerticalOverflow())
3013 contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
3015 return contentsSize;
3018 void RenderLayer::availableContentSizeChanged(AvailableSizeChangeReason reason)
3020 ScrollableArea::availableContentSizeChanged(reason);
3022 if (reason == AvailableSizeChangeReason::ScrollbarsChanged) {
3023 if (is<RenderBlock>(renderer()))
3024 downcast<RenderBlock>(renderer()).setShouldForceRelayoutChildren(true);
3025 renderer().setNeedsLayout();
3029 bool RenderLayer::shouldSuspendScrollAnimations() const
3031 return renderer().view().frameView().shouldSuspendScrollAnimations();
3035 void RenderLayer::didStartScroll()
3037 page().chrome().client().didStartOverflowScroll();
3040 void RenderLayer::didEndScroll()
3042 page().chrome().client().didEndOverflowScroll();
3045 void RenderLayer::didUpdateScroll()
3047 // Send this notification when we scroll, since this is how we keep selection updated.
3048 page().chrome().client().didLayout(ChromeClient::Scroll);
3052 IntPoint RenderLayer::lastKnownMousePosition() const
3054 return renderer().frame().eventHandler().lastKnownMousePosition();
3057 bool RenderLayer::isHandlingWheelEvent() const
3059 return renderer().frame().eventHandler().isHandlingWheelEvent();
3062 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
3067 const RenderBox* box = renderBox();
3068 const IntRect& scrollCorner = scrollCornerRect();
3070 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
3071 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
3072 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
3076 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
3081 const RenderBox* box = renderBox();
3082 const IntRect& scrollCorner = scrollCornerRect();
3084 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
3085 borderBoxRect.y() + box->borderTop(),
3087 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
3090 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
3092 const RenderBox* box = renderBox();
3093 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3094 return minX + box->borderLeft();
3095 return maxX - box->borderRight() - m_vBar->width();
3098 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
3100 const RenderBox* box = renderBox();
3101 int x = minX + box->borderLeft();
3102 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3103 x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(*this, box->borderBoxRect()).width());
3107 IntSize RenderLayer::scrollbarOffset(const Scrollbar& scrollbar) const
3109 RenderBox* box = renderBox();
3111 if (&scrollbar == m_vBar.get())
3112 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
3114 if (&scrollbar == m_hBar.get())
3115 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3117 ASSERT_NOT_REACHED();
3121 void RenderLayer::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
3123 if (!showsOverflowControls())
3126 if (&scrollbar == m_vBar.get()) {
3127 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
3128 layer->setNeedsDisplayInRect(rect);
3132 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
3133 layer->setNeedsDisplayInRect(rect);
3138 IntRect scrollRect = rect;
3139 RenderBox* box = renderBox();
3141 // If we are not yet inserted into the tree, there is no need to repaint.
3145 if (&scrollbar == m_vBar.get())
3146 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
3148 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3149 LayoutRect repaintRect = scrollRect;
3150 renderBox()->flipForWritingMode(repaintRect);
3151 renderer().repaintRectangle(repaintRect);
3154 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
3156 if (!showsOverflowControls())
3159 if (GraphicsLayer* layer = layerForScrollCorner()) {
3160 layer->setNeedsDisplayInRect(rect);
3165 m_scrollCorner->repaintRectangle(rect);
3167 m_resizer->repaintRectangle(rect);
3170 static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& renderer)
3172 if (Element* element = renderer.element()) {
3173 if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
3174 if (shadowRoot->mode() == ShadowRootMode::UserAgent)
3175 return shadowRoot->host()->renderer();
3182 Ref<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
3184 RefPtr<Scrollbar> widget;
3185 ASSERT(rendererForScrollbar(renderer()));
3186 auto& actualRenderer = *rendererForScrollbar(renderer());
3187 bool hasCustomScrollbarStyle = is<RenderBox>(actualRenderer) && downcast<RenderBox>(actualRenderer).style().hasPseudoStyle(SCROLLBAR);
3188 if (hasCustomScrollbarStyle)
3189 widget = RenderScrollbar::createCustomScrollbar(*this, orientation, downcast<RenderBox>(actualRenderer).element());
3191 widget = Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
3192 didAddScrollbar(widget.get(), orientation);
3193 if (page().expectsWheelEventTriggers())
3194 scrollAnimator().setWheelEventTestTrigger(page().testTrigger());
3196 renderer().view().frameView().addChild(*widget);
3197 return widget.releaseNonNull();
3200 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
3202 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
3206 if (!scrollbar->isCustomScrollbar())
3207 willRemoveScrollbar(scrollbar.get(), orientation);
3209 scrollbar->removeFromParent();
3210 scrollbar = nullptr;
3213 bool RenderLayer::scrollsOverflow() const
3215 if (!is<RenderBox>(renderer()))
3218 return downcast<RenderBox>(renderer()).scrollsOverflow();
3221 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
3223 if (hasScrollbar == hasHorizontalScrollbar())
3227 m_hBar = createScrollbar(HorizontalScrollbar);
3228 #if ENABLE(RUBBER_BANDING)
3229 ScrollElasticity elasticity = scrollsOverflow() && renderer().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3230 ScrollableArea::setHorizontalScrollElasticity(elasticity);
3233 destroyScrollbar(HorizontalScrollbar);
3234 #if ENABLE(RUBBER_BANDING)
3235 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityNone);
3239 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3241 m_hBar->styleChanged();
3243 m_vBar->styleChanged();
3245 // Force an update since we know the scrollbars have changed things.
3246 #if ENABLE(DASHBOARD_SUPPORT)
3247 if (renderer().document().hasAnnotatedRegions())
3248 renderer().document().setAnnotatedRegionsDirty(true);
3252 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
3254 if (hasScrollbar == hasVerticalScrollbar())
3258 m_vBar = createScrollbar(VerticalScrollbar);
3259 #if ENABLE(RUBBER_BANDING)
3260 ScrollElasticity elasticity = scrollsOverflow() && renderer().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3261 ScrollableArea::setVerticalScrollElasticity(elasticity);
3264 destroyScrollbar(VerticalScrollbar);
3265 #if ENABLE(RUBBER_BANDING)
3266 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityNone);
3270 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3272 m_hBar->styleChanged();
3274 m_vBar->styleChanged();
3276 // Force an update since we know the scrollbars have changed things.
3277 #if ENABLE(DASHBOARD_SUPPORT)
3278 if (renderer().document().hasAnnotatedRegions())
3279 renderer().document().setAnnotatedRegionsDirty(true);
3283 ScrollableArea* RenderLayer::enclosingScrollableArea() const
3285 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
3286 return scrollableLayer;
3288 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
3289 // if the frame view isn't scrollable.
3293 bool RenderLayer::isScrollableOrRubberbandable()
3295 return renderer().isScrollableOrRubberbandableBox();
3298 bool RenderLayer::hasScrollableOrRubberbandableAncestor()
3300 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
3301 if (nextLayer->isScrollableOrRubberbandable())
3308 #if ENABLE(CSS_SCROLL_SNAP)
3309 void RenderLayer::updateSnapOffsets()
3311 // FIXME: Extend support beyond HTMLElements.
3312 if (!is<HTMLElement>(enclosingElement()) || !enclosingElement()->renderBox())
3315 RenderBox* box = enclosingElement()->renderBox();
3316 updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
3319 bool RenderLayer::isScrollSnapInProgress() const
3321 if (!scrollsOverflow())
3324 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
3325 return scrollAnimator->isScrollSnapInProgress();
3331 bool RenderLayer::usesMockScrollAnimator() const
3333 return DeprecatedGlobalSettings::usesMockScrollAnimator();
3336 void RenderLayer::logMockScrollAnimatorMessage(const String& message) const
3338 renderer().document().addConsoleMessage(MessageSource::Other, MessageLevel::Debug, "RenderLayer: " + message);
3341 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
3344 || !showsOverflowControls()
3345 || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
3348 return m_vBar->width();
3351 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
3354 || !showsOverflowControls()
3355 || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
3358 return m_hBar->height();
3361 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
3363 // Currently the resize corner is either the bottom right corner or the bottom left corner.
3364 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
3365 IntSize elementSize = size();
3366 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3367 elementSize.setWidth(0);
3368 IntPoint resizerPoint = IntPoint(elementSize);
3369 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3370 return localPoint - resizerPoint;
3373 bool RenderLayer::hasOverflowControls() const
3375 return m_hBar || m_vBar || m_scrollCorner || renderer().style().resize() != RESIZE_NONE;
3378 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
3380 if (!m_hBar && !m_vBar && !canResize())
3383 RenderBox* box = renderBox();
3387 const IntRect borderBox = snappedIntRect(box->borderBoxRect());
3388 const IntRect& scrollCorner = scrollCornerRect();
3389 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
3391 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
3392 vBarRect.move(offsetFromRoot);
3393 m_vBar->setFrameRect(vBarRect);
3397 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
3398 hBarRect.move(offsetFromRoot);
3399 m_hBar->setFrameRect(hBarRect);
3403 m_scrollCorner->setFrameRect(scrollCorner);
3405 m_resizer->setFrameRect(resizerCornerRect(*this, borderBox));
3408 backing()->positionOverflowControlsLayers();