2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 "ColumnInfo.h"
50 #include "CSSPropertyNames.h"
53 #include "DocumentEventQueue.h"
55 #include "EventHandler.h"
56 #include "FloatConversion.h"
57 #include "FloatPoint3D.h"
58 #include "FloatRect.h"
59 #include "FloatRoundedRect.h"
60 #include "FlowThreadController.h"
61 #include "FocusController.h"
63 #include "FrameLoader.h"
64 #include "FrameLoaderClient.h"
65 #include "FrameSelection.h"
66 #include "FrameTree.h"
67 #include "FrameView.h"
69 #include "GraphicsContext.h"
70 #include "HTMLFrameElement.h"
71 #include "HTMLFrameOwnerElement.h"
72 #include "HTMLNames.h"
73 #include "HistogramSupport.h"
74 #include "HitTestingTransformState.h"
75 #include "HitTestRequest.h"
76 #include "HitTestResult.h"
77 #include "InspectorInstrumentation.h"
78 #include "OverflowEvent.h"
79 #include "OverlapTestRequestClient.h"
81 #include "PlatformMouseEvent.h"
82 #include "RenderFlowThread.h"
83 #include "RenderGeometryMap.h"
84 #include "RenderInline.h"
85 #include "RenderIterator.h"
86 #include "RenderLayerBacking.h"
87 #include "RenderLayerCompositor.h"
88 #include "RenderMarquee.h"
89 #include "RenderMultiColumnFlowThread.h"
90 #include "RenderNamedFlowFragment.h"
91 #include "RenderNamedFlowThread.h"
92 #include "RenderRegion.h"
93 #include "RenderReplica.h"
94 #include "RenderSVGResourceClipper.h"
95 #include "RenderScrollbar.h"
96 #include "RenderScrollbarPart.h"
97 #include "RenderTableCell.h"
98 #include "RenderTableRow.h"
99 #include "RenderTheme.h"
100 #include "RenderTreeAsText.h"
101 #include "RenderView.h"
102 #include "SVGNames.h"
103 #include "ScaleTransformOperation.h"
104 #include "ScrollAnimator.h"
105 #include "Scrollbar.h"
106 #include "ScrollbarTheme.h"
107 #include "ScrollingCoordinator.h"
108 #include "Settings.h"
109 #include "ShadowRoot.h"
110 #include "SourceGraphic.h"
111 #include "StyleProperties.h"
112 #include "StyleResolver.h"
113 #include "TextStream.h"
114 #include "TransformationMatrix.h"
115 #include "TranslateTransformOperation.h"
117 #include <wtf/StdLibExtras.h>
118 #include <wtf/text/CString.h>
120 #if ENABLE(CSS_FILTERS)
121 #include "FEColorMatrix.h"
123 #include "FilterEffectRenderer.h"
124 #include "RenderLayerFilterInfo.h"
127 #define MIN_INTERSECT_FOR_REVEAL 32
131 using namespace HTMLNames;
133 bool ClipRect::intersects(const HitTestLocation& hitTestLocation) const
135 return hitTestLocation.intersects(m_rect);
138 void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
140 #if !ENABLE(3D_RENDERING)
141 UNUSED_PARAM(has3DRendering);
149 RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
150 : m_inResizeMode(false)
151 , m_scrollDimensionsDirty(true)
152 , m_normalFlowListDirty(true)
153 , m_hasSelfPaintingLayerDescendant(false)
154 , m_hasSelfPaintingLayerDescendantDirty(false)
155 , m_hasOutOfFlowPositionedDescendant(false)
156 , m_hasOutOfFlowPositionedDescendantDirty(true)
157 , m_needsCompositedScrolling(false)
158 , m_descendantsAreContiguousInStackingOrder(false)
159 , m_isRootLayer(rendererLayerModelObject.isRenderView())
160 , m_usedTransparency(false)
161 , m_paintingInsideReflection(false)
162 , m_inOverflowRelayout(false)
163 , m_repaintStatus(NeedsNormalRepaint)
164 , m_visibleContentStatusDirty(true)
165 , m_hasVisibleContent(false)
166 , m_visibleDescendantStatusDirty(false)
167 , m_hasVisibleDescendant(false)
168 , m_isPaginated(false)
169 , m_3DTransformedDescendantStatusDirty(true)
170 , m_has3DTransformedDescendant(false)
171 , m_hasCompositingDescendant(false)
172 , m_hasTransformedAncestor(false)
173 , m_has3DTransformedAncestor(false)
174 , m_indirectCompositingReason(NoIndirectCompositingReason)
175 , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
177 , m_adjustForIOSCaretWhenScrolling(false)
178 , m_registeredAsTouchEventListenerForScrolling(false)
179 , m_inUserScroll(false)
180 , m_requiresScrollBoundsOriginUpdate(false)
182 , m_containsDirtyOverlayScrollbars(false)
183 , m_updatingMarqueePosition(false)
185 , m_layerListMutationAllowed(true)
187 #if ENABLE(CSS_FILTERS)
188 , m_hasFilterInfo(false)
190 #if ENABLE(CSS_COMPOSITING)
191 , m_blendMode(BlendModeNormal)
192 , m_hasUnisolatedCompositedBlendingDescendants(false)
193 , m_hasUnisolatedBlendingDescendants(false)
194 , m_hasUnisolatedBlendingDescendantsStatusDirty(false)
196 , m_renderer(rendererLayerModelObject)
202 , m_staticInlinePosition(0)
203 , m_staticBlockPosition(0)
204 , m_enclosingPaginationLayer(0)
206 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
207 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
209 // Non-stacking containers should have empty z-order lists. As this is already the case,
210 // there is no need to dirty / recompute these lists.
211 m_zOrderListsDirty = isStackingContainer();
213 ScrollableArea::setConstrainsScrollingToContentEdge(false);
215 if (!renderer().firstChild()) {
216 m_visibleContentStatusDirty = false;
217 m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
220 if (Element* element = renderer().element()) {
221 // We save and restore only the scrollOffset as the other scroll values are recalculated.
222 m_scrollOffset = element->savedLayerScrollOffset();
223 if (!m_scrollOffset.isZero())
224 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
225 element->setSavedLayerScrollOffset(IntSize());
229 RenderLayer::~RenderLayer()
231 if (inResizeMode() && !renderer().documentBeingDestroyed())
232 renderer().frame().eventHandler().resizeLayerDestroyed();
234 renderer().view().frameView().removeScrollableArea(this);
236 if (!renderer().documentBeingDestroyed()) {
238 unregisterAsTouchEventListenerForScrolling();
240 if (Element* element = renderer().element())
241 element->setSavedLayerScrollOffset(m_scrollOffset);
244 destroyScrollbar(HorizontalScrollbar);
245 destroyScrollbar(VerticalScrollbar);
247 if (renderer().frame().page()) {
248 if (ScrollingCoordinator* scrollingCoordinator = renderer().frame().page()->scrollingCoordinator())
249 scrollingCoordinator->willDestroyScrollableArea(this);
255 #if ENABLE(CSS_FILTERS)
256 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 // This can get called when video becomes accelerated, so the layers may change.
305 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor().updateLayerCompositingState(*this))
306 compositor().setCompositingLayersNeedRebuild();
309 m_backing->contentChanged(changeType);
312 bool RenderLayer::canRender3DTransforms() const
314 return compositor().canRender3DTransforms();
317 #if ENABLE(CSS_FILTERS)
319 bool RenderLayer::paintsWithFilters() const
321 // FIXME: Eventually there will be cases where we paint with filters even without accelerated compositing,
322 // and this whole function won't be inside the #if below.
324 if (!renderer().hasFilter())
330 if (!m_backing || !m_backing->canCompositeFilters())
336 bool RenderLayer::requiresFullLayerImageForFilters() const
338 if (!paintsWithFilters())
340 FilterEffectRenderer* renderer = filterRenderer();
341 return renderer && renderer->hasFilterThatMovesPixels();
344 FilterEffectRenderer* RenderLayer::filterRenderer() const
346 FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
347 return filterInfo ? filterInfo->renderer() : 0;
352 LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
354 hasLayerOffset = true;
357 return LayoutPoint();
359 // This is similar to root() but we check if an ancestor layer would
360 // prevent the optimization from working.
361 const RenderLayer* rootLayer = 0;
362 for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
363 hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
365 return LayoutPoint();
367 ASSERT(rootLayer == root());
370 parent()->convertToLayerCoords(rootLayer, offset);
374 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
376 RenderGeometryMap geometryMap(UseTransforms);
377 if (this != rootLayer)
378 geometryMap.pushMappingsToAncestor(parent(), 0);
379 updateLayerPositions(&geometryMap, flags);
382 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
384 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
385 // we need to keep in sync, since we may have shifted relative
386 // to our parent layer.
388 geometryMap->pushMappingsToAncestor(this, parent());
390 // Clear our cached clip rect information.
393 if (hasOverflowControls()) {
394 LayoutPoint offsetFromRoot;
396 offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint()));
398 // FIXME: It looks suspicious to call convertToLayerCoords here
399 // as canUseConvertToLayerCoords may be true for an ancestor layer.
400 convertToLayerCoords(root(), offsetFromRoot);
402 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
405 updateDescendantDependentFlags();
407 if (flags & UpdatePagination)
410 m_isPaginated = false;
411 m_enclosingPaginationLayer = 0;
414 if (m_hasVisibleContent) {
415 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
416 // mapping between them and the RenderObjects. It would be neat to enable
417 // LayoutState outside the layout() phase and use it here.
418 ASSERT(!renderer().view().layoutStateEnabled());
420 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
421 LayoutRect oldRepaintRect = m_repaintRect;
422 LayoutRect oldOutlineBox = m_outlineBox;
423 computeRepaintRects(repaintContainer, geometryMap);
425 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
426 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
427 if (flags & CheckForRepaint) {
428 if (!renderer().view().printing()) {
429 bool didRepaint = false;
430 if (m_repaintStatus & NeedsFullRepaint) {
431 renderer().repaintUsingContainer(repaintContainer, oldRepaintRect);
432 if (m_repaintRect != oldRepaintRect) {
433 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
436 } else if (shouldRepaintAfterLayout()) {
437 renderer().repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
441 if (didRepaint && renderer().isRenderNamedFlowFragmentContainer()) {
442 // If we just repainted a region, we must also repaint the flow thread since it is the one
443 // doing the actual painting of the flowed content.
444 RenderNamedFlowFragment* region = toRenderBlockFlow(&renderer())->renderNamedFlowFragment();
445 if (region->isValid())
446 region->flowThread()->layer()->repaintIncludingDescendants();
453 m_repaintStatus = NeedsNormalRepaint;
454 m_hasTransformedAncestor = flags & SeenTransformedLayer;
455 m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
457 // Go ahead and update the reflection's position and size.
459 m_reflection->layout();
461 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
462 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
464 flags &= ~IsCompositingUpdateRoot;
466 if (useRegionBasedColumns() && renderer().isInFlowRenderFlowThread()) {
468 flags |= UpdatePagination;
471 if (renderer().hasColumns())
472 flags |= UpdatePagination;
475 flags |= SeenTransformedLayer;
476 if (!transform()->isAffine())
477 flags |= Seen3DTransformedLayer;
480 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
481 child->updateLayerPositions(geometryMap, flags);
483 if ((flags & UpdateCompositingLayers) && isComposited()) {
484 RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
485 if (flags & NeedsFullRepaintInBacking)
486 updateFlags |= RenderLayerBacking::NeedsFullRepaint;
488 updateFlags |= RenderLayerBacking::IsUpdateRoot;
489 backing()->updateAfterLayout(updateFlags);
492 // With all our children positioned, now update our marquee if we need to.
494 // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
495 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
496 m_updatingMarqueePosition = true;
497 m_marquee->updateMarqueePosition();
498 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
502 geometryMap->popMappingsToAncestor(parent());
505 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
507 LayoutRect repaintRect = m_repaintRect;
508 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
509 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
510 if (child->isComposited())
513 repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants());
518 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
520 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
521 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
524 layer->m_hasSelfPaintingLayerDescendantDirty = false;
525 layer->m_hasSelfPaintingLayerDescendant = true;
529 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
531 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
532 layer->m_hasSelfPaintingLayerDescendantDirty = true;
533 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
534 // in this case, there is no need to dirty our ancestors further.
535 if (layer->isSelfPaintingLayer()) {
536 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
542 bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
544 return renderer().frame().settings().acceleratedCompositingForOverflowScrollEnabled();
547 // If we are a stacking container, then this function will determine if our
548 // descendants for a contiguous block in stacking order. This is required in
549 // order for an element to be safely promoted to a stacking container. It is safe
550 // to become a stacking container if this change would not alter the stacking
551 // order of layers on the page. That can only happen if a non-descendant appear
552 // between us and our descendants in stacking order. Here's an example:
562 // I've labeled our normal flow descendants A, B, C, and D, our stacking
563 // container descendants with their z indices, and us with 'this' (we're a
564 // stacking container and our zIndex doesn't matter here). These nodes appear in
565 // three lists: posZOrder, negZOrder, and normal flow (keep in mind that normal
566 // flow layers don't overlap). So if we arrange these lists in order we get our
569 // [-8], [A-D], [0, 2, 5, 7]--> pos z-order.
571 // Neg z-order. <-+ +--> Normal flow descendants.
573 // We can then assign new, 'stacking' order indices to these elements as follows:
575 // [-8], [A-D], [0, 2, 5, 7]
576 // 'Stacking' indices: -1 0 1 2 3 4
578 // Note that the normal flow descendants can share an index because they don't
579 // stack/overlap. Now our problem becomes very simple: a layer can safely become
580 // a stacking container if the stacking-order indices of it and its descendants
581 // appear in a contiguous block in the list of stacking indices. This problem
582 // can be solved very efficiently by calculating the min/max stacking indices in
583 // the subtree, and the number stacking container descendants. Once we have this
584 // information, we know that the subtree's indices form a contiguous block if:
586 // maxStackIndex - minStackIndex == numSCDescendants
588 // So for node A in the example above we would have:
590 // minStackIndex = -1
591 // numSCDecendants = 2
594 // maxStackIndex - minStackIndex == numSCDescendants
595 // ===> 1 - (-1) == 2
598 // Since this is true, A can safely become a stacking container.
599 // Now, for node C we have:
602 // minStackIndex = 0 <-- because C has stacking index 0.
603 // numSCDecendants = 2
606 // maxStackIndex - minStackIndex == numSCDescendants
610 // Since this is false, C cannot be safely promoted to a stacking container. This
611 // happened because of the elements with z-index 5 and 0. Now if 5 had been a
612 // child of C rather than D, and A had no child with Z index 0, we would have had:
615 // minStackIndex = 0 <-- because C has stacking index 0.
616 // numSCDecendants = 3
619 // maxStackIndex - minStackIndex == numSCDescendants
623 // And we would conclude that C could be promoted.
624 void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
626 if (!isStackingContext() || !acceleratedCompositingForOverflowScrollEnabled())
629 ASSERT(!m_normalFlowListDirty);
630 ASSERT(!m_zOrderListsDirty);
632 std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
633 std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
634 rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
636 // Create a reverse lookup.
637 HashMap<const RenderLayer*, int> lookup;
640 int stackingOrderIndex = -1;
641 size_t listSize = negZOrderList->size();
642 for (size_t i = 0; i < listSize; ++i) {
643 RenderLayer* currentLayer = negZOrderList->at(listSize - i - 1);
644 if (!currentLayer->isStackingContext())
646 lookup.set(currentLayer, stackingOrderIndex--);
651 size_t listSize = posZOrderList->size();
652 int stackingOrderIndex = 1;
653 for (size_t i = 0; i < listSize; ++i) {
654 RenderLayer* currentLayer = posZOrderList->at(i);
655 if (!currentLayer->isStackingContext())
657 lookup.set(currentLayer, stackingOrderIndex++);
664 bool firstIteration = true;
665 updateDescendantsAreContiguousInStackingOrderRecursive(lookup, minIndex, maxIndex, count, firstIteration);
668 void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const HashMap<const RenderLayer*, int>& lookup, int& minIndex, int& maxIndex, int& count, bool firstIteration)
670 if (isStackingContext() && !firstIteration) {
671 if (lookup.contains(this)) {
672 minIndex = std::min(minIndex, lookup.get(this));
673 maxIndex = std::max(maxIndex, lookup.get(this));
679 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
680 int childMinIndex = 0;
681 int childMaxIndex = 0;
683 child->updateDescendantsAreContiguousInStackingOrderRecursive(lookup, childMinIndex, childMaxIndex, childCount, false);
686 minIndex = std::min(minIndex, childMinIndex);
687 maxIndex = std::max(maxIndex, childMaxIndex);
691 if (!isStackingContext()) {
692 bool newValue = maxIndex - minIndex == count;
693 bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
694 m_descendantsAreContiguousInStackingOrder = newValue;
696 updateNeedsCompositedScrolling();
700 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
702 ASSERT(!m_visibleContentStatusDirty);
704 m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer);
705 m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap);
709 void RenderLayer::computeRepaintRectsIncludingDescendants()
711 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
712 // We should make this more efficient.
713 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
714 computeRepaintRects(renderer().containerForRepaint());
716 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
717 layer->computeRepaintRectsIncludingDescendants();
720 void RenderLayer::clearRepaintRects()
722 ASSERT(!m_hasVisibleContent);
723 ASSERT(!m_visibleContentStatusDirty);
725 m_repaintRect = LayoutRect();
726 m_outlineBox = LayoutRect();
729 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
731 ASSERT(this == renderer().view().layer());
733 RenderGeometryMap geometryMap(UseTransforms);
734 updateLayerPositionsAfterScroll(&geometryMap);
737 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
739 RenderGeometryMap geometryMap(UseTransforms);
740 if (this != renderer().view().layer())
741 geometryMap.pushMappingsToAncestor(parent(), 0);
743 // FIXME: why is it OK to not check the ancestors of this layer in order to
744 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
745 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
748 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
750 // FIXME: This shouldn't be needed, but there are some corner cases where
751 // these flags are still dirty. Update so that the check below is valid.
752 updateDescendantDependentFlags();
754 // If we have no visible content and no visible descendants, there is no point recomputing
755 // our rectangles as they will be empty. If our visibility changes, we are expected to
756 // recompute all our positions anyway.
757 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
760 bool positionChanged = updateLayerPosition();
762 flags |= HasChangedAncestor;
765 geometryMap->pushMappingsToAncestor(this, parent());
767 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
770 if (renderer().style().hasViewportConstrainedPosition())
771 flags |= HasSeenViewportConstrainedAncestor;
773 if (renderer().hasOverflowClip())
774 flags |= HasSeenAncestorWithOverflowClip;
776 if (flags & HasSeenViewportConstrainedAncestor
777 || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) {
778 // FIXME: We could track the repaint container as we walk down the tree.
779 computeRepaintRects(renderer().containerForRepaint(), geometryMap);
781 // Check that our cached rects are correct.
782 ASSERT(m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
783 ASSERT(m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint(), geometryMap));
786 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
787 child->updateLayerPositionsAfterScroll(geometryMap, flags);
789 // We don't update our reflection as scrolling is a translation which does not change the size()
790 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
794 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
795 m_updatingMarqueePosition = true;
796 m_marquee->updateMarqueePosition();
797 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
801 geometryMap->popMappingsToAncestor(parent());
804 void RenderLayer::positionNewlyCreatedOverflowControls()
806 if (!backing()->hasUnpositionedOverflowControlsLayers())
809 RenderGeometryMap geometryMap(UseTransforms);
810 if (this != renderer().view().layer() && parent())
811 geometryMap.pushMappingsToAncestor(parent(), 0);
813 LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
814 positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
817 #if ENABLE(CSS_COMPOSITING)
819 void RenderLayer::updateBlendMode()
821 bool hadBlendMode = m_blendMode != BlendModeNormal;
822 if (parent() && hadBlendMode != hasBlendMode()) {
824 parent()->updateAncestorChainHasBlendingDescendants();
826 parent()->dirtyAncestorChainHasBlendingDescendants();
829 BlendMode newBlendMode = renderer().style().blendMode();
830 if (newBlendMode != m_blendMode)
831 m_blendMode = newBlendMode;
834 void RenderLayer::updateAncestorChainHasBlendingDescendants()
836 for (auto layer = this; layer; layer = layer->parent()) {
837 if (!layer->hasUnisolatedBlendingDescendantsStatusDirty() && layer->hasUnisolatedBlendingDescendants())
839 layer->m_hasUnisolatedBlendingDescendants = true;
840 layer->m_hasUnisolatedBlendingDescendantsStatusDirty = false;
842 if (layer->isStackingContext())
847 void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
849 for (auto layer = this; layer; layer = layer->parent()) {
850 if (layer->hasUnisolatedBlendingDescendantsStatusDirty())
853 layer->m_hasUnisolatedBlendingDescendantsStatusDirty = true;
855 if (layer->isStackingContext())
861 void RenderLayer::updateTransform()
863 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
864 // so check style too.
865 bool hasTransform = renderer().hasTransform() && renderer().style().hasTransform();
866 bool had3DTransform = has3DTransform();
868 bool hadTransform = !!m_transform;
869 if (hasTransform != hadTransform) {
871 m_transform = std::make_unique<TransformationMatrix>();
873 m_transform = nullptr;
875 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
876 clearClipRectsIncludingDescendants();
880 RenderBox* box = renderBox();
882 m_transform->makeIdentity();
883 box->style().applyTransform(*m_transform, pixelSnappedForPainting(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
884 makeMatrixRenderable(*m_transform, canRender3DTransforms());
887 if (had3DTransform != has3DTransform())
888 dirty3DTransformedDescendantStatus();
891 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
894 return TransformationMatrix();
896 RenderBox* box = renderBox();
898 FloatRect pixelSnappedBorderRect = pixelSnappedForPainting(box->borderBoxRect(), box->document().deviceScaleFactor());
899 if (renderer().style().isRunningAcceleratedAnimation()) {
900 TransformationMatrix currTransform;
901 RefPtr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(&renderer());
902 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
903 makeMatrixRenderable(currTransform, canRender3DTransforms());
904 return currTransform;
907 // m_transform includes transform-origin, so we need to recompute the transform here.
908 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
909 TransformationMatrix currTransform;
910 box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
911 makeMatrixRenderable(currTransform, canRender3DTransforms());
912 return currTransform;
918 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
921 return TransformationMatrix();
923 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
924 TransformationMatrix matrix = *m_transform;
925 makeMatrixRenderable(matrix, false /* flatten 3d */);
932 RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
934 const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
936 if (layer->renderer().hasOverflowClip())
937 return const_cast<RenderLayer*>(layer);
939 layer = layer->parent();
944 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
946 RenderLayerModelObject* prevBlock = renderer;
947 RenderBlock* containingBlock;
948 for (containingBlock = renderer->containingBlock();
949 containingBlock && containingBlock != &renderer->view() && containingBlock != ancestorColumnsRenderer;
950 containingBlock = containingBlock->containingBlock()) {
951 prevBlock = containingBlock;
954 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
955 if (containingBlock != ancestorColumnsRenderer)
958 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
959 if (prevBlock->isOutOfFlowPositioned())
962 // Otherwise we are paginated by the columns block.
966 bool RenderLayer::useRegionBasedColumns() const
968 const Settings& settings = renderer().frame().settings();
969 return settings.regionBasedColumnsEnabled();
972 void RenderLayer::updatePagination()
974 m_isPaginated = false;
975 m_enclosingPaginationLayer = 0;
977 if (isComposited() || !parent())
978 return; // FIXME: We will have to deal with paginated compositing layers someday.
979 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
981 // The main difference between the paginated booleans for the old column code and the new column code
982 // is that each paginated layer has to paint on its own with the new code. There is no
983 // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on
984 // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and
985 // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
986 // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
987 // to that layer easily.
988 bool regionBasedColumnsUsed = useRegionBasedColumns();
989 if (regionBasedColumnsUsed && renderer().isInFlowRenderFlowThread()) {
990 m_enclosingPaginationLayer = this;
994 if (isNormalFlowOnly()) {
995 if (regionBasedColumnsUsed) {
996 // Content inside a transform is not considered to be paginated, since we simply
997 // paint the transform multiple times in each column, so we don't have to use
998 // fragments for the transformed content.
999 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
1000 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
1001 m_enclosingPaginationLayer = 0;
1003 m_isPaginated = parent()->renderer().hasColumns();
1007 // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
1008 // we find one, then we just check its pagination status.
1009 if (regionBasedColumnsUsed) {
1010 RenderView* renderView = &renderer().view();
1011 RenderBlock* containingBlock;
1012 for (containingBlock = renderer().containingBlock();
1013 containingBlock && containingBlock != renderView;
1014 containingBlock = containingBlock->containingBlock()) {
1015 if (containingBlock->hasLayer()) {
1016 // Content inside a transform is not considered to be paginated, since we simply
1017 // paint the transform multiple times in each column, so we don't have to use
1018 // fragments for the transformed content.
1019 m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
1020 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
1021 m_enclosingPaginationLayer = 0;
1028 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
1029 RenderLayer* ancestorStackingContainer = stackingContainer();
1030 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1031 if (curr->renderer().hasColumns()) {
1032 m_isPaginated = checkContainingBlockChainForPagination(&renderer(), curr->renderBox());
1035 if (curr == ancestorStackingContainer)
1040 bool RenderLayer::canBeStackingContainer() const
1042 if (isStackingContext() || !stackingContainer())
1045 return m_descendantsAreContiguousInStackingOrder;
1048 void RenderLayer::setHasVisibleContent()
1050 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
1051 ASSERT(!parent() || parent()->hasVisibleDescendant());
1055 m_visibleContentStatusDirty = false;
1056 m_hasVisibleContent = true;
1057 computeRepaintRects(renderer().containerForRepaint());
1058 if (!isNormalFlowOnly()) {
1059 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
1060 // As we became visible, we need to dirty our stacking containers ancestors to be properly
1061 // collected. FIXME: When compositing, we could skip this dirtying phase.
1062 for (RenderLayer* sc = stackingContainer(); sc; sc = sc->stackingContainer()) {
1063 sc->dirtyZOrderLists();
1064 if (sc->hasVisibleContent())
1070 parent()->setAncestorChainHasVisibleDescendant();
1073 void RenderLayer::dirtyVisibleContentStatus()
1075 m_visibleContentStatusDirty = true;
1077 parent()->dirtyAncestorChainVisibleDescendantStatus();
1080 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
1082 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1083 if (layer->m_visibleDescendantStatusDirty)
1086 layer->m_visibleDescendantStatusDirty = true;
1090 void RenderLayer::setAncestorChainHasVisibleDescendant()
1092 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
1093 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
1096 layer->m_hasVisibleDescendant = true;
1097 layer->m_visibleDescendantStatusDirty = false;
1101 void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
1103 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasUnisolatedBlendingDescendantsStatusDirty()) {
1104 m_hasVisibleDescendant = false;
1105 m_hasSelfPaintingLayerDescendant = false;
1106 m_hasOutOfFlowPositionedDescendant = false;
1107 #if ENABLE(CSS_COMPOSITING)
1108 m_hasUnisolatedBlendingDescendants = false;
1111 HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
1112 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1113 childOutOfFlowDescendantContainingBlocks.clear();
1114 child->updateDescendantDependentFlags(&childOutOfFlowDescendantContainingBlocks);
1116 bool childIsOutOfFlowPositioned = child->renderer().isOutOfFlowPositioned();
1117 if (childIsOutOfFlowPositioned)
1118 childOutOfFlowDescendantContainingBlocks.add(child->renderer().containingBlock());
1120 if (outOfFlowDescendantContainingBlocks) {
1121 HashSet<const RenderObject*>::const_iterator it = childOutOfFlowDescendantContainingBlocks.begin();
1122 for (; it != childOutOfFlowDescendantContainingBlocks.end(); ++it)
1123 outOfFlowDescendantContainingBlocks->add(*it);
1126 bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
1127 bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
1128 bool hasOutOfFlowPositionedDescendant = !childOutOfFlowDescendantContainingBlocks.isEmpty();
1129 #if ENABLE(CSS_COMPOSITING)
1130 bool hasUnisolatedBlendingDescendants = child->hasBlendMode() || (child->hasUnisolatedBlendingDescendants() && !child->isolatesBlending());
1132 m_hasUnisolatedBlendingDescendants |= hasUnisolatedBlendingDescendants;
1134 m_hasVisibleDescendant |= hasVisibleDescendant;
1135 m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
1136 m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant;
1138 bool allFlagsSet = m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && m_hasOutOfFlowPositionedDescendant;
1139 #if ENABLE(CSS_COMPOSITING)
1140 allFlagsSet &= m_hasUnisolatedBlendingDescendants;
1146 if (outOfFlowDescendantContainingBlocks)
1147 outOfFlowDescendantContainingBlocks->remove(&renderer());
1149 m_visibleDescendantStatusDirty = false;
1150 m_hasSelfPaintingLayerDescendantDirty = false;
1152 if (m_hasOutOfFlowPositionedDescendantDirty)
1153 updateNeedsCompositedScrolling();
1155 m_hasOutOfFlowPositionedDescendantDirty = false;
1156 #if ENABLE(CSS_COMPOSITING)
1157 m_hasUnisolatedBlendingDescendantsStatusDirty = false;
1161 if (m_visibleContentStatusDirty) {
1162 if (renderer().style().visibility() == VISIBLE)
1163 m_hasVisibleContent = true;
1165 // layer may be hidden but still have some visible content, check for this
1166 m_hasVisibleContent = false;
1167 RenderObject* r = renderer().firstChild();
1169 if (r->style().visibility() == VISIBLE && !r->hasLayer()) {
1170 m_hasVisibleContent = true;
1173 RenderObject* child = nullptr;
1174 if (!r->hasLayer() && (child = r->firstChildSlow()))
1176 else if (r->nextSibling())
1177 r = r->nextSibling();
1181 if (r == &renderer())
1183 } while (r && !r->nextSibling());
1185 r = r->nextSibling();
1189 m_visibleContentStatusDirty = false;
1193 // Return true if the new clipping behaviour requires layer update.
1194 bool RenderLayer::checkIfDescendantClippingContextNeedsUpdate(bool isClipping)
1196 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1197 RenderLayerBacking* backing = child->backing();
1198 // Layer subtree needs update when new clipping is added or existing clipping is removed.
1199 if (backing && (isClipping || backing->hasAncestorClippingLayer()))
1202 if (child->checkIfDescendantClippingContextNeedsUpdate(isClipping))
1208 void RenderLayer::dirty3DTransformedDescendantStatus()
1210 RenderLayer* curr = stackingContainer();
1212 curr->m_3DTransformedDescendantStatusDirty = true;
1214 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
1215 // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
1216 while (curr && curr->preserves3D()) {
1217 curr->m_3DTransformedDescendantStatusDirty = true;
1218 curr = curr->stackingContainer();
1222 // Return true if this layer or any preserve-3d descendants have 3d.
1223 bool RenderLayer::update3DTransformedDescendantStatus()
1225 if (m_3DTransformedDescendantStatusDirty) {
1226 m_has3DTransformedDescendant = false;
1228 updateZOrderLists();
1230 // Transformed or preserve-3d descendants can only be in the z-order lists, not
1231 // in the normal flow list, so we only need to check those.
1232 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
1233 for (unsigned i = 0; i < positiveZOrderList->size(); ++i)
1234 m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus();
1237 // Now check our negative z-index children.
1238 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
1239 for (unsigned i = 0; i < negativeZOrderList->size(); ++i)
1240 m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus();
1243 m_3DTransformedDescendantStatusDirty = false;
1246 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
1247 // the m_has3DTransformedDescendant set.
1249 return has3DTransform() || m_has3DTransformedDescendant;
1251 return has3DTransform();
1254 bool RenderLayer::updateLayerPosition()
1256 LayoutPoint localPoint;
1257 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
1258 if (renderer().isInline() && renderer().isRenderInline()) {
1259 RenderInline& inlineFlow = toRenderInline(renderer());
1260 IntRect lineBox = inlineFlow.linesBoundingBox();
1261 setSize(lineBox.size());
1262 inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
1263 localPoint += inlineBoundingBoxOffset;
1264 } else if (RenderBox* box = renderBox()) {
1265 // FIXME: Is snapping the size really needed here for the RenderBox case?
1266 setSize(pixelSnappedIntSize(box->size(), box->location()));
1267 localPoint += box->topLeftLocationOffset();
1270 if (!renderer().isOutOfFlowPositioned() && renderer().parent()) {
1271 // We must adjust our position by walking up the render tree looking for the
1272 // nearest enclosing object with a layer.
1273 RenderElement* curr = renderer().parent();
1274 while (curr && !curr->hasLayer()) {
1275 if (curr->isBox() && !curr->isTableRow()) {
1276 // Rows and cells share the same coordinate space (that of the section).
1277 // Omit them when computing our xpos/ypos.
1278 localPoint += toRenderBox(curr)->topLeftLocationOffset();
1280 curr = curr->parent();
1282 if (curr->isBox() && curr->isTableRow()) {
1283 // Put ourselves into the row coordinate space.
1284 localPoint -= toRenderBox(curr)->topLeftLocationOffset();
1288 // Subtract our parent's scroll offset.
1289 if (renderer().isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
1290 RenderLayer* positionedParent = enclosingPositionedAncestor();
1292 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
1293 if (positionedParent->renderer().hasOverflowClip()) {
1294 LayoutSize offset = positionedParent->scrolledContentOffset();
1295 localPoint -= offset;
1298 if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && positionedParent->renderer().isRenderInline()) {
1299 LayoutSize offset = toRenderInline(positionedParent->renderer()).offsetForInFlowPositionedInline(&toRenderBox(renderer()));
1300 localPoint += offset;
1302 } else if (parent()) {
1303 if (parent()->renderer().hasOverflowClip()) {
1304 IntSize scrollOffset = parent()->scrolledContentOffset();
1305 localPoint -= scrollOffset;
1309 bool positionOrOffsetChanged = false;
1310 if (renderer().isInFlowPositioned()) {
1311 LayoutSize newOffset = toRenderBoxModelObject(renderer()).offsetForInFlowPosition();
1312 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
1313 m_offsetForInFlowPosition = newOffset;
1314 localPoint.move(m_offsetForInFlowPosition);
1316 m_offsetForInFlowPosition = LayoutSize();
1319 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
1320 localPoint -= inlineBoundingBoxOffset;
1322 positionOrOffsetChanged |= location() != localPoint;
1323 setLocation(localPoint);
1324 return positionOrOffsetChanged;
1327 TransformationMatrix RenderLayer::perspectiveTransform() const
1329 if (!renderer().hasTransform())
1330 return TransformationMatrix();
1332 const RenderStyle& style = renderer().style();
1333 if (!style.hasPerspective())
1334 return TransformationMatrix();
1336 // Maybe fetch the perspective from the backing?
1337 const IntRect borderBox = toRenderBox(renderer()).pixelSnappedBorderBoxRect();
1338 const float boxWidth = borderBox.width();
1339 const float boxHeight = borderBox.height();
1341 float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), boxWidth);
1342 float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), boxHeight);
1344 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
1345 // We want it to be in the top-left, so subtract half the height and width.
1346 perspectiveOriginX -= boxWidth / 2.0f;
1347 perspectiveOriginY -= boxHeight / 2.0f;
1349 TransformationMatrix t;
1350 t.translate(perspectiveOriginX, perspectiveOriginY);
1351 t.applyPerspective(style.perspective());
1352 t.translate(-perspectiveOriginX, -perspectiveOriginY);
1357 FloatPoint RenderLayer::perspectiveOrigin() const
1359 if (!renderer().hasTransform())
1360 return FloatPoint();
1362 const LayoutRect borderBox = toRenderBox(renderer()).borderBoxRect();
1363 const RenderStyle& style = renderer().style();
1365 return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
1366 floatValueForLength(style.perspectiveOriginY(), borderBox.height()));
1369 RenderLayer* RenderLayer::stackingContainer() const
1371 RenderLayer* layer = parent();
1372 while (layer && !layer->isStackingContainer())
1373 layer = layer->parent();
1375 ASSERT(!layer || layer->isStackingContainer());
1379 static inline bool isPositionedContainer(RenderLayer* layer)
1381 return layer->isRootLayer() || layer->renderer().isPositioned() || layer->hasTransform();
1384 static inline bool isFixedPositionedContainer(RenderLayer* layer)
1386 return layer->isRootLayer() || layer->hasTransform();
1389 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
1391 RenderLayer* curr = parent();
1392 while (curr && !isPositionedContainer(curr))
1393 curr = curr->parent();
1398 static RenderLayer* parentLayerCrossFrame(const RenderLayer* layer)
1401 if (layer->parent())
1402 return layer->parent();
1404 HTMLFrameOwnerElement* ownerElement = layer->renderer().document().ownerElement();
1408 RenderElement* ownerRenderer = ownerElement->renderer();
1412 return ownerRenderer->enclosingLayer();
1415 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1417 for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
1418 if (nextLayer->renderer().isBox() && toRenderBox(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
1425 IntRect RenderLayer::scrollableAreaBoundingBox() const
1427 return renderer().absoluteBoundingBoxRect();
1430 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1432 RenderLayer* curr = parent();
1433 while (curr && !curr->isRootLayer() && !curr->transform())
1434 curr = curr->parent();
1439 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
1441 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContainer();
1444 inline bool RenderLayer::shouldRepaintAfterLayout() const
1446 if (m_repaintStatus == NeedsNormalRepaint)
1449 // Composited layers that were moved during a positioned movement only
1450 // layout, don't need to be repainted. They just need to be recomposited.
1451 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1452 return !isComposited() || backing()->paintsIntoCompositedAncestor();
1455 static bool compositedWithOwnBackingStore(const RenderLayer* layer)
1457 return layer->isComposited() && !layer->backing()->paintsIntoCompositedAncestor();
1460 RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
1462 if (includeSelf == IncludeSelf && isComposited())
1463 return const_cast<RenderLayer*>(this);
1465 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1466 if (curr->isComposited())
1467 return const_cast<RenderLayer*>(curr);
1473 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
1475 if (includeSelf == IncludeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
1476 return const_cast<RenderLayer*>(this);
1478 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1479 if (compositedWithOwnBackingStore(curr))
1480 return const_cast<RenderLayer*>(curr);
1486 #if ENABLE(CSS_FILTERS)
1488 RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
1490 const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
1491 for (; curr; curr = curr->parent()) {
1492 if (curr->requiresFullLayerImageForFilters())
1493 return const_cast<RenderLayer*>(curr);
1499 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1501 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1502 if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(curr) || curr->isRootLayer())
1503 return const_cast<RenderLayer*>(curr);
1508 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
1513 LayoutRect rectForRepaint = rect;
1514 renderer().style().filterOutsets().expandRect(rectForRepaint);
1516 FilterInfo& filterInfo = FilterInfo::get(*this);
1517 filterInfo.expandDirtySourceRect(rectForRepaint);
1519 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1520 ASSERT(parentLayer);
1521 FloatQuad repaintQuad(rectForRepaint);
1522 LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1524 if (parentLayer->isComposited()) {
1525 if (!parentLayer->backing()->paintsIntoWindow()) {
1526 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1529 // If the painting goes to window, redirect the painting to the parent RenderView.
1530 parentLayer = renderer().view().layer();
1531 parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
1534 if (parentLayer->paintsWithFilters()) {
1535 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
1539 if (parentLayer->isRootLayer()) {
1540 toRenderView(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
1544 ASSERT_NOT_REACHED();
1547 bool RenderLayer::hasAncestorWithFilterOutsets() const
1549 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1550 if (curr->renderer().style().hasFilterOutsets())
1558 RenderLayer* RenderLayer::clippingRootForPainting() const
1561 return const_cast<RenderLayer*>(this);
1563 const RenderLayer* current = this;
1565 if (current->isRootLayer())
1566 return const_cast<RenderLayer*>(current);
1568 current = compositingContainer(current);
1570 if (current->transform() || compositedWithOwnBackingStore(current))
1571 return const_cast<RenderLayer*>(current);
1574 ASSERT_NOT_REACHED();
1578 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1580 // We don't use convertToLayerCoords because it doesn't know about transforms
1581 return roundedLayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
1584 bool RenderLayer::cannotBlitToWindow() const
1586 if (isTransparent() || hasReflection() || hasTransform())
1590 return parent()->cannotBlitToWindow();
1593 bool RenderLayer::isTransparent() const
1595 if (renderer().element() && renderer().element()->isSVGElement())
1597 return renderer().isTransparent() || renderer().hasMask();
1600 RenderLayer* RenderLayer::transparentPaintingAncestor()
1605 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1606 if (curr->isComposited())
1608 if (curr->isTransparent())
1614 enum TransparencyClipBoxBehavior {
1615 PaintingTransparencyClipBox,
1616 HitTestingTransparencyClipBox
1619 enum TransparencyClipBoxMode {
1620 DescendantsOfTransparencyClipBox,
1621 RootOfTransparencyClipBox
1624 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
1626 static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
1627 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1629 // If this is a region, then the painting is actually done by its flow thread's layer.
1630 if (layer->renderer().isRenderNamedFlowFragmentContainer()) {
1631 RenderBlockFlow* regionContainer = toRenderBlockFlow(&layer->renderer());
1632 RenderNamedFlowFragment* region = regionContainer->renderNamedFlowFragment();
1633 RenderLayer* flowThreadLayer = region->flowThread()->layer();
1634 if (!layer->reflection() || layer->reflectionLayer() != flowThreadLayer) {
1635 LayoutRect flowThreadClipRect = transparencyClipBox(flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
1637 LayoutPoint offsetFromRoot;
1638 layer->convertToLayerCoords(flowThreadLayer, offsetFromRoot);
1640 LayoutSize moveOffset = (offsetFromRoot + regionContainer->contentBoxRect().location()) - region->flowThreadPortionRect().location();
1641 flowThreadClipRect.move(moveOffset);
1643 clipRect.unite(flowThreadClipRect);
1648 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
1649 TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
1651 // If we have a mask, then the clip is limited to the border box area (and there is
1652 // no need to examine child layers).
1653 if (!layer->renderer().hasMask()) {
1654 // Note: we don't have to walk z-order lists since transparent elements always establish
1655 // a stacking container. This means we can just walk the layer tree directly.
1656 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
1657 if (!layer->reflection() || layer->reflectionLayer() != curr)
1658 clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
1662 expandClipRectForRegionAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1664 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1665 // current transparencyClipBox to catch all child layers.
1666 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1667 // size into the parent layer.
1668 if (layer->renderer().hasReflection()) {
1670 layer->convertToLayerCoords(rootLayer, delta);
1671 clipRect.move(-delta.x(), -delta.y());
1672 clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
1673 clipRect.moveBy(delta);
1677 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
1678 TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
1680 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1681 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1682 // would be better to respect clips.
1684 if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
1685 || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
1686 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1687 // the transformed layer and all of its children.
1688 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
1689 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
1691 layer->convertToLayerCoords(rootLayerForTransform, delta);
1693 TransformationMatrix transform;
1694 transform.translate(delta.x(), delta.y());
1695 transform = transform * *layer->transform();
1697 // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
1698 // paints unfragmented.
1699 LayoutRect clipRect = layer->boundingBox(layer);
1700 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior);
1701 #if ENABLE(CSS_FILTERS)
1702 layer->renderer().style().filterOutsets().expandRect(clipRect);
1704 LayoutRect result = transform.mapRect(clipRect);
1705 if (!paginationLayer)
1708 // We have to break up the transformed extent across our columns.
1709 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
1710 // get our true bounding box.
1711 RenderFlowThread& enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
1712 result = enclosingFlowThread.fragmentsBoundingBox(result);
1714 LayoutPoint rootLayerDelta;
1715 paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
1716 result.moveBy(rootLayerDelta);
1720 LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes);
1721 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
1722 #if ENABLE(CSS_FILTERS)
1723 layer->renderer().style().filterOutsets().expandRect(clipRect);
1728 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1730 return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
1733 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1735 if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
1738 RenderLayer* ancestor = transparentPaintingAncestor();
1740 ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
1742 if (paintsWithTransparency(paintBehavior)) {
1743 m_usedTransparency = true;
1745 LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
1746 context->clip(clipRect);
1748 #if ENABLE(CSS_COMPOSITING)
1750 context->setCompositeOperation(context->compositeOperation(), m_blendMode);
1753 context->beginTransparencyLayer(renderer().opacity());
1755 #if ENABLE(CSS_COMPOSITING)
1757 context->setCompositeOperation(context->compositeOperation(), BlendModeNormal);
1760 #ifdef REVEAL_TRANSPARENCY_LAYERS
1761 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
1762 context->fillRect(clipRect);
1768 void RenderLayer::willBeDestroyed()
1770 if (RenderLayerBacking* layerBacking = backing())
1771 layerBacking->layerWillBeDestroyed();
1775 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1777 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1779 child->setPreviousSibling(prevSibling);
1780 prevSibling->setNextSibling(child);
1781 ASSERT(prevSibling != child);
1783 setFirstChild(child);
1786 beforeChild->setPreviousSibling(child);
1787 child->setNextSibling(beforeChild);
1788 ASSERT(beforeChild != child);
1790 setLastChild(child);
1792 child->setParent(this);
1794 if (child->isNormalFlowOnly())
1795 dirtyNormalFlowList();
1797 if (!child->isNormalFlowOnly() || child->firstChild()) {
1798 // Dirty the z-order list in which we are contained. The stackingContainer() can be null in the
1799 // case where we're building up generated content layers. This is ok, since the lists will start
1800 // off dirty in that case anyway.
1801 child->dirtyStackingContainerZOrderLists();
1804 child->updateDescendantDependentFlags();
1805 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1806 setAncestorChainHasVisibleDescendant();
1808 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1809 setAncestorChainHasSelfPaintingLayerDescendant();
1811 if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
1812 setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
1814 #if ENABLE(CSS_COMPOSITING)
1815 if (child->hasBlendMode() || (child->hasUnisolatedBlendingDescendants() && !child->isolatesBlending()))
1816 updateAncestorChainHasBlendingDescendants();
1819 compositor().layerWasAdded(*this, *child);
1822 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1824 if (!renderer().documentBeingDestroyed())
1825 compositor().layerWillBeRemoved(*this, *oldChild);
1828 if (oldChild->previousSibling())
1829 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1830 if (oldChild->nextSibling())
1831 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1833 if (m_first == oldChild)
1834 m_first = oldChild->nextSibling();
1835 if (m_last == oldChild)
1836 m_last = oldChild->previousSibling();
1838 if (oldChild->isNormalFlowOnly())
1839 dirtyNormalFlowList();
1840 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1841 // Dirty the z-order list in which we are contained. When called via the
1842 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1843 // from the main layer tree, so we need to null-check the |stackingContainer| value.
1844 oldChild->dirtyStackingContainerZOrderLists();
1847 if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
1848 dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
1850 oldChild->setPreviousSibling(0);
1851 oldChild->setNextSibling(0);
1852 oldChild->setParent(0);
1854 oldChild->updateDescendantDependentFlags();
1855 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1856 dirtyAncestorChainVisibleDescendantStatus();
1858 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1859 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1861 #if ENABLE(CSS_COMPOSITING)
1862 if (oldChild->hasBlendMode() || (oldChild->hasUnisolatedBlendingDescendants() && !oldChild->isolatesBlending()))
1863 dirtyAncestorChainHasBlendingDescendants();
1869 void RenderLayer::removeOnlyThisLayer()
1874 // Mark that we are about to lose our layer. This makes render tree
1875 // walks ignore this layer while we're removing it.
1876 renderer().setHasLayer(false);
1878 compositor().layerWillBeRemoved(*m_parent, *this);
1880 // Dirty the clip rects.
1881 clearClipRectsIncludingDescendants();
1883 RenderLayer* nextSib = nextSibling();
1885 // Remove the child reflection layer before moving other child layers.
1886 // The reflection layer should not be moved to the parent.
1888 removeChild(reflectionLayer());
1890 // Now walk our kids and reattach them to our parent.
1891 RenderLayer* current = m_first;
1893 RenderLayer* next = current->nextSibling();
1894 removeChild(current);
1895 m_parent->addChild(current, nextSib);
1896 current->setRepaintStatus(NeedsFullRepaint);
1897 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1898 ASSERT(!renderer().hasLayer());
1899 current->updateLayerPositions(0); // FIXME: use geometry map.
1903 // Remove us from the parent.
1904 m_parent->removeChild(this);
1905 renderer().destroyLayer();
1908 void RenderLayer::insertOnlyThisLayer()
1910 if (!m_parent && renderer().parent()) {
1911 // We need to connect ourselves when our renderer() has a parent.
1912 // Find our enclosingLayer and add ourselves.
1913 RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
1914 ASSERT(parentLayer);
1915 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : 0;
1916 parentLayer->addChild(this, beforeChild);
1919 // Remove all descendant layers from the hierarchy and add them to the new position.
1920 for (auto& child : childrenOfType<RenderElement>(renderer()))
1921 child.moveLayers(m_parent, this);
1923 // Clear out all the clip rects.
1924 clearClipRectsIncludingDescendants();
1927 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
1929 LayoutPoint location = roundedLocation;
1930 convertToLayerCoords(ancestorLayer, location, adjustForColumns);
1931 roundedLocation = roundedIntPoint(location);
1934 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect, ColumnOffsetAdjustment adjustForColumns) const
1936 LayoutRect rect = roundedRect;
1937 convertToLayerCoords(ancestorLayer, rect, adjustForColumns);
1938 roundedRect = pixelSnappedIntRect(rect);
1941 // Returns the layer reached on the walk up towards the ancestor.
1942 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
1944 ASSERT(ancestorLayer != layer);
1946 const RenderLayerModelObject& renderer = layer->renderer();
1947 EPosition position = renderer.style().position();
1949 // FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
1950 RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : 0;
1951 if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
1952 fixedFlowThreadContainer = 0;
1954 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
1955 // may need to be revisited in a future patch.
1956 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
1957 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
1958 // positioned in a completely different place in the viewport (RenderView).
1959 if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer.view().layer())) {
1960 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1961 // localToAbsolute() on the RenderView.
1962 FloatPoint absPos = renderer.localToAbsolute(FloatPoint(), IsFixed);
1963 location += LayoutSize(absPos.x(), absPos.y());
1964 return ancestorLayer;
1967 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
1968 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
1969 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
1970 if (position == FixedPosition && !fixedFlowThreadContainer) {
1971 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1972 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1973 // so we should always find the ancestor at or before we find the fixed position container.
1974 RenderLayer* fixedPositionContainerLayer = 0;
1975 bool foundAncestor = false;
1976 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
1977 if (currLayer == ancestorLayer)
1978 foundAncestor = true;
1980 if (isFixedPositionedContainer(currLayer)) {
1981 fixedPositionContainerLayer = currLayer;
1982 ASSERT_UNUSED(foundAncestor, foundAncestor);
1987 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1989 if (fixedPositionContainerLayer != ancestorLayer) {
1990 LayoutPoint fixedContainerCoords;
1991 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
1993 LayoutPoint ancestorCoords;
1994 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
1996 location += (fixedContainerCoords - ancestorCoords);
1997 return ancestorLayer;
2001 if (position == FixedPosition && fixedFlowThreadContainer) {
2002 ASSERT(ancestorLayer);
2003 if (ancestorLayer->isOutOfFlowRenderFlowThread()) {
2004 location += toLayoutSize(layer->location());
2005 return ancestorLayer;
2008 if (ancestorLayer == renderer.view().layer()) {
2009 // Add location in flow thread coordinates.
2010 location += toLayoutSize(layer->location());
2012 // Add flow thread offset in view coordinates since the view may be scrolled.
2013 FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
2014 location += LayoutSize(absPos.x(), absPos.y());
2015 return ancestorLayer;
2019 RenderLayer* parentLayer;
2020 if (position == AbsolutePosition || position == FixedPosition) {
2021 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
2022 parentLayer = layer->parent();
2023 bool foundAncestorFirst = false;
2024 while (parentLayer) {
2025 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
2026 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
2027 // we are bailing out before reaching root layer.
2028 if (isPositionedContainer(parentLayer))
2031 if (parentLayer == ancestorLayer) {
2032 foundAncestorFirst = true;
2036 parentLayer = parentLayer->parent();
2039 // We should not reach RenderView layer past the RenderFlowThread layer for any
2040 // children of the RenderFlowThread.
2041 if (renderer.flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
2042 ASSERT(parentLayer != renderer.view().layer());
2044 if (foundAncestorFirst) {
2045 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
2046 // to enclosingPositionedAncestor and subtract.
2047 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
2049 LayoutPoint thisCoords;
2050 layer->convertToLayerCoords(positionedAncestor, thisCoords);
2052 LayoutPoint ancestorCoords;
2053 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
2055 location += (thisCoords - ancestorCoords);
2056 return ancestorLayer;
2059 parentLayer = layer->parent();
2064 location += toLayoutSize(layer->location());
2066 if (adjustForColumns == RenderLayer::AdjustForColumns) {
2067 if (RenderLayer* parentLayer = layer->parent()) {
2068 LayoutSize layerColumnOffset;
2069 parentLayer->renderer().adjustForColumns(layerColumnOffset, location);
2070 location += layerColumnOffset;
2072 if (parentLayer->renderer().isRenderMultiColumnFlowThread()) {
2073 RenderRegion* region = toRenderMultiColumnFlowThread(parentLayer->renderer()).physicalTranslationFromFlowToRegion(location);
2075 location.moveBy(region->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
2083 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
2085 if (ancestorLayer == this)
2088 const RenderLayer* currLayer = this;
2089 while (currLayer && currLayer != ancestorLayer)
2090 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location, adjustForColumns);
2093 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect, ColumnOffsetAdjustment adjustForColumns) const
2096 convertToLayerCoords(ancestorLayer, delta, adjustForColumns);
2097 rect.move(-delta.x(), -delta.y());
2101 bool RenderLayer::hasAcceleratedTouchScrolling() const
2103 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2104 if (!scrollsOverflow())
2107 Settings* settings = renderer().document().settings();
2108 // FIXME: settings should not be null at this point. If you find a reliable way to hit this assertion, please file a bug.
2109 // See <rdar://problem/10266101>.
2112 return renderer().style().useTouchOverflowScrolling() || (settings && settings->alwaysUseAcceleratedOverflowScroll());
2118 bool RenderLayer::hasTouchScrollableOverflow() const
2120 return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2123 #if ENABLE(TOUCH_EVENTS)
2124 bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
2126 // If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
2127 if (hasTouchScrollableOverflow())
2130 return ScrollableArea::handleTouchEvent(touchEvent);
2134 void RenderLayer::registerAsTouchEventListenerForScrolling()
2136 if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
2139 renderer().document().addTouchEventListener(renderer().element());
2140 m_registeredAsTouchEventListenerForScrolling = true;
2143 void RenderLayer::unregisterAsTouchEventListenerForScrolling()
2145 if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
2148 renderer().document().removeTouchEventListener(renderer().element());
2149 m_registeredAsTouchEventListenerForScrolling = false;
2151 #endif // PLATFORM(IOS)
2153 bool RenderLayer::usesCompositedScrolling() const
2155 return isComposited() && backing()->scrollingLayer();
2158 bool RenderLayer::needsCompositedScrolling() const
2160 return m_needsCompositedScrolling;
2163 void RenderLayer::updateNeedsCompositedScrolling()
2165 bool oldNeedsCompositedScrolling = m_needsCompositedScrolling;
2167 if (!renderer().view().frameView().containsScrollableArea(this))
2168 m_needsCompositedScrolling = false;
2170 bool forceUseCompositedScrolling = acceleratedCompositingForOverflowScrollEnabled()
2171 && canBeStackingContainer()
2172 && !hasOutOfFlowPositionedDescendant();
2174 #if !PLATFORM(IOS) && ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2175 m_needsCompositedScrolling = forceUseCompositedScrolling || renderer().style().useTouchOverflowScrolling();
2177 // On iOS we don't want to opt into accelerated composited scrolling, which creates scroll bar
2178 // layers in WebCore, because we use UIKit to composite our scroll bars.
2179 m_needsCompositedScrolling = forceUseCompositedScrolling;
2181 // We gather a boolean value for use with Google UMA histograms to
2182 // quantify the actual effects of a set of patches attempting to
2183 // relax composited scrolling requirements, thereby increasing the
2184 // number of composited overflow divs.
2185 if (acceleratedCompositingForOverflowScrollEnabled())
2186 HistogramSupport::histogramEnumeration("Renderer.NeedsCompositedScrolling", m_needsCompositedScrolling, 2);
2189 if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
2190 updateSelfPaintingLayer();
2191 if (isStackingContainer())
2196 dirtyStackingContainerZOrderLists();
2198 compositor().setShouldReevaluateCompositingAfterLayout();
2199 compositor().setCompositingLayersNeedRebuild();
2203 static inline int adjustedScrollDelta(int beginningDelta) {
2204 // This implemention matches Firefox's.
2205 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
2206 const int speedReducer = 12;
2208 int adjustedDelta = beginningDelta / speedReducer;
2209 if (adjustedDelta > 1)
2210 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
2211 else if (adjustedDelta < -1)
2212 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
2214 return adjustedDelta;
2217 static inline IntSize adjustedScrollDelta(const IntSize& delta)
2219 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
2222 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
2224 IntPoint lastKnownMousePosition = renderer().frame().eventHandler().lastKnownMousePosition();
2226 // 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
2227 static IntPoint previousMousePosition;
2228 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
2229 lastKnownMousePosition = previousMousePosition;
2231 previousMousePosition = lastKnownMousePosition;
2233 IntSize delta = lastKnownMousePosition - sourcePoint;
2235 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
2237 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
2240 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
2243 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp, ScrollableArea** scrolledArea)
2248 bool restrictedByLineClamp = false;
2249 if (renderer().parent())
2250 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2252 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2253 IntSize newScrollOffset = scrollOffset() + delta;
2254 scrollToOffset(newScrollOffset, clamp);
2256 *scrolledArea = this;
2258 // If this layer can't do the scroll we ask the next layer up that can scroll to try
2259 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
2260 if (!remainingScrollOffset.isZero() && renderer().parent()) {
2261 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2262 scrollableLayer->scrollByRecursively(remainingScrollOffset, clamp, scrolledArea);
2264 renderer().frame().eventHandler().updateAutoscrollRenderer();
2267 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
2268 // have an overflow clip. Which means that it is a document node that can be scrolled.
2269 renderer().view().frameView().scrollBy(delta);
2271 *scrolledArea = &renderer().view().frameView();
2273 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
2274 // https://bugs.webkit.org/show_bug.cgi?id=28237
2278 IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const
2280 RenderBox* box = renderBox();
2283 int maxX = scrollWidth() - box->pixelSnappedClientWidth();
2284 int maxY = scrollHeight() - box->pixelSnappedClientHeight();
2286 int x = std::max(std::min(scrollOffset.width(), maxX), 0);
2287 int y = std::max(std::min(scrollOffset.height(), maxY), 0);
2288 return IntSize(x, y);
2291 void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp)
2293 IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2294 if (newScrollOffset != this->scrollOffset())
2295 scrollToOffsetWithoutAnimation(IntPoint(newScrollOffset));
2298 void RenderLayer::scrollTo(int x, int y)
2300 RenderBox* box = renderBox();
2304 if (box->style().overflowX() != OMARQUEE) {
2305 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
2306 if (m_scrollDimensionsDirty)
2307 computeScrollDimensions();
2309 if (adjustForIOSCaretWhenScrolling()) {
2310 int maxX = scrollWidth() - box->clientWidth();
2311 if (x > maxX - caretWidth) {
2313 if (x <= caretWidth)
2315 } else if (x < m_scrollOffset.width() - caretWidth)
2321 // FIXME: Eventually, we will want to perform a blit. For now never
2322 // blit, since the check for blitting is going to be very
2323 // complicated (since it will involve testing whether our layer
2324 // is either occluded by another layer or clipped by an enclosing
2325 // layer or contains fixed backgrounds, etc.).
2326 IntSize newScrollOffset = IntSize(x - scrollOrigin().x(), y - scrollOrigin().y());
2327 if (m_scrollOffset == newScrollOffset) {
2329 if (m_requiresScrollBoundsOriginUpdate)
2330 updateCompositingLayersAfterScroll();
2335 IntPoint oldPosition = IntPoint(m_scrollOffset);
2336 m_scrollOffset = newScrollOffset;
2338 InspectorInstrumentation::willScrollLayer(&renderer().frame());
2340 RenderView& view = renderer().view();
2342 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
2343 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
2344 bool inLayout = view.frameView().isInLayout();
2346 // If we're in the middle of layout, we'll just update layers once layout has finished.
2347 updateLayerPositionsAfterOverflowScroll();
2348 // Update regions, scrolling may change the clip of a particular region.
2349 #if ENABLE(DASHBOARD_SUPPORT)
2350 view.frameView().updateAnnotatedRegions();
2352 view.frameView().updateWidgetPositions();
2354 if (!m_updatingMarqueePosition) {
2355 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
2356 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
2357 // in this case we're still updating their positions; we'll update compositing layers later
2358 // when that completes.
2359 updateCompositingLayersAfterScroll();
2362 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
2363 renderer().document().dirtyTouchEventRects();
2367 Frame& frame = renderer().frame();
2368 RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
2369 // The caret rect needs to be invalidated after scrolling
2370 frame.selection().setCaretRectNeedsUpdate();
2372 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
2373 if (repaintContainer)
2374 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
2375 frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
2377 bool requiresRepaint = true;
2378 if (compositor().inCompositingMode() && usesCompositedScrolling())
2379 requiresRepaint = false;
2381 // Just schedule a full repaint of our object.
2382 if (requiresRepaint)
2383 renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
2385 // Schedule the scroll and scroll-related DOM events.
2386 if (Element* element = renderer().element()) {
2387 element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
2388 element->document().sendWillRevealEdgeEventsIfNeeded(oldPosition, IntPoint(newScrollOffset), visibleContentRect(), contentsSize(), element);
2391 InspectorInstrumentation::didScrollLayer(&frame);
2392 if (scrollsOverflow())
2393 frame.loader().client().didChangeScrollOffset();
2396 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
2398 // If scrollbars aren't explicitly forbidden, permit scrolling.
2399 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
2402 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
2403 if (frameView->wasScrolledByUser())
2406 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
2407 // like navigation to an anchor.
2408 return !frameView->frame().eventHandler().autoscrollInProgress();
2411 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2413 RenderLayer* parentLayer = 0;
2414 LayoutRect newRect = rect;
2416 // We may end up propagating a scroll event. It is important that we suspend events until
2417 // the end of the function since they could delete the layer or the layer's renderer().
2418 FrameView& frameView = renderer().view().frameView();
2420 bool restrictedByLineClamp = false;
2421 if (renderer().parent()) {
2422 parentLayer = renderer().parent()->enclosingLayer();
2423 restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
2426 if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
2427 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
2428 // This will prevent us from revealing text hidden by the slider in Safari RSS.
2429 RenderBox* box = renderBox();
2431 LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
2432 LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
2433 LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
2435 IntSize clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
2436 if (clampedScrollOffset != scrollOffset()) {
2437 IntSize oldScrollOffset = scrollOffset();
2438 scrollToOffset(clampedScrollOffset);
2439 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
2440 localExposeRect.move(-scrollOffsetDifference);
2441 newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
2443 } else if (!parentLayer && renderer().isBox() && renderBox()->canBeProgramaticallyScrolled()) {
2444 Element* ownerElement = renderer().document().ownerElement();
2446 if (ownerElement && ownerElement->renderer()) {
2447 HTMLFrameElementBase* frameElementBase = 0;
2449 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
2450 frameElementBase = toHTMLFrameElementBase(ownerElement);
2452 if (frameElementAndViewPermitScroll(frameElementBase, &frameView)) {
2453 LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
2454 LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
2456 int xOffset = roundToInt(exposeRect.x());
2457 int yOffset = roundToInt(exposeRect.y());
2458 // Adjust offsets if they're outside of the allowable range.
2459 xOffset = std::max(0, std::min(frameView.contentsWidth(), xOffset));
2460 yOffset = std::max(0, std::min(frameView.contentsHeight(), yOffset));
2462 frameView.setScrollPosition(IntPoint(xOffset, yOffset));
2463 if (frameView.safeToPropagateScrollToParent()) {
2464 parentLayer = ownerElement->renderer()->enclosingLayer();
2465 // FIXME: This doesn't correctly convert the rect to
2466 // absolute coordinates in the parent.
2467 newRect.setX(rect.x() - frameView.scrollX() + frameView.x());
2468 newRect.setY(rect.y() - frameView.scrollY() + frameView.y());
2474 LayoutRect viewRect = frameView.visibleContentRect();
2475 LayoutRect visibleRectRelativeToDocument = viewRect;
2476 IntSize scrollOffsetRelativeToDocument = frameView.scrollOffsetRelativeToDocument();
2477 visibleRectRelativeToDocument.setLocation(IntPoint(scrollOffsetRelativeToDocument.width(), scrollOffsetRelativeToDocument.height()));
2479 LayoutRect viewRect = frameView.unobscuredContentRect();
2480 LayoutRect visibleRectRelativeToDocument = viewRect;
2483 LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
2485 frameView.setScrollPosition(roundedIntPoint(r.location()));
2487 // This is the outermost view of a web page, so after scrolling this view we
2488 // scroll its container by calling Page::scrollRectIntoView.
2489 // This only has an effect on the Mac platform in applications
2490 // that put web views into scrolling containers, such as Mac OS X Mail.
2491 // The canAutoscroll function in EventHandler also knows about this.
2492 if (Page* page = frameView.frame().page())
2493 page->chrome().scrollRectIntoView(pixelSnappedIntRect(rect));
2497 if (renderer().frame().eventHandler().autoscrollInProgress())
2498 parentLayer = enclosingScrollableLayer();
2501 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
2504 void RenderLayer::updateCompositingLayersAfterScroll()
2506 if (compositor().inCompositingMode()) {
2507 // Our stacking container is guaranteed to contain all of our descendants that may need
2508 // repositioning, so update compositing layers from there.
2509 if (RenderLayer* compositingAncestor = stackingContainer()->enclosingCompositingLayer()) {
2510 if (usesCompositedScrolling() && !hasOutOfFlowPositionedDescendant())
2511 compositor().updateCompositingLayers(CompositingUpdateOnCompositedScroll, compositingAncestor);
2513 compositor().updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
2518 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
2520 // Determine the appropriate X behavior.
2521 ScrollBehavior scrollX;
2522 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
2523 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
2524 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
2525 // If the rectangle is fully visible, use the specified visible behavior.
2526 // If the rectangle is partially visible, but over a certain threshold,
2527 // then treat it as fully visible to avoid unnecessary horizontal scrolling
2528 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2529 else if (intersectWidth == visibleRect.width()) {
2530 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2531 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
2532 if (scrollX == alignCenter)
2534 } else if (intersectWidth > 0)
2535 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
2536 scrollX = ScrollAlignment::getPartialBehavior(alignX);
2538 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
2539 // If we're trying to align to the closest edge, and the exposeRect is further right
2540 // than the visibleRect, and not bigger than the visible area, then align with the right.
2541 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
2542 scrollX = alignRight;
2544 // Given the X behavior, compute the X coordinate.
2546 if (scrollX == noScroll)
2547 x = visibleRect.x();
2548 else if (scrollX == alignRight)
2549 x = exposeRect.maxX() - visibleRect.width();
2550 else if (scrollX == alignCenter)
2551 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
2555 // Determine the appropriate Y behavior.
2556 ScrollBehavior scrollY;
2557 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
2558 LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
2559 if (intersectHeight == exposeRect.height())
2560 // If the rectangle is fully visible, use the specified visible behavior.
2561 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2562 else if (intersectHeight == visibleRect.height()) {
2563 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
2564 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
2565 if (scrollY == alignCenter)
2567 } else if (intersectHeight > 0)
2568 // If the rectangle is partially visible, use the specified partial behavior
2569 scrollY = ScrollAlignment::getPartialBehavior(alignY);
2571 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
2572 // If we're trying to align to the closest edge, and the exposeRect is further down
2573 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
2574 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
2575 scrollY = alignBottom;
2577 // Given the Y behavior, compute the Y coordinate.
2579 if (scrollY == noScroll)
2580 y = visibleRect.y();
2581 else if (scrollY == alignBottom)
2582 y = exposeRect.maxY() - visibleRect.height();
2583 else if (scrollY == alignCenter)
2584 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2588 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2591 void RenderLayer::autoscroll(const IntPoint& position)
2593 IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
2594 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2597 bool RenderLayer::canResize() const
2599 // We need a special case for <iframe> because they never have
2600 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
2601 // we want to allow resizing them also.
2602 return (renderer().hasOverflowClip() || renderer().isRenderIFrame()) && renderer().style().resize() != RESIZE_NONE;
2605 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2607 // FIXME: This should be possible on generated content but is not right now.
2608 if (!inResizeMode() || !canResize() || !renderer().element())
2611 // FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
2612 // If they do it would still be better to deal with them explicitly.
2613 Element* element = renderer().element();
2614 RenderBox* renderer = toRenderBox(element->renderer());
2616 Document& document = element->document();
2617 if (!document.frame()->eventHandler().mousePressed())
2620 float zoomFactor = renderer->style().effectiveZoom();
2622 LayoutSize newOffset = offsetFromResizeCorner(document.view()->windowToContents(evt.position()));
2623 newOffset.setWidth(newOffset.width() / zoomFactor);
2624 newOffset.setHeight(newOffset.height() / zoomFactor);
2626 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2627 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2628 element->setMinimumSizeForResizing(minimumSize);
2630 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2631 if (renderer->style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
2632 newOffset.setWidth(-newOffset.width());
2633 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2636 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2638 StyledElement* styledElement = toStyledElement(element);
2639 bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
2641 EResize resize = renderer->style().resize();
2642 if (resize != RESIZE_VERTICAL && difference.width()) {
2643 if (element->isFormControlElement()) {
2644 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2645 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2646 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2648 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
2649 baseWidth = baseWidth / zoomFactor;
2650 styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
2653 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2654 if (element->isFormControlElement()) {
2655 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2656 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2657 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
2659 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
2660 baseHeight = baseHeight / zoomFactor;
2661 styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
2664 document.updateLayout();
2666 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2669 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2671 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2672 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2675 void RenderLayer::setScrollOffset(const IntPoint& offset)
2677 scrollTo(offset.x(), offset.y());
2680 int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
2682 if (scrollbar->orientation() == HorizontalScrollbar)
2683 return scrollXOffset();
2684 if (scrollbar->orientation() == VerticalScrollbar)
2685 return scrollYOffset();
2689 IntPoint RenderLayer::scrollPosition() const
2691 return IntPoint(m_scrollOffset);
2694 IntPoint RenderLayer::minimumScrollPosition() const
2696 return -scrollOrigin();
2699 IntPoint RenderLayer::maximumScrollPosition() const
2701 // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
2702 return -scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRectIncludingScrollbars(ContentsVisibleRect).size();
2705 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
2707 int verticalScrollbarWidth = 0;
2708 int horizontalScrollbarHeight = 0;
2709 if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars) {
2710 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
2711 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
2714 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
2715 IntSize(std::max(0, m_layerSize.width() - verticalScrollbarWidth),
2716 std::max(0, m_layerSize.height() - horizontalScrollbarHeight)));
2719 IntSize RenderLayer::overhangAmount() const
2724 bool RenderLayer::isActive() const
2726 Page* page = renderer().frame().page();
2727 return page && page->focusController().isActive();
2730 static int cornerStart(const RenderLayer* layer, int minX, int maxX, int thickness)
2732 if (layer->renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2733 return minX + layer->renderer().style().borderLeftWidth();
2734 return maxX - thickness - layer->renderer().style().borderRightWidth();
2737 static LayoutRect cornerRect(const RenderLayer* layer, const LayoutRect& bounds)
2739 int horizontalThickness;
2740 int verticalThickness;
2741 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2742 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2743 // even when they don't exist in order to set the resizer square size properly.
2744 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
2745 verticalThickness = horizontalThickness;
2746 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2747 horizontalThickness = layer->verticalScrollbar()->width();
2748 verticalThickness = horizontalThickness;
2749 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
2750 verticalThickness = layer->horizontalScrollbar()->height();
2751 horizontalThickness = verticalThickness;
2753 horizontalThickness = layer->verticalScrollbar()->width();
2754 verticalThickness = layer->horizontalScrollbar()->height();
2756 return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2757 bounds.maxY() - verticalThickness - layer->renderer().style().borderBottomWidth(),
2758 horizontalThickness, verticalThickness);
2761 IntRect RenderLayer::scrollCornerRect() const
2763 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
2764 // This happens when:
2765 // (a) A resizer is present and at least one scrollbar is present
2766 // (b) Both scrollbars are present.
2767 bool hasHorizontalBar = horizontalScrollbar();
2768 bool hasVerticalBar = verticalScrollbar();
2769 bool hasResizer = renderer().style().resize() != RESIZE_NONE;
2770 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2771 return pixelSnappedIntRect(cornerRect(this, renderBox()->borderBoxRect()));
2775 static LayoutRect resizerCornerRect(const RenderLayer* layer, const LayoutRect& bounds)
2777 ASSERT(layer->renderer().isBox());
2778 if (layer->renderer().style().resize() == RESIZE_NONE)
2779 return LayoutRect();
2780 return cornerRect(layer, bounds);
2783 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
2785 RenderBox* box = renderBox();
2787 return LayoutRect();
2788 LayoutRect scrollCornerAndResizer = scrollCornerRect();
2789 if (scrollCornerAndResizer.isEmpty())
2790 scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect());
2791 return scrollCornerAndResizer;
2794 bool RenderLayer::isScrollCornerVisible() const
2796 ASSERT(renderer().isBox());
2797 return !scrollCornerRect().isEmpty();
2800 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
2802 IntRect rect = scrollbarRect;
2803 rect.move(scrollbarOffset(scrollbar));
2805 return renderer().view().frameView().convertFromRenderer(&renderer(), rect);
2808 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
2810 IntRect rect = renderer().view().frameView().convertToRenderer(&renderer(), parentRect);
2811 rect.move(-scrollbarOffset(scrollbar));
2815 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
2817 IntPoint point = scrollbarPoint;
2818 point.move(scrollbarOffset(scrollbar));
2819 return renderer().view().frameView().convertFromRenderer(&renderer(), point);
2822 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
2824 IntPoint point = renderer().view().frameView().convertToRenderer(&renderer(), parentPoint);
2825 point.move(-scrollbarOffset(scrollbar));
2829 IntSize RenderLayer::contentsSize() const
2831 return IntSize(scrollWidth(), scrollHeight());
2834 bool RenderLayer::shouldSuspendScrollAnimations() const
2836 return renderer().view().frameView().shouldSuspendScrollAnimations();
2840 void RenderLayer::didStartScroll()
2842 if (Page* page = renderer().frame().page())
2843 page->chrome().client().didStartOverflowScroll();
2846 void RenderLayer::didEndScroll()
2848 if (Page* page = renderer().frame().page())
2849 page->chrome().client().didEndOverflowScroll();
2852 void RenderLayer::didUpdateScroll()
2854 // Send this notification when we scroll, since this is how we keep selection updated.
2855 if (Page* page = renderer().frame().page())
2856 page->chrome().client().didLayout(ChromeClient::Scroll);
2860 IntPoint RenderLayer::lastKnownMousePosition() const
2862 return renderer().frame().eventHandler().lastKnownMousePosition();
2865 bool RenderLayer::isHandlingWheelEvent() const
2867 return renderer().frame().eventHandler().isHandlingWheelEvent();
2870 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
2875 const RenderBox* box = renderBox();
2876 const IntRect& scrollCorner = scrollCornerRect();
2878 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
2879 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
2880 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2884 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
2889 const RenderBox* box = renderBox();
2890 const IntRect& scrollCorner = scrollCornerRect();
2892 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
2893 borderBoxRect.y() + box->borderTop(),
2895 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
2898 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
2900 const RenderBox* box = renderBox();
2901 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2902 return minX + box->borderLeft();
2903 return maxX - box->borderRight() - m_vBar->width();
2906 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
2908 const RenderBox* box = renderBox();
2909 int x = minX + box->borderLeft();
2910 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2911 x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(this, box->borderBoxRect()).width());
2915 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
2917 RenderBox* box = renderBox();
2919 if (scrollbar == m_vBar.get())
2920 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
2922 if (scrollbar == m_hBar.get())
2923 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2925 ASSERT_NOT_REACHED();
2929 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2931 if (!showsOverflowControls())
2934 if (scrollbar == m_vBar.get()) {
2935 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2936 layer->setNeedsDisplayInRect(rect);
2940 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2941 layer->setNeedsDisplayInRect(rect);
2946 IntRect scrollRect = rect;
2947 RenderBox* box = renderBox();
2949 // If we are not yet inserted into the tree, there is no need to repaint.
2953 if (scrollbar == m_vBar.get())
2954 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
2956 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2957 LayoutRect repaintRect = scrollRect;
2958 renderBox()->flipForWritingMode(repaintRect);
2959 renderer().repaintRectangle(repaintRect);
2962 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
2964 if (!showsOverflowControls())
2967 if (GraphicsLayer* layer = layerForScrollCorner()) {
2968 layer->setNeedsDisplayInRect(rect);
2973 m_scrollCorner->repaintRectangle(rect);
2975 m_resizer->repaintRectangle(rect);
2978 static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& renderer)
2980 if (Element* element = renderer.element()) {
2981 if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
2982 if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
2983 return shadowRoot->hostElement()->renderer();
2990 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
2992 RefPtr<Scrollbar> widget;
2993 RenderElement* actualRenderer = rendererForScrollbar(renderer());
2994 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style().hasPseudoStyle(SCROLLBAR);
2995 if (hasCustomScrollbarStyle)
2996 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->element());
2998 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
2999 didAddScrollbar(widget.get(), orientation);
3001 renderer().view().frameView().addChild(widget.get());
3002 return widget.release();
3005 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
3007 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
3011 if (!scrollbar->isCustomScrollbar())
3012 willRemoveScrollbar(scrollbar.get(), orientation);
3014 scrollbar->removeFromParent();
3015 scrollbar->disconnectFromScrollableArea();
3019 bool RenderLayer::scrollsOverflow() const
3021 if (!renderer().isBox())
3024 return toRenderBox(renderer()).scrollsOverflow();
3027 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
3029 if (hasScrollbar == hasHorizontalScrollbar())
3033 m_hBar = createScrollbar(HorizontalScrollbar);
3035 destroyScrollbar(HorizontalScrollbar);
3037 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3039 m_hBar->styleChanged();
3041 m_vBar->styleChanged();
3043 // Force an update since we know the scrollbars have changed things.
3044 #if ENABLE(DASHBOARD_SUPPORT)
3045 if (renderer().document().hasAnnotatedRegions())
3046 renderer().document().setAnnotatedRegionsDirty(true);
3050 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
3052 if (hasScrollbar == hasVerticalScrollbar())
3056 m_vBar = createScrollbar(VerticalScrollbar);
3058 destroyScrollbar(VerticalScrollbar);
3060 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
3062 m_hBar->styleChanged();
3064 m_vBar->styleChanged();
3066 // Force an update since we know the scrollbars have changed things.
3067 #if ENABLE(DASHBOARD_SUPPORT)
3068 if (renderer().document().hasAnnotatedRegions())
3069 renderer().document().setAnnotatedRegionsDirty(true);
3073 ScrollableArea* RenderLayer::enclosingScrollableArea() const
3075 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
3076 return scrollableLayer;
3078 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
3079 // if the frame view isn't scrollable.
3083 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
3086 || !showsOverflowControls()
3087 || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
3090 return m_vBar->width();
3093 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
3096 || !showsOverflowControls()
3097 || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
3100 return m_hBar->height();
3103 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
3105 // Currently the resize corner is either the bottom right corner or the bottom left corner.
3106 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
3107 IntSize elementSize = size();
3108 if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
3109 elementSize.setWidth(0);
3110 IntPoint resizerPoint = IntPoint(elementSize);
3111 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
3112 return localPoint - resizerPoint;
3115 bool RenderLayer::hasOverflowControls() const
3117 return m_hBar || m_vBar || m_scrollCorner || renderer().style().resize() != RESIZE_NONE;
3120 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
3122 if (!m_hBar && !m_vBar && !canResize())
3125 RenderBox* box = renderBox();
3129 const IntRect borderBox = box->pixelSnappedBorderBoxRect();
3130 const IntRect& scrollCorner = scrollCornerRect();
3131 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
3133 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
3134 vBarRect.move(offsetFromRoot);
3135 m_vBar->setFrameRect(vBarRect);
3139 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
3140 hBarRect.move(offsetFromRoot);
3141 m_hBar->setFrameRect(hBarRect);
3145 m_scrollCorner->setFrameRect(scrollCorner);
3147 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
3150 backing()->positionOverflowControlsLayers();
3153 int RenderLayer::scrollWidth() const
3155 ASSERT(renderBox());
3156 if (m_scrollDimensionsDirty)
3157 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3158 return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft() + renderBox()->x());
3161 int RenderLayer::scrollHeight() const
3163 ASSERT(renderBox());
3164 if (m_scrollDimensionsDirty)
3165 const_cast<RenderLayer*>(this)->computeScrollDimensions();
3166 return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop() + renderBox()->y());
3169 LayoutUnit RenderLayer::overflowTop() const
3171 RenderBox* box = renderBox();
3172 LayoutRect overflowRect(box->layoutOverflowRect());
3173 box->flipForWritingMode(overflowRect);
3174 return overflowRect.y();
3177 LayoutUnit RenderLayer::overflowBottom() const
3179 RenderBox* box = renderBox();
3180 LayoutRect overflowRect(box->layoutOverflowRect());
3181 box->flipForWritingMode(overflowRect);
3182 return overflowRect.maxY();
3185 LayoutUnit RenderLayer::overflowLeft() const
3187 RenderBox* box = renderBox();
3188 LayoutRect overflowRect(box->layoutOverflowRect());
3189 box->flipForWritingMode(overflowRect);
3190 return overflowRect.x();
3193 LayoutUnit RenderLayer::overflowRight() const
3195 RenderBox* box = renderBox();
3196 LayoutRect overflowRect(box->layoutOverflowRect());
3197 box->flipForWritingMode(overflowRect);
3198 return overflowRect.maxX();
3201 void RenderLayer::computeScrollDimensions()
3203 RenderBox* box = renderBox();
3206 m_scrollDimensionsDirty = false;
3208 m_scrollSize.setWidth(overflowRight() - overflowLeft());
3209 m_scrollSize.setHeight(overflowBottom() - overflowTop());
3211 int scrollableLeftOverflow = overflowLeft() - box->borderLeft();
3212 int scrollableTopOverflow = overflowTop() - box->borderTop();
3213 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
3216 bool RenderLayer::hasScrollableHorizontalOverflow() const
3218 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
3221 bool RenderLayer::hasScrollableVerticalOverflow() const
3223 return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
3226 bool RenderLayer::hasHorizontalOverflow() const
3228 ASSERT(!m_scrollDimensionsDirty);
3230 return scrollWidth() > renderBox()->pixelSnappedClientWidth();
3233 bool RenderLayer::hasVerticalOverflow() const
3235 ASSERT(!m_scrollDimensionsDirty);
3237 return scrollHeight() > renderBox()->pixelSnappedClientHeight();
3240 void RenderLayer::updateScrollbarsAfterLayout()
3242 RenderBox* box = renderBox();
3245 // List box parts handle the scrollbars by themselves so we have nothing to do.
3246 if (box->style().appearance() == ListboxPart)
3249 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
3250 bool hasVerticalOverflow = this->hasVerticalOverflow();
3252 // overflow:scroll should just enable/disable.
3253 if (renderer().style().overflowX() == OSCROLL)
3254 m_hBar->setEnabled(hasHorizontalOverflow);
3255 if (renderer().style().overflowY() == OSCROLL)
3256 m_vBar->setEnabled(hasVerticalOverflow);
3258 // overflow:auto may need to lay out again if scrollbars got added/removed.
3259 bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
3260 bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
3262 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
3263 if (box->hasAutoHorizontalScrollbar())
3264 setHasHorizontalScrollbar(hasHorizontalOverflow);
3265 if (box->hasAutoVerticalScrollbar())
3266 setHasVerticalScrollbar(hasVerticalOverflow);
3268 updateSelfPaintingLayer();
3270 // Force an update since we know the scrollbars have changed things.
3271 #if ENABLE(DASHBOARD_SUPPORT)
3272 if (renderer().document().hasAnnotatedRegions())
3273 renderer().document().setAnnotatedRegionsDirty(true);
3276 renderer().repaint();
3278 if (renderer().style().overflowX() == OAUTO || renderer().style().overflowY() == OAUTO) {
3279 if (!m_inOverflowRelayout) {
3280 // Our proprietary overflow: overlay value doesn't trigger a layout.
3281 m_inOverflowRelayout = true;
3282 renderer().setNeedsLayout(MarkOnlyThis);
3283 if (renderer().isRenderBlock()) {
3284 RenderBlock& block = toRenderBlock(renderer());
3285 block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
3286 block.layoutBlock(true);
3288 renderer().layout();
3289 m_inOverflowRelayout = false;
3294 // Set up the range (and page step/line step).
3296 int clientWidth = box->pixelSnappedClientWidth();
3297 int pageStep = std::max(std::max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
3298 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3299 m_hBar->setProportion(clientWidth, m_scrollSize.width());
3302 int clientHeight = box->pixelSnappedClientHeight();
3303 int pageStep = std::max(std::max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
3304 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
3305 m_vBar->setProportion(clientHeight, m_scrollSize.height());
3308 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
3311 void RenderLayer::updateScrollInfoAfterLayout()
3313 RenderBox* box = renderBox();
3317 m_scrollDimensionsDirty = true;
3318 IntSize originalScrollOffset = scrollOffset();
3320 computeScrollDimensions();
3322 if (box->style().overflowX() != OMARQUEE) {
3323 // Layout may cause us to be at an invalid scroll position. In this case we need
3324 // to pull our scroll offsets back to the max (or push them up to the min).
3325 IntSize clampedScrollOffset = clampScrollOffset(scrollOffset());
3327 // FIXME: This looks wrong. The caret adjust mode should only be enabled on editing related entry points.
3328 // This code was added to fix an issue where the text insertion point would always be drawn on the right edge
3329 // of a text field whose content overflowed its bounds. See <rdar://problem/15579797> for more details.
3330 setAdjustForIOSCaretWhenScrolling(true);
3332 if (clampedScrollOffset != scrollOffset())
3333 scrollToOffset(clampedScrollOffset);
3336 setAdjustForIOSCaretWhenScrolling(false);
3340 updateScrollbarsAfterLayout();
3342 if (originalScrollOffset != scrollOffset())
3343 scrollToOffsetWithoutAnimation(IntPoint(scrollOffset()));
3345 // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
3346 if (compositor().updateLayerCompositingState(*this))
3347 compositor().setCompositingLayersNeedRebuild();
3350 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
3352 const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect();
3354 if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
3357 if (rectForVerticalScrollbar(borderBox).intersects(localRect))
3360 if (scrollCornerRect().intersects(localRect))
3363 if (resizerCornerRect(this, borderBox).intersects(localRect))
3369 bool RenderLayer::showsOverflowControls() const
3372 // Don't render (custom) scrollbars if we have accelerated scrolling.
3373 if (hasAcceleratedTouchScrolling())
3380 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
3382 // Don't do anything if we have no overflow.
3383 if (!renderer().hasOverflowClip())
3386 if (!showsOverflowControls())
3389 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
3390 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
3391 // will be false, and we should just tell the root layer that there are overlay scrollbars
3392 // that need to be painted. That will cause the second pass through the layer tree to run,
3393 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
3394 // second pass doesn't need to re-enter the RenderTree to get it right.
3395 if (hasOverlayScrollbars() && !paintingOverlayControls) {
3396 m_cachedOverlayScrollbarOffset = paintOffset;
3398 // It's not necessary to do the second pass if the scrollbars paint into layers.
3399 if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar()))
3401 IntRect localDamgeRect = damageRect;
3402 localDamgeRect.moveBy(-paintOffset);
3403 if (!overflowControlsIntersectRect(localDamgeRect))
3406 RenderLayer* paintingRoot = enclosingCompositingLayer();