2 * Copyright (C) 2006-2014 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"
52 #include "DocumentEventQueue.h"
54 #include "EventHandler.h"
55 #include "FEColorMatrix.h"
57 #include "FilterEffectRenderer.h"
58 #include "FloatConversion.h"
59 #include "FloatPoint3D.h"
60 #include "FloatRect.h"
61 #include "FloatRoundedRect.h"
62 #include "FlowThreadController.h"
63 #include "FocusController.h"
65 #include "FrameLoader.h"
66 #include "FrameLoaderClient.h"
67 #include "FrameSelection.h"
68 #include "FrameTree.h"
69 #include "FrameView.h"
71 #include "GraphicsContext.h"
72 #include "HTMLFormControlElement.h"
73 #include "HTMLFrameElement.h"
74 #include "HTMLFrameOwnerElement.h"
75 #include "HTMLNames.h"
76 #include "HitTestingTransformState.h"
77 #include "HitTestRequest.h"
78 #include "HitTestResult.h"
79 #include "InspectorInstrumentation.h"
80 #include "OverflowEvent.h"
81 #include "OverlapTestRequestClient.h"
83 #include "PlatformMouseEvent.h"
84 #include "RenderFlowThread.h"
85 #include "RenderGeometryMap.h"
86 #include "RenderInline.h"
87 #include "RenderIterator.h"
88 #include "RenderLayerBacking.h"
89 #include "RenderLayerCompositor.h"
90 #include "RenderLayerFilterInfo.h"
91 #include "RenderMarquee.h"
92 #include "RenderMultiColumnFlowThread.h"
93 #include "RenderNamedFlowFragment.h"
94 #include "RenderNamedFlowThread.h"
95 #include "RenderRegion.h"
96 #include "RenderReplica.h"
97 #include "RenderSVGResourceClipper.h"
98 #include "RenderScrollbar.h"
99 #include "RenderScrollbarPart.h"
100 #include "RenderTableCell.h"
101 #include "RenderTableRow.h"
102 #include "RenderText.h"
103 #include "RenderTheme.h"
104 #include "RenderTreeAsText.h"
105 #include "RenderView.h"
106 #include "SVGNames.h"
107 #include "ScaleTransformOperation.h"
108 #include "ScrollAnimator.h"
109 #include "Scrollbar.h"
110 #include "ScrollbarTheme.h"
111 #include "ScrollingCoordinator.h"
112 #include "Settings.h"
113 #include "ShadowRoot.h"
114 #include "SourceGraphic.h"
115 #include "StyleProperties.h"
116 #include "StyleResolver.h"
117 #include "TextStream.h"
118 #include "TransformationMatrix.h"
119 #include "TranslateTransformOperation.h"
121 #include <wtf/StdLibExtras.h>
122 #include <wtf/text/CString.h>
124 #if ENABLE(CSS_SCROLL_SNAP)
125 #include "AxisScrollSnapOffsets.h"
128 #define MIN_INTERSECT_FOR_REVEAL 32
132 using namespace HTMLNames;
134 bool ClipRect::intersects(const HitTestLocation& hitTestLocation) const
136 return hitTestLocation.intersects(m_rect);
139 void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
141 #if !ENABLE(3D_RENDERING)
142 UNUSED_PARAM(has3DRendering);
150 RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
151 : m_inResizeMode(false)
152 , m_scrollDimensionsDirty(true)
153 , m_normalFlowListDirty(true)
154 , m_hasSelfPaintingLayerDescendant(false)
155 , m_hasSelfPaintingLayerDescendantDirty(false)
156 , m_hasOutOfFlowPositionedDescendant(false)
157 , m_hasOutOfFlowPositionedDescendantDirty(true)
158 , m_needsCompositedScrolling(false)
159 , m_descendantsAreContiguousInStackingOrder(false)
160 , m_isRootLayer(rendererLayerModelObject.isRenderView())
161 , m_usedTransparency(false)
162 , m_paintingInsideReflection(false)
163 , m_inOverflowRelayout(false)
164 , m_repaintStatus(NeedsNormalRepaint)
165 , m_visibleContentStatusDirty(true)
166 , m_hasVisibleContent(false)
167 , m_visibleDescendantStatusDirty(false)
168 , m_hasVisibleDescendant(false)
169 , m_3DTransformedDescendantStatusDirty(true)
170 , m_has3DTransformedDescendant(false)
171 , m_hasCompositingDescendant(false)
172 , m_hasTransformedAncestor(false)
173 , m_has3DTransformedAncestor(false)
174 , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
175 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
177 , m_adjustForIOSCaretWhenScrolling(false)
180 #if ENABLE(IOS_TOUCH_EVENTS)
181 , m_registeredAsTouchEventListenerForScrolling(false)
183 , m_inUserScroll(false)
184 , m_requiresScrollBoundsOriginUpdate(false)
186 , m_containsDirtyOverlayScrollbars(false)
187 , m_updatingMarqueePosition(false)
189 , m_layerListMutationAllowed(true)
191 , m_hasFilterInfo(false)
192 #if ENABLE(CSS_COMPOSITING)
193 , m_blendMode(BlendModeNormal)
194 , m_hasNotIsolatedCompositedBlendingDescendants(false)
195 , m_hasNotIsolatedBlendingDescendants(false)
196 , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
198 , m_renderer(rendererLayerModelObject)
200 , m_previous(nullptr)
204 , m_staticInlinePosition(0)
205 , m_staticBlockPosition(0)
206 , m_enclosingPaginationLayer(nullptr)
208 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
209 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
211 // Non-stacking containers should have empty z-order lists. As this is already the case,
212 // there is no need to dirty / recompute these lists.
213 m_zOrderListsDirty = isStackingContainer();
215 ScrollableArea::setConstrainsScrollingToContentEdge(false);
217 if (!renderer().firstChild()) {
218 m_visibleContentStatusDirty = false;
219 m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
222 if (Element* element = renderer().element()) {
223 // We save and restore only the scrollOffset as the other scroll values are recalculated.
224 m_scrollOffset = element->savedLayerScrollOffset();
225 if (!m_scrollOffset.isZero())
226 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
227 element->setSavedLayerScrollOffset(IntSize());
231 RenderLayer::~RenderLayer()
233 if (inResizeMode() && !renderer().documentBeingDestroyed())
234 renderer().frame().eventHandler().resizeLayerDestroyed();
236 renderer().view().frameView().removeScrollableArea(this);
238 if (!renderer().documentBeingDestroyed()) {
239 #if ENABLE(IOS_TOUCH_EVENTS)
240 unregisterAsTouchEventListenerForScrolling();
242 if (Element* element = renderer().element())
243 element->setSavedLayerScrollOffset(m_scrollOffset);
246 destroyScrollbar(HorizontalScrollbar);
247 destroyScrollbar(VerticalScrollbar);
249 if (renderer().frame().page()) {
250 if (ScrollingCoordinator* scrollingCoordinator = renderer().frame().page()->scrollingCoordinator())
251 scrollingCoordinator->willDestroyScrollableArea(this);
257 FilterInfo::remove(*this);
259 // Child layers will be deleted by their corresponding render objects, so
260 // we don't need to delete them ourselves.
265 String RenderLayer::name() const
268 name.append(renderer().renderName());
270 if (Element* element = renderer().element()) {
272 name.append(element->tagName());
274 if (element->hasID()) {
275 name.appendLiteral(" id=\'");
276 name.append(element->getIdAttribute());
280 if (element->hasClass()) {
281 name.appendLiteral(" class=\'");
282 for (size_t i = 0; i < element->classNames().size(); ++i) {
285 name.append(element->classNames()[i]);
292 name.appendLiteral(" (reflection)");
294 return name.toString();
297 RenderLayerCompositor& RenderLayer::compositor() const
299 return renderer().view().compositor();
302 void RenderLayer::contentChanged(ContentChangeType changeType)
304 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ImageChanged) && compositor().updateLayerCompositingState(*this))
305 compositor().setCompositingLayersNeedRebuild();
308 m_backing->contentChanged(changeType);
311 bool RenderLayer::canRender3DTransforms() const
313 return compositor().canRender3DTransforms();
316 bool RenderLayer::paintsWithFilters() const
318 // FIXME: Eventually there will be cases where we paint with filters even without accelerated compositing,
319 // and this whole function won't be inside the #if below.
321 if (!renderer().hasFilter())
327 if (!m_backing || !m_backing->canCompositeFilters())
333 bool RenderLayer::requiresFullLayerImageForFilters() const
335 if (!paintsWithFilters())
337 FilterEffectRenderer* renderer = filterRenderer();
338 return renderer && renderer->hasFilterThatMovesPixels();
341 FilterEffectRenderer* RenderLayer::filterRenderer() const
343 FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
344 return filterInfo ? filterInfo->renderer() : 0;
347 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
349 RenderGeometryMap geometryMap(UseTransforms);
350 if (this != rootLayer)
351 geometryMap.pushMappingsToAncestor(parent(), 0);
352 updateLayerPositions(&geometryMap, flags);
355 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
357 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
358 // we need to keep in sync, since we may have shifted relative
359 // to our parent layer.
361 geometryMap->pushMappingsToAncestor(this, parent());
363 // Clear our cached clip rect information.
366 if (hasOverflowControls()) {
367 LayoutSize offsetFromRoot;
369 offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
371 // FIXME: It looks suspicious to call convertToLayerCoords here
372 // as canUseConvertToLayerCoords may be true for an ancestor layer.
373 offsetFromRoot = offsetFromAncestor(root());
375 positionOverflowControls(roundedIntSize(offsetFromRoot));
378 updateDescendantDependentFlags();
380 if (flags & UpdatePagination)
383 m_enclosingPaginationLayer = nullptr;
385 if (m_hasVisibleContent) {
386 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
387 // mapping between them and the RenderObjects. It would be neat to enable
388 // LayoutState outside the layout() phase and use it here.
389 ASSERT(!renderer().view().layoutStateEnabled());
391 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
392 LayoutRect oldRepaintRect = m_repaintRect;
393 LayoutRect oldOutlineBox = m_outlineBox;
394 computeRepaintRects(repaintContainer, geometryMap);
396 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
397 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
398 if (flags & CheckForRepaint) {
399 if (!renderer().view().printing()) {
400 bool didRepaint = false;
401 if (m_repaintStatus & NeedsFullRepaint) {
402 renderer().repaintUsingContainer(repaintContainer, oldRepaintRect);
403 if (m_repaintRect != oldRepaintRect) {
404 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
407 } else if (shouldRepaintAfterLayout()) {
408 renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
412 if (didRepaint && renderer().isRenderNamedFlowFragmentContainer()) {
413 // If we just repainted a region, we must also repaint the flow thread since it is the one
414 // doing the actual painting of the flowed content.
415 RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
416 if (region.isValid())
417 region.flowThread()->layer()->repaintIncludingDescendants();
424 m_repaintStatus = NeedsNormalRepaint;
425 m_hasTransformedAncestor = flags & SeenTransformedLayer;
426 m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
428 // Go ahead and update the reflection's position and size.
430 m_reflection->layout();
432 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
433 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
435 flags &= ~IsCompositingUpdateRoot;
437 if (renderer().isInFlowRenderFlowThread()) {
439 flags |= UpdatePagination;
443 flags |= SeenTransformedLayer;
444 if (!transform()->isAffine())
445 flags |= Seen3DTransformedLayer;
448 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
449 child->updateLayerPositions(geometryMap, flags);
451 if ((flags & UpdateCompositingLayers) && isComposited()) {
452 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
453 if (flags & NeedsFullRepaintInBacking)
454 updateFlags |= RenderLayerBacking::NeedsFullRepaint;
456 updateFlags |= RenderLayerBacking::IsUpdateRoot;
457 backing()->updateAfterLayout(updateFlags);
460 // With all our children positioned, now update our marquee if we need to.
462 // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
463 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
464 m_updatingMarqueePosition = true;
465 m_marquee->updateMarqueePosition();
466 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
470 geometryMap->popMappingsToAncestor(parent());
473 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
475 LayoutRect repaintRect = m_repaintRect;
476 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
477 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
478 if (child->isComposited())
481 repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants());
486 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
488 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
489 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
492 layer->m_hasSelfPaintingLayerDescendantDirty = false;
493 layer->m_hasSelfPaintingLayerDescendant = true;
497 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
499 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
500 layer->m_hasSelfPaintingLayerDescendantDirty = true;
501 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
502 // in this case, there is no need to dirty our ancestors further.
503 if (layer->isSelfPaintingLayer()) {
504 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
510 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
512 return renderer().frame().settings().acceleratedCompositingForOverflowScrollEnabled();
515 // If we are a stacking container, then this function will determine if our
516 // descendants for a contiguous block in stacking order. This is required in
517 // order for an element to be safely promoted to a stacking container. It is safe
518 // to become a stacking container if this change would not alter the stacking
519 // order of layers on the page. That can only happen if a non-descendant appear
520 // between us and our descendants in stacking order. Here's an example:
530 // I've labeled our normal flow descendants A, B, C, and D, our stacking
531 // container descendants with their z indices, and us with 'this' (we're a
532 // stacking container and our zIndex doesn't matter here). These nodes appear in
533 // three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
534 // flow layers don't overlap). So if we arrange these lists in order we get our
537 // [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
539 // Neg z-order. <-+ +--> Normal flow descendants.
541 // We can then assign new, 'stacking' order indices to these elements as follows:
543 // [-8], [A-D], [0, 2, 5, 7]
544 // 'Stacking' indices: -1 0 1 2 3 4
546 // Note that the normal flow descendants can share an index because they don't
547 // stack/overlap. Now our problem becomes very simple: a layer can safely become
548 // a stacking container if the stacking-order indices of it and its descendants
549 // appear in a contiguous block in the list of stacking indices. This problem
550 // can be solved very efficiently by calculating the min/max stacking indices in
551 // the subtree, and the number stacking container descendants. Once we have this
552 // information, we know that the subtree's indices form a contiguous block if:
554 // maxStackIndex - minStackIndex == numSCDescendants
556 // So for node A in the example above we would have:
558 // minStackIndex = -1
559 // numSCDecendants = 2
562 // maxStackIndex - minStackIndex == numSCDescendants
563 // ===> 1 - (-1) == 2
566 // Since this is true, A can safely become a stacking container.
567 // Now, for node C we have:
570 // minStackIndex = 0 <-- because C has stacking index 0.
571 // numSCDecendants = 2
574 // maxStackIndex - minStackIndex == numSCDescendants
578 // Since this is false, C cannot be safely promoted to a stacking container. This
579 // happened because of the elements with z-index 5 and 0. Now if 5 had been a
580 // child of C rather than D, and A had no child with Z index 0, we would have had:
583 // minStackIndex = 0 <-- because C has stacking index 0.
584 // numSCDecendants = 3
587 // maxStackIndex - minStackIndex == numSCDescendants
591 // And we would conclude that C could be promoted.
592 void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
594 if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
597 ASSERT(!m_normalFlowListDirty);
598 ASSERT(!m_zOrderListsDirty);
600 std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
601 std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
602 rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
604 // Create a reverse lookup.
605 HashMap<const RenderLayer*, int> lookup;
608 int stackingOrderIndex = -1;
609 size_t listSize = negZOrderList->size();
610 for (size_t i = 0; i < listSize; ++i) {
611 RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
612 if (!currentLayer->isStackingContext())
614 lookup.set(currentLayer, stackingOrderIndex--);
619 size_t listSize = posZOrderList->size();
620 int stackingOrderIndex = 1;
621 for (size_t i = 0; i < listSize; ++i) {
622 RenderLayer* currentLayer = posZOrderList->at(i);
623 if (!currentLayer->isStackingContext())
625 lookup.set(currentLayer, stackingOrderIndex++);
632 bool firstIteration = true;
633 updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
636 void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
638 if (isStackingContext() && !firstIteration) {
639 if (lookup.contains(this)) {
640 minIndex = std::min(minIndex, lookup.get(this));
641 maxIndex = std::max(maxIndex, lookup.get(this));
647 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
648 int childMinIndex = 0;
649 int childMaxIndex = 0;
651 child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
654 minIndex = std::min(minIndex, childMinIndex);
655 maxIndex = std::max(maxIndex, childMaxIndex);
659 if (!isStackingContext()) {
660 bool newValue = maxIndex - minIndex == count;
661 bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
662 m_descendantsAreContiguousInStackingOrder = newValue;
664 updateNeedsCompositedScrolling();
668 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
670 ASSERT(!m_visibleContentStatusDirty);
672 m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer);
673 m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap);
677 void RenderLayer::computeRepaintRectsIncludingDescendants()
679 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
680 // We should make this more efficient.
681 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
682 computeRepaintRects(renderer().containerForRepaint());
684 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
685 layer->computeRepaintRectsIncludingDescendants();
688 void RenderLayer::clearRepaintRects()
690 ASSERT(!m_hasVisibleContent);
691 ASSERT(!m_visibleContentStatusDirty);
693 m_repaintRect = LayoutRect();
694 m_outlineBox = LayoutRect();
697 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
699 ASSERT(this == renderer().view().layer());
701 RenderGeometryMap geometryMap(UseTransforms);
702 updateLayerPositionsAfterScroll(&geometryMap);
705 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
707 RenderGeometryMap geometryMap(UseTransforms);
708 if (this != renderer().view().layer())
709 geometryMap.pushMappingsToAncestor(parent(), 0);
711 // FIXME: why is it OK to not check the ancestors of this layer in order to
712 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
713 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
716 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
718 // FIXME: This shouldn't be needed, but there are some corner cases where
719 // these flags are still dirty. Update so that the check below is valid.
720 updateDescendantDependentFlags();
722 // If we have no visible content and no visible descendants, there is no point recomputing
723 // our rectangles as they will be empty. If our visibility changes, we are expected to
724 // recompute all our positions anyway.
725 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
728 bool positionChanged = updateLayerPosition();
730 flags |= HasChangedAncestor;
733 geometryMap->pushMappingsToAncestor(this, parent());
735 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
738 if (renderer().style().hasViewportConstrainedPosition())
739 flags |= HasSeenViewportConstrainedAncestor;
741 if (renderer().hasOverflowClip())
742 flags |= HasSeenAncestorWithOverflowClip;
744 if (flags & HasSeenViewportConstrainedAncestor
745 || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) {
746 // FIXME: We could track the repaint container as we walk down the tree.
747 computeRepaintRects(renderer().containerForRepaint(), geometryMap);
749 // Check that our cached rects are correct.
750 ASSERT(m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
751 ASSERT(m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint(), geometryMap));
754 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
755 child->updateLayerPositionsAfterScroll(geometryMap, flags);
757 // We don't update our reflection as scrolling is a translation which does not change the size()
758 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
762 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
763 m_updatingMarqueePosition = true;
764 m_marquee->updateMarqueePosition();
765 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
769 geometryMap->popMappingsToAncestor(parent());
772 void RenderLayer::positionNewlyCreatedOverflowControls()
774 if (!backing()->hasUnpositionedOverflowControlsLayers())
777 RenderGeometryMap geometryMap(UseTransforms);
778 if (this != renderer().view().layer() && parent())
779 geometryMap.pushMappingsToAncestor(parent(), 0);
781 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
782 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
785 #if ENABLE(CSS_COMPOSITING)
787 void RenderLayer::updateBlendMode()
789 bool hadBlendMode = m_blendMode != BlendModeNormal;
790 if (parent() && hadBlendMode != hasBlendMode()) {
792 parent()->updateAncestorChainHasBlendingDescendants();
794 parent()->dirtyAncestorChainHasBlendingDescendants();
797 BlendMode newBlendMode = renderer().style().blendMode();
798 if (newBlendMode != m_blendMode)
799 m_blendMode = newBlendMode;
802 void RenderLayer::updateAncestorChainHasBlendingDescendants()
804 for (auto layer = this; layer; layer = layer->parent()) {
805 if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
807 layer->m_hasNotIsolatedBlendingDescendants = true;
808 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
810 layer->updateSelfPaintingLayer();
812 if (layer->isStackingContext())
817 void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
819 for (auto layer = this; layer; layer = layer->parent()) {
820 if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
823 layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
825 if (layer->isStackingContext())
831 void RenderLayer::updateTransform()
833 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
834 // so check style too.
835 bool hasTransform = renderer().hasTransform() && renderer().style().hasTransform();
836 bool had3DTransform = has3DTransform();
838 bool hadTransform = !!m_transform;
839 if (hasTransform != hadTransform) {
841 m_transform = std::make_unique<TransformationMatrix>();
843 m_transform = nullptr;
845 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
846 clearClipRectsIncludingDescendants();
850 RenderBox* box = renderBox();
852 m_transform->makeIdentity();
853 box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
854 makeMatrixRenderable(*m_transform, canRender3DTransforms());
857 if (had3DTransform != has3DTransform())
858 dirty3DTransformedDescendantStatus();
861 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
864 return TransformationMatrix();
866 RenderBox* box = renderBox();
868 FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
869 if (renderer().style().isRunningAcceleratedAnimation()) {
870 TransformationMatrix currTransform;
871 RefPtr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(renderer());
872 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
873 makeMatrixRenderable(currTransform, canRender3DTransforms());
874 return currTransform;
877 // m_transform includes transform-origin, so we need to recompute the transform here.
878 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
879 TransformationMatrix currTransform;
880 box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
881 makeMatrixRenderable(currTransform, canRender3DTransforms());
882 return currTransform;
888 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
891 return TransformationMatrix();
893 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
894 TransformationMatrix matrix = *m_transform;
895 makeMatrixRenderable(matrix, false /* flatten 3d */);
902 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
904 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
906 if (layer->renderer().hasOverflowClip())
907 return const_cast<RenderLayer*>(layer);
909 layer = layer->parent();
914 // FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
915 // painting of content inside paginated layers.
916 bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
918 // No enclosing layer means no compositing in the chain.
919 if (!m_enclosingPaginationLayer)
922 // If the enclosing layer is composited, we don't have to check anything in between us and that
924 if (m_enclosingPaginationLayer->isComposited())
927 // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
929 if (m_enclosingPaginationLayer == this)
932 // The enclosing paginated layer is our ancestor and is not composited, so we have to check
933 // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
937 // For normal flow layers, we can recur up the layer tree.
938 if (isNormalFlowOnly())
939 return parent()->hasCompositedLayerInEnclosingPaginationChain();
941 // Otherwise we have to go up the containing block chain. Find the first enclosing
942 // containing block layer ancestor, and check that.
943 RenderView* renderView = &renderer().view();
944 for (RenderBlock* containingBlock = renderer().containingBlock(); containingBlock && containingBlock != renderView; containingBlock = containingBlock->containingBlock()) {
945 if (containingBlock->hasLayer())
946 return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
951 void RenderLayer::updatePagination()
953 m_enclosingPaginationLayer = nullptr;
958 // Each layer that is inside a multicolumn flow thread has to be checked individually and
959 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
960 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
961 // to that layer easily.
962 if (renderer().isInFlowRenderFlowThread()) {
963 m_enclosingPaginationLayer = this;
967 if (isNormalFlowOnly()) {
968 // Content inside a transform is not considered to be paginated, since we simply
969 // paint the transform multiple times in each column, so we don't have to use
970 // fragments for the transformed content.
971 if (parent()->hasTransform())
972 m_enclosingPaginationLayer = nullptr;
974 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
978 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
979 // we find one, then we just check its pagination status.
980 RenderView* renderView = &renderer().view();
981 RenderBlock* containingBlock;
982 for (containingBlock = renderer().containingBlock(); containingBlock && containingBlock != renderView; containingBlock = containingBlock->containingBlock()) {
983 if (containingBlock->hasLayer()) {
984 // Content inside a transform is not considered to be paginated, since we simply
985 // paint the transform multiple times in each column, so we don't have to use
986 // fragments for the transformed content.
987 if (containingBlock->layer()->hasTransform())
988 m_enclosingPaginationLayer = nullptr;
990 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
996 bool RenderLayer::canBeStackingContainer() const
998 if (isStackingContext() || !stackingContainer())
1001 return m_descendantsAreContiguousInStackingOrder;
1004 void RenderLayer::setHasVisibleContent()
1006 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1007 ASSERT(!parent() || parent()->hasVisibleDescendant());
1011 m_visibleContentStatusDirty = false;
1012 m_hasVisibleContent = true;
1013 computeRepaintRects(renderer().containerForRepaint());
1014 if (!isNormalFlowOnly()) {
1015 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1016 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1017 // collected. FIXME: When compositing, we could skip this dirtying phase.
1018 for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
1019 sc->dirtyZOrderLists();
1020 if (sc->hasVisibleContent())
1026 parent()->setAncestorChainHasVisibleDescendant();
1029 void RenderLayer::dirtyVisibleContentStatus()
1031 m_visibleContentStatusDirty = true;
1033 parent()->dirtyAncestorChainVisibleDescendantStatus();
1036 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1038 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1039 if (layer->m_visibleDescendantStatusDirty)
1042 layer->m_visibleDescendantStatusDirty = true;
1046 void RenderLayer::setAncestorChainHasVisibleDescendant()
1048 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1049 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1052 layer->m_hasVisibleDescendant = true;
1053 layer->m_visibleDescendantStatusDirty = false;
1057 void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
1059 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
1060 bool hasVisibleDescendant = false;
1061 bool hasSelfPaintingLayerDescendant = false;
1062 bool hasOutOfFlowPositionedDescendant = false;
1063 #if ENABLE(CSS_COMPOSITING)
1064 bool hasNotIsolatedBlendingDescendants = false;
1067 HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
1068 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1069 childOutOfFlowDescendantContainingBlocks.clear();
1070 child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
1072 bool childIsOutOfFlowPositioned = child->renderer().isOutOfFlowPositioned();
1073 if (childIsOutOfFlowPositioned)
1074 childOutOfFlowDescendantContainingBlocks.add(child->renderer().containingBlock());
1076 if (outOfFlowDescendantContainingBlocks) {
1077 HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
1078 for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
1079 outOfFlowDescendantContainingBlocks->add(*it);
1082 hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1083 hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1084 hasOutOfFlowPositionedDescendant |= !childOutOfFlowDescendantContainingBlocks.isEmpty();
1085 #if ENABLE(CSS_COMPOSITING)
1086 hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
1089 bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant;
1090 #if ENABLE(CSS_COMPOSITING)
1091 allFlagsSet &= hasNotIsolatedBlendingDescendants;
1097 if (outOfFlowDescendantContainingBlocks)
1098 outOfFlowDescendantContainingBlocks->remove(&renderer());
1100 m_hasVisibleDescendant = hasVisibleDescendant;
1101 m_visibleDescendantStatusDirty = false;
1102 m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
1103 m_hasSelfPaintingLayerDescendantDirty = false;
1105 m_hasOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant;
1106 if (m_hasOutOfFlowPositionedDescendantDirty)
1107 updateNeedsCompositedScrolling();
1109 m_hasOutOfFlowPositionedDescendantDirty = false;
1110 #if ENABLE(CSS_COMPOSITING)
1111 m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
1112 if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
1113 m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
1114 updateSelfPaintingLayer();
1119 if (m_visibleContentStatusDirty) {
1120 if (renderer().style().visibility() == VISIBLE)
1121 m_hasVisibleContent = true;
1123 // layer may be hidden but still have some visible content, check for this
1124 m_hasVisibleContent = false;
1125 RenderObject* r = renderer().firstChild();
1127 if (r->style().visibility() == VISIBLE && !r->hasLayer()) {
1128 m_hasVisibleContent = true;
1131 RenderObject* child = nullptr;
1132 if (!r->hasLayer() && (child = r->firstChildSlow()))
1134 else if (r->nextSibling())
1135 r = r->nextSibling();
1139 if (r == &renderer())
1141 } while (r && !r->nextSibling());
1143 r = r->nextSibling();
1147 m_visibleContentStatusDirty = false;
1151 void RenderLayer::dirty3DTransformedDescendantStatus()
1153 RenderLayer* curr = stackingContainer();
1155 curr->m_3DTransformedDescendantStatusDirty = true;
1157 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1158 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1159 while (curr && curr->preserves3D()) {
1160 curr->m_3DTransformedDescendantStatusDirty = true;
1161 curr = curr->stackingContainer();
1165 // Return true if this layer or any preserve-3d descendants have 3d.
1166 bool RenderLayer::update3DTransformedDescendantStatus()
1168 if (m_3DTransformedDescendantStatusDirty) {
1169 m_has3DTransformedDescendant = false;
1171 updateZOrderLists();
1173 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1174 // in the normal flow list, so we only need to check those.
1175 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
1176 for (unsigned i = 0; i < positiveZOrderList->size(); ++i)
1177 m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus();
1180 // Now check our negative z-index children.
1181 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
1182 for (unsigned i = 0; i < negativeZOrderList->size(); ++i)
1183 m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus();
1186 m_3DTransformedDescendantStatusDirty = false;
1189 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1190 // the m_has3DTransformedDescendant set.
1192 return has3DTransform() || m_has3DTransformedDescendant;
1194 return has3DTransform();
1197 bool RenderLayer::updateLayerPosition()
1199 LayoutPoint localPoint;
1200 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1201 if (renderer().isInline() && is<RenderInline>(renderer())) {
1202 auto& inlineFlow = downcast<RenderInline>(renderer());
1203 IntRect lineBox = inlineFlow.linesBoundingBox();
1204 setSize(lineBox.size());
1205 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1206 localPoint += inlineBoundingBoxOffset;
1207 } else if (RenderBox* box = renderBox()) {
1208 // FIXME: Is snapping the size really needed here for the RenderBox case?
1209 setSize(box->pixelSnappedSize());
1210 localPoint += box->topLeftLocationOffset();
1213 if (!renderer().isOutOfFlowPositioned() && renderer().parent()) {
1214 // We must adjust our position by walking up the render tree looking for the
1215 // nearest enclosing object with a layer.
1216 RenderElement* ancestor = renderer().parent();
1217 while (ancestor && !ancestor->hasLayer()) {
1218 if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
1219 // Rows and cells share the same coordinate space (that of the section).
1220 // Omit them when computing our xpos/ypos.
1221 localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1223 ancestor = ancestor->parent();
1225 if (is<RenderBox>(*ancestor) && is<RenderTableRow>(*ancestor)) {
1226 // Put ourselves into the row coordinate space.
1227 localPoint -= downcast<RenderBox>(*ancestor).topLeftLocationOffset();
1231 // Subtract our parent's scroll offset.
1232 if (renderer().isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
1233 RenderLayer* positionedParent = enclosingPositionedAncestor();
1235 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1236 if (positionedParent->renderer().hasOverflowClip()) {
1237 LayoutSize offset = positionedParent->scrolledContentOffset();
1238 localPoint -= offset;
1241 if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
1242 LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
1243 localPoint += offset;
1245 } else if (parent()) {
1246 if (parent()->renderer().hasOverflowClip()) {
1247 IntSize scrollOffset = parent()->scrolledContentOffset();
1248 localPoint -= scrollOffset;
1252 bool positionOrOffsetChanged = false;
1253 if (renderer().isInFlowPositioned()) {
1254 LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
1255 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
1256 m_offsetForInFlowPosition = newOffset;
1257 localPoint.move(m_offsetForInFlowPosition);
1259 m_offsetForInFlowPosition = LayoutSize();
1262 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1263 localPoint -= inlineBoundingBoxOffset;
1265 positionOrOffsetChanged |= location() != localPoint;
1266 setLocation(localPoint);
1267 return positionOrOffsetChanged;
1270 TransformationMatrix RenderLayer::perspectiveTransform() const
1272 if (!renderer().hasTransform())
1273 return TransformationMatrix();
1275 const RenderStyle& style = renderer().style();
1276 if (!style.hasPerspective())
1277 return TransformationMatrix();
1279 // Maybe fetch the perspective from the backing?
1280 const IntRect borderBox = downcast<RenderBox>(renderer()).pixelSnappedBorderBoxRect();
1281 const float boxWidth = borderBox.width();
1282 const float boxHeight = borderBox.height();
1284 float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), boxWidth);
1285 float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), boxHeight);
1287 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
1288 // We want it to be in the top-left, so subtract half the height and width.
1289 perspectiveOriginX -= boxWidth / 2.0f;
1290 perspectiveOriginY -= boxHeight / 2.0f;
1292 TransformationMatrix t;
1293 t.translate(perspectiveOriginX, perspectiveOriginY);
1294 t.applyPerspective(style.perspective());
1295 t.translate(-perspectiveOriginX, -perspectiveOriginY);
1300 FloatPoint RenderLayer::perspectiveOrigin() const
1302 if (!renderer().hasTransform())
1303 return FloatPoint();
1305 const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
1306 const RenderStyle& style = renderer().style();
1308 return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
1309 floatValueForLength(style.perspectiveOriginY(), borderBox.height()));
1312 RenderLayer* RenderLayer::stackingContainer() const
1314 RenderLayer* layer = parent();
1315 while (layer && !layer->isStackingContainer())
1316 layer = layer->parent();
1318 ASSERT(!layer || layer->isStackingContainer());
1322 static inline bool isPositionedContainer(RenderLayer* layer)
1324 return layer->isRootLayer() || layer->renderer().isPositioned() || layer->hasTransform();
1327 static inline bool isFixedPositionedContainer(RenderLayer* layer)
1329 return layer->isRootLayer() || layer->hasTransform();
1332 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
1334 RenderLayer* curr = parent();
1335 while (curr && !isPositionedContainer(curr))
1336 curr = curr->parent();
1341 static RenderLayer* parentLayerCrossFrame(const RenderLayer* layer)
1344 if (layer->parent())
1345 return layer->parent();
1347 HTMLFrameOwnerElement* ownerElement = layer->renderer().document().ownerElement();
1351 RenderElement* ownerRenderer = ownerElement->renderer();
1355 return ownerRenderer->enclosingLayer();
1358 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1360 for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
1361 if (is<RenderBox>(nextLayer->renderer()) && downcast<RenderBox>(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
1368 IntRect RenderLayer::scrollableAreaBoundingBox() const
1370 return renderer().absoluteBoundingBoxRect();
1373 bool RenderLayer::isRubberBandInProgress() const
1375 #if ENABLE(RUBBER_BANDING)
1376 if (!scrollsOverflow())
1379 if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1380 return scrollAnimator->isRubberBandInProgress();
1386 bool RenderLayer::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
1388 Page* page = renderer().frame().page();
1389 return page && page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
1392 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1394 RenderLayer* curr = parent();
1395 while (curr && !curr->isRootLayer() && !curr->transform())
1396 curr = curr->parent();
1401 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
1403 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContainer();
1406 inline bool RenderLayer::shouldRepaintAfterLayout() const
1408 if (m_repaintStatus == NeedsNormalRepaint)
1411 // Composited layers that were moved during a positioned movement only
1412 // layout, don't need to be repainted. They just need to be recomposited.
1413 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1414 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1417 static bool compositedWithOwnBackingStore(const RenderLayer* layer)
1419 return layer->isComposited() && !layer->backing()->paintsIntoCompositedAncestor();
1422 RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
1424 if (includeSelf == IncludeSelf && isComposited())
1425 return const_cast<RenderLayer*>(this);
1427 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1428 if (curr->isComposited())
1429 return const_cast<RenderLayer*>(curr);
1435 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
1437 if (includeSelf == IncludeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
1438 return const_cast<RenderLayer*>(this);
1440 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1441 if (compositedWithOwnBackingStore(curr))
1442 return const_cast<RenderLayer*>(curr);
1448 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
1450 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
1451 for (; curr; curr = curr->parent()) {
1452 if (curr->requiresFullLayerImageForFilters())
1453 return const_cast<RenderLayer*>(curr);
1459 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1461 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1462 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(curr) || curr->isRootLayer())
1463 return const_cast<RenderLayer*>(curr);
1468 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
1473 LayoutRect rectForRepaint = rect;
1474 renderer().style().filterOutsets().expandRect(rectForRepaint);
1476 FilterInfo& filterInfo = FilterInfo::get(*this);
1477 filterInfo.expandDirtySourceRect(rectForRepaint);
1479 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1480 ASSERT(parentLayer);
1481 FloatQuad repaintQuad(rectForRepaint);
1482 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1484 if (parentLayer->isComposited()) {
1485 if (!parentLayer->backing()->paintsIntoWindow()) {
1486 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1489 // If the painting goes to window, redirect the painting to the parent RenderView.
1490 parentLayer = renderer().view().layer();
1491 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1494 if (parentLayer->paintsWithFilters()) {
1495 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
1499 if (parentLayer->isRootLayer()) {
1500 downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
1504 ASSERT_NOT_REACHED();
1507 bool RenderLayer::hasAncestorWithFilterOutsets() const
1509 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1510 if (curr->renderer().style().hasFilterOutsets())
1516 RenderLayer* RenderLayer::clippingRootForPainting() const
1519 return const_cast<RenderLayer*>(this);
1521 const RenderLayer* current = this;
1523 if (current->isRootLayer())
1524 return const_cast<RenderLayer*>(current);
1526 current = compositingContainer(current);
1528 if (current->transform() || compositedWithOwnBackingStore(current))
1529 return const_cast<RenderLayer*>(current);
1532 ASSERT_NOT_REACHED();
1536 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1538 // We don't use convertToLayerCoords because it doesn't know about transforms
1539 return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
1542 bool RenderLayer::cannotBlitToWindow() const
1544 if (isTransparent() || hasReflection() || hasTransform())
1548 return parent()->cannotBlitToWindow();
1551 RenderLayer* RenderLayer::transparentPaintingAncestor()
1556 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1557 if (curr->isComposited())
1559 if (curr->isTransparent())
1565 enum TransparencyClipBoxBehavior {
1566 PaintingTransparencyClipBox,
1567 HitTestingTransparencyClipBox
1570 enum TransparencyClipBoxMode {
1571 DescendantsOfTransparencyClipBox,
1572 RootOfTransparencyClipBox
1575 static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
1577 static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1578 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1580 // If this is a region, then the painting is actually done by its flow thread's layer.
1581 if (layer.renderer().isRenderNamedFlowFragmentContainer()) {
1582 RenderBlockFlow& regionContainer = downcast<RenderBlockFlow>(layer.renderer());
1583 RenderNamedFlowFragment& region = *regionContainer.renderNamedFlowFragment();
1584 RenderLayer* flowThreadLayer = region.flowThread()->layer();
1585 if (flowThreadLayer && (!layer.reflection() || layer.reflectionLayer() != flowThreadLayer)) {
1586 LayoutRect flowThreadClipRect = transparencyClipBox(*flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
1587 LayoutSize moveOffset = (regionContainer.contentBoxRect().location() + layer.offsetFromAncestor(flowThreadLayer)) - region.flowThreadPortionRect().location();
1588 flowThreadClipRect.move(moveOffset);
1590 clipRect.unite(flowThreadClipRect);
1595 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
1596 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1598 // If we have a mask, then the clip is limited to the border box area (and there is
1599 // no need to examine child layers).
1600 if (!layer.renderer().hasMask()) {
1601 // Note: we don't have to walk z-order lists since transparent elements always establish
1602 // a stacking container. This means we can just walk the layer tree directly.
1603 for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
1604 if (!layer.reflection() || layer.reflectionLayer() != curr)
1605 clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
1609 expandClipRectForRegionAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1611 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1612 // current transparencyClipBox to catch all child layers.
1613 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1614 // size into the parent layer.
1615 if (layer.renderer().hasReflection()) {
1616 LayoutSize delta = layer.offsetFromAncestor(rootLayer);
1617 clipRect.move(-delta);
1618 clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
1619 clipRect.move(delta);
1623 static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1624 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
1626 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1627 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1628 // would be better to respect clips.
1630 if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
1631 || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
1632 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1633 // the transformed layer and all of its children.
1634 RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
1635 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : 0;
1636 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1637 LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
1639 TransformationMatrix transform;
1640 transform.translate(delta.width(), delta.height());
1641 transform = transform * *layer.transform();
1643 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1644 // paints unfragmented.
1645 LayoutRect clipRect = layer.boundingBox(&layer);
1646 expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
1647 layer.renderer().style().filterOutsets().expandRect(clipRect);
1648 LayoutRect result = transform.mapRect(clipRect);
1649 if (!paginationLayer)
1652 // We have to break up the transformed extent across our columns.
1653 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1654 // get our true bounding box.
1655 auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
1656 result = enclosingFlowThread.fragmentsBoundingBox(result);
1657 result.move(paginationLayer->offsetFromAncestor(rootLayer));
1661 LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
1662 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1663 layer.renderer().style().filterOutsets().expandRect(clipRect);
1668 static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1670 return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
1673 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
1675 if (context->paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
1678 RenderLayer* ancestor = transparentPaintingAncestor();
1680 ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
1682 if (paintsWithTransparency(paintingInfo.paintBehavior)) {
1683 m_usedTransparency = true;
1685 LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
1686 adjustedClipRect.move(paintingInfo.subpixelAccumulation);
1687 FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
1688 context->clip(pixelSnappedClipRect);
1690 #if ENABLE(CSS_COMPOSITING)
1692 context->setCompositeOperation(context->compositeOperation(), blendMode());
1695 context->beginTransparencyLayer(renderer().opacity());
1697 #if ENABLE(CSS_COMPOSITING)
1699 context->setCompositeOperation(context->compositeOperation(), BlendModeNormal);
1702 #ifdef REVEAL_TRANSPARENCY_LAYERS
1703 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
1704 context->fillRect(pixelSnappedClipRect);
1710 void RenderLayer::willBeDestroyed()
1712 if (RenderLayerBacking* layerBacking = backing())
1713 layerBacking->layerWillBeDestroyed();
1717 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1719 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1721 child->setPreviousSibling(prevSibling);
1722 prevSibling->setNextSibling(child);
1723 ASSERT(prevSibling != child);
1725 setFirstChild(child);
1728 beforeChild->setPreviousSibling(child);
1729 child->setNextSibling(beforeChild);
1730 ASSERT(beforeChild != child);
1732 setLastChild(child);
1734 child->setParent(this);
1736 if (child->isNormalFlowOnly())
1737 dirtyNormalFlowList();
1739 if (!child->isNormalFlowOnly() || child->firstChild()) {
1740 // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
1741 // case where we're building up generated content layers. This is ok, since the lists will start
1742 // off dirty in that case anyway.
1743 child->dirtyStackingContainerZOrderLists();
1746 child->updateDescendantDependentFlags();
1747 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1748 setAncestorChainHasVisibleDescendant();
1750 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1751 setAncestorChainHasSelfPaintingLayerDescendant();
1753 if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
1754 setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
1756 #if ENABLE(CSS_COMPOSITING)
1757 if (child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending()))
1758 updateAncestorChainHasBlendingDescendants();
1761 compositor().layerWasAdded(*this, *child);
1764 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1766 if (!renderer().documentBeingDestroyed())
1767 compositor().layerWillBeRemoved(*this, *oldChild);
1770 if (oldChild->previousSibling())
1771 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1772 if (oldChild->nextSibling())
1773 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1775 if (m_first == oldChild)
1776 m_first = oldChild->nextSibling();
1777 if (m_last == oldChild)
1778 m_last = oldChild->previousSibling();
1780 if (oldChild->isNormalFlowOnly())
1781 dirtyNormalFlowList();
1782 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1783 // Dirty the z-order list in which we are contained. When called via the
1784 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1785 // from the main layer tree, so we need to null-check the |stackingContainer| value.
1786 oldChild->dirtyStackingContainerZOrderLists();
1789 if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
1790 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
1792 oldChild->setPreviousSibling(0);
1793 oldChild->setNextSibling(0);
1794 oldChild->setParent(0);
1796 oldChild->updateDescendantDependentFlags();
1797 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1798 dirtyAncestorChainVisibleDescendantStatus();
1800 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1801 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1803 #if ENABLE(CSS_COMPOSITING)
1804 if (oldChild->hasBlendMode() || (oldChild->hasNotIsolatedBlendingDescendants() && !oldChild->isolatesBlending()))
1805 dirtyAncestorChainHasBlendingDescendants();
1811 void RenderLayer::removeOnlyThisLayer()
1816 // Mark that we are about to lose our layer. This makes render tree
1817 // walks ignore this layer while we're removing it.
1818 renderer().setHasLayer(false);
1820 compositor().layerWillBeRemoved(*m_parent, *this);
1822 // Dirty the clip rects.
1823 clearClipRectsIncludingDescendants();
1825 RenderLayer* nextSib = nextSibling();
1827 // Remove the child reflection layer before moving other child layers.
1828 // The reflection layer should not be moved to the parent.
1830 removeChild(reflectionLayer());
1832 // Now walk our kids and reattach them to our parent.
1833 RenderLayer* current = m_first;
1835 RenderLayer* next = current->nextSibling();
1836 removeChild(current);
1837 m_parent->addChild(current, nextSib);
1838 current->setRepaintStatus(NeedsFullRepaint);
1839 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1840 ASSERT(!renderer().hasLayer());
1841 current->updateLayerPositions(0); // FIXME: use geometry map.
1845 // Remove us from the parent.
1846 m_parent->removeChild(this);
1847 renderer().destroyLayer();
1850 void RenderLayer::insertOnlyThisLayer()
1852 if (!m_parent && renderer().parent()) {
1853 // We need to connect ourselves when our renderer() has a parent.
1854 // Find our enclosingLayer and add ourselves.
1855 RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
1856 ASSERT(parentLayer);
1857 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : 0;
1858 parentLayer->addChild(this, beforeChild);
1861 // Remove all descendant layers from the hierarchy and add them to the new position.
1862 for (auto& child : childrenOfType<RenderElement>(renderer()))
1863 child.moveLayers(m_parent, this);
1865 // Clear out all the clip rects.
1866 clearClipRectsIncludingDescendants();
1869 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
1871 LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
1872 roundedLocation = roundedIntPoint(location);
1875 // Returns the layer reached on the walk up towards the ancestor.
1876 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
1878 ASSERT(ancestorLayer != layer);
1880 const RenderLayerModelObject& renderer = layer->renderer();
1881 EPosition position = renderer.style().position();
1883 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
1884 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : 0;
1885 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
1886 fixedFlowThreadContainer = nullptr;
1888 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
1889 // may need to be revisited in a future patch.
1890 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
1891 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
1892 // positioned in a completely different place in the viewport (RenderView).
1893 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
1894 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1895 // localToAbsolute() on the RenderView.
1896 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
1897 location += LayoutSize(absPos.x(), absPos.y());
1898 return ancestorLayer;
1901 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
1902 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
1903 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
1904 if (position == FixedPosition && !fixedFlowThreadContainer) {
1905 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1906 // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
1907 // so we should always find the ancestor at or before we find the fixed position container.
1908 RenderLayer* fixedPositionContainerLayer = nullptr;
1909 bool foundAncestor = false;
1910 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
1911 if (currLayer == ancestorLayer)
1912 foundAncestor = true;
1914 if (isFixedPositionedContainer(currLayer)) {
1915 fixedPositionContainerLayer = currLayer;
1916 ASSERT_UNUSED(foundAncestor, foundAncestor);
1921 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1923 if (fixedPositionContainerLayer != ancestorLayer) {
1924 LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
1925 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
1926 location += (fixedContainerCoords - ancestorCoords);
1927 return ancestorLayer;
1931 if (position == FixedPosition && fixedFlowThreadContainer) {
1932 ASSERT(ancestorLayer);
1933 if (ancestorLayer->isOutOfFlowRenderFlowThread()) {
1934 location += toLayoutSize(layer->location());
1935 return ancestorLayer;
1938 if (ancestorLayer == renderer.view().layer()) {
1939 // Add location in flow thread coordinates.
1940 location += toLayoutSize(layer->location());
1942 // Add flow thread offset in view coordinates since the view may be scrolled.
1943 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
1944 location += LayoutSize(absPos.x(), absPos.y());
1945 return ancestorLayer;
1949 RenderLayer* parentLayer;
1950 if (position == AbsolutePosition || position == FixedPosition) {
1951 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1952 parentLayer = layer->parent();
1953 bool foundAncestorFirst = false;
1954 while (parentLayer) {
1955 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
1956 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
1957 // we are bailing out before reaching root layer.
1958 if (isPositionedContainer(parentLayer))
1961 if (parentLayer == ancestorLayer) {
1962 foundAncestorFirst = true;
1966 parentLayer = parentLayer->parent();
1969 // We should not reach RenderView layer past the RenderFlowThread layer for any
1970 // children of the RenderFlowThread.
1971 if (renderer.flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
1972 ASSERT(parentLayer != renderer.view().layer());
1974 if (foundAncestorFirst) {
1975 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1976 // to enclosingPositionedAncestor and subtract.
1977 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1978 LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
1979 LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
1980 location += (thisCoords - ancestorCoords);
1981 return ancestorLayer;
1984 parentLayer = layer->parent();
1989 location += toLayoutSize(layer->location());
1991 if (adjustForColumns == RenderLayer::AdjustForColumns) {
1992 if (RenderLayer* parentLayer = layer->parent()) {
1993 if (is<RenderMultiColumnFlowThread>(parentLayer->renderer())) {
1994 RenderRegion* region = downcast<RenderMultiColumnFlowThread>(parentLayer->renderer()).physicalTranslationFromFlowToRegion(location);
1996 location.moveBy(region->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2004 LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2006 if (ancestorLayer == this)
2009 const RenderLayer* currLayer = this;
2010 LayoutPoint locationInLayerCoords = location;
2011 while (currLayer && currLayer != ancestorLayer)
2012 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
2013 return locationInLayerCoords;
2016 LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer) const
2018 return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint()));
2022 bool RenderLayer::hasAcceleratedTouchScrolling() const
2024 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2025 if (!scrollsOverflow())
2028 Settings* settings = renderer().document().settings();
2029 // FIXME: settings should not be null at this point. If you find a reliable way to hit this assertion, please file a bug.
2030 // See <rdar://problem/10266101>.
2033 return renderer().style().useTouchOverflowScrolling() || (settings && settings->alwaysUseAcceleratedOverflowScroll());
2039 bool RenderLayer::hasTouchScrollableOverflow() const
2041 return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2044 #if ENABLE(TOUCH_EVENTS)
2045 bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
2047 // If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
2048 if (hasTouchScrollableOverflow())
2051 return ScrollableArea::handleTouchEvent(touchEvent);
2054 #endif // PLATFORM(IOS)
2056 #if ENABLE(IOS_TOUCH_EVENTS)
2057 void RenderLayer::registerAsTouchEventListenerForScrolling()
2059 if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
2062 renderer().document().addTouchEventListener(renderer().element());
2063 m_registeredAsTouchEventListenerForScrolling = true;
2066 void RenderLayer::unregisterAsTouchEventListenerForScrolling()
2068 if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
2071 renderer().document().removeTouchEventListener(renderer().element());
2072 m_registeredAsTouchEventListenerForScrolling = false;
2074 #endif // ENABLE(IOS_TOUCH_EVENTS)
2076 bool RenderLayer::usesCompositedScrolling() const
2078 return isComposited() && backing()->scrollingLayer();
2081 bool RenderLayer::needsCompositedScrolling() const
2083 return m_needsCompositedScrolling;
2086 void RenderLayer::updateNeedsCompositedScrolling()
2088 bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
2090 if (!renderer().view().frameView().containsScrollableArea(this))
2091 m_needsCompositedScrolling = false;
2093 bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
2094 && canBeStackingContainer()
2095 && !hasOutOfFlowPositionedDescendant();
2097 #if !PLATFORM(IOS) && ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2098 m_needsCompositedScrolling = forceUseCompositedScrolling || renderer().style().useTouchOverflowScrolling();
2100 // On iOS we don't want to opt into accelerated composited scrolling, which creates scroll bar
2101 // layers in WebCore, because we use UIKit to composite our scroll bars.
2102 m_needsCompositedScrolling = forceUseCompositedScrolling;
2106 if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
2107 updateSelfPaintingLayer();
2108 if (isStackingContainer())
2113 dirtyStackingContainerZOrderLists();
2115 compositor().setShouldReevaluateCompositingAfterLayout();
2116 compositor().setCompositingLayersNeedRebuild();
2120 static inline int adjustedScrollDelta(int beginningDelta) {
2121 // This implemention matches Firefox's.
2122 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
2123 const int speedReducer = 12;
2125 int adjustedDelta = beginningDelta / speedReducer;
2126 if (adjustedDelta > 1)
2127 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
2128 else if (adjustedDelta < -1)
2129 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
2131 return adjustedDelta;
2134 static inline IntSize adjustedScrollDelta(const IntSize& delta)
2136 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
2139 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
2141 IntPoint lastKnownMousePosition = renderer().frame().eventHandler().lastKnownMousePosition();
2143 // 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
2144 static IntPoint previousMousePosition;
2145 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
2146 lastKnownMousePosition = previousMousePosition;
2148 previousMousePosition = lastKnownMousePosition;
2150 IntSize delta = lastKnownMousePosition - sourcePoint;
2152 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
2154 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
2157 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
2160 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp, ScrollableArea** scrolledArea)
2165 bool restrictedByLineClamp = false;
2166 if (renderer().parent())
2167 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2169 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2170 IntSize newScrollOffset = scrollOffset() + delta;
2171 scrollToOffset(newScrollOffset, clamp);
2173 *scrolledArea = this;
2175 // If this layer can't do the scroll we ask the next layer up that can scroll to try
2176 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
2177 if (!remainingScrollOffset.isZero() && renderer().parent()) {
2178 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2179 scrollableLayer->scrollByRecursively(remainingScrollOffset, clamp, scrolledArea);
2181 renderer().frame().eventHandler().updateAutoscrollRenderer();
2184 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
2185 // have an overflow clip. Which means that it is a document node that can be scrolled.
2186 renderer().view().frameView().scrollBy(delta);
2188 *scrolledArea = &renderer().view().frameView();
2190 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
2191 // https://bugs.webkit.org/show_bug.cgi?id=28237
2195 IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const
2197 RenderBox* box = renderBox();
2200 int maxX = scrollWidth() - box->pixelSnappedClientWidth();
2201 int maxY = scrollHeight() - box->pixelSnappedClientHeight();
2203 int x = std::max(std::min(scrollOffset.width(), maxX), 0);
2204 int y = std::max(std::min(scrollOffset.height(), maxY), 0);
2205 return IntSize(x, y);
2208 void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp)
2210 IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2211 if (newScrollOffset != this->scrollOffset())
2212 scrollToOffsetWithoutAnimation(IntPoint(newScrollOffset));
2215 void RenderLayer::scrollTo(int x, int y)
2217 RenderBox* box = renderBox();
2221 if (box->style().overflowX() != OMARQUEE) {
2222 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
2223 if (m_scrollDimensionsDirty)
2224 computeScrollDimensions();
2226 if (adjustForIOSCaretWhenScrolling()) {
2227 int maxX = scrollWidth() - box->clientWidth();
2228 if (x > maxX - caretWidth) {
2230 if (x <= caretWidth)
2232 } else if (x < m_scrollOffset.width() - caretWidth)
2238 // FIXME: Eventually, we will want to perform a blit. For now never
2239 // blit, since the check for blitting is going to be very
2240 // complicated (since it will involve testing whether our layer
2241 // is either occluded by another layer or clipped by an enclosing
2242 // layer or contains fixed backgrounds, etc.).
2243 IntSize newScrollOffset = IntSize(x - scrollOrigin().x(), y - scrollOrigin().y());
2244 if (m_scrollOffset == newScrollOffset) {
2246 if (m_requiresScrollBoundsOriginUpdate)
2247 updateCompositingLayersAfterScroll();
2252 IntPoint oldPosition = IntPoint(m_scrollOffset);
2253 m_scrollOffset = newScrollOffset;
2255 InspectorInstrumentation::willScrollLayer(&renderer().frame());
2257 RenderView& view = renderer().view();
2259 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
2260 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
2261 bool inLayout = view.frameView().isInLayout();
2263 // If we're in the middle of layout, we'll just update layers once layout has finished.
2264 updateLayerPositionsAfterOverflowScroll();
2265 // Update regions, scrolling may change the clip of a particular region.
2266 #if ENABLE(DASHBOARD_SUPPORT)
2267 view.frameView().updateAnnotatedRegions();
2269 view.frameView().updateWidgetPositions();
2271 if (!m_updatingMarqueePosition) {
2272 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
2273 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
2274 // in this case we're still updating their positions; we'll update compositing layers later
2275 // when that completes.
2276 updateCompositingLayersAfterScroll();
2279 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
2280 renderer().document().dirtyTouchEventRects();
2284 Frame& frame = renderer().frame();
2285 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
2286 // The caret rect needs to be invalidated after scrolling
2287 frame.selection().setCaretRectNeedsUpdate();
2289 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
2290 if (repaintContainer)
2291 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
2292 frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
2294 bool requiresRepaint = true;
2295 if (compositor().inCompositingMode() && usesCompositedScrolling())
2296 requiresRepaint = false;
2298 // Just schedule a full repaint of our object.
2299 if (requiresRepaint)
2300 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
2302 // Schedule the scroll and scroll-related DOM events.
2303 if (Element* element = renderer().element()) {
2304 element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
2305 element->document().sendWillRevealEdgeEventsIfNeeded(oldPosition, IntPoint(newScrollOffset), visibleContentRect(), contentsSize(), element);
2308 InspectorInstrumentation::didScrollLayer(&frame);
2309 if (scrollsOverflow())
2310 view.frameView().didChangeScrollOffset();
2312 view.frameView().resumeVisibleImageAnimationsIncludingSubframes();
2315 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
2317 // If scrollbars aren't explicitly forbidden, permit scrolling.
2318 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
2321 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2322 if (frameView->wasScrolledByUser())
2325 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2326 // like navigation to an anchor.
2327 return !frameView->frame().eventHandler().autoscrollInProgress();
2330 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2332 RenderLayer* parentLayer = nullptr;
2333 LayoutRect newRect = rect;
2335 // We may end up propagating a scroll event. It is important that we suspend events until
2336 // the end of the function since they could delete the layer or the layer's renderer().
2337 FrameView& frameView = renderer().view().frameView();
2339 bool restrictedByLineClamp = false;
2340 if (renderer().parent()) {
2341 parentLayer = renderer().parent()->enclosingLayer();
2342 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2345 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2346 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2347 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2348 RenderBox* box = renderBox();
2350 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
2351 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
2352 LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
2354 IntSize clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
2355 if (clampedScrollOffset != scrollOffset()) {
2356 IntSize oldScrollOffset = scrollOffset();
2357 scrollToOffset(clampedScrollOffset);
2358 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
2359 localExposeRect.move(-scrollOffsetDifference);
2360 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
2362 } else if (!parentLayer && renderer().isBox() && renderBox()->canBeProgramaticallyScrolled()) {
2363 HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
2365 if (ownerElement && ownerElement->renderer()) {
2366 HTMLFrameElementBase* frameElementBase = nullptr;
2368 if (is<HTMLFrameElementBase>(*ownerElement))
2369 frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
2371 if (frameElementAndViewPermitScroll(frameElementBase, &frameView)) {
2372 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
2373 LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
2375 int xOffset = roundToInt(exposeRect.x());
2376 int yOffset = roundToInt(exposeRect.y());
2377 // Adjust offsets if they're outside of the allowable range.
2378 xOffset = std::max(0, std::min(frameView.contentsWidth(), xOffset));
2379 yOffset = std::max(0, std::min(frameView.contentsHeight(), yOffset));
2381 frameView.setScrollPosition(IntPoint(xOffset, yOffset));
2382 if (frameView.safeToPropagateScrollToParent()) {
2383 parentLayer = ownerElement->renderer()->enclosingLayer();
2384 // FIXME: This doesn't correctly convert the rect to
2385 // absolute coordinates in the parent.
2386 newRect.setX(rect.x() - frameView.scrollX() + frameView.x());
2387 newRect.setY(rect.y() - frameView.scrollY() + frameView.y());
2389 parentLayer = nullptr;
2393 LayoutRect viewRect = frameView.visibleContentRect();
2394 LayoutRect visibleRectRelativeToDocument = viewRect;
2395 IntSize documentScrollOffsetRelativeToScrollableAreaOrigin = frameView.documentScrollOffsetRelativeToScrollableAreaOrigin();
2396 visibleRectRelativeToDocument.setLocation(IntPoint(documentScrollOffsetRelativeToScrollableAreaOrigin.width(), documentScrollOffsetRelativeToScrollableAreaOrigin.height()));
2398 LayoutRect viewRect = frameView.unobscuredContentRect();
2399 LayoutRect visibleRectRelativeToDocument = viewRect;
2402 LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
2404 frameView.setScrollPosition(roundedIntPoint(r.location()));
2406 // This is the outermost view of a web page, so after scrolling this view we
2407 // scroll its container by calling Page::scrollRectIntoView.
2408 // This only has an effect on the Mac platform in applications
2409 // that put web views into scrolling containers, such as Mac OS X Mail.
2410 // The canAutoscroll function in EventHandler also knows about this.
2411 if (Page* page = frameView.frame().page())
2412 page->chrome().scrollRectIntoView(snappedIntRect(rect));
2416 if (renderer().frame().eventHandler().autoscrollInProgress())
2417 parentLayer = enclosingScrollableLayer();
2420 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
2423 void RenderLayer::updateCompositingLayersAfterScroll()
2425 if (compositor().inCompositingMode()) {
2426 // Our stacking container is guaranteed to contain all of our descendants that may need
2427 // repositioning, so update compositing layers from there.
2428 if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
2429 if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
2430 compositor().updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor);
2432 compositor().updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
2437 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2439 // Determine the appropriate X behavior.
2440 ScrollBehavior scrollX;
2441 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
2442 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
2443 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
2444 // If the rectangle is fully visible, use the specified visible behavior.
2445 // If the rectangle is partially visible, but over a certain threshold,
2446 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2447 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2448 else if (intersectWidth == visibleRect.width()) {
2449 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2450 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2451 if (scrollX == alignCenter)
2453 } else if (intersectWidth > 0)
2454 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2455 scrollX = ScrollAlignment::getPartialBehavior(alignX);
2457 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
2458 // If we're trying to align to the closest edge, and the exposeRect is further right
2459 // than the visibleRect, and not bigger than the visible area, then align with the right.
2460 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2461 scrollX = alignRight;
2463 // Given the X behavior, compute the X coordinate.
2465 if (scrollX == noScroll)
2466 x = visibleRect.x();
2467 else if (scrollX == alignRight)
2468 x = exposeRect.maxX() - visibleRect.width();
2469 else if (scrollX == alignCenter)
2470 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2474 // Determine the appropriate Y behavior.
2475 ScrollBehavior scrollY;
2476 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
2477 LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
2478 if (intersectHeight == exposeRect.height())
2479 // If the rectangle is fully visible, use the specified visible behavior.
2480 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2481 else if (intersectHeight == visibleRect.height()) {
2482 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2483 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2484 if (scrollY == alignCenter)
2486 } else if (intersectHeight > 0)
2487 // If the rectangle is partially visible, use the specified partial behavior
2488 scrollY = ScrollAlignment::getPartialBehavior(alignY);
2490 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
2491 // If we're trying to align to the closest edge, and the exposeRect is further down
2492 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2493 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2494 scrollY = alignBottom;
2496 // Given the Y behavior, compute the Y coordinate.
2498 if (scrollY == noScroll)
2499 y = visibleRect.y();
2500 else if (scrollY == alignBottom)
2501 y = exposeRect.maxY() - visibleRect.height();
2502 else if (scrollY == alignCenter)
2503 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2507 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2510 void RenderLayer::autoscroll(const IntPoint& position)
2512 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
2513 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2516 bool RenderLayer::canResize() const
2518 // We need a special case for <iframe> because they never have
2519 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
2520 // we want to allow resizing them also.
2521 return (renderer().hasOverflowClip() || renderer().isRenderIFrame()) && renderer().style().resize() != RESIZE_NONE;
2524 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2526 // FIXME: This should be possible on generated content but is not right now.
2527 if (!inResizeMode() || !canResize() || !renderer().element())
2530 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2531 // If they do it would still be better to deal with them explicitly.
2532 Element* element = renderer().element();
2533 auto* renderer = downcast<RenderBox>(element->renderer());
2535 Document& document = element->document();
2536 if (!document.frame()->eventHandler().mousePressed())
2539 float zoomFactor = renderer->style().effectiveZoom();
2541 LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(evt.position()));
2542 newOffset.setWidth(newOffset.width() / zoomFactor);
2543 newOffset.setHeight(newOffset.height() / zoomFactor);
2545 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2546 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2547 element->setMinimumSizeForResizing(minimumSize);
2549 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2550 if (renderer->style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
2551 newOffset.setWidth(-newOffset.width());
2552 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2555 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2557 StyledElement* styledElement = downcast<StyledElement>(element);
2558 bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
2560 EResize resize = renderer->style().resize();
2561 if (resize != RESIZE_VERTICAL && difference.width()) {
2562 if (is<HTMLFormControlElement>(*element)) {
2563 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2564 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2565 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2567 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
2568 baseWidth = baseWidth / zoomFactor;
2569 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
2572 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2573 if (is<HTMLFormControlElement>(*element)) {
2574 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2575 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2576 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2578 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
2579 baseHeight = baseHeight / zoomFactor;
2580 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
2583 document.updateLayout();
2585 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2588 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2590 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2591 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2594 void RenderLayer::setScrollOffset(const IntPoint& offset)
2596 scrollTo(offset.x(), offset.y());
2599 int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
2601 if (scrollbar->orientation() == HorizontalScrollbar)
2602 return scrollXOffset();
2603 if (scrollbar->orientation() == VerticalScrollbar)
2604 return scrollYOffset();
2608 IntPoint RenderLayer::scrollPosition() const
2610 return IntPoint(m_scrollOffset);
2613 IntPoint RenderLayer::minimumScrollPosition() const
2615 return -scrollOrigin();
2618 IntPoint RenderLayer::maximumScrollPosition() const
2620 // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
2621 return -scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRectIncludingScrollbars(ContentsVisibleRect).size();
2624 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
2626 int verticalScrollbarWidth = 0;
2627 int horizontalScrollbarHeight = 0;
2628 if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars) {
2629 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
2630 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
2633 return IntRect(scrollPosition(), IntSize(std::max(0, m_layerSize.width() - verticalScrollbarWidth), std::max(0, m_layerSize.height() - horizontalScrollbarHeight)));
2636 IntSize RenderLayer::overhangAmount() const
2638 #if ENABLE(RUBBER_BANDING)
2639 if (!renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled())
2644 int physicalScrollY = scrollPosition().y() + scrollOrigin().y();
2645 if (physicalScrollY < 0)
2646 stretch.setHeight(physicalScrollY);
2647 else if (scrollableContentsSize().height() && physicalScrollY > scrollableContentsSize().height() - visibleHeight())
2648 stretch.setHeight(physicalScrollY - (scrollableContentsSize().height() - visibleHeight()));
2650 int physicalScrollX = scrollPosition().x() + scrollOrigin().x();
2651 if (physicalScrollX < 0)
2652 stretch.setWidth(physicalScrollX);
2653 else if (scrollableContentsSize().width() && physicalScrollX > scrollableContentsSize().width() - visibleWidth())
2654 stretch.setWidth(physicalScrollX - (scrollableContentsSize().width() - visibleWidth()));
2662 bool RenderLayer::isActive() const
2664 Page* page = renderer().frame().page();
2665 return page && page->focusController().isActive();
2668 static int cornerStart(const RenderLayer* layer, int minX, int maxX, int thickness)
2670 if (layer->renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2671 return minX + layer->renderer().style().borderLeftWidth();
2672 return maxX - thickness - layer->renderer().style().borderRightWidth();
2675 static LayoutRect cornerRect(const RenderLayer* layer, const LayoutRect& bounds)
2677 int horizontalThickness;
2678 int verticalThickness;
2679 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2680 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2681 // even when they don't exist in order to set the resizer square size properly.
2682 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
2683 verticalThickness = horizontalThickness;
2684 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2685 horizontalThickness = layer->verticalScrollbar()->width();
2686 verticalThickness = horizontalThickness;
2687 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
2688 verticalThickness = layer->horizontalScrollbar()->height();
2689 horizontalThickness = verticalThickness;
2691 horizontalThickness = layer->verticalScrollbar()->width();
2692 verticalThickness = layer->horizontalScrollbar()->height();
2694 return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2695 bounds.maxY() - verticalThickness - layer->renderer().style().borderBottomWidth(),
2696 horizontalThickness, verticalThickness);
2699 IntRect RenderLayer::scrollCornerRect() const
2701 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
2702 // This happens when:
2703 // (a) A resizer is present and at least one scrollbar is present
2704 // (b) Both scrollbars are present.
2705 bool hasHorizontalBar = horizontalScrollbar();
2706 bool hasVerticalBar = verticalScrollbar();
2707 bool hasResizer = renderer().style().resize() != RESIZE_NONE;
2708 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2709 return snappedIntRect(cornerRect(this, renderBox()->borderBoxRect()));
2713 static LayoutRect resizerCornerRect(const RenderLayer* layer, const LayoutRect& bounds)
2715 ASSERT(layer->renderer().isBox());
2716 if (layer->renderer().style().resize() == RESIZE_NONE)
2717 return LayoutRect();
2718 return cornerRect(layer, bounds);
2721 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
2723 RenderBox* box = renderBox();
2725 return LayoutRect();
2726 LayoutRect scrollCornerAndResizer = scrollCornerRect();
2727 if (scrollCornerAndResizer.isEmpty())
2728 scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect());
2729 return scrollCornerAndResizer;
2732 bool RenderLayer::isScrollCornerVisible() const
2734 ASSERT(renderer().isBox());
2735 return !scrollCornerRect().isEmpty();
2738 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
2740 IntRect rect = scrollbarRect;
2741 rect.move(scrollbarOffset(scrollbar));
2743 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), rect);
2746 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
2748 IntRect rect = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentRect);
2749 rect.move(-scrollbarOffset(scrollbar));
2753 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
2755 IntPoint point = scrollbarPoint;
2756 point.move(scrollbarOffset(scrollbar));
2757 return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), point);
2760 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
2762 IntPoint point = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentPoint);
2763 point.move(-scrollbarOffset(scrollbar));
2767 IntSize RenderLayer::visibleSize() const
2769 if (!renderer().isBox())
2772 return IntSize(renderBox()->pixelSnappedClientWidth(), renderBox()->pixelSnappedClientHeight());
2775 IntSize RenderLayer::contentsSize() const
2777 return IntSize(scrollWidth(), scrollHeight());
2780 IntSize RenderLayer::scrollableContentsSize() const
2782 IntSize contentsSize = this->contentsSize();
2784 if (!hasScrollableHorizontalOverflow())
2785 contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
2787 if (!hasScrollableVerticalOverflow())
2788 contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
2790 return contentsSize;
2793 bool RenderLayer::shouldSuspendScrollAnimations() const
2795 return renderer().view().frameView().shouldSuspendScrollAnimations();
2799 void RenderLayer::didStartScroll()
2801 if (Page* page = renderer().frame().page())
2802 page->chrome().client().didStartOverflowScroll();
2805 void RenderLayer::didEndScroll()
2807 if (Page* page = renderer().frame().page())
2808 page->chrome().client().didEndOverflowScroll();
2811 void RenderLayer::didUpdateScroll()
2813 // Send this notification when we scroll, since this is how we keep selection updated.
2814 if (Page* page = renderer().frame().page())
2815 page->chrome().client().didLayout(ChromeClient::Scroll);
2819 IntPoint RenderLayer::lastKnownMousePosition() const
2821 return renderer().frame().eventHandler().lastKnownMousePosition();
2824 bool RenderLayer::isHandlingWheelEvent() const
2826 return renderer().frame().eventHandler().isHandlingWheelEvent();
2829 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
2834 const RenderBox* box = renderBox();
2835 const IntRect& scrollCorner = scrollCornerRect();
2837 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
2838 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
2839 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2843 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
2848 const RenderBox* box = renderBox();
2849 const IntRect& scrollCorner = scrollCornerRect();
2851 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
2852 borderBoxRect.y() + box->borderTop(),
2854 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
2857 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
2859 const RenderBox* box = renderBox();
2860 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2861 return minX + box->borderLeft();
2862 return maxX - box->borderRight() - m_vBar->width();
2865 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
2867 const RenderBox* box = renderBox();
2868 int x = minX + box->borderLeft();
2869 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2870 x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(this, box->borderBoxRect()).width());
2874 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
2876 RenderBox* box = renderBox();
2878 if (scrollbar == m_vBar.get())
2879 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
2881 if (scrollbar == m_hBar.get())
2882 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2884 ASSERT_NOT_REACHED();
2888 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2890 if (!showsOverflowControls())
2893 if (scrollbar == m_vBar.get()) {
2894 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2895 layer->setNeedsDisplayInRect(rect);
2899 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2900 layer->setNeedsDisplayInRect(rect);
2905 IntRect scrollRect = rect;
2906 RenderBox* box = renderBox();
2908 // If we are not yet inserted into the tree, there is no need to repaint.
2912 if (scrollbar == m_vBar.get())
2913 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
2915 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2916 LayoutRect repaintRect = scrollRect;
2917 renderBox()->flipForWritingMode(repaintRect);
2918 renderer().repaintRectangle(repaintRect);
2921 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
2923 if (!showsOverflowControls())
2926 if (GraphicsLayer* layer = layerForScrollCorner()) {
2927 layer->setNeedsDisplayInRect(rect);
2932 m_scrollCorner->repaintRectangle(rect);
2934 m_resizer->repaintRectangle(rect);
2937 static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& renderer)
2939 if (Element* element = renderer.element()) {
2940 if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
2941 if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
2942 return shadowRoot->hostElement()->renderer();
2949 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
2951 RefPtr<Scrollbar> widget;
2952 RenderElement* actualRenderer = rendererForScrollbar(renderer());
2953 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style().hasPseudoStyle(SCROLLBAR);
2954 if (hasCustomScrollbarStyle)
2955 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->element());
2957 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
2958 didAddScrollbar(widget.get(), orientation);
2960 renderer().view().frameView().addChild(widget.get());
2961 return widget.release();
2964 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
2966 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
2970 if (!scrollbar->isCustomScrollbar())
2971 willRemoveScrollbar(scrollbar.get(), orientation);
2973 scrollbar->removeFromParent();
2974 scrollbar->disconnectFromScrollableArea();
2975 scrollbar = nullptr;
2978 bool RenderLayer::scrollsOverflow() const
2980 if (!is<RenderBox>(renderer()))
2983 return downcast<RenderBox>(renderer()).scrollsOverflow();
2986 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
2988 if (hasScrollbar == hasHorizontalScrollbar())
2992 m_hBar = createScrollbar(HorizontalScrollbar);
2993 #if ENABLE(RUBBER_BANDING)
2994 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
2995 ScrollableArea::setHorizontalScrollElasticity(elasticity);
2998 destroyScrollbar(HorizontalScrollbar);
2999 #if ENABLE(RUBBER_BANDING)
3000 ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityNone);
3004 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3006 m_hBar->styleChanged();
3008 m_vBar->styleChanged();
3010 // Force an update since we know the scrollbars have changed things.
3011 #if ENABLE(DASHBOARD_SUPPORT)
3012 if (renderer().document().hasAnnotatedRegions())
3013 renderer().document().setAnnotatedRegionsDirty(true);
3017 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
3019 if (hasScrollbar == hasVerticalScrollbar())
3023 m_vBar = createScrollbar(VerticalScrollbar);
3024 #if ENABLE(RUBBER_BANDING)
3025 ScrollElasticity elasticity = scrollsOverflow() && renderer().frame().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
3026 ScrollableArea::setVerticalScrollElasticity(elasticity);
3029 destroyScrollbar(VerticalScrollbar);
3030 #if ENABLE(RUBBER_BANDING)
3031 ScrollableArea::setVerticalScrollElasticity(ScrollElasticityNone);
3035 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3037 m_hBar->styleChanged();
3039 m_vBar->styleChanged();
3041 // Force an update since we know the scrollbars have changed things.
3042 #if ENABLE(DASHBOARD_SUPPORT)
3043 if (renderer().document().hasAnnotatedRegions())
3044 renderer().document().setAnnotatedRegionsDirty(true);
3048 ScrollableArea* RenderLayer::enclosingScrollableArea() const
3050 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
3051 return scrollableLayer;
3053 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
3054 // if the frame view isn't scrollable.
3058 bool RenderLayer::isScrollableOrRubberbandable()
3060 return renderer().isScrollableOrRubberbandableBox();
3063 bool RenderLayer::hasScrollableOrRubberbandableAncestor()
3065 for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
3066 if (nextLayer->isScrollableOrRubberbandable())
3073 #if ENABLE(CSS_SCROLL_SNAP)
3074 void RenderLayer::updateSnapOffsets()
3076 // FIXME: Extend support beyond HTMLElements.
3077 if (!is<HTMLElement>(enclosingElement()) || !enclosingElement()->renderBox())
3080 RenderBox* box = enclosingElement()->renderBox();
3081 updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
3085 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
3088 || !showsOverflowControls()
3089 || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
3092 return m_vBar->width();
3095 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
3098 || !showsOverflowControls()
3099 || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
3102 return m_hBar->height();
3105 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
3107 // Currently the resize corner is either the bottom right corner or the bottom left corner.
3108 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
3109 IntSize elementSize = size();
3110 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
3111 elementSize.setWidth(0);
3112 IntPoint resizerPoint = IntPoint(elementSize);
3113 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3114 return localPoint - resizerPoint;
3117 bool RenderLayer::hasOverflowControls() const
3119 return m_hBar || m_vBar || m_scrollCorner || renderer().style().resize() != RESIZE_NONE;
3122 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
3124 if (!m_hBar && !m_vBar && !canResize())
3127 RenderBox* box = renderBox();
3131 const IntRect borderBox = box->pixelSnappedBorderBoxRect();
3132 const IntRect& scrollCorner = scrollCornerRect();
3133 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
3135 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
3136 vBarRect.move(offsetFromRoot);
3137 m_vBar->setFrameRect(vBarRect);
3141 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
3142 hBarRect.move(offsetFromRoot);
3143 m_hBar->setFrameRect(hBarRect);
3147 m_scrollCorner->setFrameRect(scrollCorner);
3149 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
3152 backing()->positionOverflowControlsLayers();
3155 int RenderLayer::scrollWidth() const
3157 ASSERT(renderBox());
3158 if (m_scrollDimensionsDirty)
3159 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3160 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3161 return roundToInt(m_scrollSize.width());
3164 int RenderLayer::scrollHeight() const
3166 ASSERT(renderBox());
3167 if (m_scrollDimensionsDirty)
3168 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3169 // FIXME: This should use snappedIntSize() instead with absolute coordinates.
3170 return roundToInt(m_scrollSize.height());
3173 LayoutUnit RenderLayer::overflowTop() const
3175 RenderBox* box = renderBox();
3176 LayoutRect overflowRect(box->layoutOverflowRect());
3177 box->flipForWritingMode(overflowRect);
3178 return overflowRect.y();
3181 LayoutUnit RenderLayer::overflowBottom() const
3183 RenderBox* box = renderBox();
3184 LayoutRect overflowRect(box->layoutOverflowRect());
3185 box->flipForWritingMode(overflowRect);
3186 return overflowRect.maxY();
3189 LayoutUnit RenderLayer::overflowLeft() const
3191 RenderBox* box = renderBox();
3192 LayoutRect overflowRect(box->layoutOverflowRect());
3193 box->flipForWritingMode(overflowRect);
3194 return overflowRect.x();
3197 LayoutUnit RenderLayer::overflowRight() const
3199 RenderBox* box = renderBox();
3200 LayoutRect overflowRect(box->layoutOverflowRect());
3201 box->flipForWritingMode(overflowRect);
3202 return overflowRect.maxX();
3205 void RenderLayer::computeScrollDimensions()
3207 RenderBox* box = renderBox();
3210 m_scrollDimensionsDirty = false;
3212 m_scrollSize.setWidth(overflowRight() - overflowLeft());
3213 m_scrollSize.setHeight(overflowBottom() - overflowTop());
3215 int scrollableLeftOverflow = overflowLeft() - box->borderLeft();
3216 int scrollableTopOverflow = overflowTop() - box->borderTop();
3217 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
3220 bool RenderLayer::hasScrollableHorizontalOverflow() const
3222 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
3225 bool RenderLayer::hasScrollableVerticalOverflow() const
3227 return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
3230 bool RenderLayer::hasHorizontalOverflow() const
3232 ASSERT(!m_scrollDimensionsDirty);
3234 return scrollWidth() > renderBox()->pixelSnappedClientWidth();
3237 bool RenderLayer::hasVerticalOverflow() const
3239 ASSERT(!m_scrollDimensionsDirty);
3241 return scrollHeight() > renderBox()->pixelSnappedClientHeight();
3244 static bool styleRequiresScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
3246 EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
3247 bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme()->usesOverlayScrollbars();
3248 return overflow == OSCROLL && !overflowScrollActsLikeAuto;
3251 static bool styleDefinesAutomaticScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
3253 EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
3254 bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme()->usesOverlayScrollbars();
3255 return overflow == OAUTO || overflow == OOVERLAY || overflowScrollActsLikeAuto;
3258 void RenderLayer::updateScrollbarsAfterLayout()
3260 RenderBox* box = renderBox();
3263 // List box parts handle the scrollbars by themselves so we have nothing to do.
3264 if (box->style().appearance() == ListboxPart)
3267 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
3268 bool hasVerticalOverflow = this->hasVerticalOverflow();
3270 // If overflow requires a scrollbar, then we just need to enable or disable.
3271 if (styleRequiresScrollbar(renderer().style(), HorizontalScrollbar))
3272 m_hBar->setEnabled(hasHorizontalOverflow);
3273 if (styleRequiresScrollbar(renderer().style(), VerticalScrollbar))
3274 m_vBar->setEnabled(hasVerticalOverflow);
3276 // Scrollbars with auto behavior may need to lay out again if scrollbars got added or removed.
3277 bool autoHorizontalScrollBarChanged = box->hasHorizontalScrollbarWithAutoBehavior() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
3278 bool autoVerticalScrollBarChanged = box->hasVerticalScrollbarWithAutoBehavior() && (hasVerticalScrollbar() != hasVerticalOverflow);
3280 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
3281 if (box->hasHorizontalScrollbarWithAutoBehavior())
3282 setHasHorizontalScrollbar(hasHorizontalOverflow);
3283 if (box->hasVerticalScrollbarWithAutoBehavior())
3284 setHasVerticalScrollbar(hasVerticalOverflow);
3286 updateSelfPaintingLayer();
3288 // Force an update since we know the scrollbars have changed things.
3289 #if ENABLE(DASHBOARD_SUPPORT)
3290 if (renderer().document().hasAnnotatedRegions())
3291 renderer().document().setAnnotatedRegionsDirty(true);
3294 renderer().repaint();
3296 if (renderer().style().overflowX() == OAUTO || renderer().style().overflowY() == OAUTO) {
3297 if (!m_inOverflowRelayout) {
3298 // Our proprietary overflow: overlay value doesn't trigger a layout.
3299 m_inOverflowRelayout = true;
3300 renderer().setNeedsLayout(MarkOnlyThis);
3301 if (is<RenderBlock>(renderer())) {
3302 RenderBlock& block = downcast<RenderBlock>(renderer());
3303 block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
3304 block.layoutBlock(true);
3306 renderer().layout();
3307 m_inOverflowRelayout = false;
3312 // Set up the range (and page step/line step).
3314 int clientWidth = box->pixelSnappedClientWidth();
3315 int pageStep = Scrollbar::pageStep(clientWidth);
3316 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3317 m_hBar->setProportion(clientWidth, m_scrollSize.width().round());
3320 int clientHeight = box->pixelSnappedClientHeight();
3321 int pageStep = Scrollbar::pageStep(clientHeight);
3322 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3323 m_vBar->setProportion(clientHeight, m_scrollSize.height().round());
3326 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
3329 void RenderLayer::updateScrollInfoAfterLayout()
3331 RenderBox* box = renderBox();
3335 m_scrollDimensionsDirty = true;
3336 IntSize originalScrollOffset = scrollOffset();
3338 computeScrollDimensions();
3340 if (box->style().overflowX() != OMARQUEE && !isRubberBandInProgress()) {
3341 // Layout may cause us to be at an invalid scroll position. In this case we need
3342 // to pull our scroll offsets back to the max (or push them up to the min).
3343 IntSize clampedScrollOffset = clampScrollOffset(scrollOffset());
3345 // FIXME: This looks wrong. The caret adjust mode should only be enabled on editing related entry points.
3346 // This code was added to fix an issue where the text insertion point would always be drawn on the right edge
3347 // of a text field whose content overflowed its bounds. See <rdar://problem/15579797> for more details.
3348 setAdjustForIOSCaretWhenScrolling(true);
3350 if (clampedScrollOffset != scrollOffset())
3351 scrollToOffset(clampedScrollOffset);
3354 setAdjustForIOSCaretWhenScrolling(false);
3358 updateScrollbarsAfterLayout();
3360 if (originalScrollOffset != scrollOffset())
3361 scrollToOffsetWithoutAnimation(IntPoint(scrollOffset()));
3363 // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
3364 if (compositor().updateLayerCompositingState(*this))
3365 compositor().setCompositingLayersNeedRebuild();
3367 #if ENABLE(CSS_SCROLL_SNAP)
3368 // FIXME: Ensure that offsets are also updated in case of programmatic style changes.
3369 // https://bugs.webkit.org/show_bug.cgi?id=135964
3370 updateSnapOffsets();
3372 if (existingScrollAnimator())
3373 scrollAnimator()->updateScrollAnimatorsAndTimers();
3378 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
3380 const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect();
3382 if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
3385 if (rectForVerticalScrollbar(borderBox).intersects(localRect))
3388 if (scrollCornerRect().intersects(localRect))
3391 if (resizerCornerRect(this, borderBox).intersects(localRect))
3397 bool RenderLayer::showsOverflowControls() const
3400 // Don't render (custom) scrollbars if we have accelerated scrolling.
3401 if (hasAcceleratedTouchScrolling())
3408 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)