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 "NoEventDispatchAssertion.h"
84 #include "OverflowEvent.h"
85 #include "OverlapTestRequestClient.h"
87 #include "PlatformMouseEvent.h"
88 #include "RenderFlowThread.h"
89 #include "RenderGeometryMap.h"
90 #include "RenderInline.h"
91 #include "RenderIterator.h"
92 #include "RenderLayerBacking.h"
93 #include "RenderLayerCompositor.h"
94 #include "RenderLayerFilterInfo.h"
95 #include "RenderMarquee.h"
96 #include "RenderMultiColumnFlowThread.h"
97 #include "RenderNamedFlowFragment.h"
98 #include "RenderNamedFlowThread.h"
99 #include "RenderRegion.h"
100 #include "RenderReplica.h"
101 #include "RenderSVGResourceClipper.h"
102 #include "RenderScrollbar.h"
103 #include "RenderScrollbarPart.h"
104 #include "RenderTableCell.h"
105 #include "RenderTableRow.h"
106 #include "RenderText.h"
107 #include "RenderTheme.h"
108 #include "RenderTreeAsText.h"
109 #include "RenderView.h"
110 #include "SVGNames.h"
111 #include "ScaleTransformOperation.h"
112 #include "ScrollAnimator.h"
113 #include "Scrollbar.h"
114 #include "ScrollbarTheme.h"
115 #include "ScrollingCoordinator.h"
116 #include "Settings.h"
117 #include "ShadowRoot.h"
118 #include "SourceGraphic.h"
119 #include "StyleProperties.h"
120 #include "StyleResolver.h"
121 #include "TextStream.h"
122 #include "TransformationMatrix.h"
123 #include "TranslateTransformOperation.h"
124 #include "WheelEventTestTrigger.h"
126 #include <wtf/StdLibExtras.h>
127 #include <wtf/text/CString.h>
129 #if ENABLE(CSS_SCROLL_SNAP)
130 #include "AxisScrollSnapOffsets.h"
133 #define MIN_INTERSECT_FOR_REVEAL 32
137 using namespace HTMLNames;
140 WTF_MAKE_FAST_ALLOCATED;
142 static Ref<ClipRects> create()
144 return adoptRef(*new ClipRects);
147 static Ref<ClipRects> create(const ClipRects& other)
149 return adoptRef(*new ClipRects(other));
152 ClipRects() = default;
156 m_overflowClipRect.reset();
157 m_fixedClipRect.reset();
158 m_posClipRect.reset();
162 const ClipRect& overflowClipRect() const { return m_overflowClipRect; }
163 void setOverflowClipRect(const ClipRect& clipRect) { m_overflowClipRect = clipRect; }
165 const ClipRect& fixedClipRect() const { return m_fixedClipRect; }
166 void setFixedClipRect(const ClipRect& clipRect) { m_fixedClipRect = clipRect; }
168 const ClipRect& posClipRect() const { return m_posClipRect; }
169 void setPosClipRect(const ClipRect& clipRect) { m_posClipRect = clipRect; }
171 bool fixed() const { return m_fixed; }
172 void setFixed(bool fixed) { m_fixed = fixed; }
174 void ref() { m_refCount++; }
181 bool operator==(const ClipRects& other) const
183 return m_overflowClipRect == other.overflowClipRect()
184 && m_fixedClipRect == other.fixedClipRect()
185 && m_posClipRect == other.posClipRect()
186 && m_fixed == other.fixed();
189 ClipRects& operator=(const ClipRects& other)
191 m_overflowClipRect = other.overflowClipRect();
192 m_fixedClipRect = other.fixedClipRect();
193 m_posClipRect = other.posClipRect();
194 m_fixed = other.fixed();
199 ClipRects(const LayoutRect& clipRect)
200 : m_overflowClipRect(clipRect)
201 , m_fixedClipRect(clipRect)
202 , m_posClipRect(clipRect)
206 ClipRects(const ClipRects& other)
207 : m_overflowClipRect(other.overflowClipRect())
208 , m_fixedClipRect(other.fixedClipRect())
209 , m_posClipRect(other.posClipRect())
210 , m_fixed(other.fixed())
214 ClipRect m_overflowClipRect;
215 ClipRect m_fixedClipRect;
216 ClipRect m_posClipRect;
217 unsigned m_refCount = 1;
218 bool m_fixed = false;
221 class ClipRectsCache {
222 WTF_MAKE_FAST_ALLOCATED;
227 for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
228 m_clipRectsRoot[i] = 0;
229 m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
234 PassRefPtr<ClipRects> getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) { return m_clipRects[getIndex(clipRectsType, respectOverflow)]; }
235 void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, PassRefPtr<ClipRects> clipRects) { m_clipRects[getIndex(clipRectsType, respectOverflow)] = clipRects; }
238 const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
239 OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
243 int getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow)
245 int index = static_cast<int>(clipRectsType);
246 if (respectOverflow == RespectOverflowClip)
247 index += static_cast<int>(NumCachedClipRectsTypes);
251 RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
254 void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
256 #if !ENABLE(3D_TRANSFORMS)
257 UNUSED_PARAM(has3DRendering);
265 RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
266 : m_isRootLayer(rendererLayerModelObject.isRenderView())
267 , m_forcedStackingContext(rendererLayerModelObject.isMedia())
268 , m_inResizeMode(false)
269 , m_scrollDimensionsDirty(true)
270 , m_normalFlowListDirty(true)
271 , m_hasSelfPaintingLayerDescendant(false)
272 , m_hasSelfPaintingLayerDescendantDirty(false)
273 , m_hasOutOfFlowPositionedDescendant(false)
274 , m_hasOutOfFlowPositionedDescendantDirty(true)
275 , m_needsCompositedScrolling(false)
276 , m_descendantsAreContiguousInStackingOrder(false)
277 , m_usedTransparency(false)
278 , m_paintingInsideReflection(false)
279 , m_inOverflowRelayout(false)
280 , m_repaintStatus(NeedsNormalRepaint)
281 , m_visibleContentStatusDirty(true)
282 , m_hasVisibleContent(false)
283 , m_visibleDescendantStatusDirty(false)
284 , m_hasVisibleDescendant(false)
285 , m_registeredScrollableArea(false)
286 , m_3DTransformedDescendantStatusDirty(true)
287 , m_has3DTransformedDescendant(false)
288 , m_hasCompositingDescendant(false)
289 , m_hasTransformedAncestor(false)
290 , m_has3DTransformedAncestor(false)
291 , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
292 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
294 , m_adjustForIOSCaretWhenScrolling(false)
297 #if ENABLE(IOS_TOUCH_EVENTS)
298 , m_registeredAsTouchEventListenerForScrolling(false)
300 , m_inUserScroll(false)
301 , m_requiresScrollBoundsOriginUpdate(false)
303 , m_containsDirtyOverlayScrollbars(false)
304 , m_updatingMarqueePosition(false)
306 , m_layerListMutationAllowed(true)
308 , m_hasFilterInfo(false)
309 , m_hasComputedRepaintRect(false)
310 #if ENABLE(CSS_COMPOSITING)
311 , m_blendMode(BlendModeNormal)
312 , m_hasNotIsolatedCompositedBlendingDescendants(false)
313 , m_hasNotIsolatedBlendingDescendants(false)
314 , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
316 , m_renderer(rendererLayerModelObject)
318 , m_previous(nullptr)
322 , m_staticInlinePosition(0)
323 , m_staticBlockPosition(0)
324 , m_enclosingPaginationLayer(nullptr)
326 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
327 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
329 // Non-stacking containers should have empty z-order lists. As this is already the case,
330 // there is no need to dirty / recompute these lists.
331 m_zOrderListsDirty = isStackingContainer();
333 if (!renderer().firstChild()) {
334 m_visibleContentStatusDirty = false;
335 m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
338 if (Element* element = renderer().element()) {
339 // We save and restore only the scrollOffset as the other scroll values are recalculated.
340 m_scrollPosition = element->savedLayerScrollPosition();
341 if (!m_scrollPosition.isZero())
342 scrollAnimator().setCurrentPosition(m_scrollPosition);
343 element->setSavedLayerScrollPosition(IntPoint());
347 RenderLayer::~RenderLayer()
349 if (inResizeMode() && !renderer().documentBeingDestroyed())
350 renderer().frame().eventHandler().resizeLayerDestroyed();
352 ASSERT(m_registeredScrollableArea == renderer().view().frameView().containsScrollableArea(this));
354 if (m_registeredScrollableArea)
355 renderer().view().frameView().removeScrollableArea(this);
357 if (!renderer().documentBeingDestroyed()) {
358 #if ENABLE(IOS_TOUCH_EVENTS)
359 unregisterAsTouchEventListenerForScrolling();
361 if (Element* element = renderer().element())
362 element->setSavedLayerScrollPosition(m_scrollPosition);
365 destroyScrollbar(HorizontalScrollbar);
366 destroyScrollbar(VerticalScrollbar);
368 if (renderer().frame().page()) {
369 if (ScrollingCoordinator* scrollingCoordinator = renderer().frame().page()->scrollingCoordinator())
370 scrollingCoordinator->willDestroyScrollableArea(*this);
376 FilterInfo::remove(*this);
378 // Child layers will be deleted by their corresponding render objects, so
379 // we don't need to delete them ourselves.
384 String RenderLayer::name() const
387 name.append(renderer().renderName());
389 if (Element* element = renderer().element()) {
391 name.append(element->tagName());
393 if (element->hasID()) {
394 name.appendLiteral(" id=\'");
395 name.append(element->getIdAttribute());
399 if (element->hasClass()) {
400 name.appendLiteral(" class=\'");
401 for (size_t i = 0; i < element->classNames().size(); ++i) {
404 name.append(element->classNames()[i]);
411 name.appendLiteral(" (reflection)");
413 return name.toString();
416 RenderLayerCompositor& RenderLayer::compositor() const
418 return renderer().view().compositor();
421 void RenderLayer::contentChanged(ContentChangeType changeType)
423 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ImageChanged) && compositor().updateLayerCompositingState(*this))
424 compositor().setCompositingLayersNeedRebuild();
427 m_backing->contentChanged(changeType);
430 bool RenderLayer::canRender3DTransforms() const
432 return compositor().canRender3DTransforms();
435 bool RenderLayer::paintsWithFilters() const
437 if (!renderer().hasFilter())
443 if (!m_backing || !m_backing->canCompositeFilters())
449 bool RenderLayer::requiresFullLayerImageForFilters() const
451 if (!paintsWithFilters())
453 FilterEffectRenderer* renderer = filterRenderer();
454 return renderer && renderer->hasFilterThatMovesPixels();
457 FilterEffectRenderer* RenderLayer::filterRenderer() const
459 FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
460 return filterInfo ? filterInfo->renderer() : nullptr;
463 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
465 RenderGeometryMap geometryMap(UseTransforms);
466 if (this != rootLayer)
467 geometryMap.pushMappingsToAncestor(parent(), nullptr);
468 updateLayerPositions(&geometryMap, flags);
471 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
473 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
474 // we need to keep in sync, since we may have shifted relative
475 // to our parent layer.
477 geometryMap->pushMappingsToAncestor(this, parent());
479 // Clear our cached clip rect information.
482 if (hasOverflowControls()) {
483 LayoutSize offsetFromRoot;
485 offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
487 // FIXME: It looks suspicious to call convertToLayerCoords here
488 // as canUseConvertToLayerCoords may be true for an ancestor layer.
489 offsetFromRoot = offsetFromAncestor(root());
491 positionOverflowControls(roundedIntSize(offsetFromRoot));
494 updateDescendantDependentFlags();
496 if (flags & UpdatePagination)
499 m_enclosingPaginationLayer = nullptr;
501 if (m_hasVisibleContent) {
502 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
503 // mapping between them and the RenderObjects. It would be neat to enable
504 // LayoutState outside the layout() phase and use it here.
505 ASSERT(!renderer().view().layoutStateEnabled());
507 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
508 LayoutRect oldRepaintRect = m_repaintRect;
509 LayoutRect oldOutlineBox = m_outlineBox;
510 computeRepaintRects(repaintContainer, geometryMap);
512 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
513 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
514 if ((flags & CheckForRepaint) && m_hasComputedRepaintRect) {
515 if (!renderer().view().printing()) {
516 bool didRepaint = false;
517 if (m_repaintStatus & NeedsFullRepaint) {
518 renderer().repaintUsingContainer(repaintContainer, oldRepaintRect);
519 if (m_repaintRect != oldRepaintRect) {
520 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
523 } else if (shouldRepaintAfterLayout()) {
524 renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
528 if (didRepaint && renderer().isRenderNamedFlowFragmentContainer()) {
529 // If we just repainted a region, we must also repaint the flow thread since it is the one
530 // doing the actual painting of the flowed content.
531 RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
532 if (region.isValid())
533 region.flowThread()->layer()->repaintIncludingDescendants();
540 m_repaintStatus = NeedsNormalRepaint;
541 m_hasTransformedAncestor = flags & SeenTransformedLayer;
542 m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
544 // Update the reflection's position and size.
546 m_reflection->layout();
548 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
549 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
551 flags &= ~IsCompositingUpdateRoot;
553 if (renderer().isInFlowRenderFlowThread()) {
555 flags |= UpdatePagination;
559 flags |= SeenTransformedLayer;
560 if (!transform()->isAffine())
561 flags |= Seen3DTransformedLayer;
564 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
565 child->updateLayerPositions(geometryMap, flags);
567 if ((flags & UpdateCompositingLayers) && isComposited()) {
568 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
569 if (flags & NeedsFullRepaintInBacking)
570 updateFlags |= RenderLayerBacking::NeedsFullRepaint;
572 updateFlags |= RenderLayerBacking::IsUpdateRoot;
573 backing()->updateAfterLayout(updateFlags);
576 // With all our children positioned, now update our marquee if we need to.
578 // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
579 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
580 m_updatingMarqueePosition = true;
581 m_marquee->updateMarqueePosition();
582 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
586 geometryMap->popMappingsToAncestor(parent());
588 renderer().document().markers().invalidateRectsForAllMarkers();
591 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
593 LayoutRect repaintRect = m_repaintRect;
594 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
595 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
596 if (child->isComposited())
599 repaintRect.uniteIfNonZero(child->repaintRectIncludingNonCompositingDescendants());
604 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
606 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
607 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
610 layer->m_hasSelfPaintingLayerDescendantDirty = false;
611 layer->m_hasSelfPaintingLayerDescendant = true;
615 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
617 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
618 layer->m_hasSelfPaintingLayerDescendantDirty = true;
619 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
620 // in this case, there is no need to dirty our ancestors further.
621 if (layer->isSelfPaintingLayer()) {
622 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
628 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
630 return renderer().frame().settings().acceleratedCompositingForOverflowScrollEnabled();
633 // If we are a stacking container, then this function will determine if our
634 // descendants for a contiguous block in stacking order. This is required in
635 // order for an element to be safely promoted to a stacking container. It is safe
636 // to become a stacking container if this change would not alter the stacking
637 // order of layers on the page. That can only happen if a non-descendant appear
638 // between us and our descendants in stacking order. Here's an example:
648 // I've labeled our normal flow descendants A, B, C, and D, our stacking
649 // container descendants with their z indices, and us with 'this' (we're a
650 // stacking container and our zIndex doesn't matter here). These nodes appear in
651 // three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
652 // flow layers don't overlap). So if we arrange these lists in order we get our
655 // [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
657 // Neg z-order. <-+ +--> Normal flow descendants.
659 // We can then assign new, 'stacking' order indices to these elements as follows:
661 // [-8], [A-D], [0, 2, 5, 7]
662 // 'Stacking' indices: -1 0 1 2 3 4
664 // Note that the normal flow descendants can share an index because they don't
665 // stack/overlap. Now our problem becomes very simple: a layer can safely become
666 // a stacking container if the stacking-order indices of it and its descendants
667 // appear in a contiguous block in the list of stacking indices. This problem
668 // can be solved very efficiently by calculating the min/max stacking indices in
669 // the subtree, and the number stacking container descendants. Once we have this
670 // information, we know that the subtree's indices form a contiguous block if:
672 // maxStackIndex - minStackIndex == numSCDescendants
674 // So for node A in the example above we would have:
676 // minStackIndex = -1
677 // numSCDecendants = 2
680 // maxStackIndex - minStackIndex == numSCDescendants
681 // ===> 1 - (-1) == 2
684 // Since this is true, A can safely become a stacking container.
685 // Now, for node C we have:
688 // minStackIndex = 0 <-- because C has stacking index 0.
689 // numSCDecendants = 2
692 // maxStackIndex - minStackIndex == numSCDescendants
696 // Since this is false, C cannot be safely promoted to a stacking container. This
697 // happened because of the elements with z-index 5 and 0. Now if 5 had been a
698 // child of C rather than D, and A had no child with Z index 0, we would have had:
701 // minStackIndex = 0 <-- because C has stacking index 0.
702 // numSCDecendants = 3
705 // maxStackIndex - minStackIndex == numSCDescendants
709 // And we would conclude that C could be promoted.
710 void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
712 if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
715 ASSERT(!m_normalFlowListDirty);
716 ASSERT(!m_zOrderListsDirty);
718 std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
719 std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
720 rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
722 // Create a reverse lookup.
723 HashMap<const RenderLayer*, int> lookup;
726 int stackingOrderIndex = -1;
727 size_t listSize = negZOrderList->size();
728 for (size_t i = 0; i < listSize; ++i) {
729 RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
730 if (!currentLayer->isStackingContext())
732 lookup.set(currentLayer, stackingOrderIndex--);
737 size_t listSize = posZOrderList->size();
738 int stackingOrderIndex = 1;
739 for (size_t i = 0; i < listSize; ++i) {
740 RenderLayer* currentLayer = posZOrderList->at(i);
741 if (!currentLayer->isStackingContext())
743 lookup.set(currentLayer, stackingOrderIndex++);
750 bool firstIteration = true;
751 updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
754 void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
756 if (isStackingContext() && !firstIteration) {
757 if (lookup.contains(this)) {
758 minIndex = std::min(minIndex, lookup.get(this));
759 maxIndex = std::max(maxIndex, lookup.get(this));
765 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
766 int childMinIndex = 0;
767 int childMaxIndex = 0;
769 child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
772 minIndex = std::min(minIndex, childMinIndex);
773 maxIndex = std::max(maxIndex, childMaxIndex);
777 if (!isStackingContext()) {
778 bool newValue = maxIndex - minIndex == count;
779 bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
780 m_descendantsAreContiguousInStackingOrder = newValue;
782 updateNeedsCompositedScrolling();
786 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
788 ASSERT(!m_visibleContentStatusDirty);
790 if (!isSelfPaintingLayer()) {
795 m_hasComputedRepaintRect = true;
796 m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer);
797 m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap);
801 void RenderLayer::computeRepaintRectsIncludingDescendants()
803 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
804 // We should make this more efficient.
805 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
806 computeRepaintRects(renderer().containerForRepaint());
808 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
809 layer->computeRepaintRectsIncludingDescendants();
812 void RenderLayer::clearRepaintRects()
814 ASSERT(!m_visibleContentStatusDirty);
816 m_hasComputedRepaintRect = false;
817 m_repaintRect = LayoutRect();
818 m_outlineBox = LayoutRect();
821 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
823 ASSERT(this == renderer().view().layer());
825 RenderGeometryMap geometryMap(UseTransforms);
826 updateLayerPositionsAfterScroll(&geometryMap);
829 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
831 RenderGeometryMap geometryMap(UseTransforms);
832 if (this != renderer().view().layer())
833 geometryMap.pushMappingsToAncestor(parent(), nullptr);
835 // FIXME: why is it OK to not check the ancestors of this layer in order to
836 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
837 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
840 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
842 // FIXME: This shouldn't be needed, but there are some corner cases where
843 // these flags are still dirty. Update so that the check below is valid.
844 updateDescendantDependentFlags();
846 // If we have no visible content and no visible descendants, there is no point recomputing
847 // our rectangles as they will be empty. If our visibility changes, we are expected to
848 // recompute all our positions anyway.
849 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
852 bool positionChanged = updateLayerPosition();
854 flags |= HasChangedAncestor;
856 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
859 if (renderer().style().hasViewportConstrainedPosition())
860 flags |= HasSeenViewportConstrainedAncestor;
862 if (renderer().hasOverflowClip())
863 flags |= HasSeenAncestorWithOverflowClip;
865 bool shouldComputeRepaintRects = (flags & HasSeenViewportConstrainedAncestor || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) && isSelfPaintingLayer();
866 bool isVisuallyEmpty = !isVisuallyNonEmpty();
867 bool shouldPushAndPopMappings = geometryMap && ((shouldComputeRepaintRects && !isVisuallyEmpty) || firstChild());
868 if (shouldPushAndPopMappings)
869 geometryMap->pushMappingsToAncestor(this, parent());
871 if (shouldComputeRepaintRects) {
872 // When scrolling, we don't compute repaint rects for visually non-empty layers.
875 else // FIXME: We could track the repaint container as we walk down the tree.
876 computeRepaintRects(renderer().containerForRepaint(), geometryMap);
878 // Check that our cached rects are correct.
879 ASSERT(!m_hasComputedRepaintRect || (m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint())));
880 ASSERT(!m_hasComputedRepaintRect || m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
883 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
884 child->updateLayerPositionsAfterScroll(geometryMap, flags);
886 // We don't update our reflection as scrolling is a translation which does not change the size()
887 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
891 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
892 m_updatingMarqueePosition = true;
893 m_marquee->updateMarqueePosition();
894 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
897 if (shouldPushAndPopMappings)
898 geometryMap->popMappingsToAncestor(parent());
900 renderer().document().markers().invalidateRectsForAllMarkers();
903 void RenderLayer::positionNewlyCreatedOverflowControls()
905 if (!backing()->hasUnpositionedOverflowControlsLayers())
908 RenderGeometryMap geometryMap(UseTransforms);
909 if (this != renderer().view().layer() && parent())
910 geometryMap.pushMappingsToAncestor(parent(), nullptr);
912 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
913 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
916 #if ENABLE(CSS_COMPOSITING)
918 void RenderLayer::updateBlendMode()
920 bool hadBlendMode = m_blendMode != BlendModeNormal;
921 if (parent() && hadBlendMode != hasBlendMode()) {
923 parent()->updateAncestorChainHasBlendingDescendants();
925 parent()->dirtyAncestorChainHasBlendingDescendants();
928 BlendMode newBlendMode = renderer().style().blendMode();
929 if (newBlendMode != m_blendMode)
930 m_blendMode = newBlendMode;
933 void RenderLayer::updateAncestorChainHasBlendingDescendants()
935 for (auto* layer = this; layer; layer = layer->parent()) {
936 if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
938 layer->m_hasNotIsolatedBlendingDescendants = true;
939 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
941 layer->updateSelfPaintingLayer();
943 if (layer->isStackingContext())
948 void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
950 for (auto* layer = this; layer; layer = layer->parent()) {
951 if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
954 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
956 if (layer->isStackingContext())
962 void RenderLayer::updateTransform()
964 bool hasTransform = renderer().hasTransform();
965 bool had3DTransform = has3DTransform();
967 bool hadTransform = !!m_transform;
968 if (hasTransform != hadTransform) {
970 m_transform = std::make_unique<TransformationMatrix>();
972 m_transform = nullptr;
974 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
975 clearClipRectsIncludingDescendants();
979 RenderBox* box = renderBox();
981 m_transform->makeIdentity();
982 box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
983 makeMatrixRenderable(*m_transform, canRender3DTransforms());
986 if (had3DTransform != has3DTransform())
987 dirty3DTransformedDescendantStatus();
990 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
993 return TransformationMatrix();
995 RenderBox* box = renderBox();
997 if (renderer().style().isRunningAcceleratedAnimation()) {
998 TransformationMatrix currTransform;
999 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1000 std::unique_ptr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(renderer());
1001 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
1002 makeMatrixRenderable(currTransform, canRender3DTransforms());
1003 return currTransform;
1006 // m_transform includes transform-origin, so we need to recompute the transform here.
1007 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
1008 TransformationMatrix currTransform;
1009 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1010 box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
1011 makeMatrixRenderable(currTransform, canRender3DTransforms());
1012 return currTransform;
1015 return *m_transform;
1018 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
1021 return TransformationMatrix();
1023 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
1024 TransformationMatrix matrix = *m_transform;
1025 makeMatrixRenderable(matrix, false /* flatten 3d */);
1029 return *m_transform;
1032 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
1034 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
1036 if (layer->renderer().hasOverflowClip())
1037 return const_cast<RenderLayer*>(layer);
1039 layer = layer->parent();
1044 // FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
1045 // painting of content inside paginated layers.
1046 bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
1048 // No enclosing layer means no compositing in the chain.
1049 if (!m_enclosingPaginationLayer)
1052 // If the enclosing layer is composited, we don't have to check anything in between us and that
1054 if (m_enclosingPaginationLayer->isComposited())
1057 // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
1059 if (m_enclosingPaginationLayer == this)
1062 // The enclosing paginated layer is our ancestor and is not composited, so we have to check
1063 // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
1067 // For normal flow layers, we can recur up the layer tree.
1068 if (isNormalFlowOnly())
1069 return parent()->hasCompositedLayerInEnclosingPaginationChain();
1071 // Otherwise we have to go up the containing block chain. Find the first enclosing
1072 // containing block layer ancestor, and check that.
1073 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1074 if (containingBlock->hasLayer())
1075 return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
1080 void RenderLayer::updatePagination()
1082 m_enclosingPaginationLayer = nullptr;
1087 // Each layer that is inside a multicolumn flow thread has to be checked individually and
1088 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
1089 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
1090 // to that layer easily.
1091 if (renderer().isInFlowRenderFlowThread()) {
1092 m_enclosingPaginationLayer = this;
1096 if (isNormalFlowOnly()) {
1097 // Content inside a transform is not considered to be paginated, since we simply
1098 // paint the transform multiple times in each column, so we don't have to use
1099 // fragments for the transformed content.
1100 if (parent()->hasTransform())
1101 m_enclosingPaginationLayer = nullptr;
1103 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1107 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
1108 // we find one, then we just check its pagination status.
1109 for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
1110 if (containingBlock->hasLayer()) {
1111 // Content inside a transform is not considered to be paginated, since we simply
1112 // paint the transform multiple times in each column, so we don't have to use
1113 // fragments for the transformed content.
1114 if (containingBlock->layer()->hasTransform())
1115 m_enclosingPaginationLayer = nullptr;
1117 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
1123 bool RenderLayer::canBeStackingContainer() const
1125 if (isStackingContext() || !stackingContainer())
1128 return m_descendantsAreContiguousInStackingOrder;
1131 void RenderLayer::setHasVisibleContent()
1133 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1134 ASSERT(!parent() || parent()->hasVisibleDescendant());
1138 m_visibleContentStatusDirty = false;
1139 m_hasVisibleContent = true;
1140 computeRepaintRects(renderer().containerForRepaint());
1141 if (!isNormalFlowOnly()) {
1142 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1143 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1144 // collected. FIXME: When compositing, we could skip this dirtying phase.
1145 for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
1146 sc->dirtyZOrderLists();
1147 if (sc->hasVisibleContent())
1153 parent()->setAncestorChainHasVisibleDescendant();
1156 void RenderLayer::dirtyVisibleContentStatus()
1158 m_visibleContentStatusDirty = true;
1160 parent()->dirtyAncestorChainVisibleDescendantStatus();
1163 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1165 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1166 if (layer->m_visibleDescendantStatusDirty)
1169 layer->m_visibleDescendantStatusDirty = true;
1173 void RenderLayer::setAncestorChainHasVisibleDescendant()
1175 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1176 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1179 layer->m_hasVisibleDescendant = true;
1180 layer->m_visibleDescendantStatusDirty = false;
1184 void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
1186 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
1187 bool hasVisibleDescendant = false;
1188 bool hasSelfPaintingLayerDescendant = false;
1189 bool hasOutOfFlowPositionedDescendant = false;
1190 #if ENABLE(CSS_COMPOSITING)
1191 bool hasNotIsolatedBlendingDescendants = false;
1194 HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
1195 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1196 childOutOfFlowDescendantContainingBlocks.clear();
1197 child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
1199 bool childIsOutOfFlowPositioned = child->renderer().isOutOfFlowPositioned();
1200 if (childIsOutOfFlowPositioned)
1201 childOutOfFlowDescendantContainingBlocks.add(child->renderer().containingBlock());
1203 if (outOfFlowDescendantContainingBlocks) {
1204 HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
1205 for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
1206 outOfFlowDescendantContainingBlocks->add(*it);
1209 hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1210 hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1211 hasOutOfFlowPositionedDescendant |= !childOutOfFlowDescendantContainingBlocks.isEmpty();
1212 #if ENABLE(CSS_COMPOSITING)
1213 hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
1216 bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant;
1217 #if ENABLE(CSS_COMPOSITING)
1218 allFlagsSet &= hasNotIsolatedBlendingDescendants;
1224 if (outOfFlowDescendantContainingBlocks)
1225 outOfFlowDescendantContainingBlocks->remove(&renderer());
1227 m_hasVisibleDescendant = hasVisibleDescendant;
1228 m_visibleDescendantStatusDirty = false;
1229 m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
1230 m_hasSelfPaintingLayerDescendantDirty = false;
1232 m_hasOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant;
1233 if (m_hasOutOfFlowPositionedDescendantDirty)
1234 updateNeedsCompositedScrolling();
1236 m_hasOutOfFlowPositionedDescendantDirty = false;
1237 #if ENABLE(CSS_COMPOSITING)
1238 m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
1239 if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
1240 m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1241 updateSelfPaintingLayer();
1246 if (m_visibleContentStatusDirty) {
1247 if (renderer().style().visibility() == VISIBLE)
1248 m_hasVisibleContent = true;
1250 // layer may be hidden but still have some visible content, check for this
1251 m_hasVisibleContent = false;
1252 RenderObject* r = renderer().firstChild();
1254 if (r->style().visibility() == VISIBLE && !r->hasLayer()) {
1255 m_hasVisibleContent = true;
1258 RenderObject* child = nullptr;
1259 if (!r->hasLayer() && (child = r->firstChildSlow()))
1261 else if (r->nextSibling())
1262 r = r->nextSibling();
1266 if (r == &renderer())
1268 } while (r && !r->nextSibling());
1270 r = r->nextSibling();
1274 m_visibleContentStatusDirty = false;
1278 void RenderLayer::dirty3DTransformedDescendantStatus()
1280 RenderLayer* curr = stackingContainer();
1282 curr->m_3DTransformedDescendantStatusDirty = true;
1284 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1285 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1286 while (curr && curr->preserves3D()) {
1287 curr->m_3DTransformedDescendantStatusDirty = true;
1288 curr = curr->stackingContainer();
1292 // Return true if this layer or any preserve-3d descendants have 3d.
1293 bool RenderLayer::update3DTransformedDescendantStatus()
1295 if (m_3DTransformedDescendantStatusDirty) {
1296 m_has3DTransformedDescendant = false;
1298 updateZOrderLists();
1300 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1301 // in the normal flow list, so we only need to check those.
1302 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
1303 for (auto* layer : *positiveZOrderList)
1304 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1307 // Now check our negative z-index children.
1308 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
1309 for (auto* layer : *negativeZOrderList)
1310 m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
1313 m_3DTransformedDescendantStatusDirty = false;
1316 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1317 // the m_has3DTransformedDescendant set.
1319 return has3DTransform() || m_has3DTransformedDescendant;
1321 return has3DTransform();
1324 bool RenderLayer::updateLayerPosition()
1326 LayoutPoint localPoint;
1327 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1328 if (renderer().isInline() && is<RenderInline>(renderer())) {
1329 auto& inlineFlow = downcast<RenderInline>(renderer());
1330 IntRect lineBox = inlineFlow.linesBoundingBox();
1331 setSize(lineBox.size());
1332 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1333 localPoint += inlineBoundingBoxOffset;
1334 } else if (RenderBox* box = renderBox()) {
1335 // FIXME: Is snapping the size really needed here for the RenderBox case?
1336 setSize(snappedIntRect(box->frameRect()).size());
1337 box->applyTopLeftLocationOffset(localPoint);
1340 RenderElement* ancestor;
1341 if (!renderer().isOutOfFlowPositioned() && (ancestor = renderer().parent())) {
1342 // We must adjust our position by walking up the render tree looking for the
1343 // nearest enclosing object with a layer.
1344 while (ancestor && !ancestor->hasLayer()) {
1345 if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
1346 // Rows and cells share the same coordinate space (that of the section).
1347 // Omit them when computing our xpos/ypos.
1348 localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1350 ancestor = ancestor->parent();
1352 if (is<RenderBox>(*ancestor) && is<RenderTableRow>(*ancestor)) {
1353 // Put ourselves into the row coordinate space.
1354 localPoint -= downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1358 // Subtract our parent's scroll offset.
1359 RenderLayer* positionedParent;
1360 if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
1361 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1362 if (positionedParent->renderer().hasOverflowClip())
1363 localPoint -= toLayoutSize(positionedParent->scrollPosition());
1365 if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
1366 LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
1367 localPoint += offset;
1369 } else if (parent()) {
1370 if (parent()->renderer().hasOverflowClip())
1371 localPoint -= toLayoutSize(parent()->scrollPosition());
1374 bool positionOrOffsetChanged = false;
1375 if (renderer().isInFlowPositioned()) {
1376 LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
1377 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
1378 m_offsetForInFlowPosition = newOffset;
1379 localPoint.move(m_offsetForInFlowPosition);
1381 m_offsetForInFlowPosition = LayoutSize();
1384 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1385 localPoint -= inlineBoundingBoxOffset;
1387 positionOrOffsetChanged |= location() != localPoint;
1388 setLocation(localPoint);
1389 return positionOrOffsetChanged;
1392 TransformationMatrix RenderLayer::perspectiveTransform() const
1394 RenderBox* box = renderBox();
1396 return TransformationMatrix();
1398 if (!box->hasTransformRelatedProperty())
1399 return TransformationMatrix();
1401 const RenderStyle& style = box->style();
1402 if (!style.hasPerspective())
1403 return TransformationMatrix();
1405 // Maybe fetch the perspective from the backing?
1406 const FloatRect borderBox = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
1407 float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), borderBox.width());
1408 float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), borderBox.height());
1410 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
1411 // We want it to be in the top-left, so subtract half the height and width.
1412 perspectiveOriginX -= borderBox.width() / 2.0f;
1413 perspectiveOriginY -= borderBox.height() / 2.0f;
1415 TransformationMatrix t;
1416 t.translate(perspectiveOriginX, perspectiveOriginY);
1417 t.applyPerspective(style.perspective());
1418 t.translate(-perspectiveOriginX, -perspectiveOriginY);
1423 FloatPoint RenderLayer::perspectiveOrigin() const
1425 if (!renderer().hasTransformRelatedProperty())
1426 return FloatPoint();
1428 const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
1429 const RenderStyle& style = renderer().style();
1431 return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
1432 floatValueForLength(style.perspectiveOriginY(), borderBox.height()));
1435 RenderLayer* RenderLayer::stackingContainer() const
1437 RenderLayer* layer = parent();
1438 while (layer && !layer->isStackingContainer())
1439 layer = layer->parent();
1441 ASSERT(!layer || layer->isStackingContainer());
1445 static inline bool isContainerForPositioned(RenderLayer& layer, EPosition position)
1449 return layer.renderer().canContainFixedPositionObjects();
1451 case AbsolutePosition:
1452 return layer.renderer().canContainAbsolutelyPositionedObjects();
1455 ASSERT_NOT_REACHED();
1460 RenderLayer* RenderLayer::enclosingAncestorForPosition(EPosition position) const
1462 RenderLayer* curr = parent();
1463 while (curr && !isContainerForPositioned(*curr, position))
1464 curr = curr->parent();
1469 static RenderLayer* parentLayerCrossFrame(const RenderLayer& layer)
1472 return layer.parent();
1474 HTMLFrameOwnerElement* ownerElement = layer.renderer().document().ownerElement();
1478 RenderElement* ownerRenderer = ownerElement->renderer();
1482 return ownerRenderer->enclosingLayer();
1485 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1487 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
1488 if (is<RenderBox>(nextLayer->renderer()) && downcast<RenderBox>(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
1495 IntRect RenderLayer::scrollableAreaBoundingBox(bool* isInsideFixed) const
1497 return renderer().absoluteBoundingBoxRect(/* useTransforms */ true, isInsideFixed);
1500 bool RenderLayer::isRubberBandInProgress() const
1502 #if ENABLE(RUBBER_BANDING)
1503 if (!scrollsOverflow())
1506 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1507 return scrollAnimator->isRubberBandInProgress();
1513 bool RenderLayer::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
1515 Page* page = renderer().frame().page();
1516 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
1519 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1521 RenderLayer* curr = parent();
1522 while (curr && !curr->isRootLayer() && !curr->transform())
1523 curr = curr->parent();
1528 static inline const RenderLayer* compositingContainer(const RenderLayer& layer)
1530 return layer.isNormalFlowOnly() ? layer.parent() : layer.stackingContainer();
1533 inline bool RenderLayer::shouldRepaintAfterLayout() const
1535 if (m_repaintStatus == NeedsNormalRepaint)
1538 // Composited layers that were moved during a positioned movement only
1539 // layout, don't need to be repainted. They just need to be recomposited.
1540 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1541 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1544 bool compositedWithOwnBackingStore(const RenderLayer& layer)
1546 return layer.isComposited() && !layer.backing()->paintsIntoCompositedAncestor();
1549 RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
1551 if (includeSelf == IncludeSelf && isComposited())
1552 return const_cast<RenderLayer*>(this);
1554 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1555 if (curr->isComposited())
1556 return const_cast<RenderLayer*>(curr);
1562 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
1564 if (includeSelf == IncludeSelf && compositedWithOwnBackingStore(*this))
1565 return const_cast<RenderLayer*>(this);
1567 for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
1568 if (compositedWithOwnBackingStore(*curr))
1569 return const_cast<RenderLayer*>(curr);
1575 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
1577 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
1578 for (; curr; curr = curr->parent()) {
1579 if (curr->requiresFullLayerImageForFilters())
1580 return const_cast<RenderLayer*>(curr);
1586 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1588 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1589 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(*curr) || curr->isRootLayer())
1590 return const_cast<RenderLayer*>(curr);
1595 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
1600 LayoutRect rectForRepaint = rect;
1601 renderer().style().filterOutsets().expandRect(rectForRepaint);
1603 FilterInfo& filterInfo = FilterInfo::get(*this);
1604 filterInfo.expandDirtySourceRect(rectForRepaint);
1606 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1607 ASSERT(parentLayer);
1608 FloatQuad repaintQuad(rectForRepaint);
1609 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1611 if (parentLayer->isComposited()) {
1612 if (!parentLayer->backing()->paintsIntoWindow()) {
1613 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1616 // If the painting goes to window, redirect the painting to the parent RenderView.
1617 parentLayer = renderer().view().layer();
1618 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1621 if (parentLayer->paintsWithFilters()) {
1622 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
1626 if (parentLayer->isRootLayer()) {
1627 downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
1631 ASSERT_NOT_REACHED();
1634 bool RenderLayer::hasAncestorWithFilterOutsets() const
1636 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1637 if (curr->renderer().style().hasFilterOutsets())
1643 RenderLayer* RenderLayer::clippingRootForPainting() const
1646 return const_cast<RenderLayer*>(this);
1648 const RenderLayer* current = this;
1650 if (current->isRootLayer())
1651 return const_cast<RenderLayer*>(current);
1653 current = compositingContainer(*current);
1655 if (current->transform() || compositedWithOwnBackingStore(*current))
1656 return const_cast<RenderLayer*>(current);
1659 ASSERT_NOT_REACHED();
1663 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1665 // We don't use convertToLayerCoords because it doesn't know about transforms
1666 return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
1669 bool RenderLayer::cannotBlitToWindow() const
1671 if (isTransparent() || hasReflection() || hasTransform())
1675 return parent()->cannotBlitToWindow();
1678 RenderLayer* RenderLayer::transparentPaintingAncestor()
1683 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1684 if (curr->isComposited())
1686 if (curr->isTransparent())
1692 enum TransparencyClipBoxBehavior {
1693 PaintingTransparencyClipBox,
1694 HitTestingTransparencyClipBox
1697 enum TransparencyClipBoxMode {
1698 DescendantsOfTransparencyClipBox,
1699 RootOfTransparencyClipBox
1702 static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
1704 static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1705 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1707 // If this is a region, then the painting is actually done by its flow thread's layer.
1708 if (layer.renderer().isRenderNamedFlowFragmentContainer()) {
1709 RenderBlockFlow& regionContainer = downcast<RenderBlockFlow>(layer.renderer());
1710 RenderNamedFlowFragment& region = *regionContainer.renderNamedFlowFragment();
1711 RenderLayer* flowThreadLayer = region.flowThread()->layer();
1712 if (flowThreadLayer && (!layer.reflection() || layer.reflectionLayer() != flowThreadLayer)) {
1713 LayoutRect flowThreadClipRect = transparencyClipBox(*flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
1714 LayoutSize moveOffset = (regionContainer.contentBoxRect().location() + layer.offsetFromAncestor(flowThreadLayer)) - region.flowThreadPortionRect().location();
1715 flowThreadClipRect.move(moveOffset);
1717 clipRect.unite(flowThreadClipRect);
1722 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1723 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1725 // If we have a mask, then the clip is limited to the border box area (and there is
1726 // no need to examine child layers).
1727 if (!layer.renderer().hasMask()) {
1728 // Note: we don't have to walk z-order lists since transparent elements always establish
1729 // a stacking container. This means we can just walk the layer tree directly.
1730 for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
1731 if (!layer.reflection() || layer.reflectionLayer() != curr)
1732 clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
1736 expandClipRectForRegionAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1738 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1739 // current transparencyClipBox to catch all child layers.
1740 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1741 // size into the parent layer.
1742 if (layer.renderer().hasReflection()) {
1743 LayoutSize delta = layer.offsetFromAncestor(rootLayer);
1744 clipRect.move(-delta);
1745 clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
1746 clipRect.move(delta);
1750 static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1751 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
1753 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1754 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1755 // would be better to respect clips.
1757 if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
1758 || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
1759 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1760 // the transformed layer and all of its children.
1761 RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
1762 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : nullptr;
1763 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1764 LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
1766 TransformationMatrix transform;
1767 transform.translate(delta.width(), delta.height());
1768 transform.multiply(*layer.transform());
1770 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1771 // paints unfragmented.
1772 LayoutRect clipRect = layer.boundingBox(&layer);
1773 expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
1774 layer.renderer().style().filterOutsets().expandRect(clipRect);
1775 LayoutRect result = transform.mapRect(clipRect);
1776 if (!paginationLayer)
1779 // We have to break up the transformed extent across our columns.
1780 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1781 // get our true bounding box.
1782 auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
1783 result = enclosingFlowThread.fragmentsBoundingBox(result);
1784 result.move(paginationLayer->offsetFromAncestor(rootLayer));
1788 LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
1789 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1790 layer.renderer().style().filterOutsets().expandRect(clipRect);
1795 static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1797 return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
1800 void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
1802 if (context.paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
1805 RenderLayer* ancestor = transparentPaintingAncestor();
1807 ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
1809 if (paintsWithTransparency(paintingInfo.paintBehavior)) {
1810 m_usedTransparency = true;
1812 LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
1813 adjustedClipRect.move(paintingInfo.subpixelAccumulation);
1814 FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
1815 context.clip(pixelSnappedClipRect);
1817 #if ENABLE(CSS_COMPOSITING)
1818 bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRootLayer());
1819 if (usesCompositeOperation)
1820 context.setCompositeOperation(context.compositeOperation(), blendMode());
1823 context.beginTransparencyLayer(renderer().opacity());
1825 #if ENABLE(CSS_COMPOSITING)
1826 if (usesCompositeOperation)
1827 context.setCompositeOperation(context.compositeOperation(), BlendModeNormal);
1830 #ifdef REVEAL_TRANSPARENCY_LAYERS
1831 context.setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
1832 context.fillRect(pixelSnappedClipRect);
1838 void RenderLayer::willBeDestroyed()
1840 if (RenderLayerBacking* layerBacking = backing())
1841 layerBacking->layerWillBeDestroyed();
1845 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1847 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1849 child->setPreviousSibling(prevSibling);
1850 prevSibling->setNextSibling(child);
1851 ASSERT(prevSibling != child);
1853 setFirstChild(child);
1856 beforeChild->setPreviousSibling(child);
1857 child->setNextSibling(beforeChild);
1858 ASSERT(beforeChild != child);
1860 setLastChild(child);
1862 child->setParent(this);
1864 if (child->isNormalFlowOnly())
1865 dirtyNormalFlowList();
1867 if (!child->isNormalFlowOnly() || child->firstChild()) {
1868 // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
1869 // case where we're building up generated content layers. This is ok, since the lists will start
1870 // off dirty in that case anyway.
1871 child->dirtyStackingContainerZOrderLists();
1874 child->updateDescendantDependentFlags();
1875 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1876 setAncestorChainHasVisibleDescendant();
1878 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1879 setAncestorChainHasSelfPaintingLayerDescendant();
1881 if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
1882 setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
1884 #if ENABLE(CSS_COMPOSITING)
1885 if (child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending()))
1886 updateAncestorChainHasBlendingDescendants();
1889 compositor().layerWasAdded(*this, *child);
1892 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1894 if (!renderer().documentBeingDestroyed())
1895 compositor().layerWillBeRemoved(*this, *oldChild);
1898 if (oldChild->previousSibling())
1899 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1900 if (oldChild->nextSibling())
1901 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1903 if (m_first == oldChild)
1904 m_first = oldChild->nextSibling();
1905 if (m_last == oldChild)
1906 m_last = oldChild->previousSibling();
1908 if (oldChild->isNormalFlowOnly())
1909 dirtyNormalFlowList();
1910 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1911 // Dirty the z-order list in which we are contained. When called via the
1912 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1913 // from the main layer tree, so we need to null-check the |stackingContainer| value.
1914 oldChild->dirtyStackingContainerZOrderLists();
1917 if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
1918 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
1920 oldChild->setPreviousSibling(nullptr);
1921 oldChild->setNextSibling(nullptr);
1922 oldChild->setParent(nullptr);
1924 oldChild->updateDescendantDependentFlags();
1925 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1926 dirtyAncestorChainVisibleDescendantStatus();
1928 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1929 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1931 #if ENABLE(CSS_COMPOSITING)
1932 if (oldChild->hasBlendMode() || (oldChild->hasNotIsolatedBlendingDescendants() && !oldChild->isolatesBlending()))
1933 dirtyAncestorChainHasBlendingDescendants();
1939 void RenderLayer::removeOnlyThisLayer()
1944 // Mark that we are about to lose our layer. This makes render tree
1945 // walks ignore this layer while we're removing it.
1946 renderer().setHasLayer(false);
1948 compositor().layerWillBeRemoved(*m_parent, *this);
1950 // Dirty the clip rects.
1951 clearClipRectsIncludingDescendants();
1953 RenderLayer* nextSib = nextSibling();
1955 // Remove the child reflection layer before moving other child layers.
1956 // The reflection layer should not be moved to the parent.
1958 removeChild(reflectionLayer());
1960 // Now walk our kids and reattach them to our parent.
1961 RenderLayer* current = m_first;
1963 RenderLayer* next = current->nextSibling();
1964 removeChild(current);
1965 m_parent->addChild(current, nextSib);
1966 current->setRepaintStatus(NeedsFullRepaint);
1967 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1968 ASSERT(!renderer().hasLayer());
1969 current->updateLayerPositions(); // FIXME: use geometry map.
1973 // Remove us from the parent.
1974 m_parent->removeChild(this);
1975 renderer().destroyLayer();
1978 void RenderLayer::insertOnlyThisLayer()
1980 if (!m_parent && renderer().parent()) {
1981 // We need to connect ourselves when our renderer() has a parent.
1982 // Find our enclosingLayer and add ourselves.
1983 RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
1984 ASSERT(parentLayer);
1985 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : nullptr;
1986 parentLayer->addChild(this, beforeChild);
1989 // Remove all descendant layers from the hierarchy and add them to the new position.
1990 for (auto& child : childrenOfType<RenderElement>(renderer()))
1991 child.moveLayers(m_parent, this);
1993 // Clear out all the clip rects.
1994 clearClipRectsIncludingDescendants();
1997 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
1999 LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
2000 roundedLocation = roundedIntPoint(location);
2003 // Returns the layer reached on the walk up towards the ancestor.
2004 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
2006 ASSERT(ancestorLayer != layer);
2008 const RenderLayerModelObject& renderer = layer->renderer();
2009 EPosition position = renderer.style().position();
2011 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
2012 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : nullptr;
2013 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
2014 fixedFlowThreadContainer = nullptr;
2016 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
2017 // may need to be revisited in a future patch.
2018 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
2019 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
2020 // positioned in a completely different place in the viewport (RenderView).
2021 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
2022 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
2023 // localToAbsolute() on the RenderView.
2024 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
2025 location += LayoutSize(absPos.x(), absPos.y());
2026 return ancestorLayer;
2029 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
2030 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
2031 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
2032 if (position == FixedPosition && !fixedFlowThreadContainer) {
2033 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
2034 // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
2035 // so we should always find the ancestor at or before we find the fixed position container.
2036 RenderLayer* fixedPositionContainerLayer = nullptr;
2037 bool foundAncestor = false;
2038 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
2039 if (currLayer == ancestorLayer)
2040 foundAncestor = true;
2042 if (isContainerForPositioned(*currLayer, FixedPosition)) {
2043 fixedPositionContainerLayer = currLayer;
2044 ASSERT_UNUSED(foundAncestor, foundAncestor);
2049 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
2051 if (fixedPositionContainerLayer != ancestorLayer) {
2052 LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
2053 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
2054 location += (fixedContainerCoords - ancestorCoords);
2055 return ancestorLayer;
2059 if (position == FixedPosition && fixedFlowThreadContainer) {
2060 ASSERT(ancestorLayer);
2061 if (ancestorLayer->isOutOfFlowRenderFlowThread()) {
2062 location += toLayoutSize(layer->location());
2063 return ancestorLayer;
2066 if (ancestorLayer == renderer.view().layer()) {
2067 // Add location in flow thread coordinates.
2068 location += toLayoutSize(layer->location());
2070 // Add flow thread offset in view coordinates since the view may be scrolled.
2071 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
2072 location += LayoutSize(absPos.x(), absPos.y());
2073 return ancestorLayer;
2077 RenderLayer* parentLayer;
2078 if (position == AbsolutePosition || position == FixedPosition) {
2079 // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
2080 parentLayer = layer->parent();
2081 bool foundAncestorFirst = false;
2082 while (parentLayer) {
2083 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
2084 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
2085 // we are bailing out before reaching root layer.
2086 if (isContainerForPositioned(*parentLayer, position))
2089 if (parentLayer == ancestorLayer) {
2090 foundAncestorFirst = true;
2094 parentLayer = parentLayer->parent();
2097 // We should not reach RenderView layer past the RenderFlowThread layer for any
2098 // children of the RenderFlowThread.
2099 if (renderer.flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
2100 ASSERT(parentLayer != renderer.view().layer());
2102 if (foundAncestorFirst) {
2103 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
2104 // to enclosingAncestorForPosition and subtract.
2105 RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
2106 LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
2107 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
2108 location += (thisCoords - ancestorCoords);
2109 return ancestorLayer;
2112 parentLayer = layer->parent();
2117 location += toLayoutSize(layer->location());
2119 if (adjustForColumns == RenderLayer::AdjustForColumns) {
2120 if (RenderLayer* parentLayer = layer->parent()) {
2121 if (is<RenderMultiColumnFlowThread>(parentLayer->renderer())) {
2122 RenderRegion* region = downcast<RenderMultiColumnFlowThread>(parentLayer->renderer()).physicalTranslationFromFlowToRegion(location);
2124 location.moveBy(region->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2132 LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2134 if (ancestorLayer == this)
2137 const RenderLayer* currLayer = this;
2138 LayoutPoint locationInLayerCoords = location;
2139 while (currLayer && currLayer != ancestorLayer)
2140 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
2141 return locationInLayerCoords;
2144 LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer, ColumnOffsetAdjustment adjustForColumns) const
2146 return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint(), adjustForColumns));
2150 bool RenderLayer::hasAcceleratedTouchScrolling() const
2152 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2153 if (!scrollsOverflow())
2156 Settings* settings = renderer().document().settings();
2157 // FIXME: settings should not be null at this point. If you find a reliable way to hit this assertion, please file a bug.
2158 // See <rdar://problem/10266101>.
2161 return renderer().style().useTouchOverflowScrolling() || (settings && settings->alwaysUseAcceleratedOverflowScroll());
2167 bool RenderLayer::hasTouchScrollableOverflow() const
2169 return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2172 #if ENABLE(TOUCH_EVENTS)
2173 bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
2175 // If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
2176 if (hasTouchScrollableOverflow())
2179 return ScrollableArea::handleTouchEvent(touchEvent);
2182 #endif // PLATFORM(IOS)
2184 #if ENABLE(IOS_TOUCH_EVENTS)
2185 void RenderLayer::registerAsTouchEventListenerForScrolling()
2187 if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
2190 renderer().document().addTouchEventListener(renderer().element());
2191 m_registeredAsTouchEventListenerForScrolling = true;
2194 void RenderLayer::unregisterAsTouchEventListenerForScrolling()
2196 if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
2199 renderer().document().removeTouchEventListener(renderer().element());
2200 m_registeredAsTouchEventListenerForScrolling = false;
2202 #endif // ENABLE(IOS_TOUCH_EVENTS)
2204 bool RenderLayer::usesCompositedScrolling() const
2206 return isComposited() && backing()->scrollingLayer();
2209 bool RenderLayer::usesAsyncScrolling() const
2211 return hasAcceleratedTouchScrolling() && usesCompositedScrolling();
2214 bool RenderLayer::needsCompositedScrolling() const
2216 return m_needsCompositedScrolling;
2219 void RenderLayer::updateNeedsCompositedScrolling()
2221 bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
2223 if (!renderer().view().frameView().containsScrollableArea(this))
2224 m_needsCompositedScrolling = false;
2226 bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
2227 && canBeStackingContainer()
2228 && !hasOutOfFlowPositionedDescendant();
2230 #if !PLATFORM(IOS) && ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2231 m_needsCompositedScrolling = forceUseCompositedScrolling || renderer().style().useTouchOverflowScrolling();
2233 // On iOS we don't want to opt into accelerated composited scrolling, which creates scroll bar
2234 // layers in WebCore, because we use UIKit to composite our scroll bars.
2235 m_needsCompositedScrolling = forceUseCompositedScrolling;
2239 if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
2240 updateSelfPaintingLayer();
2241 if (isStackingContainer())
2246 dirtyStackingContainerZOrderLists();
2248 compositor().setShouldReevaluateCompositingAfterLayout();
2249 compositor().setCompositingLayersNeedRebuild();
2253 static inline int adjustedScrollDelta(int beginningDelta) {
2254 // This implemention matches Firefox's.
2255 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
2256 const int speedReducer = 12;
2258 int adjustedDelta = beginningDelta / speedReducer;
2259 if (adjustedDelta > 1)
2260 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
2261 else if (adjustedDelta < -1)
2262 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
2264 return adjustedDelta;
2267 static inline IntSize adjustedScrollDelta(const IntSize& delta)
2269 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
2272 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
2274 IntPoint lastKnownMousePosition = renderer().frame().eventHandler().lastKnownMousePosition();
2276 // 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
2277 static IntPoint previousMousePosition;
2278 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
2279 lastKnownMousePosition = previousMousePosition;
2281 previousMousePosition = lastKnownMousePosition;
2283 IntSize delta = lastKnownMousePosition - sourcePoint;
2285 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
2287 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
2290 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
2293 // FIXME: unify with the scrollRectToVisible() code below.
2294 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp, ScrollableArea** scrolledArea)
2299 bool restrictedByLineClamp = false;
2300 if (renderer().parent())
2301 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2303 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2304 ScrollOffset newScrollOffset = scrollOffset() + delta;
2305 scrollToOffset(newScrollOffset, clamp);
2307 *scrolledArea = this;
2309 // If this layer can't do the scroll we ask the next layer up that can scroll to try
2310 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
2311 if (!remainingScrollOffset.isZero() && renderer().parent()) {
2312 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2313 scrollableLayer->scrollByRecursively(remainingScrollOffset, clamp, scrolledArea);
2315 renderer().frame().eventHandler().updateAutoscrollRenderer();
2318 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
2319 // have an overflow clip. Which means that it is a document node that can be scrolled.
2320 renderer().view().frameView().scrollBy(delta);
2322 *scrolledArea = &renderer().view().frameView();
2324 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
2325 // https://bugs.webkit.org/show_bug.cgi?id=28237
2329 void RenderLayer::scrollToXPosition(int x, ScrollOffsetClamping clamp)
2331 ScrollPosition position(x, m_scrollPosition.y());
2332 scrollToOffset(scrollOffsetFromPosition(position), clamp);
2335 void RenderLayer::scrollToYPosition(int y, ScrollOffsetClamping clamp)
2337 ScrollPosition position(m_scrollPosition.x(), y);
2338 scrollToOffset(scrollOffsetFromPosition(position), clamp);
2341 ScrollOffset RenderLayer::clampScrollOffset(const ScrollOffset& scrollOffset) const
2343 return scrollOffset.constrainedBetween(IntPoint(), maximumScrollOffset());
2346 void RenderLayer::scrollToOffset(const ScrollOffset& scrollOffset, ScrollOffsetClamping clamp)
2348 ScrollOffset newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2349 if (newScrollOffset != this->scrollOffset())
2350 scrollToOffsetWithoutAnimation(newScrollOffset);
2353 void RenderLayer::scrollTo(const ScrollPosition& position)
2355 RenderBox* box = renderBox();
2359 LOG_WITH_STREAM(Scrolling, stream << "RenderLayer::scrollTo " << position);
2361 ScrollPosition newPosition = position;
2362 if (!box->isHTMLMarquee()) {
2363 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
2364 if (m_scrollDimensionsDirty)
2365 computeScrollDimensions();
2367 if (adjustForIOSCaretWhenScrolling()) {
2368 // FIXME: It's not clear what this code is trying to do. Behavior seems reasonable with it removed.
2369 int maxOffset = scrollWidth() - roundToInt(box->clientWidth());
2370 ScrollOffset newOffset = scrollOffsetFromPosition(newPosition);
2371 int scrollXOffset = newOffset.x();
2372 if (scrollXOffset > maxOffset - caretWidth) {
2373 scrollXOffset += caretWidth;
2374 if (scrollXOffset <= caretWidth)
2376 } else if (scrollXOffset < m_scrollPosition.x() - caretWidth)
2377 scrollXOffset -= caretWidth;
2379 newOffset.setX(scrollXOffset);
2380 newPosition = scrollPositionFromOffset(newOffset);
2385 if (m_scrollPosition == newPosition) {
2387 if (m_requiresScrollBoundsOriginUpdate)
2388 updateCompositingLayersAfterScroll();
2393 ScrollPosition oldPosition = IntPoint(m_scrollPosition);
2394 m_scrollPosition = newPosition;
2396 RenderView& view = renderer().view();
2398 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
2399 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
2400 if (!view.frameView().isInRenderTreeLayout()) {
2401 // If we're in the middle of layout, we'll just update layers once layout has finished.
2402 updateLayerPositionsAfterOverflowScroll();
2403 // Update regions, scrolling may change the clip of a particular region.
2404 #if ENABLE(DASHBOARD_SUPPORT)
2405 view.frameView().updateAnnotatedRegions();
2407 view.frameView().updateWidgetPositions();
2409 if (!m_updatingMarqueePosition) {
2410 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
2411 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
2412 // in this case we're still updating their positions; we'll update compositing layers later
2413 // when that completes.
2414 updateCompositingLayersAfterScroll();
2417 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
2418 renderer().document().dirtyTouchEventRects();
2420 DebugPageOverlays::didLayout(renderer().frame());
2423 Frame& frame = renderer().frame();
2424 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
2425 // The caret rect needs to be invalidated after scrolling
2426 frame.selection().setCaretRectNeedsUpdate();
2428 LayoutRect rectForRepaint = m_hasComputedRepaintRect ? m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
2430 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
2431 if (repaintContainer)
2432 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
2433 frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
2435 bool requiresRepaint = true;
2436 if (compositor().inCompositingMode() && usesCompositedScrolling())
2437 requiresRepaint = false;
2439 // Just schedule a full repaint of our object.
2440 if (requiresRepaint)
2441 renderer().repaintUsingContainer(repaintContainer, rectForRepaint);
2443 // Schedule the scroll and scroll-related DOM events.
2444 if (Element* element = renderer().element()) {
2445 element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
2446 element->document().sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize(), element);
2449 if (scrollsOverflow())
2450 view.frameView().didChangeScrollOffset();
2452 view.frameView().viewportContentsChanged();
2455 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)
2457 // If scrollbars aren't explicitly forbidden, permit scrolling.
2458 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
2461 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2462 if (frameView.wasScrolledByUser())
2465 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2466 // like navigation to an anchor.
2467 return !frameView.frame().eventHandler().autoscrollInProgress();
2470 bool RenderLayer::allowsCurrentScroll() const
2472 if (!renderer().hasOverflowClip())
2475 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2476 // FIXME: Is this still needed? It used to be relevant for Safari RSS.
2477 if (renderer().parent() && !renderer().parent()->style().lineClamp().isNone())
2480 RenderBox* box = renderBox();
2481 ASSERT(box); // Only boxes can have overflowClip set.
2483 if (renderer().frame().eventHandler().autoscrollInProgress()) {
2484 // The "programmatically" here is misleading; this asks whether the box has scrollable overflow,
2485 // or is a special case like a form control.
2486 return box->canBeProgramaticallyScrolled();
2489 // Programmatic scrolls can scroll overflow:hidden.
2490 return box->hasHorizontalOverflow() || box->hasVerticalOverflow();
2493 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2495 LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << rect);
2497 RenderLayer* parentLayer = nullptr;
2498 LayoutRect newRect = rect;
2500 // We may end up propagating a scroll event. It is important that we suspend events until
2501 // the end of the function since they could delete the layer or the layer's renderer().
2502 FrameView& frameView = renderer().view().frameView();
2504 if (renderer().parent())
2505 parentLayer = renderer().parent()->enclosingLayer();
2507 if (allowsCurrentScroll()) {
2508 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2509 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2510 RenderBox* box = renderBox();
2512 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect))).boundingBox());
2513 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
2514 LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
2516 ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
2517 if (clampedScrollOffset != scrollOffset()) {
2518 ScrollOffset oldScrollOffset = scrollOffset();
2519 scrollToOffset(clampedScrollOffset);
2520 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
2521 localExposeRect.move(-scrollOffsetDifference);
2522 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
2524 } else if (!parentLayer && renderer().isRenderView()) {
2525 HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
2527 if (ownerElement && ownerElement->renderer()) {
2528 HTMLFrameElementBase* frameElementBase = nullptr;
2530 if (is<HTMLFrameElementBase>(*ownerElement))
2531 frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
2533 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
2534 // If this assertion fires we need to protect the ownerElement from being destroyed.
2535 NoEventDispatchAssertion assertNoEventDispatch;
2537 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
2538 LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
2540 IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
2541 // Adjust offsets if they're outside of the allowable range.
2542 scrollOffset = scrollOffset.constrainedBetween(IntPoint(), IntPoint(frameView.contentsSize()));
2543 frameView.setScrollPosition(scrollOffset);
2545 if (frameView.safeToPropagateScrollToParent()) {
2546 parentLayer = ownerElement->renderer()->enclosingLayer();
2547 // Convert the rect into the coordinate space of the parent frame's document.
2548 newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
2550 parentLayer = nullptr;
2554 LayoutRect viewRect = frameView.visibleContentRect();
2555 LayoutRect visibleRectRelativeToDocument = viewRect;
2556 visibleRectRelativeToDocument.setLocation(frameView.documentScrollPositionRelativeToScrollableAreaOrigin());
2558 LayoutRect viewRect = frameView.unobscuredContentRect();
2559 LayoutRect visibleRectRelativeToDocument = viewRect;
2562 LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
2564 frameView.setScrollPosition(roundedIntPoint(r.location()));
2566 // This is the outermost view of a web page, so after scrolling this view we
2567 // scroll its container by calling Page::scrollRectIntoView.
2568 // This only has an effect on the Mac platform in applications
2569 // that put web views into scrolling containers, such as Mac OS X Mail.
2570 // The canAutoscroll function in EventHandler also knows about this.
2571 if (Page* page = frameView.frame().page())
2572 page->chrome().scrollRectIntoView(snappedIntRect(rect));
2577 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
2580 void RenderLayer::updateCompositingLayersAfterScroll()
2582 if (compositor().inCompositingMode()) {
2583 // Our stacking container is guaranteed to contain all of our descendants that may need
2584 // repositioning, so update compositing layers from there.
2585 if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
2586 if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
2587 compositor().updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor);
2589 compositor().updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
2594 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2596 // Determine the appropriate X behavior.
2597 ScrollBehavior scrollX;
2598 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
2599 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
2600 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
2601 // If the rectangle is fully visible, use the specified visible behavior.
2602 // If the rectangle is partially visible, but over a certain threshold,
2603 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2604 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2605 else if (intersectWidth == visibleRect.width()) {
2606 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2607 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2608 if (scrollX == alignCenter)
2610 } else if (intersectWidth > 0)
2611 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2612 scrollX = ScrollAlignment::getPartialBehavior(alignX);
2614 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
2615 // If we're trying to align to the closest edge, and the exposeRect is further right
2616 // than the visibleRect, and not bigger than the visible area, then align with the right.
2617 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2618 scrollX = alignRight;
2620 // Given the X behavior, compute the X coordinate.
2622 if (scrollX == noScroll)
2623 x = visibleRect.x();
2624 else if (scrollX == alignRight)
2625 x = exposeRect.maxX() - visibleRect.width();
2626 else if (scrollX == alignCenter)
2627 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2631 // Determine the appropriate Y behavior.
2632 ScrollBehavior scrollY;
2633 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
2634 LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
2635 if (intersectHeight == exposeRect.height())
2636 // If the rectangle is fully visible, use the specified visible behavior.
2637 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2638 else if (intersectHeight == visibleRect.height()) {
2639 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2640 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2641 if (scrollY == alignCenter)
2643 } else if (intersectHeight > 0)
2644 // If the rectangle is partially visible, use the specified partial behavior
2645 scrollY = ScrollAlignment::getPartialBehavior(alignY);
2647 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
2648 // If we're trying to align to the closest edge, and the exposeRect is further down
2649 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2650 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2651 scrollY = alignBottom;
2653 // Given the Y behavior, compute the Y coordinate.
2655 if (scrollY == noScroll)
2656 y = visibleRect.y();
2657 else if (scrollY == alignBottom)
2658 y = exposeRect.maxY() - visibleRect.height();
2659 else if (scrollY == alignCenter)
2660 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2664 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2667 void RenderLayer::autoscroll(const IntPoint& position)
2669 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
2670 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2673 bool RenderLayer::canResize() const
2675 // We need a special case for <iframe> because they never have
2676 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
2677 // we want to allow resizing them also.
2678 return (renderer().hasOverflowClip() || renderer().isRenderIFrame()) && renderer().style().resize() != RESIZE_NONE;
2681 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2683 // FIXME: This should be possible on generated content but is not right now.
2684 if (!inResizeMode() || !canResize() || !renderer().element())
2687 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2688 // If they do it would still be better to deal with them explicitly.
2689 Element* element = renderer().element();
2690 auto* renderer = downcast<RenderBox>(element->renderer());
2692 Document& document = element->document();
2693 if (!document.frame()->eventHandler().mousePressed())
2696 float zoomFactor = renderer->style().effectiveZoom();
2698 LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(evt.position()));
2699 newOffset.setWidth(newOffset.width() / zoomFactor);
2700 newOffset.setHeight(newOffset.height() / zoomFactor);
2702 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2703 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2704 element->setMinimumSizeForResizing(minimumSize);
2706 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2707 if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
2708 newOffset.setWidth(-newOffset.width());
2709 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2712 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2714 StyledElement* styledElement = downcast<StyledElement>(element);
2715 bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
2717 EResize resize = renderer->style().resize();
2718 if (resize != RESIZE_VERTICAL && difference.width()) {
2719 if (is<HTMLFormControlElement>(*element)) {
2720 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2721 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2722 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2724 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
2725 baseWidth = baseWidth / zoomFactor;
2726 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
2729 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2730 if (is<HTMLFormControlElement>(*element)) {
2731 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2732 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2733 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2735 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
2736 baseHeight = baseHeight / zoomFactor;
2737 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
2740 document.updateLayout();
2742 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2745 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2747 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2748 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2751 void RenderLayer::setScrollOffset(const ScrollOffset& offset)
2753 scrollTo(scrollPositionFromOffset(offset));
2756 int RenderLayer::scrollOffset(ScrollbarOrientation orientation) const
2758 if (orientation == HorizontalScrollbar)
2759 return scrollOffset().x();
2761 if (orientation == VerticalScrollbar)
2762 return scrollOffset().y();
2767 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
2769 IntSize scrollbarSpace;
2770 if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars)
2771 scrollbarSpace = scrollbarIntrusion();
2773 // FIXME: This seems wrong: m_layerSize includes borders. Can we just use the ScrollableArea implementation?
2774 return IntRect(scrollPosition(), IntSize(std::max(0, m_layerSize.width() - scrollbarSpace.width()), std::max(0, m_layerSize.height() - scrollbarSpace.height())));
2777 IntSize RenderLayer::overhangAmount() const
2779 #if ENABLE(RUBBER_BANDING)
2780 if (!renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled())
2785 // FIXME: use maximumScrollOffset(), or just move this to ScrollableArea.
2786 ScrollOffset scrollOffset = scrollOffsetFromPosition(scrollPosition());
2787 if (scrollOffset.y() < 0)
2788 stretch.setHeight(scrollOffset.y());
2789 else if (scrollableContentsSize().height() && scrollOffset.y() > scrollableContentsSize().height() - visibleHeight())
2790 stretch.setHeight(scrollOffset.y() - (scrollableContentsSize().height() - visibleHeight()));
2792 if (scrollOffset.x() < 0)
2793 stretch.setWidth(scrollOffset.x());
2794 else if (scrollableContentsSize().width() && scrollOffset.x() > scrollableContentsSize().width() - visibleWidth())
2795 stretch.setWidth(scrollOffset.x() - (scrollableContentsSize().width() - visibleWidth()));
2803 bool RenderLayer::isActive() const
2805 Page* page = renderer().frame().page();
2806 return page && page->focusController().isActive();
2809 static int cornerStart(const RenderLayer& layer, int minX, int maxX, int thickness)
2811 if (layer.shouldPlaceBlockDirectionScrollbarOnLeft())
2812 return minX + layer.renderer().style().borderLeftWidth();
2813 return maxX - thickness - layer.renderer().style().borderRightWidth();
2816 static LayoutRect cornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2818 int horizontalThickness;
2819 int verticalThickness;
2820 if (!layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2821 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2822 // even when they don't exist in order to set the resizer square size properly.
2823 horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
2824 verticalThickness = horizontalThickness;
2825 } else if (layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
2826 horizontalThickness = layer.verticalScrollbar()->width();
2827 verticalThickness = horizontalThickness;
2828 } else if (layer.horizontalScrollbar() && !layer.verticalScrollbar()) {
2829 verticalThickness = layer.horizontalScrollbar()->height();
2830 horizontalThickness = verticalThickness;
2832 horizontalThickness = layer.verticalScrollbar()->width();
2833 verticalThickness = layer.horizontalScrollbar()->height();
2835 return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2836 bounds.maxY() - verticalThickness - layer.renderer().style().borderBottomWidth(),
2837 horizontalThickness, verticalThickness);
2840 IntRect RenderLayer::scrollCornerRect() const
2842 // We have a scrollbar corner when a non overlay scrollbar is visible and not filling the entire length of the box.
2843 // This happens when:
2844 // (a) A resizer is present and at least one non overlay scrollbar is present
2845 // (b) Both non overlay scrollbars are present.
2846 // Overlay scrollbars always fill the entire length of the box so we never have scroll corner in that case.
2847 bool hasHorizontalBar = m_hBar && !m_hBar->isOverlayScrollbar();
2848 bool hasVerticalBar = m_vBar && !m_vBar->isOverlayScrollbar();
2849 bool hasResizer = renderer().style().resize() != RESIZE_NONE;
2850 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2851 return snappedIntRect(cornerRect(*this, renderBox()->borderBoxRect()));
2855 static LayoutRect resizerCornerRect(const RenderLayer& layer, const LayoutRect& bounds)
2857 ASSERT(layer.renderer().isBox());
2858 if (layer.renderer().style().resize() == RESIZE_NONE)
2859 return LayoutRect();
2860 return cornerRect(layer, bounds);
2863 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
2865 RenderBox* box = renderBox();
2867 return LayoutRect();
2868 LayoutRect scrollCornerAndResizer = scrollCornerRect();
2869 if (scrollCornerAndResizer.isEmpty())
2870 scrollCornerAndResizer = resizerCornerRect(*this, box->borderBoxRect());
2871 return scrollCornerAndResizer;
2874 bool RenderLayer::isScrollCornerVisible() const
2876 ASSERT(renderer().isBox());
2877 return !scrollCornerRect().isEmpty();
2880 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
2882 IntRect rect = scrollbarRect;
2883 rect.move(scrollbarOffset(scrollbar));
2885 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), rect);
2888 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
2890 IntRect rect = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentRect);
2891 rect.move(-scrollbarOffset(scrollbar));
2895 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
2897 IntPoint point = scrollbarPoint;
2898 point.move(scrollbarOffset(scrollbar));
2899 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), point);
2902 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
2904 IntPoint point = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentPoint);
2905 point.move(-scrollbarOffset(scrollbar));
2909 IntSize RenderLayer::visibleSize() const
2911 RenderBox* box = renderBox();
2915 return IntSize(roundToInt(box->clientWidth()), roundToInt(box->clientHeight()));
2918 IntSize RenderLayer::contentsSize() const
2920 return IntSize(scrollWidth(), scrollHeight());
2923 IntSize RenderLayer::scrollableContentsSize() const
2925 IntSize contentsSize = this->contentsSize();
2927 if (!hasScrollableHorizontalOverflow())
2928 contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
2930 if (!hasScrollableVerticalOverflow())
2931 contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
2933 return contentsSize;
2936 void RenderLayer::availableContentSizeChanged(AvailableSizeChangeReason reason)
2938 ScrollableArea::availableContentSizeChanged(reason);
2940 if (reason == AvailableSizeChangeReason::ScrollbarsChanged) {
2941 if (is<RenderBlock>(renderer()))
2942 downcast<RenderBlock>(renderer()).setShouldForceRelayoutChildren(true);
2943 renderer().setNeedsLayout();
2947 bool RenderLayer::shouldSuspendScrollAnimations() const
2949 return renderer().view().frameView().shouldSuspendScrollAnimations();
2953 void RenderLayer::didStartScroll()
2955 if (Page* page = renderer().frame().page())
2956 page->chrome().client().didStartOverflowScroll();
2959 void RenderLayer::didEndScroll()
2961 if (Page* page = renderer().frame().page())
2962 page->chrome().client().didEndOverflowScroll();
2965 void RenderLayer::didUpdateScroll()
2967 // Send this notification when we scroll, since this is how we keep selection updated.
2968 if (Page* page = renderer().frame().page())
2969 page->chrome().client().didLayout(ChromeClient::Scroll);
2973 IntPoint RenderLayer::lastKnownMousePosition() const
2975 return renderer().frame().eventHandler().lastKnownMousePosition();
2978 bool RenderLayer::isHandlingWheelEvent() const
2980 return renderer().frame().eventHandler().isHandlingWheelEvent();
2983 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
2988 const RenderBox* box = renderBox();
2989 const IntRect& scrollCorner = scrollCornerRect();
2991 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
2992 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
2993 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2997 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
3002 const RenderBox* box = renderBox();
3003 const IntRect& scrollCorner = scrollCornerRect();
3005 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
3006 borderBoxRect.y() + box->borderTop(),
3008 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
3011 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
3013 const RenderBox* box = renderBox();
3014 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3015 return minX + box->borderLeft();
3016 return maxX - box->borderRight() - m_vBar->width();
3019 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
3021 const RenderBox* box = renderBox();
3022 int x = minX + box->borderLeft();
3023 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3024 x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(*this, box->borderBoxRect()).width());
3028 IntSize RenderLayer::scrollbarOffset(const Scrollbar& scrollbar) const
3030 RenderBox* box = renderBox();
3032 if (&scrollbar == m_vBar.get())
3033 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
3035 if (&scrollbar == m_hBar.get())
3036 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3038 ASSERT_NOT_REACHED();
3042 void RenderLayer::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
3044 if (!showsOverflowControls())
3047 if (&scrollbar == m_vBar.get()) {
3048 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
3049 layer->setNeedsDisplayInRect(rect);
3053 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
3054 layer->setNeedsDisplayInRect(rect);
3059 IntRect scrollRect = rect;
3060 RenderBox* box = renderBox();
3062 // If we are not yet inserted into the tree, there is no need to repaint.
3066 if (&scrollbar == m_vBar.get())
3067 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
3069 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
3070 LayoutRect repaintRect = scrollRect;
3071 renderBox()->flipForWritingMode(repaintRect);
3072 renderer().repaintRectangle(repaintRect);
3075 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
3077 if (!showsOverflowControls())
3080 if (GraphicsLayer* layer = layerForScrollCorner()) {
3081 layer->setNeedsDisplayInRect(rect);
3086 m_scrollCorner->repaintRectangle(rect);
3088 m_resizer->repaintRectangle(rect);
3091 static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& renderer)
3093 if (Element* element = renderer.element()) {
3094 if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
3095 if (shadowRoot->type() == ShadowRoot::Type::UserAgent)
3096 return shadowRoot->host()->renderer();
3103 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
3105 RefPtr<Scrollbar> widget;
3106 RenderElement* actualRenderer = rendererForScrollbar(renderer());
3107 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style().hasPseudoStyle(SCROLLBAR);
3108 if (hasCustomScrollbarStyle)
3109 widget = RenderScrollbar::createCustomScrollbar(*this, orientation, actualRenderer->element());
3111 widget = Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
3112 didAddScrollbar(widget.get(), orientation);
3113 if (Page* page = renderer().frame().page()) {
3114 if (page->expectsWheelEventTriggers())
3115 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
3118 renderer().view().frameView().addChild(widget.get());
3119 return WTFMove(widget);
3122 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
3124 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
3128 if (!scrollbar->isCustomScrollbar())
3129 willRemoveScrollbar(scrollbar.get(), orientation);
3131 scrollbar->removeFromParent();
3132 scrollbar = nullptr;
3135 bool RenderLayer::scrollsOverflow() const
3137 if (!is<RenderBox>(renderer()))
3140 return downcast<RenderBox>(renderer()).scrollsOverflow();
3143 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
3145 if (hasScrollbar == hasHorizontalScrollbar())
3149 m_hBar = createScrollbar(HorizontalScrollbar);
3150 #if ENABLE(RUBBER_BANDING)
3151 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3152 ScrollableArea::setHorizontalScrollElasticity(elasticity);
3155 destroyScrollbar(HorizontalScrollbar);
3156 #if ENABLE(RUBBER_BANDING)
3157 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityNone);
3161 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3163 m_hBar->styleChanged();
3165 m_vBar->styleChanged();
3167 // Force an update since we know the scrollbars have changed things.
3168 #if ENABLE(DASHBOARD_SUPPORT)
3169 if (renderer().document().hasAnnotatedRegions())
3170 renderer().document().setAnnotatedRegionsDirty(true);
3174 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
3176 if (hasScrollbar == hasVerticalScrollbar())
3180 m_vBar = createScrollbar(VerticalScrollbar);
3181 #if ENABLE(RUBBER_BANDING)
3182 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3183 ScrollableArea::setVerticalScrollElasticity(elasticity);
3186 destroyScrollbar(VerticalScrollbar);
3187 #if ENABLE(RUBBER_BANDING)
3188 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityNone);
3192 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3194 m_hBar->styleChanged();
3196 m_vBar->styleChanged();
3198 // Force an update since we know the scrollbars have changed things.
3199 #if ENABLE(DASHBOARD_SUPPORT)
3200 if (renderer().document().hasAnnotatedRegions())
3201 renderer().document().setAnnotatedRegionsDirty(true);
3205 ScrollableArea* RenderLayer::enclosingScrollableArea() const
3207 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
3208 return scrollableLayer;
3210 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
3211 // if the frame view isn't scrollable.
3215 bool RenderLayer::isScrollableOrRubberbandable()
3217 return renderer().isScrollableOrRubberbandableBox();
3220 bool RenderLayer::hasScrollableOrRubberbandableAncestor()
3222 for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
3223 if (nextLayer->isScrollableOrRubberbandable())
3230 #if ENABLE(CSS_SCROLL_SNAP)
3231 void RenderLayer::updateSnapOffsets()
3233 // FIXME: Extend support beyond HTMLElements.
3234 if (!is<HTMLElement>(enclosingElement()) || !enclosingElement()->renderBox())
3237 RenderBox* box = enclosingElement()->renderBox();
3238 updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
3241 bool RenderLayer::isScrollSnapInProgress() const
3243 if (!scrollsOverflow())
3246 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
3247 return scrollAnimator->isScrollSnapInProgress();
3253 bool RenderLayer::usesMockScrollAnimator() const
3255 return Settings::usesMockScrollAnimator();
3258 void RenderLayer::logMockScrollAnimatorMessage(const String& message) const
3260 renderer().document().addConsoleMessage(MessageSource::Other, MessageLevel::Debug, "RenderLayer: " + message);
3263 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
3266 || !showsOverflowControls()
3267 || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
3270 return m_vBar->width();
3273 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
3276 || !showsOverflowControls()
3277 || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
3280 return m_hBar->height();
3283 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
3285 // Currently the resize corner is either the bottom right corner or the bottom left corner.
3286 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
3287 IntSize elementSize = size();
3288 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3289 elementSize.setWidth(0);
3290 IntPoint resizerPoint = IntPoint(elementSize);
3291 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3292 return localPoint - resizerPoint;
3295 bool RenderLayer::hasOverflowControls() const
3297 return m_hBar || m_vBar || m_scrollCorner || renderer().style().resize() != RESIZE_NONE;
3300 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
3302 if (!m_hBar && !m_vBar && !canResize())
3305 RenderBox* box = renderBox();
3309 const IntRect borderBox = snappedIntRect(box->borderBoxRect());
3310 const IntRect& scrollCorner = scrollCornerRect();
3311 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
3313 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
3314 vBarRect.move(offsetFromRoot);
3315 m_vBar->setFrameRect(vBarRect);
3319 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
3320 hBarRect.move(offsetFromRoot);
3321 m_hBar->setFrameRect(hBarRect);
3325 m_scrollCorner->setFrameRect(scrollCorner);
3327 m_resizer->setFrameRect(resizerCornerRect(*this, borderBox));
3330 backing()->positionOverflowControlsLayers();
3333 int RenderLayer::scrollWidth() const
3335 ASSERT(renderBox());
3336 if (m_scrollDimensionsDirty)
3337 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3338 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3339 return m_scrollSize.width();
3342 int RenderLayer::scrollHeight() const
3344 ASSERT(renderBox());
3345 if (m_scrollDimensionsDirty)
3346 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3347 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3348 return m_scrollSize.height();
3351 LayoutUnit RenderLayer::overflowTop() const
3353 RenderBox* box = renderBox();
3354 LayoutRect overflowRect(box->layoutOverflowRect());
3355 box->flipForWritingMode(overflowRect);
3356 return overflowRect.y();
3359 LayoutUnit RenderLayer::overflowBottom() const
3361 RenderBox* box = renderBox();
3362 LayoutRect overflowRect(box->layoutOverflowRect());
3363 box->flipForWritingMode(overflowRect);
3364 return overflowRect.maxY();
3367 LayoutUnit RenderLayer::overflowLeft() const
3369 RenderBox* box = renderBox();
3370 LayoutRect overflowRect(box->layoutOverflowRect());
3371 box->flipForWritingMode(overflowRect);
3372 return overflowRect.x();
3375 LayoutUnit RenderLayer::overflowRight() const
3377 RenderBox* box = renderBox();
3378 LayoutRect overflowRect(box->layoutOverflowRect());
3379 box->flipForWritingMode(overflowRect);
3380 return overflowRect.maxX();
3383 void RenderLayer::computeScrollDimensions()
3385 RenderBox* box = renderBox();
3388 m_scrollDimensionsDirty = false;
3390 m_scrollSize.setWidth(roundToInt(overflowRight() - overflowLeft()));
3391 m_scrollSize.setHeight(roundToInt(overflowBottom() - overflowTop()));
3393 int scrollableLeftOverflow = roundToInt(overflowLeft() - box->borderLeft());
3394 if (shouldPlaceBlockDirectionScrollbarOnLeft())
3395 scrollableLeftOverflow -= verticalScrollbarWidth();
3396 int scrollableTopOverflow = roundToInt(overflowTop() - box->borderTop());
3397 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
3400 bool RenderLayer::hasScrollableHorizontalOverflow() const
3402 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
3405 bool RenderLayer::hasScrollableVerticalOverflow() const
3407 return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
3410 bool RenderLayer::hasHorizontalOverflow() const
3412 ASSERT(!m_scrollDimensionsDirty);
3414 return scrollWidth() > roundToInt(renderBox()->clientWidth());