2 * Copyright (C) 2006-2016 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"
47 #include "AnimationController.h"
49 #include "CSSPropertyNames.h"
51 #include "DebugPageOverlays.h"
53 #include "DocumentEventQueue.h"
54 #include "DocumentMarkerController.h"
56 #include "EventHandler.h"
57 #include "FEColorMatrix.h"
59 #include "FilterEffectRenderer.h"
60 #include "FloatConversion.h"
61 #include "FloatPoint3D.h"
62 #include "FloatRect.h"
63 #include "FloatRoundedRect.h"
64 #include "FlowThreadController.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 "HitTestingTransformState.h"
80 #include "HitTestRequest.h"
81 #include "HitTestResult.h"
83 #include "MainFrame.h"
84 #include "NoEventDispatchAssertion.h"
85 #include "OverflowEvent.h"
86 #include "OverlapTestRequestClient.h"
88 #include "PlatformMouseEvent.h"
89 #include "RenderFlowThread.h"
90 #include "RenderGeometryMap.h"
91 #include "RenderInline.h"
92 #include "RenderIterator.h"
93 #include "RenderLayerBacking.h"
94 #include "RenderLayerCompositor.h"
95 #include "RenderLayerFilterInfo.h"
96 #include "RenderMarquee.h"
97 #include "RenderMultiColumnFlowThread.h"
98 #include "RenderNamedFlowFragment.h"
99 #include "RenderNamedFlowThread.h"
100 #include "RenderRegion.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 "TextStream.h"
123 #include "TransformationMatrix.h"
124 #include "TranslateTransformOperation.h"
125 #include "WheelEventTestTrigger.h"
127 #include <wtf/StdLibExtras.h>
128 #include <wtf/text/CString.h>
130 #if ENABLE(CSS_SCROLL_SNAP)
131 #include "AxisScrollSnapOffsets.h"
134 #define MIN_INTERSECT_FOR_REVEAL 32
138 using namespace HTMLNames;
141 WTF_MAKE_FAST_ALLOCATED;
143 static Ref<ClipRects> create()
145 return adoptRef(*new ClipRects);
148 static Ref<ClipRects> create(const ClipRects& other)
150 return adoptRef(*new ClipRects(other));
153 ClipRects() = default;
157 m_overflowClipRect.reset();
158 m_fixedClipRect.reset();
159 m_posClipRect.reset();
163 const ClipRect& overflowClipRect() const { return m_overflowClipRect; }
164 void setOverflowClipRect(const ClipRect& clipRect) { m_overflowClipRect = clipRect; }
166 const ClipRect& fixedClipRect() const { return m_fixedClipRect; }
167 void setFixedClipRect(const ClipRect& clipRect) { m_fixedClipRect = clipRect; }
169 const ClipRect& posClipRect() const { return m_posClipRect; }
170 void setPosClipRect(const ClipRect& clipRect) { m_posClipRect = clipRect; }
172 bool fixed() const { return m_fixed; }
173 void setFixed(bool fixed) { m_fixed = fixed; }
175 void ref() { m_refCount++; }
182 bool operator==(const ClipRects& other) const
184 return m_overflowClipRect == other.overflowClipRect()
185 && m_fixedClipRect == other.fixedClipRect()
186 && m_posClipRect == other.posClipRect()
187 && m_fixed == other.fixed();
190 ClipRects& operator=(const ClipRects& other)
192 m_overflowClipRect = other.overflowClipRect();
193 m_fixedClipRect = other.fixedClipRect();
194 m_posClipRect = other.posClipRect();
195 m_fixed = other.fixed();
200 ClipRects(const LayoutRect& clipRect)
201 : m_overflowClipRect(clipRect)
202 , m_fixedClipRect(clipRect)
203 , m_posClipRect(clipRect)
207 ClipRects(const ClipRects& other)
208 : m_overflowClipRect(other.overflowClipRect())
209 , m_fixedClipRect(other.fixedClipRect())
210 , m_posClipRect(other.posClipRect())
211 , m_fixed(other.fixed())
215 ClipRect m_overflowClipRect;
216 ClipRect m_fixedClipRect;
217 ClipRect m_posClipRect;
218 unsigned m_refCount = 1;
219 bool m_fixed = false;
222 class ClipRectsCache {
223 WTF_MAKE_FAST_ALLOCATED;
228 for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
229 m_clipRectsRoot[i] = 0;
230 m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
235 PassRefPtr<ClipRects> getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) { return m_clipRects[getIndex(clipRectsType, respectOverflow)]; }
236 void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, PassRefPtr<ClipRects> clipRects) { m_clipRects[getIndex(clipRectsType, respectOverflow)] = clipRects; }
239 const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
240 OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
244 int getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow)
246 int index = static_cast<int>(clipRectsType);
247 if (respectOverflow == RespectOverflowClip)
248 index += static_cast<int>(NumCachedClipRectsTypes);
252 RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
255 void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
257 #if !ENABLE(3D_TRANSFORMS)
258 UNUSED_PARAM(has3DRendering);
266 RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
267 : m_isRootLayer(rendererLayerModelObject.isRenderView())
268 , m_forcedStackingContext(rendererLayerModelObject.isMedia())
269 , m_inResizeMode(false)
270 , m_scrollDimensionsDirty(true)
271 , m_normalFlowListDirty(true)
272 , m_hasSelfPaintingLayerDescendant(false)
273 , m_hasSelfPaintingLayerDescendantDirty(false)
274 , m_hasOutOfFlowPositionedDescendant(false)
275 , m_hasOutOfFlowPositionedDescendantDirty(true)
276 , m_needsCompositedScrolling(false)
277 , m_descendantsAreContiguousInStackingOrder(false)
278 , m_usedTransparency(false)
279 , m_paintingInsideReflection(false)
280 , m_inOverflowRelayout(false)
281 , m_repaintStatus(NeedsNormalRepaint)
282 , m_visibleContentStatusDirty(true)
283 , m_hasVisibleContent(false)
284 , m_visibleDescendantStatusDirty(false)
285 , m_hasVisibleDescendant(false)
286 , m_registeredScrollableArea(false)
287 , m_3DTransformedDescendantStatusDirty(true)
288 , m_has3DTransformedDescendant(false)
289 , m_hasCompositingDescendant(false)
290 , m_hasTransformedAncestor(false)
291 , m_has3DTransformedAncestor(false)
292 , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
293 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
295 , m_adjustForIOSCaretWhenScrolling(false)
298 #if ENABLE(IOS_TOUCH_EVENTS)
299 , m_registeredAsTouchEventListenerForScrolling(false)
301 , m_inUserScroll(false)
302 , m_requiresScrollBoundsOriginUpdate(false)
304 , m_containsDirtyOverlayScrollbars(false)
305 , m_updatingMarqueePosition(false)
307 , m_layerListMutationAllowed(true)
309 , m_hasFilterInfo(false)
310 , m_hasComputedRepaintRect(false)
311 #if ENABLE(CSS_COMPOSITING)
312 , m_blendMode(BlendModeNormal)
313 , m_hasNotIsolatedCompositedBlendingDescendants(false)
314 , m_hasNotIsolatedBlendingDescendants(false)
315 , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
317 , m_renderer(rendererLayerModelObject)
319 , m_previous(nullptr)
323 , m_staticInlinePosition(0)
324 , m_staticBlockPosition(0)
325 , m_enclosingPaginationLayer(nullptr)
327 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
328 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
330 // Non-stacking containers should have empty z-order lists. As this is already the case,
331 // there is no need to dirty / recompute these lists.
332 m_zOrderListsDirty = isStackingContainer();
334 if (!renderer().firstChild()) {
335 m_visibleContentStatusDirty = false;
336 m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
339 if (Element* element = renderer().element()) {
340 // We save and restore only the scrollOffset as the other scroll values are recalculated.
341 m_scrollPosition = element->savedLayerScrollPosition();
342 if (!m_scrollPosition.isZero())
343 scrollAnimator().setCurrentPosition(m_scrollPosition);
344 element->setSavedLayerScrollPosition(IntPoint());
348 RenderLayer::~RenderLayer()
350 if (inResizeMode() && !renderer().documentBeingDestroyed())
351 renderer().frame().eventHandler().resizeLayerDestroyed();
353 ASSERT(m_registeredScrollableArea == renderer().view().frameView().containsScrollableArea(this));
355 if (m_registeredScrollableArea)
356 renderer().view().frameView().removeScrollableArea(this);
358 if (!renderer().documentBeingDestroyed()) {
359 #if ENABLE(IOS_TOUCH_EVENTS)
360 unregisterAsTouchEventListenerForScrolling();
362 if (Element* element = renderer().element())
363 element->setSavedLayerScrollPosition(m_scrollPosition);
366 destroyScrollbar(HorizontalScrollbar);
367 destroyScrollbar(VerticalScrollbar);
369 if (renderer().frame().page()) {
370 if (ScrollingCoordinator* scrollingCoordinator = renderer().frame().page()->scrollingCoordinator())
371 scrollingCoordinator->willDestroyScrollableArea(*this);
377 FilterInfo::remove(*this);
379 // Child layers will be deleted by their corresponding render objects, so
380 // we don't need to delete them ourselves.
385 String RenderLayer::name() const
388 name.append(renderer().renderName());
390 if (Element* element = renderer().element()) {
392 name.append(element->tagName());
394 if (element->hasID()) {
395 name.appendLiteral(" id=\'");
396 name.append(element->getIdAttribute());
400 if (element->hasClass()) {
401 name.appendLiteral(" class=\'");
402 for (size_t i = 0; i < element->classNames().size(); ++i) {
405 name.append(element->classNames()[i]);
412 name.appendLiteral(" (reflection)");
414 return name.toString();
417 RenderLayerCompositor& RenderLayer::compositor() const
419 return renderer().view().compositor();
422 void RenderLayer::contentChanged(ContentChangeType changeType)
424 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ImageChanged) && compositor().updateLayerCompositingState(*this))
425 compositor().setCompositingLayersNeedRebuild();
428 m_backing->contentChanged(changeType);
431 bool RenderLayer::canRender3DTransforms() const
433 return compositor().canRender3DTransforms();
436 bool RenderLayer::paintsWithFilters() const
438 if (!renderer().hasFilter())
444 if (!m_backing || !m_backing->canCompositeFilters())
450 bool RenderLayer::requiresFullLayerImageForFilters() const
452 if (!paintsWithFilters())
454 FilterEffectRenderer* renderer = filterRenderer();
455 return renderer && renderer->hasFilterThatMovesPixels();
458 FilterEffectRenderer* RenderLayer::filterRenderer() const
460 FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
461 return filterInfo ? filterInfo->renderer() : nullptr;
464 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
466 RenderGeometryMap geometryMap(UseTransforms);
467 if (this != rootLayer)
468 geometryMap.pushMappingsToAncestor(parent(), nullptr);
469 updateLayerPositions(&geometryMap, flags);
472 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
474 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
475 // we need to keep in sync, since we may have shifted relative
476 // to our parent layer.
478 geometryMap->pushMappingsToAncestor(this, parent());
480 // Clear our cached clip rect information.
483 if (hasOverflowControls()) {
484 LayoutSize offsetFromRoot;
486 offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
488 // FIXME: It looks suspicious to call convertToLayerCoords here
489 // as canUseConvertToLayerCoords may be true for an ancestor layer.
490 offsetFromRoot = offsetFromAncestor(root());
492 positionOverflowControls(roundedIntSize(offsetFromRoot));
495 updateDescendantDependentFlags();
497 if (flags & UpdatePagination)
500 m_enclosingPaginationLayer = nullptr;
502 if (m_hasVisibleContent) {
503 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
504 // mapping between them and the RenderObjects. It would be neat to enable
505 // LayoutState outside the layout() phase and use it here.
506 ASSERT(!renderer().view().layoutStateEnabled());
508 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
509 LayoutRect oldRepaintRect = m_repaintRect;
510 LayoutRect oldOutlineBox = m_outlineBox;
511 computeRepaintRects(repaintContainer, geometryMap);
513 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
514 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
515 if ((flags & CheckForRepaint) && m_hasComputedRepaintRect) {
516 if (!renderer().view().printing()) {
517 bool didRepaint = false;
518 if (m_repaintStatus & NeedsFullRepaint) {
519 renderer().repaintUsingContainer(repaintContainer, oldRepaintRect);
520 if (m_repaintRect != oldRepaintRect) {
521 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
524 } else if (shouldRepaintAfterLayout()) {
525 renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
529 if (didRepaint && renderer().isRenderNamedFlowFragmentContainer()) {
530 // If we just repainted a region, we must also repaint the flow thread since it is the one
531 // doing the actual painting of the flowed content.
532 RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
533 if (region.isValid())
534 region.flowThread()->layer()->repaintIncludingDescendants();
541 m_repaintStatus = NeedsNormalRepaint;
542 m_hasTransformedAncestor = flags & SeenTransformedLayer;
543 m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
545 // Update the reflection's position and size.
547 m_reflection->layout();
549 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
550 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
552 flags &= ~IsCompositingUpdateRoot;
554 if (renderer().isInFlowRenderFlowThread()) {
556 flags |= UpdatePagination;
560 flags |= SeenTransformedLayer;
561 if (!transform()->isAffine())
562 flags |= Seen3DTransformedLayer;
565 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
566 child->updateLayerPositions(geometryMap, flags);
568 if ((flags & UpdateCompositingLayers) && isComposited()) {
569 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
570 if (flags & NeedsFullRepaintInBacking)
571 updateFlags |= RenderLayerBacking::NeedsFullRepaint;
573 updateFlags |= RenderLayerBacking::IsUpdateRoot;
574 backing()->updateAfterLayout(updateFlags);
577 // With all our children positioned, now update our marquee if we need to.
579 // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
580 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
581 m_updatingMarqueePosition = true;
582 m_marquee->updateMarqueePosition();
583 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
587 geometryMap->popMappingsToAncestor(parent());
589 renderer().document().markers().invalidateRectsForAllMarkers();
592 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
594 LayoutRect repaintRect = m_repaintRect;
595 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
596 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
597 if (child->isComposited())
600 repaintRect.uniteIfNonZero(child->repaintRectIncludingNonCompositingDescendants());
605 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
607 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
608 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
611 layer->m_hasSelfPaintingLayerDescendantDirty = false;
612 layer->m_hasSelfPaintingLayerDescendant = true;
616 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
618 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
619 layer->m_hasSelfPaintingLayerDescendantDirty = true;
620 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
621 // in this case, there is no need to dirty our ancestors further.
622 if (layer->isSelfPaintingLayer()) {
623 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
629 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
631 return renderer().frame().settings().acceleratedCompositingForOverflowScrollEnabled();
634 // If we are a stacking container, then this function will determine if our
635 // descendants for a contiguous block in stacking order. This is required in
636 // order for an element to be safely promoted to a stacking container. It is safe
637 // to become a stacking container if this change would not alter the stacking
638 // order of layers on the page. That can only happen if a non-descendant appear
639 // between us and our descendants in stacking order. Here's an example:
649 // I've labeled our normal flow descendants A, B, C, and D, our stacking
650 // container descendants with their z indices, and us with 'this' (we're a
651 // stacking container and our zIndex doesn't matter here). These nodes appear in
652 // three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
653 // flow layers don't overlap). So if we arrange these lists in order we get our
656 // [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
658 // Neg z-order. <-+ +--> Normal flow descendants.
660 // We can then assign new, 'stacking' order indices to these elements as follows:
662 // [-8], [A-D], [0, 2, 5, 7]
663 // 'Stacking' indices: -1 0 1 2 3 4
665 // Note that the normal flow descendants can share an index because they don't
666 // stack/overlap. Now our problem becomes very simple: a layer can safely become
667 // a stacking container if the stacking-order indices of it and its descendants
668 // appear in a contiguous block in the list of stacking indices. This problem
669 // can be solved very efficiently by calculating the min/max stacking indices in
670 // the subtree, and the number stacking container descendants. Once we have this
671 // information, we know that the subtree's indices form a contiguous block if:
673 // maxStackIndex - minStackIndex == numSCDescendants
675 // So for node A in the example above we would have:
677 // minStackIndex = -1
678 // numSCDecendants = 2
681 // maxStackIndex - minStackIndex == numSCDescendants
682 // ===> 1 - (-1) == 2
685 // Since this is true, A can safely become a stacking container.
686 // Now, for node C we have:
689 // minStackIndex = 0 <-- because C has stacking index 0.
690 // numSCDecendants = 2
693 // maxStackIndex - minStackIndex == numSCDescendants
697 // Since this is false, C cannot be safely promoted to a stacking container. This
698 // happened because of the elements with z-index 5 and 0. Now if 5 had been a
699 // child of C rather than D, and A had no child with Z index 0, we would have had:
702 // minStackIndex = 0 <-- because C has stacking index 0.
703 // numSCDecendants = 3
706 // maxStackIndex - minStackIndex == numSCDescendants
710 // And we would conclude that C could be promoted.
711 void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
713 if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
716 ASSERT(!m_normalFlowListDirty);
717 ASSERT(!m_zOrderListsDirty);
719 std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
720 std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
721 rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
723 // Create a reverse lookup.
724 HashMap<const RenderLayer*, int> lookup;
727 int stackingOrderIndex = -1;
728 size_t listSize = negZOrderList->size();
729 for (size_t i = 0; i < listSize; ++i) {
730 RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
731 if (!currentLayer->isStackingContext())
733 lookup.set(currentLayer, stackingOrderIndex--);
738 size_t listSize = posZOrderList->size();
739 int stackingOrderIndex = 1;
740 for (size_t i = 0; i < listSize; ++i) {
741 RenderLayer* currentLayer = posZOrderList->at(i);
742 if (!currentLayer->isStackingContext())
744 lookup.set(currentLayer, stackingOrderIndex++);
751 bool firstIteration = true;
752 updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
755 void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
757 if (isStackingContext() && !firstIteration) {
758 if (lookup.contains(this)) {
759 minIndex = std::min(minIndex, lookup.get(this));
760 maxIndex = std::max(maxIndex, lookup.get(this));
766 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
767 int childMinIndex = 0;
768 int childMaxIndex = 0;
770 child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
773 minIndex = std::min(minIndex, childMinIndex);
774 maxIndex = std::max(maxIndex, childMaxIndex);
778 if (!isStackingContext()) {
779 bool newValue = maxIndex - minIndex == count;
780 bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
781 m_descendantsAreContiguousInStackingOrder = newValue;
783 updateNeedsCompositedScrolling();
787 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
789 ASSERT(!m_visibleContentStatusDirty);
791 if (!isSelfPaintingLayer()) {
796 m_hasComputedRepaintRect = true;
797 m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer);
798 m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap);
802 void RenderLayer::computeRepaintRectsIncludingDescendants()
804 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
805 // We should make this more efficient.
806 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
807 computeRepaintRects(renderer().containerForRepaint());
809 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
810 layer->computeRepaintRectsIncludingDescendants();
813 void RenderLayer::clearRepaintRects()
815 ASSERT(!m_visibleContentStatusDirty);
817 m_hasComputedRepaintRect = false;
818 m_repaintRect = LayoutRect();
819 m_outlineBox = LayoutRect();
822 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
824 ASSERT(this == renderer().view().layer());
826 RenderGeometryMap geometryMap(UseTransforms);
827 updateLayerPositionsAfterScroll(&geometryMap);
830 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
832 RenderGeometryMap geometryMap(UseTransforms);
833 if (this != renderer().view().layer())
834 geometryMap.pushMappingsToAncestor(parent(), nullptr);
836 // FIXME: why is it OK to not check the ancestors of this layer in order to
837 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
838 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
841 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
843 // FIXME: This shouldn't be needed, but there are some corner cases where
844 // these flags are still dirty. Update so that the check below is valid.
845 updateDescendantDependentFlags();
847 // If we have no visible content and no visible descendants, there is no point recomputing
848 // our rectangles as they will be empty. If our visibility changes, we are expected to
849 // recompute all our positions anyway.
850 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
853 bool positionChanged = updateLayerPosition();
855 flags |= HasChangedAncestor;
857 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
860 if (renderer().style().hasViewportConstrainedPosition())
861 flags |= HasSeenViewportConstrainedAncestor;
863 if (renderer().hasOverflowClip())
864 flags |= HasSeenAncestorWithOverflowClip;
866 bool shouldComputeRepaintRects = (flags & HasSeenViewportConstrainedAncestor || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) && isSelfPaintingLayer();
867 bool isVisuallyEmpty = !isVisuallyNonEmpty();
868 bool shouldPushAndPopMappings = geometryMap && ((shouldComputeRepaintRects && !isVisuallyEmpty) || firstChild());
869 if (shouldPushAndPopMappings)
870 geometryMap->pushMappingsToAncestor(this, parent());
872 if (shouldComputeRepaintRects) {
873 // When scrolling, we don't compute repaint rects for visually non-empty layers.
876 else // FIXME: We could track the repaint container as we walk down the tree.
877 computeRepaintRects(renderer().containerForRepaint(), geometryMap);
879 // Check that our cached rects are correct.
880 ASSERT(!m_hasComputedRepaintRect || (m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint())));
881 ASSERT(!m_hasComputedRepaintRect || m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
884 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
885 child->updateLayerPositionsAfterScroll(geometryMap, flags);
887 // We don't update our reflection as scrolling is a translation which does not change the size()
888 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
892 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
893 m_updatingMarqueePosition = true;
894 m_marquee->updateMarqueePosition();
895 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
898 if (shouldPushAndPopMappings)
899 geometryMap->popMappingsToAncestor(parent());
901 renderer().document().markers().invalidateRectsForAllMarkers();
904 void RenderLayer::positionNewlyCreatedOverflowControls()
906 if (!backing()->hasUnpositionedOverflowControlsLayers())
909 RenderGeometryMap geometryMap(UseTransforms);
910 if (this != renderer().view().layer() && parent())
911 geometryMap.pushMappingsToAncestor(parent(), nullptr);
913 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
914 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
917 #if ENABLE(CSS_COMPOSITING)
919 void RenderLayer::updateBlendMode()
921 bool hadBlendMode = m_blendMode != BlendModeNormal;
922 if (parent() && hadBlendMode != hasBlendMode()) {
924 parent()->updateAncestorChainHasBlendingDescendants();
926 parent()->dirtyAncestorChainHasBlendingDescendants();
929 BlendMode newBlendMode = renderer().style().blendMode();
930 if (newBlendMode != m_blendMode)
931 m_blendMode = newBlendMode;
934 void RenderLayer::updateAncestorChainHasBlendingDescendants()
936 for (auto* layer = this; layer; layer = layer->parent()) {
937 if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
939 layer->m_hasNotIsolatedBlendingDescendants = true;
940 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
942 layer->updateSelfPaintingLayer();
944 if (layer->isStackingContext())
949 void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
951 for (auto* layer = this; layer; layer = layer->parent()) {
952 if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
955 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
957 if (layer->isStackingContext())
963 void RenderLayer::updateTransform()
965 bool hasTransform = renderer().hasTransform();
966 bool had3DTransform = has3DTransform();
968 bool hadTransform = !!m_transform;
969 if (hasTransform != hadTransform) {
971 m_transform = std::make_unique<TransformationMatrix>();
973 m_transform = nullptr;
975 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
976 clearClipRectsIncludingDescendants();
980 RenderBox* box = renderBox();
982 m_transform->makeIdentity();
983 box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
984 makeMatrixRenderable(*m_transform, canRender3DTransforms());
987 if (had3DTransform != has3DTransform())
988 dirty3DTransformedDescendantStatus();
991 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
994 return TransformationMatrix();
996 RenderBox* box = renderBox();
998 if (renderer().style().isRunningAcceleratedAnimation()) {
999 TransformationMatrix currTransform;
1000 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1001 std::unique_ptr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(renderer());
1002 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
1003 makeMatrixRenderable(currTransform, canRender3DTransforms());
1004 return currTransform;
1007 // m_transform includes transform-origin, so we need to recompute the transform here.
1008 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
1009 TransformationMatrix currTransform;
1010 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1011 box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
1012 makeMatrixRenderable(currTransform, canRender3DTransforms());
1013 return currTransform;
1016 return *m_transform;
1019 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
1022 return TransformationMatrix();
1024 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
1025 TransformationMatrix matrix = *m_transform;
1026 makeMatrixRenderable(matrix, false /* flatten 3d */);
1030 return *m_transform;
1033 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
1035 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
1037 if (layer->renderer().hasOverflowClip())
1038 return const_cast<RenderLayer*>(layer);
1040 layer = layer->parent();
1045 // FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
1046 // painting of content inside paginated layers.
1047 bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
1049 // No enclosing layer means no compositing in the chain.
1050 if (!m_enclosingPaginationLayer)
1053 // If the enclosing layer is composited, we don't have to check anything in between us and that
1055 if (m_enclosingPaginationLayer->isComposited())
1058 // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
1060 if (m_enclosingPaginationLayer == this)
1063 // The enclosing paginated layer is our ancestor and is not composited, so we have to check
1064 // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
1068 // For normal flow layers, we can recur up the layer tree.
1069 if (isNormalFlowOnly())
1070 return parent()->hasCompositedLayerInEnclosingPaginationChain();
1072 // Otherwise we have to go up the containing block chain. Find the first enclosing
1073 // containing block layer ancestor, and check that.
1074 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1075 if (containingBlock->hasLayer())
1076 return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
1081 void RenderLayer::updatePagination()
1083 m_enclosingPaginationLayer = nullptr;
1088 // Each layer that is inside a multicolumn flow thread has to be checked individually and
1089 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
1090 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
1091 // to that layer easily.
1092 if (renderer().isInFlowRenderFlowThread()) {
1093 m_enclosingPaginationLayer = this;
1097 if (isNormalFlowOnly()) {
1098 // Content inside a transform is not considered to be paginated, since we simply
1099 // paint the transform multiple times in each column, so we don't have to use
1100 // fragments for the transformed content.
1101 if (parent()->hasTransform())
1102 m_enclosingPaginationLayer = nullptr;
1104 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1108 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
1109 // we find one, then we just check its pagination status.
1110 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1111 if (containingBlock->hasLayer()) {
1112 // Content inside a transform is not considered to be paginated, since we simply
1113 // paint the transform multiple times in each column, so we don't have to use
1114 // fragments for the transformed content.
1115 if (containingBlock->layer()->hasTransform())
1116 m_enclosingPaginationLayer = nullptr;
1118 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1124 bool RenderLayer::canBeStackingContainer() const
1126 if (isStackingContext() || !stackingContainer())
1129 return m_descendantsAreContiguousInStackingOrder;
1132 void RenderLayer::setHasVisibleContent()
1134 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1135 ASSERT(!parent() || parent()->hasVisibleDescendant());
1139 m_visibleContentStatusDirty = false;
1140 m_hasVisibleContent = true;
1141 computeRepaintRects(renderer().containerForRepaint());
1142 if (!isNormalFlowOnly()) {
1143 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1144 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1145 // collected. FIXME: When compositing, we could skip this dirtying phase.
1146 for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
1147 sc->dirtyZOrderLists();
1148 if (sc->hasVisibleContent())
1154 parent()->setAncestorChainHasVisibleDescendant();
1157 void RenderLayer::dirtyVisibleContentStatus()
1159 m_visibleContentStatusDirty = true;
1161 parent()->dirtyAncestorChainVisibleDescendantStatus();
1164 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1166 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1167 if (layer->m_visibleDescendantStatusDirty)
1170 layer->m_visibleDescendantStatusDirty = true;
1174 void RenderLayer::setAncestorChainHasVisibleDescendant()
1176 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1177 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1180 layer->m_hasVisibleDescendant = true;
1181 layer->m_visibleDescendantStatusDirty = false;
1185 void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
1187 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
1188 bool hasVisibleDescendant = false;
1189 bool hasSelfPaintingLayerDescendant = false;
1190 bool hasOutOfFlowPositionedDescendant = false;
1191 #if ENABLE(CSS_COMPOSITING)
1192 bool hasNotIsolatedBlendingDescendants = false;
1195 HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
1196 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1197 childOutOfFlowDescendantContainingBlocks.clear();
1198 child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
1200 bool childIsOutOfFlowPositioned = child->renderer().isOutOfFlowPositioned();
1201 if (childIsOutOfFlowPositioned)
1202 childOutOfFlowDescendantContainingBlocks.add(child->renderer().containingBlock());
1204 if (outOfFlowDescendantContainingBlocks) {
1205 HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
1206 for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
1207 outOfFlowDescendantContainingBlocks->add(*it);
1210 hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1211 hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1212 hasOutOfFlowPositionedDescendant |= !childOutOfFlowDescendantContainingBlocks.isEmpty();
1213 #if ENABLE(CSS_COMPOSITING)
1214 hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
1217 bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant;
1218 #if ENABLE(CSS_COMPOSITING)
1219 allFlagsSet &= hasNotIsolatedBlendingDescendants;
1225 if (outOfFlowDescendantContainingBlocks)
1226 outOfFlowDescendantContainingBlocks->remove(&renderer());
1228 m_hasVisibleDescendant = hasVisibleDescendant;
1229 m_visibleDescendantStatusDirty = false;
1230 m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
1231 m_hasSelfPaintingLayerDescendantDirty = false;
1233 m_hasOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant;
1234 if (m_hasOutOfFlowPositionedDescendantDirty)
1235 updateNeedsCompositedScrolling();
1237 m_hasOutOfFlowPositionedDescendantDirty = false;
1238 #if ENABLE(CSS_COMPOSITING)
1239 m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
1240 if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
1241 m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1242 updateSelfPaintingLayer();
1247 if (m_visibleContentStatusDirty) {
1248 if (renderer().style().visibility() == VISIBLE)
1249 m_hasVisibleContent = true;
1251 // layer may be hidden but still have some visible content, check for this
1252 m_hasVisibleContent = false;
1253 RenderObject* r = renderer().firstChild();
1255 if (r->style().visibility() == VISIBLE && !r->hasLayer()) {
1256 m_hasVisibleContent = true;
1259 RenderObject* child = nullptr;
1260 if (!r->hasLayer() && (child = r->firstChildSlow()))
1262 else if (r->nextSibling())
1263 r = r->nextSibling();
1267 if (r == &renderer())
1269 } while (r && !r->nextSibling());
1271 r = r->nextSibling();
1275 m_visibleContentStatusDirty = false;
1279 void RenderLayer::dirty3DTransformedDescendantStatus()
1281 RenderLayer* curr = stackingContainer();
1283 curr->m_3DTransformedDescendantStatusDirty = true;
1285 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1286 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1287 while (curr && curr->preserves3D()) {
1288 curr->m_3DTransformedDescendantStatusDirty = true;
1289 curr = curr->stackingContainer();
1293 // Return true if this layer or any preserve-3d descendants have 3d.
1294 bool RenderLayer::update3DTransformedDescendantStatus()
1296 if (m_3DTransformedDescendantStatusDirty) {
1297 m_has3DTransformedDescendant = false;
1299 updateZOrderLists();
1301 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1302 // in the normal flow list, so we only need to check those.
1303 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
1304 for (auto* layer : *positiveZOrderList)
1305 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1308 // Now check our negative z-index children.
1309 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
1310 for (auto* layer : *negativeZOrderList)
1311 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1314 m_3DTransformedDescendantStatusDirty = false;
1317 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1318 // the m_has3DTransformedDescendant set.
1320 return has3DTransform() || m_has3DTransformedDescendant;
1322 return has3DTransform();
1325 bool RenderLayer::updateLayerPosition()
1327 LayoutPoint localPoint;
1328 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1329 if (renderer().isInline() && is<RenderInline>(renderer())) {
1330 auto& inlineFlow = downcast<RenderInline>(renderer());
1331 IntRect lineBox = inlineFlow.linesBoundingBox();
1332 setSize(lineBox.size());
1333 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1334 localPoint += inlineBoundingBoxOffset;
1335 } else if (RenderBox* box = renderBox()) {
1336 // FIXME: Is snapping the size really needed here for the RenderBox case?
1337 setSize(snappedIntRect(box->frameRect()).size());
1338 box->applyTopLeftLocationOffset(localPoint);
1341 RenderElement* ancestor;
1342 if (!renderer().isOutOfFlowPositioned() && (ancestor = renderer().parent())) {
1343 // We must adjust our position by walking up the render tree looking for the
1344 // nearest enclosing object with a layer.
1345 while (ancestor && !ancestor->hasLayer()) {
1346 if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
1347 // Rows and cells share the same coordinate space (that of the section).
1348 // Omit them when computing our xpos/ypos.
1349 localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1351 ancestor = ancestor->parent();
1353 if (is<RenderBox>(*ancestor) && is<RenderTableRow>(*ancestor)) {
1354 // Put ourselves into the row coordinate space.
1355 localPoint -= downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1359 // Subtract our parent's scroll offset.
1360 RenderLayer* positionedParent;
1361 if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
1362 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1363 if (positionedParent->renderer().hasOverflowClip())
1364 localPoint -= toLayoutSize(positionedParent->scrollPosition());
1366 if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
1367 LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
1368 localPoint += offset;
1370 } else if (parent()) {
1371 if (parent()->renderer().hasOverflowClip())
1372 localPoint -= toLayoutSize(parent()->scrollPosition());
1375 bool positionOrOffsetChanged = false;
1376 if (renderer().isInFlowPositioned()) {
1377 LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
1378 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
1379 m_offsetForInFlowPosition = newOffset;
1380 localPoint.move(m_offsetForInFlowPosition);
1382 m_offsetForInFlowPosition = LayoutSize();
1385 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1386 localPoint -= inlineBoundingBoxOffset;
1388 positionOrOffsetChanged |= location() != localPoint;
1389 setLocation(localPoint);
1390 return positionOrOffsetChanged;
1393 TransformationMatrix RenderLayer::perspectiveTransform() const
1395 RenderBox* box = renderBox();
1397 return TransformationMatrix();
1399 if (!box->hasTransformRelatedProperty())
1400 return TransformationMatrix();
1402 const RenderStyle& style = box->style();
1403 if (!style.hasPerspective())
1404 return TransformationMatrix();
1406 // Maybe fetch the perspective from the backing?
1407 const FloatRect borderBox = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1408 float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), borderBox.width());
1409 float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), borderBox.height());
1411 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
1412 // We want it to be in the top-left, so subtract half the height and width.
1413 perspectiveOriginX -= borderBox.width() / 2.0f;
1414 perspectiveOriginY -= borderBox.height() / 2.0f;
1416 TransformationMatrix t;
1417 t.translate(perspectiveOriginX, perspectiveOriginY);
1418 t.applyPerspective(style.perspective());
1419 t.translate(-perspectiveOriginX, -perspectiveOriginY);
1424 FloatPoint RenderLayer::perspectiveOrigin() const
1426 if (!renderer().hasTransformRelatedProperty())
1427 return FloatPoint();
1429 const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
1430 const RenderStyle& style = renderer().style();
1432 return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
1433 floatValueForLength(style.perspectiveOriginY(), borderBox.height()));
1436 RenderLayer* RenderLayer::stackingContainer() const
1438 RenderLayer* layer = parent();
1439 while (layer && !layer->isStackingContainer())
1440 layer = layer->parent();
1442 ASSERT(!layer || layer->isStackingContainer());
1446 static inline bool isContainerForPositioned(RenderLayer& layer, EPosition position)
1450 return layer.renderer().canContainFixedPositionObjects();
1452 case AbsolutePosition:
1453 return layer.renderer().canContainAbsolutelyPositionedObjects();
1456 ASSERT_NOT_REACHED();
1461 RenderLayer* RenderLayer::enclosingAncestorForPosition(EPosition position) const
1463 RenderLayer* curr = parent();
1464 while (curr && !isContainerForPositioned(*curr, position))
1465 curr = curr->parent();
1470 static RenderLayer* parentLayerCrossFrame(const RenderLayer& layer)
1473 return layer.parent();
1475 HTMLFrameOwnerElement* ownerElement = layer.renderer().document().ownerElement();
1479 RenderElement* ownerRenderer = ownerElement->renderer();
1483 return ownerRenderer->enclosingLayer();
1486 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1488 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
1489 if (is<RenderBox>(nextLayer->renderer()) && downcast<RenderBox>(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
1496 IntRect RenderLayer::scrollableAreaBoundingBox(bool* isInsideFixed) const
1498 return renderer().absoluteBoundingBoxRect(/* useTransforms */ true, isInsideFixed);
1501 bool RenderLayer::isRubberBandInProgress() const
1503 #if ENABLE(RUBBER_BANDING)
1504 if (!scrollsOverflow())
1507 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1508 return scrollAnimator->isRubberBandInProgress();
1514 bool RenderLayer::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
1516 Page* page = renderer().frame().page();
1517 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
1520 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1522 RenderLayer* curr = parent();
1523 while (curr && !curr->isRootLayer() && !curr->transform())
1524 curr = curr->parent();
1529 static inline const RenderLayer* compositingContainer(const RenderLayer& layer)
1531 return layer.isNormalFlowOnly() ? layer.parent() : layer.stackingContainer();
1534 inline bool RenderLayer::shouldRepaintAfterLayout() const
1536 if (m_repaintStatus == NeedsNormalRepaint)
1539 // Composited layers that were moved during a positioned movement only
1540 // layout, don't need to be repainted. They just need to be recomposited.
1541 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1542 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1545 bool compositedWithOwnBackingStore(const RenderLayer& layer)
1547 return layer.isComposited() && !layer.backing()->paintsIntoCompositedAncestor();
1550 RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
1552 if (includeSelf == IncludeSelf && isComposited())
1553 return const_cast<RenderLayer*>(this);
1555 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1556 if (curr->isComposited())
1557 return const_cast<RenderLayer*>(curr);
1563 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
1565 if (includeSelf == IncludeSelf && compositedWithOwnBackingStore(*this))
1566 return const_cast<RenderLayer*>(this);
1568 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1569 if (compositedWithOwnBackingStore(*curr))
1570 return const_cast<RenderLayer*>(curr);
1576 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
1578 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
1579 for (; curr; curr = curr->parent()) {
1580 if (curr->requiresFullLayerImageForFilters())
1581 return const_cast<RenderLayer*>(curr);
1587 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1589 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1590 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(*curr) || curr->isRootLayer())
1591 return const_cast<RenderLayer*>(curr);
1596 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
1601 LayoutRect rectForRepaint = rect;
1602 renderer().style().filterOutsets().expandRect(rectForRepaint);
1604 FilterInfo& filterInfo = FilterInfo::get(*this);
1605 filterInfo.expandDirtySourceRect(rectForRepaint);
1607 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1608 ASSERT(parentLayer);
1609 FloatQuad repaintQuad(rectForRepaint);
1610 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1612 if (parentLayer->isComposited()) {
1613 if (!parentLayer->backing()->paintsIntoWindow()) {
1614 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1617 // If the painting goes to window, redirect the painting to the parent RenderView.
1618 parentLayer = renderer().view().layer();
1619 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1622 if (parentLayer->paintsWithFilters()) {
1623 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
1627 if (parentLayer->isRootLayer()) {
1628 downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
1632 ASSERT_NOT_REACHED();
1635 bool RenderLayer::hasAncestorWithFilterOutsets() const
1637 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1638 if (curr->renderer().style().hasFilterOutsets())
1644 RenderLayer* RenderLayer::clippingRootForPainting() const
1647 return const_cast<RenderLayer*>(this);
1649 const RenderLayer* current = this;
1651 if (current->isRootLayer())
1652 return const_cast<RenderLayer*>(current);
1654 current = compositingContainer(*current);
1656 if (current->transform() || compositedWithOwnBackingStore(*current))
1657 return const_cast<RenderLayer*>(current);
1660 ASSERT_NOT_REACHED();
1664 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1666 // We don't use convertToLayerCoords because it doesn't know about transforms
1667 return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
1670 bool RenderLayer::cannotBlitToWindow() const
1672 if (isTransparent() || hasReflection() || hasTransform())
1676 return parent()->cannotBlitToWindow();
1679 RenderLayer* RenderLayer::transparentPaintingAncestor()
1684 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1685 if (curr->isComposited())
1687 if (curr->isTransparent())
1693 enum TransparencyClipBoxBehavior {
1694 PaintingTransparencyClipBox,
1695 HitTestingTransparencyClipBox
1698 enum TransparencyClipBoxMode {
1699 DescendantsOfTransparencyClipBox,
1700 RootOfTransparencyClipBox
1703 static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
1705 static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1706 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1708 // If this is a region, then the painting is actually done by its flow thread's layer.
1709 if (layer.renderer().isRenderNamedFlowFragmentContainer()) {
1710 RenderBlockFlow& regionContainer = downcast<RenderBlockFlow>(layer.renderer());
1711 RenderNamedFlowFragment& region = *regionContainer.renderNamedFlowFragment();
1712 RenderLayer* flowThreadLayer = region.flowThread()->layer();
1713 if (flowThreadLayer && (!layer.reflection() || layer.reflectionLayer() != flowThreadLayer)) {
1714 LayoutRect flowThreadClipRect = transparencyClipBox(*flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
1715 LayoutSize moveOffset = (regionContainer.contentBoxRect().location() + layer.offsetFromAncestor(flowThreadLayer)) - region.flowThreadPortionRect().location();
1716 flowThreadClipRect.move(moveOffset);
1718 clipRect.unite(flowThreadClipRect);
1723 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1724 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1726 // If we have a mask, then the clip is limited to the border box area (and there is
1727 // no need to examine child layers).
1728 if (!layer.renderer().hasMask()) {
1729 // Note: we don't have to walk z-order lists since transparent elements always establish
1730 // a stacking container. This means we can just walk the layer tree directly.
1731 for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
1732 if (!layer.reflection() || layer.reflectionLayer() != curr)
1733 clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
1737 expandClipRectForRegionAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1739 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1740 // current transparencyClipBox to catch all child layers.
1741 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1742 // size into the parent layer.
1743 if (layer.renderer().hasReflection()) {
1744 LayoutSize delta = layer.offsetFromAncestor(rootLayer);
1745 clipRect.move(-delta);
1746 clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
1747 clipRect.move(delta);
1751 static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1752 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
1754 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1755 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1756 // would be better to respect clips.
1758 if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
1759 || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
1760 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1761 // the transformed layer and all of its children.
1762 RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
1763 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : nullptr;
1764 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1765 LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
1767 TransformationMatrix transform;
1768 transform.translate(delta.width(), delta.height());
1769 transform.multiply(*layer.transform());
1771 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1772 // paints unfragmented.
1773 LayoutRect clipRect = layer.boundingBox(&layer);
1774 expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
1775 layer.renderer().style().filterOutsets().expandRect(clipRect);
1776 LayoutRect result = transform.mapRect(clipRect);
1777 if (!paginationLayer)
1780 // We have to break up the transformed extent across our columns.
1781 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1782 // get our true bounding box.
1783 auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
1784 result = enclosingFlowThread.fragmentsBoundingBox(result);
1785 result.move(paginationLayer->offsetFromAncestor(rootLayer));
1789 LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
1790 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1791 layer.renderer().style().filterOutsets().expandRect(clipRect);
1796 static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1798 return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
1801 void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
1803 if (context.paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
1806 RenderLayer* ancestor = transparentPaintingAncestor();
1808 ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
1810 if (paintsWithTransparency(paintingInfo.paintBehavior)) {
1811 m_usedTransparency = true;
1813 LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
1814 adjustedClipRect.move(paintingInfo.subpixelAccumulation);
1815 FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
1816 context.clip(pixelSnappedClipRect);
1818 #if ENABLE(CSS_COMPOSITING)
1819 bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRootLayer());
1820 if (usesCompositeOperation)
1821 context.setCompositeOperation(context.compositeOperation(), blendMode());
1824 context.beginTransparencyLayer(renderer().opacity());
1826 #if ENABLE(CSS_COMPOSITING)
1827 if (usesCompositeOperation)
1828 context.setCompositeOperation(context.compositeOperation(), BlendModeNormal);
1831 #ifdef REVEAL_TRANSPARENCY_LAYERS
1832 context.setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
1833 context.fillRect(pixelSnappedClipRect);
1839 void RenderLayer::willBeDestroyed()
1841 if (RenderLayerBacking* layerBacking = backing())
1842 layerBacking->layerWillBeDestroyed();
1846 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1848 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1850 child->setPreviousSibling(prevSibling);
1851 prevSibling->setNextSibling(child);
1852 ASSERT(prevSibling != child);
1854 setFirstChild(child);
1857 beforeChild->setPreviousSibling(child);
1858 child->setNextSibling(beforeChild);
1859 ASSERT(beforeChild != child);
1861 setLastChild(child);
1863 child->setParent(this);
1865 if (child->isNormalFlowOnly())
1866 dirtyNormalFlowList();
1868 if (!child->isNormalFlowOnly() || child->firstChild()) {
1869 // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
1870 // case where we're building up generated content layers. This is ok, since the lists will start
1871 // off dirty in that case anyway.
1872 child->dirtyStackingContainerZOrderLists();
1875 child->updateDescendantDependentFlags();
1876 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1877 setAncestorChainHasVisibleDescendant();
1879 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1880 setAncestorChainHasSelfPaintingLayerDescendant();
1882 if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
1883 setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
1885 #if ENABLE(CSS_COMPOSITING)
1886 if (child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending()))
1887 updateAncestorChainHasBlendingDescendants();
1890 compositor().layerWasAdded(*this, *child);
1893 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1895 if (!renderer().documentBeingDestroyed())
1896 compositor().layerWillBeRemoved(*this, *oldChild);
1899 if (oldChild->previousSibling())
1900 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1901 if (oldChild->nextSibling())
1902 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1904 if (m_first == oldChild)
1905 m_first = oldChild->nextSibling();
1906 if (m_last == oldChild)
1907 m_last = oldChild->previousSibling();
1909 if (oldChild->isNormalFlowOnly())
1910 dirtyNormalFlowList();
1911 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1912 // Dirty the z-order list in which we are contained. When called via the
1913 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1914 // from the main layer tree, so we need to null-check the |stackingContainer| value.
1915 oldChild->dirtyStackingContainerZOrderLists();
1918 if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
1919 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
1921 oldChild->setPreviousSibling(nullptr);
1922 oldChild->setNextSibling(nullptr);
1923 oldChild->setParent(nullptr);
1925 oldChild->updateDescendantDependentFlags();
1926 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1927 dirtyAncestorChainVisibleDescendantStatus();
1929 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1930 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1932 #if ENABLE(CSS_COMPOSITING)
1933 if (oldChild->hasBlendMode() || (oldChild->hasNotIsolatedBlendingDescendants() && !oldChild->isolatesBlending()))
1934 dirtyAncestorChainHasBlendingDescendants();
1940 void RenderLayer::removeOnlyThisLayer()
1945 // Mark that we are about to lose our layer. This makes render tree
1946 // walks ignore this layer while we're removing it.
1947 renderer().setHasLayer(false);
1949 compositor().layerWillBeRemoved(*m_parent, *this);
1951 // Dirty the clip rects.
1952 clearClipRectsIncludingDescendants();
1954 RenderLayer* nextSib = nextSibling();
1956 // Remove the child reflection layer before moving other child layers.
1957 // The reflection layer should not be moved to the parent.
1959 removeChild(reflectionLayer());
1961 // Now walk our kids and reattach them to our parent.
1962 RenderLayer* current = m_first;
1964 RenderLayer* next = current->nextSibling();
1965 removeChild(current);
1966 m_parent->addChild(current, nextSib);
1967 current->setRepaintStatus(NeedsFullRepaint);
1968 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1969 ASSERT(!renderer().hasLayer());
1970 current->updateLayerPositions(); // FIXME: use geometry map.
1974 // Remove us from the parent.
1975 m_parent->removeChild(this);
1976 renderer().destroyLayer();
1979 void RenderLayer::insertOnlyThisLayer()
1981 if (!m_parent && renderer().parent()) {
1982 // We need to connect ourselves when our renderer() has a parent.
1983 // Find our enclosingLayer and add ourselves.
1984 RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
1985 ASSERT(parentLayer);
1986 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : nullptr;
1987 parentLayer->addChild(this, beforeChild);
1990 // Remove all descendant layers from the hierarchy and add them to the new position.
1991 for (auto& child : childrenOfType<RenderElement>(renderer()))
1992 child.moveLayers(m_parent, this);
1994 // Clear out all the clip rects.
1995 clearClipRectsIncludingDescendants();
1998 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
2000 LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
2001 roundedLocation = roundedIntPoint(location);
2004 // Returns the layer reached on the walk up towards the ancestor.
2005 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
2007 ASSERT(ancestorLayer != layer);
2009 const RenderLayerModelObject& renderer = layer->renderer();
2010 EPosition position = renderer.style().position();
2012 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
2013 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : nullptr;
2014 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
2015 fixedFlowThreadContainer = nullptr;
2017 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
2018 // may need to be revisited in a future patch.
2019 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
2020 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
2021 // positioned in a completely different place in the viewport (RenderView).
2022 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
2023 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
2024 // localToAbsolute() on the RenderView.
2025 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
2026 location += LayoutSize(absPos.x(), absPos.y());
2027 return ancestorLayer;
2030 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
2031 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
2032 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
2033 if (position == FixedPosition && !fixedFlowThreadContainer) {
2034 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
2035 // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
2036 // so we should always find the ancestor at or before we find the fixed position container.
2037 RenderLayer* fixedPositionContainerLayer = nullptr;
2038 bool foundAncestor = false;
2039 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
2040 if (currLayer == ancestorLayer)
2041 foundAncestor = true;
2043 if (isContainerForPositioned(*currLayer, FixedPosition)) {
2044 fixedPositionContainerLayer = currLayer;
2045 ASSERT_UNUSED(foundAncestor, foundAncestor);
2050 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
2052 if (fixedPositionContainerLayer != ancestorLayer) {
2053 LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
2054 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
2055 location += (fixedContainerCoords - ancestorCoords);
2056 return ancestorLayer;
2060 if (position == FixedPosition && fixedFlowThreadContainer) {
2061 ASSERT(ancestorLayer);
2062 if (ancestorLayer->isOutOfFlowRenderFlowThread()) {
2063 location += toLayoutSize(layer->location());
2064 return ancestorLayer;
2067 if (ancestorLayer == renderer.view().layer()) {
2068 // Add location in flow thread coordinates.
2069 location += toLayoutSize(layer->location());
2071 // Add flow thread offset in view coordinates since the view may be scrolled.
2072 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
2073 location += LayoutSize(absPos.x(), absPos.y());
2074 return ancestorLayer;
2078 RenderLayer* parentLayer;
2079 if (position == AbsolutePosition || position == FixedPosition) {
2080 // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
2081 parentLayer = layer->parent();
2082 bool foundAncestorFirst = false;
2083 while (parentLayer) {
2084 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
2085 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
2086 // we are bailing out before reaching root layer.
2087 if (isContainerForPositioned(*parentLayer, position))
2090 if (parentLayer == ancestorLayer) {
2091 foundAncestorFirst = true;
2095 parentLayer = parentLayer->parent();
2098 // We should not reach RenderView layer past the RenderFlowThread layer for any
2099 // children of the RenderFlowThread.
2100 if (renderer.flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
2101 ASSERT(parentLayer != renderer.view().layer());
2103 if (foundAncestorFirst) {
2104 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
2105 // to enclosingAncestorForPosition and subtract.
2106 RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
2107 LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
2108 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
2109 location += (thisCoords - ancestorCoords);
2110 return ancestorLayer;
2113 parentLayer = layer->parent();
2118 location += toLayoutSize(layer->location());
2120 if (adjustForColumns == RenderLayer::AdjustForColumns) {
2121 if (RenderLayer* parentLayer = layer->parent()) {
2122 if (is<RenderMultiColumnFlowThread>(parentLayer->renderer())) {
2123 RenderRegion* region = downcast<RenderMultiColumnFlowThread>(parentLayer->renderer()).physicalTranslationFromFlowToRegion(location);
2125 location.moveBy(region->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2133 LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2135 if (ancestorLayer == this)
2138 const RenderLayer* currLayer = this;
2139 LayoutPoint locationInLayerCoords = location;
2140 while (currLayer && currLayer != ancestorLayer)
2141 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
2142 return locationInLayerCoords;
2145 LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer, ColumnOffsetAdjustment adjustForColumns) const
2147 return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint(), adjustForColumns));
2151 bool RenderLayer::hasAcceleratedTouchScrolling() const
2153 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2154 if (!scrollsOverflow())
2157 Settings* settings = renderer().document().settings();
2158 // FIXME: settings should not be null at this point. If you find a reliable way to hit this assertion, please file a bug.
2159 // See <rdar://problem/10266101>.
2162 return renderer().style().useTouchOverflowScrolling() || (settings && settings->alwaysUseAcceleratedOverflowScroll());
2168 bool RenderLayer::hasTouchScrollableOverflow() const
2170 return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2173 #if ENABLE(TOUCH_EVENTS)
2174 bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
2176 // If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
2177 if (hasTouchScrollableOverflow())
2180 return ScrollableArea::handleTouchEvent(touchEvent);
2183 #endif // PLATFORM(IOS)
2185 #if ENABLE(IOS_TOUCH_EVENTS)
2186 void RenderLayer::registerAsTouchEventListenerForScrolling()
2188 if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
2191 renderer().document().addTouchEventListener(renderer().element());
2192 m_registeredAsTouchEventListenerForScrolling = true;
2195 void RenderLayer::unregisterAsTouchEventListenerForScrolling()
2197 if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
2200 renderer().document().removeTouchEventListener(renderer().element());
2201 m_registeredAsTouchEventListenerForScrolling = false;
2203 #endif // ENABLE(IOS_TOUCH_EVENTS)
2205 bool RenderLayer::usesCompositedScrolling() const
2207 return isComposited() && backing()->scrollingLayer();
2210 bool RenderLayer::usesAsyncScrolling() const
2212 return hasAcceleratedTouchScrolling() && usesCompositedScrolling();
2215 bool RenderLayer::needsCompositedScrolling() const
2217 return m_needsCompositedScrolling;
2220 void RenderLayer::updateNeedsCompositedScrolling()
2222 bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
2224 if (!renderer().view().frameView().containsScrollableArea(this))
2225 m_needsCompositedScrolling = false;
2227 bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
2228 && canBeStackingContainer()
2229 && !hasOutOfFlowPositionedDescendant();
2231 #if !PLATFORM(IOS) && ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2232 m_needsCompositedScrolling = forceUseCompositedScrolling || renderer().style().useTouchOverflowScrolling();
2234 // On iOS we don't want to opt into accelerated composited scrolling, which creates scroll bar
2235 // layers in WebCore, because we use UIKit to composite our scroll bars.
2236 m_needsCompositedScrolling = forceUseCompositedScrolling;
2240 if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
2241 updateSelfPaintingLayer();
2242 if (isStackingContainer())
2247 dirtyStackingContainerZOrderLists();
2249 compositor().setShouldReevaluateCompositingAfterLayout();
2250 compositor().setCompositingLayersNeedRebuild();
2254 static inline int adjustedScrollDelta(int beginningDelta) {
2255 // This implemention matches Firefox's.
2256 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
2257 const int speedReducer = 12;
2259 int adjustedDelta = beginningDelta / speedReducer;
2260 if (adjustedDelta > 1)
2261 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
2262 else if (adjustedDelta < -1)
2263 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
2265 return adjustedDelta;
2268 static inline IntSize adjustedScrollDelta(const IntSize& delta)
2270 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
2273 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
2275 IntPoint lastKnownMousePosition = renderer().frame().eventHandler().lastKnownMousePosition();
2277 // 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
2278 static IntPoint previousMousePosition;
2279 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
2280 lastKnownMousePosition = previousMousePosition;
2282 previousMousePosition = lastKnownMousePosition;
2284 IntSize delta = lastKnownMousePosition - sourcePoint;
2286 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
2288 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
2291 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
2294 // FIXME: unify with the scrollRectToVisible() code below.
2295 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp, ScrollableArea** scrolledArea)
2300 bool restrictedByLineClamp = false;
2301 if (renderer().parent())
2302 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2304 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2305 ScrollOffset newScrollOffset = scrollOffset() + delta;
2306 scrollToOffset(newScrollOffset, clamp);
2308 *scrolledArea = this;
2310 // If this layer can't do the scroll we ask the next layer up that can scroll to try
2311 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
2312 if (!remainingScrollOffset.isZero() && renderer().parent()) {
2313 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2314 scrollableLayer->scrollByRecursively(remainingScrollOffset, clamp, scrolledArea);
2316 renderer().frame().eventHandler().updateAutoscrollRenderer();
2319 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
2320 // have an overflow clip. Which means that it is a document node that can be scrolled.
2321 renderer().view().frameView().scrollBy(delta);
2323 *scrolledArea = &renderer().view().frameView();
2325 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
2326 // https://bugs.webkit.org/show_bug.cgi?id=28237
2330 void RenderLayer::scrollToXPosition(int x, ScrollOffsetClamping clamp)
2332 ScrollPosition position(x, m_scrollPosition.y());
2333 scrollToOffset(scrollOffsetFromPosition(position), clamp);
2336 void RenderLayer::scrollToYPosition(int y, ScrollOffsetClamping clamp)
2338 ScrollPosition position(m_scrollPosition.x(), y);
2339 scrollToOffset(scrollOffsetFromPosition(position), clamp);
2342 ScrollOffset RenderLayer::clampScrollOffset(const ScrollOffset& scrollOffset) const
2344 return scrollOffset.constrainedBetween(IntPoint(), maximumScrollOffset());
2347 void RenderLayer::scrollToOffset(const ScrollOffset& scrollOffset, ScrollOffsetClamping clamp)
2349 ScrollOffset newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2350 if (newScrollOffset != this->scrollOffset())
2351 scrollToOffsetWithoutAnimation(newScrollOffset);
2354 void RenderLayer::scrollTo(const ScrollPosition& position)
2356 RenderBox* box = renderBox();
2360 LOG_WITH_STREAM(Scrolling, stream << "RenderLayer::scrollTo " << position);
2362 ScrollPosition newPosition = position;
2363 if (!box->isHTMLMarquee()) {
2364 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
2365 if (m_scrollDimensionsDirty)
2366 computeScrollDimensions();
2368 if (adjustForIOSCaretWhenScrolling()) {
2369 // FIXME: It's not clear what this code is trying to do. Behavior seems reasonable with it removed.
2370 int maxOffset = scrollWidth() - roundToInt(box->clientWidth());
2371 ScrollOffset newOffset = scrollOffsetFromPosition(newPosition);
2372 int scrollXOffset = newOffset.x();
2373 if (scrollXOffset > maxOffset - caretWidth) {
2374 scrollXOffset += caretWidth;
2375 if (scrollXOffset <= caretWidth)
2377 } else if (scrollXOffset < m_scrollPosition.x() - caretWidth)
2378 scrollXOffset -= caretWidth;
2380 newOffset.setX(scrollXOffset);
2381 newPosition = scrollPositionFromOffset(newOffset);
2386 if (m_scrollPosition == newPosition) {
2388 if (m_requiresScrollBoundsOriginUpdate)
2389 updateCompositingLayersAfterScroll();
2394 ScrollPosition oldPosition = IntPoint(m_scrollPosition);
2395 m_scrollPosition = newPosition;
2397 RenderView& view = renderer().view();
2399 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
2400 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
2401 if (!view.frameView().isInRenderTreeLayout()) {
2402 // If we're in the middle of layout, we'll just update layers once layout has finished.
2403 updateLayerPositionsAfterOverflowScroll();
2404 // Update regions, scrolling may change the clip of a particular region.
2405 #if ENABLE(DASHBOARD_SUPPORT)
2406 view.frameView().updateAnnotatedRegions();
2408 view.frameView().updateWidgetPositions();
2410 if (!m_updatingMarqueePosition) {
2411 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
2412 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
2413 // in this case we're still updating their positions; we'll update compositing layers later
2414 // when that completes.
2415 updateCompositingLayersAfterScroll();
2418 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
2419 renderer().document().dirtyTouchEventRects();
2421 DebugPageOverlays::didLayout(renderer().frame());
2424 Frame& frame = renderer().frame();
2425 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
2426 // The caret rect needs to be invalidated after scrolling
2427 frame.selection().setCaretRectNeedsUpdate();
2429 LayoutRect rectForRepaint = m_hasComputedRepaintRect ? m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
2431 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
2432 if (repaintContainer)
2433 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
2434 frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
2436 bool requiresRepaint = true;
2437 if (compositor().inCompositingMode() && usesCompositedScrolling())
2438 requiresRepaint = false;
2440 // Just schedule a full repaint of our object.
2441 if (requiresRepaint)
2442 renderer().repaintUsingContainer(repaintContainer, rectForRepaint);
2444 // Schedule the scroll and scroll-related DOM events.
2445 if (Element* element = renderer().element()) {
2446 element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
2447 element->document().sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize(), element);
2450 if (scrollsOverflow())
2451 view.frameView().didChangeScrollOffset();
2453 view.frameView().viewportContentsChanged();
2456 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)
2458 // If scrollbars aren't explicitly forbidden, permit scrolling.
2459 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
2462 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2463 if (frameView.wasScrolledByUser())
2466 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2467 // like navigation to an anchor.
2468 return !frameView.frame().eventHandler().autoscrollInProgress();
2471 bool RenderLayer::allowsCurrentScroll() const
2473 if (!renderer().hasOverflowClip())
2476 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2477 // FIXME: Is this still needed? It used to be relevant for Safari RSS.
2478 if (renderer().parent() && !renderer().parent()->style().lineClamp().isNone())
2481 RenderBox* box = renderBox();
2482 ASSERT(box); // Only boxes can have overflowClip set.
2484 if (renderer().frame().eventHandler().autoscrollInProgress()) {
2485 // The "programmatically" here is misleading; this asks whether the box has scrollable overflow,
2486 // or is a special case like a form control.
2487 return box->canBeProgramaticallyScrolled();
2490 // Programmatic scrolls can scroll overflow:hidden.
2491 return box->hasHorizontalOverflow() || box->hasVerticalOverflow();
2494 void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2496 LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << rect);
2498 RenderLayer* parentLayer = nullptr;
2499 LayoutRect newRect = rect;
2501 // We may end up propagating a scroll event. It is important that we suspend events until
2502 // the end of the function since they could delete the layer or the layer's renderer().
2503 FrameView& frameView = renderer().view().frameView();
2505 if (renderer().parent())
2506 parentLayer = renderer().parent()->enclosingLayer();
2508 if (allowsCurrentScroll()) {
2509 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2510 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2511 RenderBox* box = renderBox();
2513 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect))).boundingBox());
2514 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
2515 LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
2517 ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
2518 if (clampedScrollOffset != scrollOffset()) {
2519 ScrollOffset oldScrollOffset = scrollOffset();
2520 scrollToOffset(clampedScrollOffset);
2521 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
2522 localExposeRect.move(-scrollOffsetDifference);
2523 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
2525 } else if (!parentLayer && renderer().isRenderView()) {
2526 HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
2528 if (ownerElement && ownerElement->renderer()) {
2529 HTMLFrameElementBase* frameElementBase = nullptr;
2531 if (is<HTMLFrameElementBase>(*ownerElement))
2532 frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
2534 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
2535 // If this assertion fires we need to protect the ownerElement from being destroyed.
2536 NoEventDispatchAssertion assertNoEventDispatch;
2538 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
2539 LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
2541 IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
2542 // Adjust offsets if they're outside of the allowable range.
2543 scrollOffset = scrollOffset.constrainedBetween(IntPoint(), IntPoint(frameView.contentsSize()));
2544 frameView.setScrollPosition(scrollOffset);
2546 if (frameView.safeToPropagateScrollToParent()) {
2547 parentLayer = ownerElement->renderer()->enclosingLayer();
2548 // Convert the rect into the coordinate space of the parent frame's document.
2549 newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
2551 parentLayer = nullptr;
2554 if (revealMode == SelectionRevealMode::RevealUpToMainFrame && frameView.frame().isMainFrame())
2558 LayoutRect viewRect = frameView.visibleContentRect();
2559 LayoutRect visibleRectRelativeToDocument = viewRect;
2560 visibleRectRelativeToDocument.setLocation(frameView.documentScrollPositionRelativeToScrollableAreaOrigin());
2562 LayoutRect viewRect = frameView.unobscuredContentRect();
2563 LayoutRect visibleRectRelativeToDocument = viewRect;
2566 LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
2568 frameView.setScrollPosition(roundedIntPoint(r.location()));
2570 // This is the outermost view of a web page, so after scrolling this view we
2571 // scroll its container by calling Page::scrollRectIntoView.
2572 // This only has an effect on the Mac platform in applications
2573 // that put web views into scrolling containers, such as Mac OS X Mail.
2574 // The canAutoscroll function in EventHandler also knows about this.
2575 if (Page* page = frameView.frame().page())
2576 page->chrome().scrollRectIntoView(snappedIntRect(rect));
2581 parentLayer->scrollRectToVisible(revealMode, newRect, alignX, alignY);
2584 void RenderLayer::updateCompositingLayersAfterScroll()
2586 if (compositor().inCompositingMode()) {
2587 // Our stacking container is guaranteed to contain all of our descendants that may need
2588 // repositioning, so update compositing layers from there.
2589 if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
2590 if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
2591 compositor().updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor);
2593 compositor().updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
2598 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2600 // Determine the appropriate X behavior.
2601 ScrollBehavior scrollX;
2602 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
2603 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
2604 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
2605 // If the rectangle is fully visible, use the specified visible behavior.
2606 // If the rectangle is partially visible, but over a certain threshold,
2607 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2608 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2609 else if (intersectWidth == visibleRect.width()) {
2610 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2611 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2612 if (scrollX == alignCenter)
2614 } else if (intersectWidth > 0)
2615 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2616 scrollX = ScrollAlignment::getPartialBehavior(alignX);
2618 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
2619 // If we're trying to align to the closest edge, and the exposeRect is further right
2620 // than the visibleRect, and not bigger than the visible area, then align with the right.
2621 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2622 scrollX = alignRight;
2624 // Given the X behavior, compute the X coordinate.
2626 if (scrollX == noScroll)
2627 x = visibleRect.x();
2628 else if (scrollX == alignRight)
2629 x = exposeRect.maxX() - visibleRect.width();
2630 else if (scrollX == alignCenter)
2631 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2635 // Determine the appropriate Y behavior.
2636 ScrollBehavior scrollY;
2637 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
2638 LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
2639 if (intersectHeight == exposeRect.height())
2640 // If the rectangle is fully visible, use the specified visible behavior.
2641 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2642 else if (intersectHeight == visibleRect.height()) {
2643 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2644 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2645 if (scrollY == alignCenter)
2647 } else if (intersectHeight > 0)
2648 // If the rectangle is partially visible, use the specified partial behavior
2649 scrollY = ScrollAlignment::getPartialBehavior(alignY);
2651 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
2652 // If we're trying to align to the closest edge, and the exposeRect is further down
2653 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2654 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2655 scrollY = alignBottom;
2657 // Given the Y behavior, compute the Y coordinate.
2659 if (scrollY == noScroll)
2660 y = visibleRect.y();
2661 else if (scrollY == alignBottom)
2662 y = exposeRect.maxY() - visibleRect.height();
2663 else if (scrollY == alignCenter)
2664 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2668 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2671 void RenderLayer::autoscroll(const IntPoint& position)
2673 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
2674 scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2677 bool RenderLayer::canResize() const
2679 // We need a special case for <iframe> because they never have
2680 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
2681 // we want to allow resizing them also.
2682 return (renderer().hasOverflowClip() || renderer().isRenderIFrame()) && renderer().style().resize() != RESIZE_NONE;
2685 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2687 // FIXME: This should be possible on generated content but is not right now.
2688 if (!inResizeMode() || !canResize() || !renderer().element())
2691 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2692 // If they do it would still be better to deal with them explicitly.
2693 Element* element = renderer().element();
2694 auto* renderer = downcast<RenderBox>(element->renderer());
2696 Document& document = element->document();
2697 if (!document.frame()->eventHandler().mousePressed())
2700 float zoomFactor = renderer->style().effectiveZoom();
2702 LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(evt.position()));
2703 newOffset.setWidth(newOffset.width() / zoomFactor);
2704 newOffset.setHeight(newOffset.height() / zoomFactor);
2706 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2707 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2708 element->setMinimumSizeForResizing(minimumSize);
2710 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2711 if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
2712 newOffset.setWidth(-newOffset.width());
2713 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2716 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2718 StyledElement* styledElement = downcast<StyledElement>(element);
2719 bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
2721 EResize resize = renderer->style().resize();
2722 if (resize != RESIZE_VERTICAL && difference.width()) {
2723 if (is<HTMLFormControlElement>(*element)) {
2724 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2725 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2726 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2728 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
2729 baseWidth = baseWidth / zoomFactor;
2730 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
2733 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2734 if (is<HTMLFormControlElement>(*element)) {
2735 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2736 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2737 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2739 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
2740 baseHeight = baseHeight / zoomFactor;
2741 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
2744 document.updateLayout();
2746 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2749 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2751 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2752 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2755 void RenderLayer::setScrollOffset(const ScrollOffset& offset)
2757 scrollTo(scrollPositionFromOffset(offset));
2760 int RenderLayer::scrollOffset(ScrollbarOrientation orientation) const
2762 if (orientation == HorizontalScrollbar)
2763 return scrollOffset().x();
2765 if (orientation == VerticalScrollbar)
2766 return scrollOffset().y();
2771 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
2773 IntSize scrollbarSpace;
2774 if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars)
2775 scrollbarSpace = scrollbarIntrusion();
2777 // FIXME: This seems wrong: m_layerSize includes borders. Can we just use the ScrollableArea implementation?
2778 return IntRect(scrollPosition(), IntSize(std::max(0, m_layerSize.width() - scrollbarSpace.width()), std::max(0, m_layerSize.height() - scrollbarSpace.height())));
2781 IntSize RenderLayer::overhangAmount() const
2783 #if ENABLE(RUBBER_BANDING)
2784 if (!renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled())
2789 // FIXME: use maximumScrollOffset(), or just move this to ScrollableArea.
2790 ScrollOffset scrollOffset = scrollOffsetFromPosition(scrollPosition());
2791 if (scrollOffset.y() < 0)
2792 stretch.setHeight(scrollOffset.y());
2793 else if (scrollableContentsSize().height() && scrollOffset.y() > scrollableContentsSize().height() - visibleHeight())
2794 stretch.setHeight(scrollOffset.y() - (scrollableContentsSize().height() - visibleHeight()));
2796 if (scrollOffset.x() < 0)
2797 stretch.setWidth(scrollOffset.x());
2798 else if (scrollableContentsSize().width() && scrollOffset.x() > scrollableContentsSize().width() - visibleWidth())
2799 stretch.setWidth(scrollOffset.x() - (scrollableContentsSize().width() - visibleWidth()));
2807 bool RenderLayer::isActive() const
2809 Page* page = renderer().frame().page();
2810 return page && page->focusController().isActive();
2813 static int cornerStart(const RenderLayer& layer, int minX, int maxX, int thickness)
2815 if (layer.shouldPlaceBlockDirectionScrollbarOnLeft())
2816 return minX + layer.renderer().style().borderLeftWidth();
2817 return maxX - thickness - layer.renderer().style().borderRightWidth();
2820 static LayoutRect cornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2822 int horizontalThickness;
2823 int verticalThickness;
2824 if (!layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2825 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2826 // even when they don't exist in order to set the resizer square size properly.
2827 horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
2828 verticalThickness = horizontalThickness;
2829 } else if (layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2830 horizontalThickness = layer.verticalScrollbar()->width();
2831 verticalThickness = horizontalThickness;
2832 } else if (layer.horizontalScrollbar() && !layer.verticalScrollbar()) {
2833 verticalThickness = layer.horizontalScrollbar()->height();
2834 horizontalThickness = verticalThickness;
2836 horizontalThickness = layer.verticalScrollbar()->width();
2837 verticalThickness = layer.horizontalScrollbar()->height();
2839 return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2840 bounds.maxY() - verticalThickness - layer.renderer().style().borderBottomWidth(),
2841 horizontalThickness, verticalThickness);
2844 IntRect RenderLayer::scrollCornerRect() const
2846 // We have a scrollbar corner when a non overlay scrollbar is visible and not filling the entire length of the box.
2847 // This happens when:
2848 // (a) A resizer is present and at least one non overlay scrollbar is present
2849 // (b) Both non overlay scrollbars are present.
2850 // Overlay scrollbars always fill the entire length of the box so we never have scroll corner in that case.
2851 bool hasHorizontalBar = m_hBar && !m_hBar->isOverlayScrollbar();
2852 bool hasVerticalBar = m_vBar && !m_vBar->isOverlayScrollbar();
2853 bool hasResizer = renderer().style().resize() != RESIZE_NONE;
2854 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2855 return snappedIntRect(cornerRect(*this, renderBox()->borderBoxRect()));
2859 static LayoutRect resizerCornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2861 ASSERT(layer.renderer().isBox());
2862 if (layer.renderer().style().resize() == RESIZE_NONE)
2863 return LayoutRect();
2864 return cornerRect(layer, bounds);
2867 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
2869 RenderBox* box = renderBox();
2871 return LayoutRect();
2872 LayoutRect scrollCornerAndResizer = scrollCornerRect();
2873 if (scrollCornerAndResizer.isEmpty())
2874 scrollCornerAndResizer = resizerCornerRect(*this, box->borderBoxRect());
2875 return scrollCornerAndResizer;
2878 bool RenderLayer::isScrollCornerVisible() const
2880 ASSERT(renderer().isBox());
2881 return !scrollCornerRect().isEmpty();
2884 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
2886 IntRect rect = scrollbarRect;
2887 rect.move(scrollbarOffset(scrollbar));
2889 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), rect);
2892 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
2894 IntRect rect = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentRect);
2895 rect.move(-scrollbarOffset(scrollbar));
2899 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
2901 IntPoint point = scrollbarPoint;
2902 point.move(scrollbarOffset(scrollbar));
2903 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), point);
2906 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
2908 IntPoint point = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentPoint);
2909 point.move(-scrollbarOffset(scrollbar));
2913 IntSize RenderLayer::visibleSize() const
2915 RenderBox* box = renderBox();
2919 return IntSize(roundToInt(box->clientWidth()), roundToInt(box->clientHeight()));
2922 IntSize RenderLayer::contentsSize() const
2924 return IntSize(scrollWidth(), scrollHeight());
2927 IntSize RenderLayer::scrollableContentsSize() const
2929 IntSize contentsSize = this->contentsSize();
2931 if (!hasScrollableHorizontalOverflow())
2932 contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
2934 if (!hasScrollableVerticalOverflow())
2935 contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
2937 return contentsSize;
2940 void RenderLayer::availableContentSizeChanged(AvailableSizeChangeReason reason)
2942 ScrollableArea::availableContentSizeChanged(reason);
2944 if (reason == AvailableSizeChangeReason::ScrollbarsChanged) {
2945 if (is<RenderBlock>(renderer()))
2946 downcast<RenderBlock>(renderer()).setShouldForceRelayoutChildren(true);
2947 renderer().setNeedsLayout();
2951 bool RenderLayer::shouldSuspendScrollAnimations() const
2953 return renderer().view().frameView().shouldSuspendScrollAnimations();
2957 void RenderLayer::didStartScroll()
2959 if (Page* page = renderer().frame().page())
2960 page->chrome().client().didStartOverflowScroll();
2963 void RenderLayer::didEndScroll()
2965 if (Page* page = renderer().frame().page())
2966 page->chrome().client().didEndOverflowScroll();
2969 void RenderLayer::didUpdateScroll()
2971 // Send this notification when we scroll, since this is how we keep selection updated.
2972 if (Page* page = renderer().frame().page())
2973 page->chrome().client().didLayout(ChromeClient::Scroll);
2977 IntPoint RenderLayer::lastKnownMousePosition() const
2979 return renderer().frame().eventHandler().lastKnownMousePosition();
2982 bool RenderLayer::isHandlingWheelEvent() const
2984 return renderer().frame().eventHandler().isHandlingWheelEvent();
2987 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
2992 const RenderBox* box = renderBox();
2993 const IntRect& scrollCorner = scrollCornerRect();
2995 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
2996 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
2997 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
3001 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
3006 const RenderBox* box = renderBox();
3007 const IntRect& scrollCorner = scrollCornerRect();
3009 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
3010 borderBoxRect.y() + box->borderTop(),
3012 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
3015 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
3017 const RenderBox* box = renderBox();
3018 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3019 return minX + box->borderLeft();
3020 return maxX - box->borderRight() - m_vBar->width();
3023 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
3025 const RenderBox* box = renderBox();
3026 int x = minX + box->borderLeft();
3027 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3028 x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(*this, box->borderBoxRect()).width());
3032 IntSize RenderLayer::scrollbarOffset(const Scrollbar& scrollbar) const
3034 RenderBox* box = renderBox();
3036 if (&scrollbar == m_vBar.get())
3037 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
3039 if (&scrollbar == m_hBar.get())
3040 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3042 ASSERT_NOT_REACHED();
3046 void RenderLayer::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
3048 if (!showsOverflowControls())
3051 if (&scrollbar == m_vBar.get()) {
3052 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
3053 layer->setNeedsDisplayInRect(rect);
3057 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
3058 layer->setNeedsDisplayInRect(rect);
3063 IntRect scrollRect = rect;
3064 RenderBox* box = renderBox();
3066 // If we are not yet inserted into the tree, there is no need to repaint.
3070 if (&scrollbar == m_vBar.get())
3071 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
3073 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3074 LayoutRect repaintRect = scrollRect;
3075 renderBox()->flipForWritingMode(repaintRect);
3076 renderer().repaintRectangle(repaintRect);
3079 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
3081 if (!showsOverflowControls())
3084 if (GraphicsLayer* layer = layerForScrollCorner()) {
3085 layer->setNeedsDisplayInRect(rect);
3090 m_scrollCorner->repaintRectangle(rect);
3092 m_resizer->repaintRectangle(rect);
3095 static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& renderer)
3097 if (Element* element = renderer.element()) {
3098 if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
3099 if (shadowRoot->type() == ShadowRoot::Type::UserAgent)
3100 return shadowRoot->host()->renderer();
3107 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
3109 RefPtr<Scrollbar> widget;
3110 RenderElement* actualRenderer = rendererForScrollbar(renderer());
3111 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style().hasPseudoStyle(SCROLLBAR);
3112 if (hasCustomScrollbarStyle)
3113 widget = RenderScrollbar::createCustomScrollbar(*this, orientation, actualRenderer->element());
3115 widget = Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
3116 didAddScrollbar(widget.get(), orientation);
3117 if (Page* page = renderer().frame().page()) {
3118 if (page->expectsWheelEventTriggers())
3119 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
3122 renderer().view().frameView().addChild(widget.get());
3123 return WTFMove(widget);
3126 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
3128 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
3132 if (!scrollbar->isCustomScrollbar())
3133 willRemoveScrollbar(scrollbar.get(), orientation);
3135 scrollbar->removeFromParent();
3136 scrollbar = nullptr;
3139 bool RenderLayer::scrollsOverflow() const
3141 if (!is<RenderBox>(renderer()))
3144 return downcast<RenderBox>(renderer()).scrollsOverflow();
3147 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
3149 if (hasScrollbar == hasHorizontalScrollbar())
3153 m_hBar = createScrollbar(HorizontalScrollbar);
3154 #if ENABLE(RUBBER_BANDING)
3155 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3156 ScrollableArea::setHorizontalScrollElasticity(elasticity);
3159 destroyScrollbar(HorizontalScrollbar);
3160 #if ENABLE(RUBBER_BANDING)
3161 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityNone);
3165 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3167 m_hBar->styleChanged();
3169 m_vBar->styleChanged();
3171 // Force an update since we know the scrollbars have changed things.
3172 #if ENABLE(DASHBOARD_SUPPORT)
3173 if (renderer().document().hasAnnotatedRegions())
3174 renderer().document().setAnnotatedRegionsDirty(true);
3178 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
3180 if (hasScrollbar == hasVerticalScrollbar())
3184 m_vBar = createScrollbar(VerticalScrollbar);
3185 #if ENABLE(RUBBER_BANDING)
3186 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3187 ScrollableArea::setVerticalScrollElasticity(elasticity);
3190 destroyScrollbar(VerticalScrollbar);
3191 #if ENABLE(RUBBER_BANDING)
3192 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityNone);
3196 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3198 m_hBar->styleChanged();
3200 m_vBar->styleChanged();
3202 // Force an update since we know the scrollbars have changed things.
3203 #if ENABLE(DASHBOARD_SUPPORT)
3204 if (renderer().document().hasAnnotatedRegions())
3205 renderer().document().setAnnotatedRegionsDirty(true);
3209 ScrollableArea* RenderLayer::enclosingScrollableArea() const
3211 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
3212 return scrollableLayer;
3214 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
3215 // if the frame view isn't scrollable.
3219 bool RenderLayer::isScrollableOrRubberbandable()
3221 return renderer().isScrollableOrRubberbandableBox();
3224 bool RenderLayer::hasScrollableOrRubberbandableAncestor()
3226 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
3227 if (nextLayer->isScrollableOrRubberbandable())
3234 #if ENABLE(CSS_SCROLL_SNAP)
3235 void RenderLayer::updateSnapOffsets()
3237 // FIXME: Extend support beyond HTMLElements.
3238 if (!is<HTMLElement>(enclosingElement()) || !enclosingElement()->renderBox())
3241 RenderBox* box = enclosingElement()->renderBox();
3242 updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
3245 bool RenderLayer::isScrollSnapInProgress() const
3247 if (!scrollsOverflow())
3250 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
3251 return scrollAnimator->isScrollSnapInProgress();
3257 bool RenderLayer::usesMockScrollAnimator() const
3259 return Settings::usesMockScrollAnimator();
3262 void RenderLayer::logMockScrollAnimatorMessage(const String& message) const
3264 renderer().document().addConsoleMessage(MessageSource::Other, MessageLevel::Debug, "RenderLayer: " + message);
3267 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
3270 || !showsOverflowControls()
3271 || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
3274 return m_vBar->width();
3277 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
3280 || !showsOverflowControls()
3281 || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
3284 return m_hBar->height();
3287 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
3289 // Currently the resize corner is either the bottom right corner or the bottom left corner.
3290 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
3291 IntSize elementSize = size();
3292 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3293 elementSize.setWidth(0);
3294 IntPoint resizerPoint = IntPoint(elementSize);
3295 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3296 return localPoint - resizerPoint;
3299 bool RenderLayer::hasOverflowControls() const
3301 return m_hBar || m_vBar || m_scrollCorner || renderer().style().resize() != RESIZE_NONE;
3304 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
3306 if (!m_hBar && !m_vBar && !canResize())
3309 RenderBox* box = renderBox();
3313 const IntRect borderBox = snappedIntRect(box->borderBoxRect());
3314 const IntRect& scrollCorner = scrollCornerRect();
3315 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
3317 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
3318 vBarRect.move(offsetFromRoot);
3319 m_vBar->setFrameRect(vBarRect);
3323 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
3324 hBarRect.move(offsetFromRoot);
3325 m_hBar->setFrameRect(hBarRect);
3329 m_scrollCorner->setFrameRect(scrollCorner);
3331 m_resizer->setFrameRect(resizerCornerRect(*this, borderBox));
3334 backing()->positionOverflowControlsLayers();
3337 int RenderLayer::scrollWidth() const
3339 ASSERT(renderBox());
3340 if (m_scrollDimensionsDirty)
3341 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3342 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3343 return m_scrollSize.width();
3346 int RenderLayer::scrollHeight() const
3348 ASSERT(renderBox());
3349 if (m_scrollDimensionsDirty)
3350 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3351 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3352 return m_scrollSize.height();
3355 LayoutUnit RenderLayer::overflowTop() const
3357 RenderBox* box = renderBox();
3358 LayoutRect overflowRect(box->layoutOverflowRect());
3359 box->flipForWritingMode(overflowRect);
3360 return overflowRect.y();
3363 LayoutUnit RenderLayer::overflowBottom() const
3365 RenderBox* box = renderBox();
3366 LayoutRect overflowRect(box->layoutOverflowRect());
3367 box->flipForWritingMode(overflowRect);
3368 return overflowRect.maxY();
3371 LayoutUnit RenderLayer::overflowLeft() const
3373 RenderBox* box = renderBox();
3374 LayoutRect overflowRect(box->layoutOverflowRect());
3375 box->flipForWritingMode(overflowRect);
3376 return overflowRect.x();
3379 LayoutUnit RenderLayer::overflowRight() const
3381 RenderBox* box = renderBox();
3382 LayoutRect overflowRect(box->layoutOverflowRect());
3383 box->flipForWritingMode(overflowRect);
3384 return overflowRect.maxX();
3387 void RenderLayer::computeScrollDimensions()
3389 RenderBox* box = renderBox();
3392 m_scrollDimensionsDirty = false;
3394 m_scrollSize.setWidth(roundToInt(overflowRight() - overflowLeft()));
3395 m_scrollSize.setHeight(roundToInt(overflowBottom() - overflowTop()));
3397 int scrollableLeftOverflow = roundToInt(overflowLeft() - box->borderLeft());
3398 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3399 scrollableLeftOverflow -= verticalScrollbarWidth();
3400 int scrollableTopOverflow = roundToInt(overflowTop() - box->borderTop());
3401 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
3404 bool RenderLayer::hasScrollableHorizontalOverflow() const
3406 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
3409 bool RenderLayer::hasScrollableVerticalOverflow() const
3411 return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
3414 bool RenderLayer::hasHorizontalOverflow() const
3416 ASSERT(!m_scrollDimensionsDirty);
3418 return scrollWidth() > roundToInt(renderBox()->clientWidth());
3421 bool RenderLayer::hasVerticalOverflow() const
3423 ASSERT(!m_scrollDimensionsDirty);
3425 return scrollHeight() > roundToInt(renderBox()->clientHeight());
3428 static bool styleRequiresScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
3430 EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
3431 bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
3432 return overflow == OSCROLL && !overflowScrollActsLikeAuto;
3435 static bool styleDefinesAutomaticScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
3437 EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
3438 bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
3439 return overflow == OAUTO || overflow == OOVERLAY || overflowScrollActsLikeAuto;
3442 void RenderLayer::updateScrollbarsAfterLayout()
3444 RenderBox* box = renderBox();
3447 // List box parts handle the scrollbars by themselves so we have nothing to do.
3448 if (box->style().appearance() == ListboxPart)
3451 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
3452 bool hasVerticalOverflow = this->hasVerticalOverflow();
3454 // If overflow requires a scrollbar, then we just need to enable or disable.
3455 if (m_hBar && styleRequiresScrollbar(renderer().style(), HorizontalScrollbar))
3456 m_hBar->setEnabled(hasHorizontalOverflow);
3457 if (m_vBar && styleRequiresScrollbar(renderer().style(), VerticalScrollbar))
3458 m_vBar->setEnabled(hasVerticalOverflow);
3460 // Scrollbars with auto behavior may need to lay out again if scrollbars got added or removed.
3461 bool autoHorizontalScrollBarChanged = box->hasHorizontalScrollbarWithAutoBehavior() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
3462 bool autoVerticalScrollBarChanged = box->hasVerticalScrollbarWithAutoBehavior() && (hasVerticalScrollbar() != hasVerticalOverflow);
3464 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
3465 if (box->hasHorizontalScrollbarWithAutoBehavior())
3466 setHasHorizontalScrollbar(hasHorizontalOverflow);
3467 if (box->hasVerticalScrollbarWithAutoBehavior())
3468 setHasVerticalScrollbar(hasVerticalOverflow);
3470 updateSelfPaintingLayer();
3472 // Force an update since we know the scrollbars have changed things.
3473 #if ENABLE(DASHBOARD_SUPPORT)
3474 if (renderer().document().hasAnnotatedRegions())
3475 renderer().document().setAnnotatedRegionsDirty(true);
3478 renderer().repaint();
3480 if (renderer().style().overflowX() == OAUTO || renderer().style().overflowY() == OAUTO) {
3481 if (!m_inOverflowRelayout) {
3482 // Our proprietary overflow: overlay value doesn't trigger a layout.
3483 m_inOverflowRelayout = true;
3484 renderer().setNeedsLayout(MarkOnlyThis);
3485 if (is<RenderBlock>(renderer())) {
3486 RenderBlock& block = downcast<RenderBlock>(renderer());
3487 block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
3488 block.layoutBlock(true);
3490 renderer().layout();
3491 m_inOverflowRelayout = false;
3496 // Set up the range (and page step/line step).
3498 int clientWidth = roundToInt(box->clientWidth());
3499 int pageStep = Scrollbar::pageStep(clientWidth);
3500 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3501 m_hBar->setProportion(clientWidth, m_scrollSize.width());
3504 int clientHeight = roundToInt(box->clientHeight());
3505 int pageStep = Scrollbar::pageStep(clientHeight);
3506 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3507 m_vBar->setProportion(clientHeight, m_scrollSize.height());
3510 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
3513 void RenderLayer::updateScrollInfoAfterLayout()
3515 RenderBox* box = renderBox();
3519 m_scrollDimensionsDirty = true;
3520 ScrollOffset originalScrollOffset = scrollOffset();
3522 computeScrollDimensions();
3524 #if ENABLE(CSS_SCROLL_SNAP)
3525 // FIXME: Ensure that offsets are also updated in case of programmatic style changes.
3526 // https://bugs.webkit.org/show_bug.cgi?id=135964
3527 updateSnapOffsets();
3530 if (!box->isHTMLMarquee() && !isRubberBandInProgress()) {
3531 // Layout may cause us to be at an invalid scroll position. In this case we need
3532 // to pull our scroll offsets back to the max (or push them up to the min).
3533 ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset());
3535 // FIXME: This looks wrong. The caret adjust mode should only be enabled on editing related entry points.
3536 // This code was added to fix an issue where the text insertion point would always be drawn on the right edge
3537 // of a text field whose content overflowed its bounds. See <rdar://problem/15579797> for more details.
3538 setAdjustForIOSCaretWhenScrolling(true);
3540 if (clampedScrollOffset != scrollOffset())
3541 scrollToOffset(clampedScrollOffset);
3544 setAdjustForIOSCaretWhenScrolling(false);
3548 updateScrollbarsAfterLayout();
3550 if (originalScrollOffset != scrollOffset())
3551 scrollToOffsetWithoutAnimation(IntPoint(scrollOffset()));
3553 // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
3554 if (compositor().updateLayerCompositingState(*this))
3555 compositor().setCompositingLayersNeedRebuild();
3557 updateScrollSnapState();
3560 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
3562 const IntRect borderBox = snappedIntRect(renderBox()->borderBoxRect());
3564 if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
3567 if (rectForVerticalScrollbar(borderBox).intersects(localRect))
3570 if (scrollCornerRect().intersects(localRect))
3573 if (resizerCornerRect(*this, borderBox).intersects(localRect))
3579 bool RenderLayer::showsOverflowControls() const
3582 // Don't render (custom) scrollbars if we have accelerated scrolling.
3583 if (hasAcceleratedTouchScrolling())
3590 void RenderLayer::paintOverflowControls(GraphicsContext& context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
3592 // Don't do anything if we have no overflow.
3593 if (!renderer().hasOverflowClip())
3596 if (!showsOverflowControls())
3599 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
3600 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
3601 // will be false, and we should just tell the root layer that there are overlay scrollbars
3602 // that need to be painted. That will cause the second pass through the layer tree to run,
3603 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
3604 // second pass doesn't need to re-enter the RenderTree to get it right.
3605 if (hasOverlayScrollbars() && !paintingOverlayControls) {
3606 m_cachedOverlayScrollbarOffset = paintOffset;
3608 // It's not necessary to do the second pass if the scrollbars paint into layers.
3609 if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar()))
3611 IntRect localDamgeRect = damageRect;
3612 localDamgeRect.moveBy(-paintOffset);
3613 if (!overflowControlsIntersectRect(localDamgeRect))
3616 RenderLayer* paintingRoot = enclosingCompositingLayer();
3618 paintingRoot = renderer().view().layer();
3620 paintingRoot->setContainsDirtyOverlayScrollbars(true);
3624 // This check is required to avoid painting custom CSS scrollbars twice.
3625 if (paintingOverlayControls && !hasOverlayScrollbars())
3628 IntPoint adjustedPaintOffset = paintOffset;
3629 if (paintingOverlayControls)
3630 adjustedPaintOffset = m_cachedOverlayScrollbarOffset;
3632 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
3633 // widgets can move without layout occurring (most notably when you scroll a document that
3634 // contains fixed positioned elements).
3635 positionOverflowControls(toIntSize(adjustedPaintOffset));
3637 // Now that we're sure the scrollbars are in the right place, paint them.
3638 if (m_hBar && !layerForHorizontalScrollbar())
3639 m_hBar->paint(context, damageRect);
3640 if (m_vBar && !layerForVerticalScrollbar())
3641 m_vBar->paint(context, damageRect);
3643 if (layerForScrollCorner())
3646 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
3648 paintScrollCorner(context, adjustedPaintOffset, damageRect);
3650 // Paint our resizer last, since it sits on top of the scroll corner.
3651 paintResizer(context, adjustedPaintOffset, damageRect);
3654 void RenderLayer::paintScrollCorner(GraphicsContext& context, const IntPoint& paintOffset, const IntRect& damageRect)
3656 IntRect absRect = scrollCornerRect();
3657 absRect.moveBy(paintOffset);
3658 if (!absRect.intersects(damageRect))
3661 if (context.updatingControlTints()) {
3662 updateScrollCornerStyle();
3666 if (m_scrollCorner) {
3667 m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
3671 // We don't want to paint white if we have overlay scrollbars, since we need
3672 // to see what is behind it.
3673 if (!hasOverlayScrollbars())
3674 context.fillRect(absRect, Color::white);
3677 void RenderLayer::drawPlatformResizerImage(GraphicsContext& context, const LayoutRect& resizerCornerRect)
3679 RefPtr<Image> resizeCornerImage;
3680 FloatSize cornerResizerSize;
3681 if (renderer().document().deviceScaleFactor() >= 2) {
3682 static NeverDestroyed<Image*> resizeCornerImageHiRes(Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef());
3683 resizeCornerImage = resizeCornerImageHiRes;
3684 cornerResizerSize = resizeCornerImage->size();
3685 cornerResizerSize.scale(0.5f);
3687 static NeverDestroyed<Image*> resizeCornerImageLoRes(Image::loadPlatformResource("textAreaResizeCorner").leakRef());
3688 resizeCornerImage = resizeCornerImageLoRes;
3689 cornerResizerSize = resizeCornerImage->size();
3692 if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
3694 context.translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
3695 context.scale(FloatSize(-1.0, 1.0));
3696 if (resizeCornerImage)
3697 context.drawImage(*resizeCornerImage, FloatRect(FloatPoint(), cornerResizerSize));
3702 if (!resizeCornerImage)
3704 FloatRect imageRect = snapRectToDevicePixels(LayoutRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize), renderer().document().deviceScaleFactor());
3705 context.drawImage(*resizeCornerImage, imageRect);
3708 void RenderLayer::paintResizer(GraphicsContext& context, const LayoutPoint& paintOffset, const LayoutRect& damageRect)
3710 if (renderer().style().resize() == RESIZE_NONE)
3713 RenderBox* box = renderBox();
3716 LayoutRect absRect = resizerCornerRect(*this, box->borderBoxRect());
3717 absRect.moveBy(paintOffset);
3718 if (!absRect.intersects(damageRect))
3721 if (context.updatingControlTints()) {
3722 updateResizerStyle();
3727 m_resizer->paintIntoRect(context, paintOffset, absRect);
3731 drawPlatformResizerImage(context, absRect);
3733 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
3734 // Clipping will exclude the right and bottom edges of this frame.
3735 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
3736 GraphicsContextStateSaver stateSaver(context);
3737 context.clip(absRect);
3738 LayoutRect largerCorner = absRect;
3739 largerCorner.setSize(LayoutSize(largerCorner.width() + LayoutUnit::fromPixel(1), largerCorner.height() + LayoutUnit::fromPixel(1)));
3740 context.setStrokeColor(Color(makeRGB(217, 217, 217)));
3741 context.setStrokeThickness(1.0f);
3742 context.setFillColor(Color::transparent);
3743 context.drawRect(snappedIntRect(largerCorner));
3747 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
3752 RenderBox* box = renderBox();
3755 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3757 IntRect localBounds(IntPoint(), snappedIntRect(box->frameRect()).size());
3758 return resizerCornerRect(*this, localBounds).contains(localPoint);
3761 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
3763 if (!m_hBar && !m_vBar && !canResize())
3766 RenderBox* box = renderBox();
3769 IntRect resizeControlRect;
3770 if (renderer().style().resize() != RESIZE_NONE) {
3771 resizeControlRect = snappedIntRect(resizerCornerRect(*this, box->borderBoxRect()));
3772 if (resizeControlRect.contains(localPoint))
3776 int resizeControlSize = std::max(resizeControlRect.height(), 0);
3778 // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
3780 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
3781 LayoutRect vBarRect(verticalScrollbarStart(0, box->width()),
3784 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
3785 if (vBarRect.contains(localPoint)) {
3786 result.setScrollbar(m_vBar.get());
3791 resizeControlSize = std::max(resizeControlRect.width(), 0);
3792 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
3793 LayoutRect hBarRect(horizontalScrollbarStart(0),
3794 box->height() - box->borderBottom() - m_hBar->height(),
3795 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
3797 if (hBarRect.contains(localPoint)) {
3798 result.setScrollbar(m_hBar.get());
3806 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
3808 return ScrollableArea::scroll(direction, granularity, multiplier);
3811 void RenderLayer::paint(GraphicsContext& context, const LayoutRect& damageRect, const LayoutSize& subpixelAccumulation, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot, PaintLayerFlags paintFlags)
3813 OverlapTestRequestMap overlapTestRequests;
3815 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, subpixelAccumulation, subtreePaintRoot, &overlapTestRequests);
3816 paintLayer(context, paintingInfo, paintFlags);
3818 for (auto& widget : overlapTestRequests.keys())
3819 widget->setOverlapTestResult(false);
3822 void RenderLayer::paintOverlayScrollbars(GraphicsContext& context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot)
3824 if (!m_containsDirtyOverlayScrollbars)
3827 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), subtreePaintRoot);
3828 paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars);
3830 m_containsDirtyOverlayScrollbars = false;
3833 static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
3835 if (startLayer == endLayer)
3837 for (const auto* currentBlock = startLayer->renderer().containingBlock(); currentBlock && !is<RenderView>(*currentBlock); currentBlock = currentBlock->containingBlock()) {
3838 if (currentBlock->layer() == endLayer)
3845 void RenderLayer::clipToRect(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const ClipRect& clipRect, BorderRadiusClippingRule rule)
3847 float deviceScaleFactor = renderer().document().deviceScaleFactor();
3848 bool needsClipping = !clipRect.isInfinite() && clipRect.rect() != paintingInfo.paintDirtyRect;
3849 if (needsClipping || clipRect.affectedByRadius())
3852 if (needsClipping) {
3853 LayoutRect adjustedClipRect = clipRect.rect();
3854 adjustedClipRect.move(paintingInfo.subpixelAccumulation);
3855 context.clip(snapRectToDevicePixels(adjustedClipRect, deviceScaleFactor));
3858 if (clipRect.affectedByRadius()) {
3859 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
3860 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
3861 // containing block chain so we check that also.
3862 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
3863 if (layer->renderer().hasOverflowClip() && layer->renderer().style().hasBorderRadius() && inContainingBlockChain(this, layer)) {
3864 LayoutRect adjustedClipRect = LayoutRect(toLayoutPoint(layer->offsetFromAncestor(paintingInfo.rootLayer, AdjustForColumns)), layer->size());
3865 adjustedClipRect.move(paintingInfo.subpixelAccumulation);
3866 FloatRoundedRect roundedRect = layer->renderer().style().getRoundedInnerBorderFor(adjustedClipRect).pixelSnappedRoundedRectForPainting(deviceScaleFactor);
3867 if (roundedRect.intersectionIsRectangular(paintingInfo.paintDirtyRect))
3868 context.clip(snapRectToDevicePixels(intersection(paintingInfo.paintDirtyRect, adjustedClipRect), deviceScaleFactor));
3870 context.clipRoundedRect(roundedRect);
3873 if (layer == paintingInfo.rootLayer)
3879 void RenderLayer::restoreClip(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const ClipRect& clipRect)
3881 if ((!clipRect.isInfinite() && clipRect.rect() != paintingInfo.paintDirtyRect) || clipRect.affectedByRadius())
3885 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
3887 Vector<OverlapTestRequestClient*> overlappedRequestClients;
3888 LayoutRect boundingBox = layer->boundingBox(rootLayer, layer->offsetFromAncestor(rootLayer));
3889 for (auto& request : overlapTestRequests) {
3890 if (!boundingBox.intersects(request.value))
3893 request.key->setOverlapTestResult(true);
3894 overlappedRequestClients.append(request.key);
3896 for (auto* client : overlappedRequestClients)
3897 overlapTestRequests.remove(client);
3900 static inline bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
3902 return paintingReflection && !layer->has3DTransform();
3905 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
3907 // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
3908 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
3909 // will do a full repaint().
3910 if (layer->renderer().document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer().isDocumentElementRenderer())
3913 // Avoid painting all layers if the document is in a state where visual updates aren't allowed.
3914 // A full repaint will occur in Document::setVisualUpdatesAllowed(bool) if painting is suppressed here.
3915 if (!layer->renderer().document().visualUpdatesAllowed())
3921 static inline bool paintForFixedRootBackground(const RenderLayer* layer, RenderLayer::PaintLayerFlags paintFlags)
3923 return layer->renderer().isDocumentElementRenderer() && (paintFlags & RenderLayer::PaintLayerPaintingRootBackgroundOnly);
3926 void RenderLayer::paintLayer(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3928 if (isComposited()) {
3929 // The updatingControlTints() painting pass goes through compositing layers,
3930 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
3931 if (context.updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers))
3932 paintFlags |= PaintLayerTemporaryClipRects;
3933 else if (!backing()->paintsIntoWindow()
3934 && !backing()->paintsIntoCompositedAncestor()
3935 && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)
3936 && !paintForFixedRootBackground(this, paintFlags)) {
3937 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
3940 } else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) {
3941 // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible
3942 // unless their position or viewport size is changed.
3943 ASSERT(renderer().style().position() == FixedPosition);
3947 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
3948 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
3951 if (shouldSuppressPaintingLayer(this))
3954 // If this layer is totally invisible then there is nothing to paint.
3955 if (!renderer().opacity())
3958 // Don't paint the layer if the renderer doesn't belong to this region.
3959 // This is true as long as we clamp the range of a box to its containing block range.
3960 RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
3961 if (namedFlowFragment) {
3962 ASSERT(namedFlowFragment->isValid());
3963 if (!namedFlowFragment->flowThread()->objectShouldFragmentInFlowRegion(&renderer(), namedFlowFragment))
3967 if (paintsWithTransparency(paintingInfo.paintBehavior))
3968 paintFlags |= PaintLayerHaveTransparency;
3970 // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice.
3971 if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
3972 TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
3973 // If the transform can't be inverted, then don't paint anything.
3974 if (!layerTransform.isInvertible())
3977 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency