2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 "ColumnInfo.h"
48 #include "CSSPropertyNames.h"
51 #include "DocumentEventQueue.h"
52 #include "EventHandler.h"
53 #if ENABLE(CSS_FILTERS)
54 #include "FEColorMatrix.h"
56 #include "FilterEffectRenderer.h"
58 #include "FloatConversion.h"
59 #include "FloatPoint3D.h"
60 #include "FloatRect.h"
61 #include "FocusController.h"
63 #include "FrameSelection.h"
64 #include "FrameTree.h"
65 #include "FrameView.h"
67 #include "GraphicsContext.h"
68 #include "HTMLFrameElement.h"
69 #include "HTMLFrameOwnerElement.h"
70 #include "HTMLNames.h"
71 #include "HitTestingTransformState.h"
72 #include "HitTestRequest.h"
73 #include "HitTestResult.h"
74 #include "OverflowEvent.h"
75 #include "OverlapTestRequestClient.h"
77 #include "PlatformMouseEvent.h"
78 #include "RenderArena.h"
79 #include "RenderFlowThread.h"
80 #include "RenderGeometryMap.h"
81 #include "RenderInline.h"
82 #include "RenderMarquee.h"
83 #include "RenderReplica.h"
84 #include "RenderSVGResourceClipper.h"
85 #include "RenderScrollbar.h"
86 #include "RenderScrollbarPart.h"
87 #include "RenderTheme.h"
88 #include "RenderTreeAsText.h"
89 #include "RenderView.h"
90 #include "ScaleTransformOperation.h"
91 #include "ScrollAnimator.h"
92 #include "Scrollbar.h"
93 #include "ScrollbarTheme.h"
94 #include "ScrollingCoordinator.h"
96 #include "SourceGraphic.h"
97 #include "StylePropertySet.h"
98 #include "StyleResolver.h"
99 #include "TextStream.h"
100 #include "TransformationMatrix.h"
101 #include "TranslateTransformOperation.h"
102 #include "WebCoreMemoryInstrumentation.h"
103 #include <wtf/MemoryInstrumentationVector.h>
104 #include <wtf/StdLibExtras.h>
105 #include <wtf/UnusedParam.h>
106 #include <wtf/text/CString.h>
108 #if USE(ACCELERATED_COMPOSITING)
109 #include "RenderLayerBacking.h"
110 #include "RenderLayerCompositor.h"
114 #include "SVGNames.h"
117 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
118 #include "CustomFilterGlobalContext.h"
119 #include "CustomFilterOperation.h"
120 #include "CustomFilterValidatedProgram.h"
121 #include "ValidatedCustomFilterOperation.h"
124 #if PLATFORM(BLACKBERRY)
125 #define DISABLE_ROUNDED_CORNER_CLIPPING
128 #define MIN_INTERSECT_FOR_REVEAL 32
134 using namespace HTMLNames;
136 const int MinimumWidthWhileResizing = 100;
137 const int MinimumHeightWhileResizing = 40;
139 bool ClipRect::intersects(const HitTestLocation& hitTestLocation)
141 return hitTestLocation.intersects(m_rect);
144 RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
145 : m_inResizeMode(false)
146 , m_scrollDimensionsDirty(true)
147 , m_normalFlowListDirty(true)
148 , m_hasSelfPaintingLayerDescendant(false)
149 , m_hasSelfPaintingLayerDescendantDirty(false)
150 , m_isRootLayer(renderer->isRenderView())
151 , m_usedTransparency(false)
152 , m_paintingInsideReflection(false)
153 , m_inOverflowRelayout(false)
154 , m_repaintStatus(NeedsNormalRepaint)
155 , m_visibleContentStatusDirty(true)
156 , m_hasVisibleContent(false)
157 , m_visibleDescendantStatusDirty(false)
158 , m_hasVisibleDescendant(false)
159 , m_isPaginated(false)
160 , m_3DTransformedDescendantStatusDirty(true)
161 , m_has3DTransformedDescendant(false)
162 #if USE(ACCELERATED_COMPOSITING)
163 , m_hasCompositingDescendant(false)
164 , m_indirectCompositingReason(NoIndirectCompositingReason)
166 , m_containsDirtyOverlayScrollbars(false)
167 , m_updatingMarqueePosition(false)
169 , m_layerListMutationAllowed(true)
171 , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell())
172 #if ENABLE(CSS_FILTERS)
173 , m_hasFilterInfo(false)
175 #if ENABLE(CSS_COMPOSITING)
176 , m_blendMode(BlendModeNormal)
178 , m_renderer(renderer)
184 , m_staticInlinePosition(0)
185 , m_staticBlockPosition(0)
190 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
191 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
193 // Non-stacking contexts should have empty z-order lists. As this is already the case,
194 // there is no need to dirty / recompute these lists.
195 m_zOrderListsDirty = isStackingContext();
197 ScrollableArea::setConstrainsScrollingToContentEdge(false);
199 if (!renderer->firstChild() && renderer->style()) {
200 m_visibleContentStatusDirty = false;
201 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
204 Node* node = renderer->node();
205 if (node && node->isElementNode()) {
206 // We save and restore only the scrollOffset as the other scroll values are recalculated.
207 Element* element = toElement(node);
208 m_scrollOffset = element->savedLayerScrollOffset();
209 if (!m_scrollOffset.isZero())
210 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
211 element->setSavedLayerScrollOffset(IntSize());
215 RenderLayer::~RenderLayer()
217 if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
218 if (Frame* frame = renderer()->frame())
219 frame->eventHandler()->resizeLayerDestroyed();
222 if (Frame* frame = renderer()->frame()) {
223 if (FrameView* frameView = frame->view())
224 frameView->removeScrollableArea(this);
227 if (!m_renderer->documentBeingDestroyed()) {
228 Node* node = m_renderer->node();
229 if (node && node->isElementNode())
230 toElement(node)->setSavedLayerScrollOffset(m_scrollOffset);
233 destroyScrollbar(HorizontalScrollbar);
234 destroyScrollbar(VerticalScrollbar);
239 #if ENABLE(CSS_FILTERS)
240 removeFilterInfoIfNeeded();
243 // Child layers will be deleted by their corresponding render objects, so
244 // we don't need to delete them ourselves.
246 #if USE(ACCELERATED_COMPOSITING)
251 m_scrollCorner->destroy();
253 m_resizer->destroy();
256 #if USE(ACCELERATED_COMPOSITING)
257 RenderLayerCompositor* RenderLayer::compositor() const
259 if (!renderer()->view())
261 return renderer()->view()->compositor();
264 void RenderLayer::contentChanged(ContentChangeType changeType)
266 // This can get called when video becomes accelerated, so the layers may change.
267 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this))
268 compositor()->setCompositingLayersNeedRebuild();
271 m_backing->contentChanged(changeType);
273 #endif // USE(ACCELERATED_COMPOSITING)
275 bool RenderLayer::canRender3DTransforms() const
277 #if USE(ACCELERATED_COMPOSITING)
278 return compositor()->canRender3DTransforms();
284 #if ENABLE(CSS_FILTERS)
285 bool RenderLayer::paintsWithFilters() const
287 // FIXME: Eventually there will be more factors than isComposited() to decide whether or not to render the filter
288 if (!renderer()->hasFilter())
291 #if USE(ACCELERATED_COMPOSITING)
295 if (!m_backing || !m_backing->canCompositeFilters())
302 bool RenderLayer::requiresFullLayerImageForFilters() const
304 if (!paintsWithFilters())
306 FilterEffectRenderer* filter = filterRenderer();
307 return filter ? filter->hasFilterThatMovesPixels() : false;
311 LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
313 hasLayerOffset = true;
316 return LayoutPoint();
318 // This is similar to root() but we check if an ancestor layer would
319 // prevent the optimization from working.
320 const RenderLayer* rootLayer = 0;
321 for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
322 hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
324 return LayoutPoint();
326 ASSERT(rootLayer == root());
329 parent()->convertToLayerCoords(rootLayer, offset);
333 void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
335 RenderGeometryMap geometryMap(UseTransforms);
336 if (this != rootLayer)
337 geometryMap.pushMappingsToAncestor(parent(), 0);
338 updateLayerPositions(&geometryMap, flags);
341 void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
343 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
344 // we need to keep in sync, since we may have shifted relative
345 // to our parent layer.
347 geometryMap->pushMappingsToAncestor(this, parent());
349 // Clear our cached clip rect information.
352 if (hasOverflowControls()) {
353 LayoutPoint offsetFromRoot;
355 offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint()));
357 // FIXME: It looks suspicious to call convertToLayerCoords here
358 // as canUseConvertToLayerCoords may be true for an ancestor layer.
359 convertToLayerCoords(root(), offsetFromRoot);
361 positionOverflowControls(toSize(roundedIntPoint(offsetFromRoot)));
364 updateDescendantDependentFlags();
366 if (flags & UpdatePagination)
369 m_isPaginated = false;
371 if (m_hasVisibleContent) {
372 RenderView* view = renderer()->view();
374 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
375 // mapping between them and the RenderObjects. It would be neat to enable
376 // LayoutState outside the layout() phase and use it here.
377 ASSERT(!view->layoutStateEnabled());
379 RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint();
380 LayoutRect oldRepaintRect = m_repaintRect;
381 LayoutRect oldOutlineBox = m_outlineBox;
382 computeRepaintRects(repaintContainer, geometryMap);
384 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
385 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
386 if (flags & CheckForRepaint) {
387 if (view && !view->printing()) {
388 if (m_repaintStatus & NeedsFullRepaint) {
389 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect));
390 if (m_repaintRect != oldRepaintRect)
391 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
392 } else if (shouldRepaintAfterLayout())
393 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
399 m_repaintStatus = NeedsNormalRepaint;
401 // Go ahead and update the reflection's position and size.
403 m_reflection->layout();
405 #if USE(ACCELERATED_COMPOSITING)
406 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
407 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
409 flags &= ~IsCompositingUpdateRoot;
412 if (renderer()->hasColumns())
413 flags |= UpdatePagination;
415 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
416 child->updateLayerPositions(geometryMap, flags);
418 #if USE(ACCELERATED_COMPOSITING)
419 if ((flags & UpdateCompositingLayers) && isComposited())
420 backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
423 // With all our children positioned, now update our marquee if we need to.
425 // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
426 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
427 m_updatingMarqueePosition = true;
428 m_marquee->updateMarqueePosition();
429 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
433 geometryMap->popMappingsToAncestor(parent());
436 LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
438 LayoutRect repaintRect = m_repaintRect;
439 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
440 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
441 if (child->isComposited())
444 repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants());
449 void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
451 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
452 if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
455 layer->m_hasSelfPaintingLayerDescendantDirty = false;
456 layer->m_hasSelfPaintingLayerDescendant = true;
460 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
462 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
463 layer->m_hasSelfPaintingLayerDescendantDirty = true;
464 // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
465 // in this case, there is no need to dirty our ancestors further.
466 if (layer->isSelfPaintingLayer()) {
467 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
473 void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
475 ASSERT(!m_visibleContentStatusDirty);
477 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
478 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, geometryMap);
482 void RenderLayer::computeRepaintRectsIncludingDescendants()
484 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
485 // We should make this more efficient.
486 // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
487 computeRepaintRects(renderer()->containerForRepaint());
489 for (RenderLayer* layer = firstChild(); layer; layer = layer->nextSibling())
490 layer->computeRepaintRectsIncludingDescendants();
493 void RenderLayer::clearRepaintRects()
495 ASSERT(!m_hasVisibleContent);
496 ASSERT(!m_visibleContentStatusDirty);
498 m_repaintRect = IntRect();
499 m_outlineBox = IntRect();
502 void RenderLayer::updateLayerPositionsAfterDocumentScroll()
504 ASSERT(this == renderer()->view()->layer());
506 RenderGeometryMap geometryMap(UseTransforms);
507 updateLayerPositionsAfterScroll(&geometryMap);
510 void RenderLayer::updateLayerPositionsAfterOverflowScroll()
512 RenderGeometryMap geometryMap(UseTransforms);
513 RenderView* view = renderer()->view();
514 if (this != view->layer())
515 geometryMap.pushMappingsToAncestor(parent(), 0);
517 // FIXME: why is it OK to not check the ancestors of this layer in order to
518 // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
519 updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
522 void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
524 // FIXME: This shouldn't be needed, but there are some corner cases where
525 // these flags are still dirty. Update so that the check below is valid.
526 updateDescendantDependentFlags();
528 // If we have no visible content and no visible descendants, there is no point recomputing
529 // our rectangles as they will be empty. If our visibility changes, we are expected to
530 // recompute all our positions anyway.
531 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
534 bool positionChanged = updateLayerPosition();
536 flags |= HasChangedAncestor;
539 geometryMap->pushMappingsToAncestor(this, parent());
541 if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
544 if (renderer()->style()->hasViewportConstrainedPosition())
545 flags |= HasSeenViewportConstrainedAncestor;
547 if (renderer()->hasOverflowClip())
548 flags |= HasSeenAncestorWithOverflowClip;
550 if (flags & HasSeenViewportConstrainedAncestor
551 || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) {
552 // FIXME: We could track the repaint container as we walk down the tree.
553 computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
555 // Check that our cached rects are correct.
556 ASSERT(m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint()));
557 ASSERT(m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap));
560 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
561 child->updateLayerPositionsAfterScroll(geometryMap, flags);
563 // We don't update our reflection as scrolling is a translation which does not change the size()
564 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
568 bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
569 m_updatingMarqueePosition = true;
570 m_marquee->updateMarqueePosition();
571 m_updatingMarqueePosition = oldUpdatingMarqueePosition;
575 geometryMap->popMappingsToAncestor(parent());
578 #if ENABLE(CSS_COMPOSITING)
579 void RenderLayer::updateBlendMode()
581 BlendMode newBlendMode = renderer()->style()->blendMode();
582 if (newBlendMode != m_blendMode) {
583 m_blendMode = newBlendMode;
585 backing()->setBlendMode(newBlendMode);
590 void RenderLayer::updateTransform()
592 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
593 // so check style too.
594 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
595 bool had3DTransform = has3DTransform();
597 bool hadTransform = m_transform;
598 if (hasTransform != hadTransform) {
600 m_transform = adoptPtr(new TransformationMatrix);
604 // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
605 clearClipRectsIncludingDescendants();
609 RenderBox* box = renderBox();
611 m_transform->makeIdentity();
612 box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
613 makeMatrixRenderable(*m_transform, canRender3DTransforms());
616 if (had3DTransform != has3DTransform())
617 dirty3DTransformedDescendantStatus();
620 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
623 return TransformationMatrix();
625 #if USE(ACCELERATED_COMPOSITING)
626 if (renderer()->style()->isRunningAcceleratedAnimation()) {
627 TransformationMatrix currTransform;
628 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
629 style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin);
630 makeMatrixRenderable(currTransform, canRender3DTransforms());
631 return currTransform;
634 // m_transform includes transform-origin, so we need to recompute the transform here.
635 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
636 RenderBox* box = renderBox();
637 TransformationMatrix currTransform;
638 box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
639 makeMatrixRenderable(currTransform, canRender3DTransforms());
640 return currTransform;
643 UNUSED_PARAM(applyOrigin);
649 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
652 return TransformationMatrix();
654 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
655 TransformationMatrix matrix = *m_transform;
656 makeMatrixRenderable(matrix, false /* flatten 3d */);
663 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
665 RenderView* view = renderer->view();
666 RenderLayerModelObject* prevBlock = renderer;
667 RenderBlock* containingBlock;
668 for (containingBlock = renderer->containingBlock();
669 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
670 containingBlock = containingBlock->containingBlock())
671 prevBlock = containingBlock;
673 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
674 if (containingBlock != ancestorColumnsRenderer)
677 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
678 if (prevBlock->isOutOfFlowPositioned())
681 // Otherwise we are paginated by the columns block.
685 void RenderLayer::updatePagination()
687 m_isPaginated = false;
688 if (isComposited() || !parent())
689 return; // FIXME: We will have to deal with paginated compositing layers someday.
690 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
692 if (isNormalFlowOnly()) {
693 m_isPaginated = parent()->renderer()->hasColumns();
697 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context.
698 RenderLayer* ancestorStackingContext = stackingContext();
699 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
700 if (curr->renderer()->hasColumns()) {
701 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
704 if (curr == ancestorStackingContext)
709 void RenderLayer::setHasVisibleContent()
711 if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
712 ASSERT(!parent() || parent()->hasVisibleDescendant());
716 m_visibleContentStatusDirty = false;
717 m_hasVisibleContent = true;
718 computeRepaintRects(renderer()->containerForRepaint());
719 if (!isNormalFlowOnly()) {
720 // We don't collect invisible layers in z-order lists if we are not in compositing mode.
721 // As we became visible, we need to dirty our stacking contexts ancestors to be properly
722 // collected. FIXME: When compositing, we could skip this dirtying phase.
723 for (RenderLayer* sc = stackingContext(); sc; sc = sc->stackingContext()) {
724 sc->dirtyZOrderLists();
725 if (sc->hasVisibleContent())
731 parent()->setAncestorChainHasVisibleDescendant();
734 void RenderLayer::dirtyVisibleContentStatus()
736 m_visibleContentStatusDirty = true;
738 parent()->dirtyAncestorChainVisibleDescendantStatus();
741 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
743 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
744 if (layer->m_visibleDescendantStatusDirty)
747 layer->m_visibleDescendantStatusDirty = true;
751 void RenderLayer::setAncestorChainHasVisibleDescendant()
753 for (RenderLayer* layer = this; layer; layer = layer->parent()) {
754 if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
757 layer->m_hasVisibleDescendant = true;
758 layer->m_visibleDescendantStatusDirty = false;
762 void RenderLayer::updateDescendantDependentFlags()
764 if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty) {
765 m_hasVisibleDescendant = false;
766 m_hasSelfPaintingLayerDescendant = false;
767 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
768 child->updateDescendantDependentFlags();
770 bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
771 bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
773 m_hasVisibleDescendant |= hasVisibleDescendant;
774 m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
776 if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant)
779 m_visibleDescendantStatusDirty = false;
780 m_hasSelfPaintingLayerDescendantDirty = false;
783 if (m_visibleContentStatusDirty) {
784 if (renderer()->style()->visibility() == VISIBLE)
785 m_hasVisibleContent = true;
787 // layer may be hidden but still have some visible content, check for this
788 m_hasVisibleContent = false;
789 RenderObject* r = renderer()->firstChild();
791 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
792 m_hasVisibleContent = true;
795 if (r->firstChild() && !r->hasLayer())
797 else if (r->nextSibling())
798 r = r->nextSibling();
804 } while (r && !r->nextSibling());
806 r = r->nextSibling();
810 m_visibleContentStatusDirty = false;
814 void RenderLayer::dirty3DTransformedDescendantStatus()
816 RenderLayer* curr = stackingContext();
818 curr->m_3DTransformedDescendantStatusDirty = true;
820 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
821 // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
822 while (curr && curr->preserves3D()) {
823 curr->m_3DTransformedDescendantStatusDirty = true;
824 curr = curr->stackingContext();
828 // Return true if this layer or any preserve-3d descendants have 3d.
829 bool RenderLayer::update3DTransformedDescendantStatus()
831 if (m_3DTransformedDescendantStatusDirty) {
832 m_has3DTransformedDescendant = false;
836 // Transformed or preserve-3d descendants can only be in the z-order lists, not
837 // in the normal flow list, so we only need to check those.
838 if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
839 for (unsigned i = 0; i < positiveZOrderList->size(); ++i)
840 m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus();
843 // Now check our negative z-index children.
844 if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
845 for (unsigned i = 0; i < negativeZOrderList->size(); ++i)
846 m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus();
849 m_3DTransformedDescendantStatusDirty = false;
852 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
853 // the m_has3DTransformedDescendant set.
855 return has3DTransform() || m_has3DTransformedDescendant;
857 return has3DTransform();
860 bool RenderLayer::updateLayerPosition()
862 LayoutPoint localPoint;
863 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
864 if (renderer()->isInline() && renderer()->isRenderInline()) {
865 RenderInline* inlineFlow = toRenderInline(renderer());
866 IntRect lineBox = inlineFlow->linesBoundingBox();
867 setSize(lineBox.size());
868 inlineBoundingBoxOffset = toSize(lineBox.location());
869 localPoint += inlineBoundingBoxOffset;
870 } else if (RenderBox* box = renderBox()) {
871 // FIXME: Is snapping the size really needed here for the RenderBox case?
872 setSize(pixelSnappedIntSize(box->size(), box->location()));
873 localPoint += box->topLeftLocationOffset();
876 if (!renderer()->isOutOfFlowPositioned() && renderer()->parent()) {
877 // We must adjust our position by walking up the render tree looking for the
878 // nearest enclosing object with a layer.
879 RenderObject* curr = renderer()->parent();
880 while (curr && !curr->hasLayer()) {
881 if (curr->isBox() && !curr->isTableRow()) {
882 // Rows and cells share the same coordinate space (that of the section).
883 // Omit them when computing our xpos/ypos.
884 localPoint += toRenderBox(curr)->topLeftLocationOffset();
886 curr = curr->parent();
888 if (curr->isBox() && curr->isTableRow()) {
889 // Put ourselves into the row coordinate space.
890 localPoint -= toRenderBox(curr)->topLeftLocationOffset();
894 // Subtract our parent's scroll offset.
895 if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
896 RenderLayer* positionedParent = enclosingPositionedAncestor();
898 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
899 LayoutSize offset = positionedParent->scrolledContentOffset();
900 localPoint -= offset;
902 if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) {
903 LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(toRenderBox(renderer()));
904 localPoint += offset;
906 } else if (parent()) {
907 if (isComposited()) {
908 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
909 // They won't split across columns properly.
910 LayoutSize columnOffset;
911 if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns())
912 renderer()->view()->adjustForColumns(columnOffset, localPoint);
914 parent()->renderer()->adjustForColumns(columnOffset, localPoint);
916 localPoint += columnOffset;
919 IntSize scrollOffset = parent()->scrolledContentOffset();
920 localPoint -= scrollOffset;
923 bool positionOrOffsetChanged = false;
924 if (renderer()->isInFlowPositioned()) {
925 LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFlowPosition();
926 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
927 m_offsetForInFlowPosition = newOffset;
928 localPoint.move(m_offsetForInFlowPosition);
930 m_offsetForInFlowPosition = LayoutSize();
933 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
934 localPoint -= inlineBoundingBoxOffset;
936 positionOrOffsetChanged |= location() != localPoint;
937 setLocation(localPoint);
938 return positionOrOffsetChanged;
941 TransformationMatrix RenderLayer::perspectiveTransform() const
943 if (!renderer()->hasTransform())
944 return TransformationMatrix();
946 RenderStyle* style = renderer()->style();
947 if (!style->hasPerspective())
948 return TransformationMatrix();
950 // Maybe fetch the perspective from the backing?
951 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect();
952 const float boxWidth = borderBox.width();
953 const float boxHeight = borderBox.height();
955 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth);
956 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight);
958 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
959 // We want it to be in the top-left, so subtract half the height and width.
960 perspectiveOriginX -= boxWidth / 2.0f;
961 perspectiveOriginY -= boxHeight / 2.0f;
963 TransformationMatrix t;
964 t.translate(perspectiveOriginX, perspectiveOriginY);
965 t.applyPerspective(style->perspective());
966 t.translate(-perspectiveOriginX, -perspectiveOriginY);
971 FloatPoint RenderLayer::perspectiveOrigin() const
973 if (!renderer()->hasTransform())
976 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
977 RenderStyle* style = renderer()->style();
979 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()),
980 floatValueForLength(style->perspectiveOriginY(), borderBox.height()));
983 RenderLayer* RenderLayer::stackingContext() const
985 RenderLayer* layer = parent();
986 while (layer && !layer->isStackingContext())
987 layer = layer->parent();
989 ASSERT(!layer || layer->isStackingContext());
993 static inline bool isPositionedContainer(RenderLayer* layer)
995 RenderLayerModelObject* layerRenderer = layer->renderer();
996 return layer->isRootLayer() || layerRenderer->isPositioned() || layer->hasTransform();
999 static inline bool isFixedPositionedContainer(RenderLayer* layer)
1001 return layer->isRootLayer() || layer->hasTransform();
1004 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
1006 RenderLayer* curr = parent();
1007 while (curr && !isPositionedContainer(curr))
1008 curr = curr->parent();
1013 RenderLayer* RenderLayer::enclosingScrollableLayer() const
1015 for (RenderObject* nextRenderer = renderer()->parent(); nextRenderer; nextRenderer = nextRenderer->parent()) {
1016 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea())
1017 return nextRenderer->enclosingLayer();
1023 IntRect RenderLayer::scrollableAreaBoundingBox() const
1025 return renderer()->absoluteBoundingBoxRect();
1028 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
1030 RenderLayer* curr = parent();
1031 while (curr && !curr->isRootLayer() && !curr->transform())
1032 curr = curr->parent();
1037 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
1039 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
1042 inline bool RenderLayer::shouldRepaintAfterLayout() const
1044 #if USE(ACCELERATED_COMPOSITING)
1045 if (m_repaintStatus == NeedsNormalRepaint)
1048 // Composited layers that were moved during a positioned movement only
1049 // layout, don't need to be repainted. They just need to be recomposited.
1050 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
1051 return !isComposited();
1057 #if USE(ACCELERATED_COMPOSITING)
1058 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
1060 if (includeSelf && isComposited())
1061 return const_cast<RenderLayer*>(this);
1063 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1064 if (curr->isComposited())
1065 return const_cast<RenderLayer*>(curr);
1071 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const
1073 if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
1074 return const_cast<RenderLayer*>(this);
1076 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
1077 if (curr->isComposited() && !curr->backing()->paintsIntoCompositedAncestor())
1078 return const_cast<RenderLayer*>(curr);
1085 #if ENABLE(CSS_FILTERS)
1086 RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const
1088 const RenderLayer* curr = includeSelf ? this : parent();
1089 for (; curr; curr = curr->parent()) {
1090 if (curr->requiresFullLayerImageForFilters())
1091 return const_cast<RenderLayer*>(curr);
1097 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
1099 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1100 if ((curr != this && curr->requiresFullLayerImageForFilters()) || curr->isComposited() || curr->isRootLayer())
1101 return const_cast<RenderLayer*>(curr);
1106 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, bool immediate)
1111 LayoutRect rectForRepaint = rect;
1113 #if ENABLE(CSS_FILTERS)
1114 if (renderer()->style()->hasFilterOutsets()) {
1119 renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset);
1120 rectForRepaint.move(-leftOutset, -topOutset);
1121 rectForRepaint.expand(leftOutset + rightOutset, topOutset + bottomOutset);
1125 RenderLayerFilterInfo* filterInfo = this->filterInfo();
1127 filterInfo->expandDirtySourceRect(rectForRepaint);
1129 #if ENABLE(CSS_SHADERS)
1130 ASSERT(filterInfo->renderer());
1131 if (filterInfo->renderer()->hasCustomShaderFilter()) {
1132 // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the
1133 // shader can address any ouput pixel.
1134 // Note: This is only for output rect, so there's no need to expand the dirty source rect.
1135 rectForRepaint.unite(calculateLayerBounds(this));
1139 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1140 ASSERT(parentLayer);
1141 FloatQuad repaintQuad(rectForRepaint);
1142 LayoutRect parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox();
1144 #if USE(ACCELERATED_COMPOSITING)
1145 if (parentLayer->isComposited()) {
1146 if (!parentLayer->backing()->paintsIntoWindow()) {
1147 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1150 // If the painting goes to window, redirect the painting to the parent RenderView.
1151 parentLayer = renderer()->view()->layer();
1152 parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox();
1156 if (parentLayer->paintsWithFilters()) {
1157 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect, immediate);
1161 if (parentLayer->isRootLayer()) {
1162 RenderView* view = toRenderView(parentLayer->renderer());
1163 view->repaintViewRectangle(parentLayerRect, immediate);
1167 ASSERT_NOT_REACHED();
1170 bool RenderLayer::hasAncestorWithFilterOutsets() const
1172 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
1173 RenderLayerModelObject* renderer = curr->renderer();
1174 if (renderer->style()->hasFilterOutsets())
1181 RenderLayer* RenderLayer::clippingRootForPainting() const
1183 #if USE(ACCELERATED_COMPOSITING)
1185 return const_cast<RenderLayer*>(this);
1188 const RenderLayer* current = this;
1190 if (current->isRootLayer())
1191 return const_cast<RenderLayer*>(current);
1193 current = compositingContainer(current);
1195 if (current->transform()
1196 #if USE(ACCELERATED_COMPOSITING)
1197 || (current->isComposited() && !current->backing()->paintsIntoCompositedAncestor())
1200 return const_cast<RenderLayer*>(current);
1203 ASSERT_NOT_REACHED();
1207 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1209 // We don't use convertToLayerCoords because it doesn't know about transforms
1210 return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, UseTransforms | SnapOffsetForTransforms));
1213 bool RenderLayer::cannotBlitToWindow() const
1215 if (isTransparent() || hasReflection() || hasTransform())
1219 return parent()->cannotBlitToWindow();
1222 bool RenderLayer::isTransparent() const
1225 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
1228 return renderer()->isTransparent() || renderer()->hasMask();
1231 RenderLayer* RenderLayer::transparentPaintingAncestor()
1236 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1237 if (curr->isComposited())
1239 if (curr->isTransparent())
1245 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, PaintBehavior);
1247 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
1249 // If we have a mask, then the clip is limited to the border box area (and there is
1250 // no need to examine child layers).
1251 if (!layer->renderer()->hasMask()) {
1252 // Note: we don't have to walk z-order lists since transparent elements always establish
1253 // a stacking context. This means we can just walk the layer tree directly.
1254 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
1255 if (!layer->reflection() || layer->reflectionLayer() != curr)
1256 clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
1260 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1261 // current transparencyClipBox to catch all child layers.
1262 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1263 // size into the parent layer.
1264 if (layer->renderer()->hasReflection()) {
1266 layer->convertToLayerCoords(rootLayer, delta);
1267 clipRect.move(-delta.x(), -delta.y());
1268 clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
1269 clipRect.moveBy(delta);
1273 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
1275 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1276 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1277 // would be better to respect clips.
1279 if (rootLayer != layer && layer->paintsWithTransform(paintBehavior)) {
1280 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1281 // the transformed layer and all of its children.
1283 layer->convertToLayerCoords(rootLayer, delta);
1285 TransformationMatrix transform;
1286 transform.translate(delta.x(), delta.y());
1287 transform = transform * *layer->transform();
1289 LayoutRect clipRect = layer->boundingBox(layer);
1290 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, paintBehavior);
1291 return transform.mapRect(clipRect);
1294 LayoutRect clipRect = layer->boundingBox(rootLayer);
1295 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, paintBehavior);
1299 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1301 return intersection(transparencyClipBox(this, rootLayer, paintBehavior), paintDirtyRect);
1304 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1306 if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
1309 RenderLayer* ancestor = transparentPaintingAncestor();
1311 ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
1313 if (paintsWithTransparency(paintBehavior)) {
1314 m_usedTransparency = true;
1316 LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
1317 context->clip(clipRect);
1318 context->beginTransparencyLayer(renderer()->opacity());
1319 #ifdef REVEAL_TRANSPARENCY_LAYERS
1320 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
1321 context->fillRect(clipRect);
1326 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena)
1328 return renderArena->allocate(sz);
1331 void RenderLayer::operator delete(void* ptr, size_t sz)
1333 // Stash size where destroy can find it.
1334 *(size_t *)ptr = sz;
1337 void RenderLayer::destroy(RenderArena* renderArena)
1341 // Recover the size left there for us by operator delete and free the memory.
1342 renderArena->free(*(size_t *)this, this);
1345 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1347 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1349 child->setPreviousSibling(prevSibling);
1350 prevSibling->setNextSibling(child);
1351 ASSERT(prevSibling != child);
1353 setFirstChild(child);
1356 beforeChild->setPreviousSibling(child);
1357 child->setNextSibling(beforeChild);
1358 ASSERT(beforeChild != child);
1360 setLastChild(child);
1362 child->setParent(this);
1364 if (child->isNormalFlowOnly())
1365 dirtyNormalFlowList();
1367 if (!child->isNormalFlowOnly() || child->firstChild()) {
1368 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
1369 // case where we're building up generated content layers. This is ok, since the lists will start
1370 // off dirty in that case anyway.
1371 child->dirtyStackingContextZOrderLists();
1374 child->updateDescendantDependentFlags();
1375 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1376 setAncestorChainHasVisibleDescendant();
1378 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
1379 setAncestorChainHasSelfPaintingLayerDescendant();
1381 #if USE(ACCELERATED_COMPOSITING)
1382 compositor()->layerWasAdded(this, child);
1386 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1388 #if USE(ACCELERATED_COMPOSITING)
1389 if (!renderer()->documentBeingDestroyed())
1390 compositor()->layerWillBeRemoved(this, oldChild);
1394 if (oldChild->previousSibling())
1395 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1396 if (oldChild->nextSibling())
1397 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1399 if (m_first == oldChild)
1400 m_first = oldChild->nextSibling();
1401 if (m_last == oldChild)
1402 m_last = oldChild->previousSibling();
1404 if (oldChild->isNormalFlowOnly())
1405 dirtyNormalFlowList();
1406 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1407 // Dirty the z-order list in which we are contained. When called via the
1408 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1409 // from the main layer tree, so we need to null-check the |stackingContext| value.
1410 oldChild->dirtyStackingContextZOrderLists();
1413 oldChild->setPreviousSibling(0);
1414 oldChild->setNextSibling(0);
1415 oldChild->setParent(0);
1417 oldChild->updateDescendantDependentFlags();
1418 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1419 dirtyAncestorChainVisibleDescendantStatus();
1421 if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
1422 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
1427 void RenderLayer::removeOnlyThisLayer()
1432 // Mark that we are about to lose our layer. This makes render tree
1433 // walks ignore this layer while we're removing it.
1434 m_renderer->setHasLayer(false);
1436 #if USE(ACCELERATED_COMPOSITING)
1437 compositor()->layerWillBeRemoved(m_parent, this);
1440 // Dirty the clip rects.
1441 clearClipRectsIncludingDescendants();
1443 RenderLayer* nextSib = nextSibling();
1445 // Remove the child reflection layer before moving other child layers.
1446 // The reflection layer should not be moved to the parent.
1448 removeChild(reflectionLayer());
1450 // Now walk our kids and reattach them to our parent.
1451 RenderLayer* current = m_first;
1453 RenderLayer* next = current->nextSibling();
1454 removeChild(current);
1455 m_parent->addChild(current, nextSib);
1456 current->setRepaintStatus(NeedsFullRepaint);
1457 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1458 ASSERT(!renderer()->hasLayer());
1459 current->updateLayerPositions(0); // FIXME: use geometry map.
1463 // Remove us from the parent.
1464 m_parent->removeChild(this);
1465 m_renderer->destroyLayer();
1468 void RenderLayer::insertOnlyThisLayer()
1470 if (!m_parent && renderer()->parent()) {
1471 // We need to connect ourselves when our renderer() has a parent.
1472 // Find our enclosingLayer and add ourselves.
1473 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
1474 ASSERT(parentLayer);
1475 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
1476 parentLayer->addChild(this, beforeChild);
1479 // Remove all descendant layers from the hierarchy and add them to the new position.
1480 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
1481 curr->moveLayers(m_parent, this);
1483 // Clear out all the clip rects.
1484 clearClipRectsIncludingDescendants();
1487 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const
1489 LayoutPoint location = roundedLocation;
1490 convertToLayerCoords(ancestorLayer, location);
1491 roundedLocation = roundedIntPoint(location);
1494 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const
1496 LayoutRect rect = roundedRect;
1497 convertToLayerCoords(ancestorLayer, rect);
1498 roundedRect = pixelSnappedIntRect(rect);
1501 // Returns the layer reached on the walk up towards the ancestor.
1502 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location)
1504 ASSERT(ancestorLayer != layer);
1506 const RenderLayerModelObject* renderer = layer->renderer();
1507 EPosition position = renderer->style()->position();
1509 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
1510 // may need to be revisited in a future patch.
1511 // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
1512 // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
1513 // positioned in a completely different place in the viewport (RenderView).
1514 if (position == FixedPosition && !renderer->inRenderFlowThread() && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
1515 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1516 // localToAbsolute() on the RenderView.
1517 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed);
1518 location += LayoutSize(absPos.x(), absPos.y());
1519 return ancestorLayer;
1522 // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
1523 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
1524 // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
1525 if (position == FixedPosition && !renderer->inRenderFlowThread()) {
1526 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1527 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1528 // so we should always find the ancestor at or before we find the fixed position container.
1529 RenderLayer* fixedPositionContainerLayer = 0;
1530 bool foundAncestor = false;
1531 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
1532 if (currLayer == ancestorLayer)
1533 foundAncestor = true;
1535 if (isFixedPositionedContainer(currLayer)) {
1536 fixedPositionContainerLayer = currLayer;
1537 ASSERT_UNUSED(foundAncestor, foundAncestor);
1542 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1544 if (fixedPositionContainerLayer != ancestorLayer) {
1545 LayoutPoint fixedContainerCoords;
1546 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
1548 LayoutPoint ancestorCoords;
1549 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
1551 location += (fixedContainerCoords - ancestorCoords);
1552 return ancestorLayer;
1556 RenderLayer* parentLayer;
1557 if (position == AbsolutePosition || position == FixedPosition) {
1558 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1559 parentLayer = layer->parent();
1560 bool foundAncestorFirst = false;
1561 while (parentLayer) {
1562 // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
1563 // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
1564 // we are bailing out before reaching root layer.
1565 if (isPositionedContainer(parentLayer))
1568 if (parentLayer == ancestorLayer) {
1569 foundAncestorFirst = true;
1573 parentLayer = parentLayer->parent();
1576 // We should not reach RenderView layer past the RenderFlowThread layer for any
1577 // children of the RenderFlowThread.
1578 if (renderer->inRenderFlowThread() && !renderer->isRenderFlowThread())
1579 ASSERT(parentLayer != renderer->view()->layer());
1581 if (foundAncestorFirst) {
1582 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1583 // to enclosingPositionedAncestor and subtract.
1584 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1586 LayoutPoint thisCoords;
1587 layer->convertToLayerCoords(positionedAncestor, thisCoords);
1589 LayoutPoint ancestorCoords;
1590 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
1592 location += (thisCoords - ancestorCoords);
1593 return ancestorLayer;
1596 parentLayer = layer->parent();
1601 location += toSize(layer->location());
1605 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
1607 if (ancestorLayer == this)
1610 const RenderLayer* currLayer = this;
1611 while (currLayer && currLayer != ancestorLayer)
1612 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location);
1615 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
1618 convertToLayerCoords(ancestorLayer, delta);
1619 rect.move(-delta.x(), -delta.y());
1622 #if USE(ACCELERATED_COMPOSITING)
1623 bool RenderLayer::usesCompositedScrolling() const
1625 if (!scrollsOverflow() || !allowsScrolling())
1628 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1629 return renderer()->style()->useTouchOverflowScrolling();
1636 static inline int adjustedScrollDelta(int beginningDelta) {
1637 // This implemention matches Firefox's.
1638 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
1639 const int speedReducer = 12;
1641 int adjustedDelta = beginningDelta / speedReducer;
1642 if (adjustedDelta > 1)
1643 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
1644 else if (adjustedDelta < -1)
1645 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
1647 return adjustedDelta;
1650 static inline IntSize adjustedScrollDelta(const IntSize& delta)
1652 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
1655 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
1657 Frame* frame = renderer()->frame();
1661 IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
1663 // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
1664 static IntPoint previousMousePosition;
1665 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
1666 currentMousePosition = previousMousePosition;
1668 previousMousePosition = currentMousePosition;
1670 IntSize delta = currentMousePosition - sourcePoint;
1672 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
1674 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
1677 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
1680 void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp)
1685 bool restrictedByLineClamp = false;
1686 if (renderer()->parent())
1687 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1689 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1690 IntSize newScrollOffset = scrollOffset() + delta;
1691 scrollToOffset(newScrollOffset, clamp);
1693 // If this layer can't do the scroll we ask the next layer up that can scroll to try
1694 IntSize remainingScrollOffset = newScrollOffset - scrollOffset();
1695 if (!remainingScrollOffset.isZero() && renderer()->parent()) {
1696 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
1697 scrollableLayer->scrollByRecursively(remainingScrollOffset);
1699 Frame* frame = renderer()->frame();
1701 frame->eventHandler()->updateAutoscrollRenderer();
1703 } else if (renderer()->view()->frameView()) {
1704 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
1705 // have an overflow clip. Which means that it is a document node that can be scrolled.
1706 renderer()->view()->frameView()->scrollBy(delta);
1707 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
1708 // https://bugs.webkit.org/show_bug.cgi?id=28237
1712 IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const
1714 RenderBox* box = renderBox();
1717 int maxX = scrollWidth() - box->pixelSnappedClientWidth();
1718 int maxY = scrollHeight() - box->pixelSnappedClientHeight();
1720 int x = max(min(scrollOffset.width(), maxX), 0);
1721 int y = max(min(scrollOffset.height(), maxY), 0);
1722 return IntSize(x, y);
1725 void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp)
1727 IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
1728 if (newScrollOffset != this->scrollOffset())
1729 scrollToOffsetWithoutAnimation(toPoint(newScrollOffset));
1732 void RenderLayer::scrollTo(int x, int y)
1734 RenderBox* box = renderBox();
1738 if (box->style()->overflowX() != OMARQUEE) {
1739 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
1740 if (m_scrollDimensionsDirty)
1741 computeScrollDimensions();
1744 // FIXME: Eventually, we will want to perform a blit. For now never
1745 // blit, since the check for blitting is going to be very
1746 // complicated (since it will involve testing whether our layer
1747 // is either occluded by another layer or clipped by an enclosing
1748 // layer or contains fixed backgrounds, etc.).
1749 IntSize newScrollOffset = IntSize(x - scrollOrigin().x(), y - scrollOrigin().y());
1750 if (m_scrollOffset == newScrollOffset)
1752 m_scrollOffset = newScrollOffset;
1754 Frame* frame = renderer()->frame();
1755 InspectorInstrumentation::willScrollLayer(frame);
1757 RenderView* view = renderer()->view();
1759 // We should have a RenderView if we're trying to scroll.
1762 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
1763 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
1764 bool inLayout = view ? view->frameView()->isInLayout() : false;
1766 // If we're in the middle of layout, we'll just update layers once layout has finished.
1767 updateLayerPositionsAfterOverflowScroll();
1769 // Update regions, scrolling may change the clip of a particular region.
1770 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
1771 view->frameView()->updateAnnotatedRegions();
1773 view->updateWidgetPositions();
1776 if (!m_updatingMarqueePosition) {
1777 // Avoid updating compositing layers if, higher on the stack, we're already updating layer
1778 // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and
1779 // in this case we're still updating their positions; we'll update compositing layers later
1780 // when that completes.
1781 updateCompositingLayersAfterScroll();
1785 RenderLayerModelObject* repaintContainer = renderer()->containerForRepaint();
1787 // The caret rect needs to be invalidated after scrolling
1788 frame->selection()->setCaretRectNeedsUpdate();
1790 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
1791 if (repaintContainer)
1792 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent, SnapOffsetForTransforms);
1793 frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
1796 // Just schedule a full repaint of our object.
1797 if (view && !usesCompositedScrolling())
1798 renderer()->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
1800 // Schedule the scroll DOM event.
1801 if (renderer()->node())
1802 renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), DocumentEventQueue::ScrollEventElementTarget);
1804 InspectorInstrumentation::didScrollLayer(frame);
1807 static inline bool frameElementAndViewPermitScroll(HTMLFrameElement* frameElement, FrameView* frameView)
1809 // If scrollbars aren't explicitly forbidden, permit scrolling.
1810 if (frameElement && frameElement->scrollingMode() != ScrollbarAlwaysOff)
1813 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
1814 if (frameView->wasScrolledByUser())
1817 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
1818 // like navigation to an anchor.
1819 return !frameView->frame()->eventHandler()->autoscrollInProgress();
1822 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1824 RenderLayer* parentLayer = 0;
1825 LayoutRect newRect = rect;
1827 // We may end up propagating a scroll event. It is important that we suspend events until
1828 // the end of the function since they could delete the layer or the layer's renderer().
1829 FrameView* frameView = renderer()->document()->view();
1831 frameView->pauseScheduledEvents();
1833 bool restrictedByLineClamp = false;
1834 if (renderer()->parent()) {
1835 parentLayer = renderer()->parent()->enclosingLayer();
1836 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1839 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1840 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
1841 // This will prevent us from revealing text hidden by the slider in Safari RSS.
1842 RenderBox* box = renderBox();
1844 FloatPoint absPos = box->localToAbsolute();
1845 absPos.move(box->borderLeft(), box->borderTop());
1847 LayoutRect layerBounds = LayoutRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
1848 LayoutRect exposeRect = LayoutRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
1849 LayoutRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
1851 int roundedAdjustedX = roundToInt(r.x() - absPos.x());
1852 int roundedAdjustedY = roundToInt(r.y() - absPos.y());
1853 IntSize clampedScrollOffset = clampScrollOffset(IntSize(roundedAdjustedX, roundedAdjustedY));
1854 if (clampedScrollOffset != scrollOffset()) {
1855 IntSize oldScrollOffset = scrollOffset();
1856 scrollToOffset(clampedScrollOffset);
1857 IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
1858 newRect.move(-scrollOffsetDifference);
1860 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled()) {
1862 Element* ownerElement = 0;
1863 if (renderer()->document())
1864 ownerElement = renderer()->document()->ownerElement();
1866 if (ownerElement && ownerElement->renderer()) {
1867 HTMLFrameElement* frameElement = 0;
1869 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
1870 frameElement = static_cast<HTMLFrameElement*>(ownerElement);
1872 if (frameElementAndViewPermitScroll(frameElement, frameView)) {
1873 LayoutRect viewRect = frameView->visibleContentRect();
1874 LayoutRect exposeRect = getRectToExpose(viewRect, rect, alignX, alignY);
1876 int xOffset = roundToInt(exposeRect.x());
1877 int yOffset = roundToInt(exposeRect.y());
1878 // Adjust offsets if they're outside of the allowable range.
1879 xOffset = max(0, min(frameView->contentsWidth(), xOffset));
1880 yOffset = max(0, min(frameView->contentsHeight(), yOffset));
1882 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
1883 if (frameView->safeToPropagateScrollToParent()) {
1884 parentLayer = ownerElement->renderer()->enclosingLayer();
1885 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
1886 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
1891 LayoutRect viewRect = frameView->visibleContentRect();
1892 LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1894 frameView->setScrollPosition(roundedIntPoint(r.location()));
1896 // This is the outermost view of a web page, so after scrolling this view we
1897 // scroll its container by calling Page::scrollRectIntoView.
1898 // This only has an effect on the Mac platform in applications
1899 // that put web views into scrolling containers, such as Mac OS X Mail.
1900 // The canAutoscroll function in EventHandler also knows about this.
1901 if (Frame* frame = frameView->frame()) {
1902 if (Page* page = frame->page())
1903 page->chrome()->scrollRectIntoView(pixelSnappedIntRect(rect));
1910 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
1913 frameView->resumeScheduledEvents();
1916 void RenderLayer::updateCompositingLayersAfterScroll()
1918 #if USE(ACCELERATED_COMPOSITING)
1919 if (compositor()->inCompositingMode()) {
1920 // Our stacking context is guaranteed to contain all of our descendants that may need
1921 // repositioning, so update compositing layers from there.
1922 if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) {
1923 if (compositor()->compositingConsultsOverlap())
1924 compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
1926 bool isUpdateRoot = true;
1927 compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
1934 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1936 // Determine the appropriate X behavior.
1937 ScrollBehavior scrollX;
1938 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
1939 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
1940 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
1941 // If the rectangle is fully visible, use the specified visible behavior.
1942 // If the rectangle is partially visible, but over a certain threshold,
1943 // then treat it as fully visible to avoid unnecessary horizontal scrolling
1944 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1945 else if (intersectWidth == visibleRect.width()) {
1946 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1947 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1948 if (scrollX == alignCenter)
1950 } else if (intersectWidth > 0)
1951 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
1952 scrollX = ScrollAlignment::getPartialBehavior(alignX);
1954 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
1955 // If we're trying to align to the closest edge, and the exposeRect is further right
1956 // than the visibleRect, and not bigger than the visible area, then align with the right.
1957 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
1958 scrollX = alignRight;
1960 // Given the X behavior, compute the X coordinate.
1962 if (scrollX == noScroll)
1963 x = visibleRect.x();
1964 else if (scrollX == alignRight)
1965 x = exposeRect.maxX() - visibleRect.width();
1966 else if (scrollX == alignCenter)
1967 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
1971 // Determine the appropriate Y behavior.
1972 ScrollBehavior scrollY;
1973 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
1974 LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
1975 if (intersectHeight == exposeRect.height())
1976 // If the rectangle is fully visible, use the specified visible behavior.
1977 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1978 else if (intersectHeight == visibleRect.height()) {
1979 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1980 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1981 if (scrollY == alignCenter)
1983 } else if (intersectHeight > 0)
1984 // If the rectangle is partially visible, use the specified partial behavior
1985 scrollY = ScrollAlignment::getPartialBehavior(alignY);
1987 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
1988 // If we're trying to align to the closest edge, and the exposeRect is further down
1989 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
1990 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
1991 scrollY = alignBottom;
1993 // Given the Y behavior, compute the Y coordinate.
1995 if (scrollY == noScroll)
1996 y = visibleRect.y();
1997 else if (scrollY == alignBottom)
1998 y = exposeRect.maxY() - visibleRect.height();
1999 else if (scrollY == alignCenter)
2000 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
2004 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
2007 void RenderLayer::autoscroll()
2009 Frame* frame = renderer()->frame();
2013 FrameView* frameView = frame->view();
2017 #if ENABLE(DRAG_SUPPORT)
2018 frame->eventHandler()->updateSelectionForMouseDrag();
2021 IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
2022 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
2025 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
2027 // FIXME: This should be possible on generated content but is not right now.
2028 if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
2031 ASSERT(renderer()->node()->isElementNode());
2032 Element* element = static_cast<Element*>(renderer()->node());
2033 RenderBox* renderer = toRenderBox(element->renderer());
2035 EResize resize = renderer->style()->resize();
2036 if (resize == RESIZE_NONE)
2039 Document* document = element->document();
2040 if (!document->frame()->eventHandler()->mousePressed())
2043 float zoomFactor = renderer->style()->effectiveZoom();
2045 LayoutSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.position()));
2046 newOffset.setWidth(newOffset.width() / zoomFactor);
2047 newOffset.setHeight(newOffset.height() / zoomFactor);
2049 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
2050 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
2051 element->setMinimumSizeForResizing(minimumSize);
2053 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
2054 if (renderer->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
2055 newOffset.setWidth(-newOffset.width());
2056 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
2059 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
2061 ASSERT(element->isStyledElement());
2062 StyledElement* styledElement = static_cast<StyledElement*>(element);
2063 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
2065 if (resize != RESIZE_VERTICAL && difference.width()) {
2066 if (element->isFormControlElement()) {
2067 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2068 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false);
2069 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false);
2071 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingWidth());
2072 baseWidth = baseWidth / zoomFactor;
2073 styledElement->setInlineStyleProperty(CSSPropertyWidth, String::number(roundToInt(baseWidth + difference.width())) + "px", false);
2076 if (resize != RESIZE_HORIZONTAL && difference.height()) {
2077 if (element->isFormControlElement()) {
2078 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
2079 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false);
2080 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false);
2082 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingHeight());
2083 baseHeight = baseHeight / zoomFactor;
2084 styledElement->setInlineStyleProperty(CSSPropertyHeight, String::number(roundToInt(baseHeight + difference.height())) + "px", false);
2087 document->updateLayout();
2089 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
2092 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
2094 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
2095 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
2098 void RenderLayer::setScrollOffset(const IntPoint& offset)
2100 scrollTo(offset.x(), offset.y());
2103 int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
2105 if (scrollbar->orientation() == HorizontalScrollbar)
2106 return scrollXOffset();
2107 if (scrollbar->orientation() == VerticalScrollbar)
2108 return scrollYOffset();
2112 IntPoint RenderLayer::scrollPosition() const
2114 return scrollOrigin() + m_scrollOffset;
2117 IntPoint RenderLayer::minimumScrollPosition() const
2119 return scrollOrigin();
2122 IntPoint RenderLayer::maximumScrollPosition() const
2124 // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
2125 return scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRect(true).size();
2128 IntRect RenderLayer::visibleContentRect(bool includeScrollbars) const
2130 int verticalScrollbarWidth = 0;
2131 int horizontalScrollbarHeight = 0;
2132 if (includeScrollbars) {
2133 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
2134 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
2137 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
2138 IntSize(max(0, m_layerSize.width() - verticalScrollbarWidth),
2139 max(0, m_layerSize.height() - horizontalScrollbarHeight)));
2142 IntSize RenderLayer::overhangAmount() const
2147 bool RenderLayer::isActive() const
2149 Page* page = renderer()->frame()->page();
2150 return page && page->focusController()->isActive();
2153 static int cornerStart(const RenderLayer* layer, int minX, int maxX, int thickness)
2155 if (layer->renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2156 return minX + layer->renderer()->style()->borderLeftWidth();
2157 return maxX - thickness - layer->renderer()->style()->borderRightWidth();
2160 static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds)
2162 int horizontalThickness;
2163 int verticalThickness;
2164 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2165 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
2166 // even when they don't exist in order to set the resizer square size properly.
2167 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
2168 verticalThickness = horizontalThickness;
2169 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
2170 horizontalThickness = layer->verticalScrollbar()->width();
2171 verticalThickness = horizontalThickness;
2172 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
2173 verticalThickness = layer->horizontalScrollbar()->height();
2174 horizontalThickness = verticalThickness;
2176 horizontalThickness = layer->verticalScrollbar()->width();
2177 verticalThickness = layer->horizontalScrollbar()->height();
2179 return IntRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
2180 bounds.maxY() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
2181 horizontalThickness, verticalThickness);
2184 IntRect RenderLayer::scrollCornerRect() const
2186 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
2187 // This happens when:
2188 // (a) A resizer is present and at least one scrollbar is present
2189 // (b) Both scrollbars are present.
2190 bool hasHorizontalBar = horizontalScrollbar();
2191 bool hasVerticalBar = verticalScrollbar();
2192 bool hasResizer = renderer()->style()->resize() != RESIZE_NONE;
2193 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
2194 return cornerRect(this, renderBox()->pixelSnappedBorderBoxRect());
2198 static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
2200 ASSERT(layer->renderer()->isBox());
2201 if (layer->renderer()->style()->resize() == RESIZE_NONE)
2203 return cornerRect(layer, bounds);
2206 IntRect RenderLayer::scrollCornerAndResizerRect() const
2208 RenderBox* box = renderBox();
2211 IntRect scrollCornerAndResizer = scrollCornerRect();
2212 if (scrollCornerAndResizer.isEmpty())
2213 scrollCornerAndResizer = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2214 return scrollCornerAndResizer;
2217 bool RenderLayer::isScrollCornerVisible() const
2219 ASSERT(renderer()->isBox());
2220 return !scrollCornerRect().isEmpty();
2223 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
2225 RenderView* view = renderer()->view();
2227 return scrollbarRect;
2229 IntRect rect = scrollbarRect;
2230 rect.move(scrollbarOffset(scrollbar));
2232 return view->frameView()->convertFromRenderer(renderer(), rect);
2235 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
2237 RenderView* view = renderer()->view();
2241 IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect);
2242 rect.move(-scrollbarOffset(scrollbar));
2246 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
2248 RenderView* view = renderer()->view();
2250 return scrollbarPoint;
2252 IntPoint point = scrollbarPoint;
2253 point.move(scrollbarOffset(scrollbar));
2254 return view->frameView()->convertFromRenderer(renderer(), point);
2257 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
2259 RenderView* view = renderer()->view();
2263 IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint);
2265 point.move(-scrollbarOffset(scrollbar));
2269 IntSize RenderLayer::contentsSize() const
2271 return IntSize(scrollWidth(), scrollHeight());
2274 int RenderLayer::visibleHeight() const
2276 return m_layerSize.height();
2279 int RenderLayer::visibleWidth() const
2281 return m_layerSize.width();
2284 bool RenderLayer::shouldSuspendScrollAnimations() const
2286 RenderView* view = renderer()->view();
2289 return view->frameView()->shouldSuspendScrollAnimations();
2292 bool RenderLayer::scrollbarsCanBeActive() const
2294 RenderView* view = renderer()->view();
2297 return view->frameView()->scrollbarsCanBeActive();
2300 IntPoint RenderLayer::currentMousePosition() const
2302 return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint();
2305 IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
2310 const RenderBox* box = renderBox();
2311 const IntRect& scrollCorner = scrollCornerRect();
2313 return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
2314 borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
2315 borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2319 IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
2324 const RenderBox* box = renderBox();
2325 const IntRect& scrollCorner = scrollCornerRect();
2327 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
2328 borderBoxRect.y() + box->borderTop(),
2330 borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
2333 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
2335 const RenderBox* box = renderBox();
2336 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2337 return minX + box->borderLeft();
2338 return maxX - box->borderRight() - m_vBar->width();
2341 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
2343 const RenderBox* box = renderBox();
2344 int x = minX + box->borderLeft();
2345 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2346 x += m_vBar ? m_vBar->width() : resizerCornerRect(this, box->pixelSnappedBorderBoxRect()).width();
2350 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
2352 RenderBox* box = renderBox();
2354 if (scrollbar == m_vBar.get())
2355 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
2357 if (scrollbar == m_hBar.get())
2358 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2360 ASSERT_NOT_REACHED();
2364 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2366 #if USE(ACCELERATED_COMPOSITING)
2367 if (scrollbar == m_vBar.get()) {
2368 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2369 layer->setNeedsDisplayInRect(rect);
2373 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2374 layer->setNeedsDisplayInRect(rect);
2379 IntRect scrollRect = rect;
2380 RenderBox* box = renderBox();
2382 // If we are not yet inserted into the tree, there is no need to repaint.
2386 if (scrollbar == m_vBar.get())
2387 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
2389 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2390 renderer()->repaintRectangle(scrollRect);
2393 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
2395 #if USE(ACCELERATED_COMPOSITING)
2396 if (GraphicsLayer* layer = layerForScrollCorner()) {
2397 layer->setNeedsDisplayInRect(rect);
2402 m_scrollCorner->repaintRectangle(rect);
2404 m_resizer->repaintRectangle(rect);
2407 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
2409 RefPtr<Scrollbar> widget;
2410 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
2411 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
2412 if (hasCustomScrollbarStyle)
2413 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node());
2415 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
2416 if (orientation == HorizontalScrollbar)
2417 didAddHorizontalScrollbar(widget.get());
2419 didAddVerticalScrollbar(widget.get());
2421 renderer()->document()->view()->addChild(widget.get());
2422 return widget.release();
2425 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
2427 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
2431 if (!scrollbar->isCustomScrollbar()) {
2432 if (orientation == HorizontalScrollbar)
2433 willRemoveHorizontalScrollbar(scrollbar.get());
2435 willRemoveVerticalScrollbar(scrollbar.get());
2438 scrollbar->removeFromParent();
2439 scrollbar->disconnectFromScrollableArea();
2443 bool RenderLayer::scrollsOverflow() const
2445 if (!renderer()->isBox())
2448 return toRenderBox(renderer())->scrollsOverflow();
2451 bool RenderLayer::allowsScrolling() const
2453 return (m_hBar && m_hBar->enabled()) || (m_vBar && m_vBar->enabled());
2456 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
2458 if (hasScrollbar == hasHorizontalScrollbar())
2462 m_hBar = createScrollbar(HorizontalScrollbar);
2464 destroyScrollbar(HorizontalScrollbar);
2466 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2468 m_hBar->styleChanged();
2470 m_vBar->styleChanged();
2472 // Force an update since we know the scrollbars have changed things.
2473 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
2474 if (renderer()->document()->hasAnnotatedRegions())
2475 renderer()->document()->setAnnotatedRegionsDirty(true);
2479 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
2481 if (hasScrollbar == hasVerticalScrollbar())
2485 m_vBar = createScrollbar(VerticalScrollbar);
2487 destroyScrollbar(VerticalScrollbar);
2489 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2491 m_hBar->styleChanged();
2493 m_vBar->styleChanged();
2495 // Force an update since we know the scrollbars have changed things.
2496 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
2497 if (renderer()->document()->hasAnnotatedRegions())
2498 renderer()->document()->setAnnotatedRegionsDirty(true);
2502 ScrollableArea* RenderLayer::enclosingScrollableArea() const
2504 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2505 return scrollableLayer;
2507 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
2508 // if the frame view isn't scrollable.
2512 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
2514 if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2516 return m_vBar->width();
2519 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
2521 if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2523 return m_hBar->height();
2526 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
2528 // Currently the resize corner is either the bottom right corner or the bottom left corner.
2529 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
2530 IntSize elementSize = size();
2531 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2532 elementSize.setWidth(0);
2533 IntPoint resizerPoint = toPoint(elementSize);
2534 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
2535 return localPoint - resizerPoint;
2538 bool RenderLayer::hasOverflowControls() const
2540 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
2543 void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
2545 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2548 RenderBox* box = renderBox();
2552 const IntRect borderBox = box->pixelSnappedBorderBoxRect();
2553 const IntRect& scrollCorner = scrollCornerRect();
2554 IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
2556 IntRect vBarRect = rectForVerticalScrollbar(borderBox);
2557 vBarRect.move(offsetFromRoot);
2558 m_vBar->setFrameRect(vBarRect);
2562 IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
2563 hBarRect.move(offsetFromRoot);
2564 m_hBar->setFrameRect(hBarRect);
2568 m_scrollCorner->setFrameRect(scrollCorner);
2570 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
2572 #if USE(ACCELERATED_COMPOSITING)
2574 backing()->positionOverflowControlsLayers(offsetFromRoot);
2578 int RenderLayer::scrollWidth() const
2580 ASSERT(renderBox());
2581 if (m_scrollDimensionsDirty)
2582 const_cast<RenderLayer*>(this)->computeScrollDimensions();
2583 return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft() + renderBox()->x());
2586 int RenderLayer::scrollHeight() const
2588 ASSERT(renderBox());
2589 if (m_scrollDimensionsDirty)
2590 const_cast<RenderLayer*>(this)->computeScrollDimensions();
2591 return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop() + renderBox()->y());
2594 LayoutUnit RenderLayer::overflowTop() const
2596 RenderBox* box = renderBox();
2597 LayoutRect overflowRect(box->layoutOverflowRect());
2598 box->flipForWritingMode(overflowRect);
2599 return overflowRect.y();
2602 LayoutUnit RenderLayer::overflowBottom() const
2604 RenderBox* box = renderBox();
2605 LayoutRect overflowRect(box->layoutOverflowRect());
2606 box->flipForWritingMode(overflowRect);
2607 return overflowRect.maxY();
2610 LayoutUnit RenderLayer::overflowLeft() const
2612 RenderBox* box = renderBox();
2613 LayoutRect overflowRect(box->layoutOverflowRect());
2614 box->flipForWritingMode(overflowRect);
2615 return overflowRect.x();
2618 LayoutUnit RenderLayer::overflowRight() const
2620 RenderBox* box = renderBox();
2621 LayoutRect overflowRect(box->layoutOverflowRect());
2622 box->flipForWritingMode(overflowRect);
2623 return overflowRect.maxX();
2626 void RenderLayer::computeScrollDimensions()
2628 RenderBox* box = renderBox();
2631 m_scrollDimensionsDirty = false;
2633 m_scrollSize.setWidth(overflowRight() - overflowLeft());
2634 m_scrollSize.setHeight(overflowBottom() - overflowTop());
2636 int scrollableLeftOverflow = overflowLeft() - box->borderLeft();
2637 int scrollableTopOverflow = overflowTop() - box->borderTop();
2638 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
2641 bool RenderLayer::hasScrollableHorizontalOverflow() const
2643 return hasHorizontalOverflow() && renderBox()->scrollsOverflowX();
2646 bool RenderLayer::hasScrollableVerticalOverflow() const
2648 return hasVerticalOverflow() && renderBox()->scrollsOverflowY();
2651 bool RenderLayer::hasHorizontalOverflow() const
2653 ASSERT(!m_scrollDimensionsDirty);
2655 return scrollWidth() > renderBox()->pixelSnappedClientWidth();
2658 bool RenderLayer::hasVerticalOverflow() const
2660 ASSERT(!m_scrollDimensionsDirty);
2662 return scrollHeight() > renderBox()->pixelSnappedClientHeight();
2665 void RenderLayer::updateScrollbarsAfterLayout()
2667 RenderBox* box = renderBox();
2670 // List box parts handle the scrollbars by themselves so we have nothing to do.
2671 if (box->style()->appearance() == ListboxPart)
2674 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
2675 bool hasVerticalOverflow = this->hasVerticalOverflow();
2677 // overflow:scroll should just enable/disable.
2678 if (renderer()->style()->overflowX() == OSCROLL)
2679 m_hBar->setEnabled(hasHorizontalOverflow);
2680 if (renderer()->style()->overflowY() == OSCROLL)
2681 m_vBar->setEnabled(hasVerticalOverflow);
2683 // overflow:auto may need to lay out again if scrollbars got added/removed.
2684 bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
2685 bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
2687 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
2688 if (box->hasAutoHorizontalScrollbar())
2689 setHasHorizontalScrollbar(hasHorizontalOverflow);
2690 if (box->hasAutoVerticalScrollbar())
2691 setHasVerticalScrollbar(hasVerticalOverflow);
2693 updateSelfPaintingLayer();
2695 // Force an update since we know the scrollbars have changed things.
2696 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
2697 if (renderer()->document()->hasAnnotatedRegions())
2698 renderer()->document()->setAnnotatedRegionsDirty(true);
2701 renderer()->repaint();
2703 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) {
2704 if (!m_inOverflowRelayout) {
2705 // Our proprietary overflow: overlay value doesn't trigger a layout.
2706 m_inOverflowRelayout = true;
2707 renderer()->setNeedsLayout(true, MarkOnlyThis);
2708 if (renderer()->isRenderBlock()) {
2709 RenderBlock* block = toRenderBlock(renderer());
2710 block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
2711 block->layoutBlock(true);
2713 renderer()->layout();
2714 m_inOverflowRelayout = false;
2719 // Set up the range (and page step/line step).
2721 int clientWidth = box->pixelSnappedClientWidth();
2722 int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
2723 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2724 m_hBar->setProportion(clientWidth, m_scrollSize.width());
2727 int clientHeight = box->pixelSnappedClientHeight();
2728 int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
2729 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2730 m_vBar->setProportion(clientHeight, m_scrollSize.height());
2733 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
2736 void RenderLayer::updateScrollInfoAfterLayout()
2738 RenderBox* box = renderBox();
2742 m_scrollDimensionsDirty = true;
2743 IntSize originalScrollOffset = scrollOffset();
2745 computeScrollDimensions();
2747 if (box->style()->overflowX() != OMARQUEE) {
2748 // Layout may cause us to be at an invalid scroll position. In this case we need
2749 // to pull our scroll offsets back to the max (or push them up to the min).
2750 IntSize clampedScrollOffset = clampScrollOffset(scrollOffset());
2751 if (clampedScrollOffset != scrollOffset())
2752 scrollToOffset(clampedScrollOffset);
2755 updateScrollbarsAfterLayout();
2757 if (originalScrollOffset != scrollOffset())
2758 scrollToOffsetWithoutAnimation(toPoint(scrollOffset()));
2760 #if USE(ACCELERATED_COMPOSITING)
2761 // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
2762 if (renderer()->view() && compositor()->updateLayerCompositingState(this))
2763 compositor()->setCompositingLayersNeedRebuild();
2767 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
2769 const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect();
2771 if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
2774 if (rectForVerticalScrollbar(borderBox).intersects(localRect))
2777 if (scrollCornerRect().intersects(localRect))
2780 if (resizerCornerRect(this, borderBox).intersects(localRect))
2786 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
2788 // Don't do anything if we have no overflow.
2789 if (!renderer()->hasOverflowClip())
2792 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
2793 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
2794 // will be false, and we should just tell the root layer that there are overlay scrollbars
2795 // that need to be painted. That will cause the second pass through the layer tree to run,
2796 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
2797 // second pass doesn't need to re-enter the RenderTree to get it right.
2798 if (hasOverlayScrollbars() && !paintingOverlayControls) {
2799 m_cachedOverlayScrollbarOffset = paintOffset;
2800 #if USE(ACCELERATED_COMPOSITING)
2801 // It's not necessary to do the second pass if the scrollbars paint into layers.
2802 if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar()))
2805 IntRect localDamgeRect = damageRect;
2806 localDamgeRect.moveBy(-paintOffset);
2807 if (!overflowControlsIntersectRect(localDamgeRect))
2810 RenderView* renderView = renderer()->view();
2812 RenderLayer* paintingRoot = 0;
2813 #if USE(ACCELERATED_COMPOSITING)
2814 paintingRoot = enclosingCompositingLayer();
2817 paintingRoot = renderView->layer();
2819 paintingRoot->setContainsDirtyOverlayScrollbars(true);
2823 // This check is required to avoid painting custom CSS scrollbars twice.
2824 if (paintingOverlayControls && !hasOverlayScrollbars())
2827 IntPoint adjustedPaintOffset = paintOffset;
2828 if (paintingOverlayControls)
2829 adjustedPaintOffset = m_cachedOverlayScrollbarOffset;
2831 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
2832 // widgets can move without layout occurring (most notably when you scroll a document that
2833 // contains fixed positioned elements).
2834 positionOverflowControls(toSize(adjustedPaintOffset));
2836 // Now that we're sure the scrollbars are in the right place, paint them.
2838 #if USE(ACCELERATED_COMPOSITING)
2839 && !layerForHorizontalScrollbar()
2842 m_hBar->paint(context, damageRect);
2844 #if USE(ACCELERATED_COMPOSITING)
2845 && !layerForVerticalScrollbar()
2848 m_vBar->paint(context, damageRect);
2850 #if USE(ACCELERATED_COMPOSITING)
2851 if (layerForScrollCorner())
2855 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
2857 paintScrollCorner(context, adjustedPaintOffset, damageRect);
2859 // Paint our resizer last, since it sits on top of the scroll corner.
2860 paintResizer(context, adjustedPaintOffset, damageRect);
2863 void RenderLayer::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
2865 RenderBox* box = renderBox();
2868 IntRect absRect = scrollCornerRect();
2869 absRect.moveBy(paintOffset);
2870 if (!absRect.intersects(damageRect))
2873 if (context->updatingControlTints()) {
2874 updateScrollCornerStyle();
2878 if (m_scrollCorner) {
2879 m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
2883 // We don't want to paint white if we have overlay scrollbars, since we need
2884 // to see what is behind it.
2885 if (!hasOverlayScrollbars())
2886 context->fillRect(absRect, Color::white, box->style()->colorSpace());
2889 void RenderLayer::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect)
2891 float deviceScaleFactor = WebCore::deviceScaleFactor(renderer()->frame());
2893 RefPtr<Image> resizeCornerImage;
2894 IntSize cornerResizerSize;
2895 if (deviceScaleFactor >= 2) {
2896 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef()));
2897 resizeCornerImage = resizeCornerImageHiRes;
2898 cornerResizerSize = resizeCornerImage->size();
2899 cornerResizerSize.scale(0.5f);
2901 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner").leakRef()));
2902 resizeCornerImage = resizeCornerImageLoRes;
2903 cornerResizerSize = resizeCornerImage->size();
2906 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
2908 context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
2909 context->scale(FloatSize(-1.0, 1.0));
2910 context->drawImage(resizeCornerImage.get(), renderer()->style()->colorSpace(), IntRect(IntPoint(), cornerResizerSize));
2914 IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
2915 context->drawImage(resizeCornerImage.get(), renderer()->style()->colorSpace(), imageRect);
2918 void RenderLayer::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
2920 if (renderer()->style()->resize() == RESIZE_NONE)
2923 RenderBox* box = renderBox();
2926 IntRect absRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2927 absRect.moveBy(paintOffset);
2928 if (!absRect.intersects(damageRect))
2931 if (context->updatingControlTints()) {
2932 updateResizerStyle();
2937 m_resizer->paintIntoRect(context, paintOffset, absRect);
2941 drawPlatformResizerImage(context, absRect);
2943 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
2944 // Clipping will exclude the right and bottom edges of this frame.
2945 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
2946 GraphicsContextStateSaver stateSaver(*context);
2947 context->clip(absRect);
2948 IntRect largerCorner = absRect;
2949 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
2950 context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
2951 context->setStrokeThickness(1.0f);
2952 context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
2953 context->drawRect(largerCorner);
2957 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
2959 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
2962 RenderBox* box = renderBox();
2965 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
2967 IntRect localBounds(0, 0, box->pixelSnappedWidth(), box->pixelSnappedHeight());
2968 return resizerCornerRect(this, localBounds).contains(localPoint);
2971 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
2973 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2976 RenderBox* box = renderBox();
2979 IntRect resizeControlRect;
2980 if (renderer()->style()->resize() != RESIZE_NONE) {
2981 resizeControlRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2982 if (resizeControlRect.contains(localPoint))
2986 int resizeControlSize = max(resizeControlRect.height(), 0);
2988 // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
2990 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
2991 LayoutRect vBarRect(verticalScrollbarStart(0, box->width()),
2994 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
2995 if (vBarRect.contains(localPoint)) {
2996 result.setScrollbar(m_vBar.get());
3001 resizeControlSize = max(resizeControlRect.width(), 0);
3002 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
3003 LayoutRect hBarRect(horizontalScrollbarStart(0),
3004 box->height() - box->borderBottom() - m_hBar->height(),
3005 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
3007 if (hBarRect.contains(localPoint)) {
3008 result.setScrollbar(m_hBar.get());
3016 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
3018 return ScrollableArea::scroll(direction, granularity, multiplier);
3021 void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags)
3023 OverlapTestRequestMap overlapTestRequests;
3025 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests);
3026 paintLayer(context, paintingInfo, paintFlags);
3028 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
3029 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
3030 it->key->setOverlapTestResult(false);
3033 void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
3035 if (!m_containsDirtyOverlayScrollbars)
3038 LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
3039 paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars);
3041 m_containsDirtyOverlayScrollbars = false;
3044 #ifndef DISABLE_ROUNDED_CORNER_CLIPPING
3045 static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
3047 if (startLayer == endLayer)
3050 RenderView* view = startLayer->renderer()->view();
3051 for (RenderBlock* currentBlock = startLayer->renderer()->containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) {
3052 if (currentBlock->layer() == endLayer)
3060 void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect,
3061 BorderRadiusClippingRule rule)
3063 if (clipRect.rect() == paintDirtyRect)
3066 context->clip(pixelSnappedIntRect(clipRect.rect()));
3068 if (!clipRect.hasRadius())
3071 #ifndef DISABLE_ROUNDED_CORNER_CLIPPING
3072 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
3073 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
3074 // containing block chain so we check that also.
3075 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
3076 if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
3078 layer->convertToLayerCoords(rootLayer, delta);
3079 context->addRoundedRectClip(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
3082 if (layer == rootLayer)
3088 void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
3090 if (clipRect.rect() == paintDirtyRect)
3095 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
3097 Vector<OverlapTestRequestClient*> overlappedRequestClients;
3098 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
3099 LayoutRect boundingBox = layer->boundingBox(rootLayer);
3100 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
3101 if (!boundingBox.intersects(it->value))
3104 it->key->setOverlapTestResult(true);
3105 overlappedRequestClients.append(it->key);
3107 for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
3108 overlapTestRequests.remove(overlappedRequestClients[i]);
3111 #if USE(ACCELERATED_COMPOSITING)
3112 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
3114 return paintingReflection && !layer->has3DTransform();
3118 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
3120 // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
3121 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
3122 // will do a full repaint().
3123 if (layer->renderer()->document()->didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isRoot())
3126 // Avoid painting all layers if the document is in a state where visual updates aren't allowed.
3127 // A full repaint will occur in Document::implicitClose() if painting is suppressed here.
3128 if (!layer->renderer()->document()->visualUpdatesAllowed())
3135 void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3137 #if USE(ACCELERATED_COMPOSITING)
3138 if (isComposited()) {
3139 // The updatingControlTints() painting pass goes through compositing layers,
3140 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
3141 if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers))
3142 paintFlags |= PaintLayerTemporaryClipRects;
3143 else if (!backing()->paintsIntoWindow()
3144 && !backing()->paintsIntoCompositedAncestor()
3145 && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
3146 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
3149 } else if (compositor()->fixedPositionLayerNotCompositedReason(this) == RenderLayerCompositor::LayerBoundsOutOfView) {
3150 // Don't paint out-of-view fixed position layers (when doing prepainting) because they will never be visible
3151 // unless their position or viewport size is changed.
3156 // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
3157 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
3160 if (shouldSuppressPaintingLayer(this))
3163 // If this layer is totally invisible then there is nothing to paint.
3164 if (!renderer()->opacity())
3167 if (paintsWithTransparency(paintingInfo.paintBehavior))
3168 paintFlags |= PaintLayerHaveTransparency;
3170 // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice.
3171 if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
3172 TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
3173 // If the transform can't be inverted, then don't paint anything.
3174 if (!layerTransform.isInvertible())
3177 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
3178 // layer from the parent now, assuming there is a parent
3179 if (paintFlags & PaintLayerHaveTransparency) {
3181 parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
3183 beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
3186 // Make sure the parent's clip rects have been calculated.
3187 ClipRect clipRect = paintingInfo.paintDirtyRect;
3189 ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
3190 IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
3191 clipRect = backgroundClipRect(clipRectsContext);
3192 clipRect.intersect(paintingInfo.paintDirtyRect);
3194 // Push the parent coordinate space's clip.
3195 parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
3198 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
3199 // This involves subtracting out the position of the layer in our current coordinate space, but preserving
3200 // the accumulated error for sub-pixel layout.
3202 convertToLayerCoords(paintingInfo.rootLayer, delta);
3203 TransformationMatrix transform(layerTransform);
3204 IntPoint roundedDelta = roundedIntPoint(delta);
3205 transform.translateRight(roundedDelta.x(), roundedDelta.y());
3206 LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
3208 // Apply the transform.
3210 GraphicsContextStateSaver stateSaver(*context);
3211 context->concatCTM(transform.toAffineTransform());
3213 // Now do a paint with the root layer shifted to be us.
3214 LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior, adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests);
3215 paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
3218 // Restore the clip.
3220 parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
3225 paintLayerContentsAndReflection(context, paintingInfo, paintFlags);
3228 void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3230 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
3232 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
3234 // Paint the reflection first if we have one.
3235 if (m_reflection && !m_paintingInsideReflection) {
3236 // Mark that we are now inside replica painting.
3237 m_paintingInsideReflection = true;
3238 reflectionLayer()->paintLayer(context, paintingInfo, localPaintFlags | PaintLayerPaintingReflection);
3239 m_paintingInsideReflection = false;
3242 localPaintFlags |= PaintLayerPaintingCompositingAllPhases;
3243 paintLayerContents(context, paintingInfo, localPaintFlags);
3246 void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3248 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
3250 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
3251 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
3252 bool isSelfPaintingLayer = this->isSelfPaintingLayer();
3253 bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
3254 // Outline always needs to be painted even if we have no visible content.
3255 bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars;
3256 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
3258 bool useClipRect = true;
3259 GraphicsContext* transparencyLayerContext = context;
3261 // Ensure our lists are up-to-date.
3262 updateLayerListsIfNeeded();
3264 LayoutPoint offsetFromRoot;
3265 convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
3267 IntRect rootRelativeBounds;
3268 bool rootRelativeBoundsComputed = false;
3270 bool didQuantizeFonts = true;
3271 bool scrollingOnMainThread = true;
3272 Frame* frame = renderer()->frame();
3273 #if ENABLE(THREADED_SCROLLING)
3275 if (Page* page = frame->page()) {
3276 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
3277 scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread();
3282 // FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
3283 // things on the scrolling thread.
3284 bool needToAdjustSubpixelQuantization = scrollingOnMainThread || (renderer()->hasOverflowClip() && !usesCompositedScrolling()) || (frame && frame->ownerElement());
3285 if (needToAdjustSubpixelQuantization) {
3286 didQuantizeFonts = context->shouldSubpixelQuantizeFonts();
3287 context->setShouldSubpixelQuantizeFonts(false);
3290 // Apply clip-path to context.
3291 bool hasClipPath = false;
3292 RenderStyle* style = renderer()->style();
3293 if (renderer()->hasClipPath() && !context->paintingDisabled() && style) {
3294 ASSERT(style->clipPath());
3295 if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) {
3298 ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath());
3300 if (!rootRelativeBoundsComputed) {
3301 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
3302 rootRelativeBoundsComputed = true;
3305 context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
3308 else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) {
3309 ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath());
3310 Document* document = renderer()->document();
3311 // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
3312 Element* element = document ? document->getElementById(referenceClipPathOperation->fragment()) : 0;
3313 if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
3314 if (!rootRelativeBoundsComputed) {
3315 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
3316 rootRelativeBoundsComputed = true;
3319 static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context);
3325 LayerPaintingInfo localPaintingInfo(paintingInfo);
3326 #if ENABLE(CSS_FILTERS)
3327 FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters());
3328 if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) {
3329 RenderLayerFilterInfo* filterInfo = this->filterInfo();
3331 LayoutRect filterRepaintRect = filterInfo->dirtySourceRect();
3332 filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y());
3334 if (!rootRelativeBoundsComputed) {
3335 rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
3336 rootRelativeBoundsComputed = true;
3339 if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
3340 // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
3341 filterInfo->resetDirtySourceRect();
3343 // Rewire the old context to a memory buffer, so that we can capture the contents of the layer.
3344 // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer
3345 // on the original context and avoid duplicating "beginFilterEffect" after each transpareny layer call. Also, note that
3346 // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method.
3347 context = filterPainter.beginFilterEffect(context);
3349 // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
3350 if (filterPainter.hasStartedFilterEffect()) {
3351 localPaintingInfo.paintDirtyRect = filterPainter.repaintRect();
3352 // If the filter needs the full source image, we need to avoid using the clip rectangles.
3353 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
3354 // Note that we will still apply the clipping on the final rendering of the filter.
3355 useClipRect = !filterRenderer()->hasFilterThatMovesPixels();
3361 // Calculate the clip rects we should use only when we need them.
3362 LayoutRect layerBounds;
3363 ClipRect damageRect, clipRectToApply, outlineRect;
3364 LayoutPoint paintOffset;
3366 if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
3367 ClipRectsContext clipRectsContext(localPaintingInfo.rootLayer, localPaintingInfo.region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize, localPaintFlags & PaintLayerPaintingOverflowContents ? IgnoreOverflowClip : RespectOverflowClip);
3368 calculateRects(clipRectsContext, localPaintingInfo.paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, &offsetFromRoot);
3369 paintOffset = toPoint(layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation);
3370 if (this == localPaintingInfo.rootLayer)
3371 paintOffset = roundedIntPoint(paintOffset);
3374 bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText;
3375 bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
3377 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
3378 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
3379 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
3380 // so it will be tested against as we descend through the renderers.
3381 RenderObject* paintingRootForRenderer = 0;
3382 if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot))
3383 paintingRootForRenderer = localPaintingInfo.paintingRoot;
3385 if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
3386 performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
3388 // We want to paint our layer, but only if we intersect the damage rect.
3389 if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents))
3390 shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), localPaintingInfo.rootLayer, &offsetFromRoot);
3392 if (localPaintFlags & PaintLayerPaintingCompositingBackgroundPhase) {
3393 if (shouldPaintContent && !selectionOnly) {
3394 // Begin transparency layers lazily now that we know we have to paint something.
3395 if (haveTransparency)
3396 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
3399 // Paint our background first, before painting any child layers.
3400 // Establish the clip used to paint our background.
3401 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
3404 // Paint the background.
3405 PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, localPaintingInfo.region, 0);
3406 renderer()->paint(paintInfo, paintOffset);
3409 // Restore the clip.
3410 restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
3414 // Now walk the sorted list of children with negative z-indices.
3415 paintList(negZOrderList(), context, localPaintingInfo, localPaintFlags);
3418 if (localPaintFlags & PaintLayerPaintingCompositingForegroundPhase) {
3419 // Now establish the appropriate clip and paint our child RenderObjects.
3420 if (shouldPaintContent && !clipRectToApply.isEmpty()) {
3421 // Begin transparency layers lazily now that we know we have to paint something.
3422 if (haveTransparency)
3423 beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
3426 // Set up the clip used when painting our children.
3427 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, clipRectToApply);
3430 PaintInfo paintInfo(context, pixelSnappedIntRect(clipRectToApply.rect()),
3431 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
3432 forceBlackText, paintingRootForRenderer, localPaintingInfo.region, 0);
3433 renderer()->paint(paintInfo, paintOffset);
3434 if (!selectionOnly) {
3435 paintInfo.phase = PaintPhaseFloat;
3436 renderer()->paint(paintInfo, paintOffset);
3437 paintInfo.phase = PaintPhaseForeground;
3438 paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
3439 renderer()->paint(paintInfo, paintOffset);
3440 paintInfo.phase = PaintPhaseChildOutlines;
3441 renderer()->paint(paintInfo, paintOffset);
3445 // Now restore our clip.
3446 restoreClip(context, localPaintingInfo.paintDirtyRect, clipRectToApply);
3450 if (shouldPaintOutline && !outlineRect.isEmpty()) {
3451 // Paint our own outline
3452 PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, localPaintingInfo.region, 0);
3453 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius);
3454 renderer()->paint(paintInfo, paintOffset);
3455 restoreClip(context, localPaintingInfo.paintDirtyRect, outlineRect);
3458 // Paint any child layers that have overflow.
3459 paintList(m_normalFlowList.get(), context, localPaintingInfo, localPaintFlags);
3461 // Now walk the sorted list of children with positive z-indices.
3462 paintList(posZOrderList(), context, localPaintingInfo, localPaintFlags);
3465 if (isPaintingOverlayScrollbars) {
3466 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect);
3467 paintOverflowControls(context, roundedIntPoint(paintOffset), pixelSnappedIntRect(damageRect.rect()), true);
3468 restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
3471 #if ENABLE(CSS_FILTERS)
3472 if (filterPainter.hasStartedFilterEffect()) {
3473 // Apply the correct clipping (ie. overflow: hidden).
3474 clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect);
3475 context = filterPainter.applyFilterEffect();
3476 restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, damageRect);
3480 // Make sure that we now use the original transparency context.
3481 ASSERT(transparencyLayerContext == context);
3483 if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) {
3485 clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
3488 PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, localPaintingInfo.region, 0);
3489 renderer()->paint(paintInfo, paintOffset);
3492 // Restore the clip.
3493 restoreClip(context, localPaintingInfo.paintDirtyRect, damageRect);
3497 // End our transparency layer
3498 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
3499 context->endTransparencyLayer();
3501 m_usedTransparency = false;
3504 // Re-set this to whatever it was before we painted the layer.
3505 if (needToAdjustSubpixelQuantization)
3506 context->setShouldSubpixelQuantizeFonts(didQuantizeFonts);
3512 void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3517 if (!hasSelfPaintingLayerDescendant())
3520 #if !ASSERT_DISABLED
3521 LayerListMutationDetector mutationChecker(this);
3524 for (size_t i = 0; i < list->size(); ++i) {
3525 RenderLayer* childLayer = list->at(i);
3526 if (!childLayer->isPaginated())
3527 childLayer->paintLayer(context, paintingInfo, paintFlags);
3529 paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags);
3533 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
3535 // We need to do multiple passes, breaking up our child layer into strips.
3536 Vector<RenderLayer*> columnLayers;
3537 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
3538 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
3539 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
3540 columnLayers.append(curr);
3541 if (curr == ancestorLayer)
3545 // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before
3546 // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
3547 // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer.
3548 if (!columnLayers.size())
3551 paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1);
3554 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo,
3555 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
3557 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
3559 ASSERT(columnBlock && columnBlock->hasColumns());
3560 if (!columnBlock || !columnBlock->hasColumns())
3563 LayoutPoint layerOffset;
3564 // FIXME: It looks suspicious to call convertToLayerCoords here
3565 // as canUseConvertToLayerCoords is true for this layer.
3566 columnBlock->layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset);
3568 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
3570 ColumnInfo* colInfo = columnBlock->columnInfo();
3571 unsigned colCount = columnBlock->columnCount(colInfo);
3572 LayoutUnit currLogicalTopOffset = 0;
3573 for (unsigned i = 0; i < colCount; i++) {
3574 // For each rect, we clip to the rect, and then we adjust our coords.
3575 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
3576 columnBlock->flipForWritingMode(colRect);
3577 LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
3580 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3581 offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset);
3583 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
3585 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3586 offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset);
3588 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
3591 colRect.moveBy(layerOffset);
3593 LayoutRect localDirtyRect(paintingInfo.paintDirtyRect);
3594 localDirtyRect.intersect(colRect);
3596 if (!localDirtyRect.isEmpty()) {
3597 GraphicsContextStateSaver stateSaver(*context);
3599 // Each strip pushes a clip, since column boxes are specified as being
3600 // like overflow:hidden.
3601 context->clip(pixelSnappedIntRect(colRect));
3604 // Apply a translation transform to change where the layer paints.
3605 TransformationMatrix oldTransform;
3606 bool oldHasTransform = childLayer->transform();
3607 if (oldHasTransform)
3608 oldTransform = *childLayer->transform();
3609 TransformationMatrix newTransform(oldTransform);
3610 newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height()));
3612 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
3614 LayerPaintingInfo localPaintingInfo(paintingInfo);
3615 localPaintingInfo.paintDirtyRect = localDirtyRect;
3616 childLayer->paintLayer(context, localPaintingInfo, paintFlags);
3618 if (oldHasTransform)
3619 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
3621 childLayer->m_transform.clear();
3623 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
3624 // This involves subtracting out the position of the layer in our current coordinate space.
3625 LayoutPoint childOffset;
3626 columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset);
3627 TransformationMatrix transform;
3628 transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height()));
3630 // Apply the transform.
3631 context->concatCTM(transform.toAffineTransform());
3633 // Now do a paint with the root layer shifted to be the next multicol block.
3634 LayerPaintingInfo columnPaintingInfo(paintingInfo);
3635 columnPaintingInfo.rootLayer = columnLayers[colIndex - 1];
3636 columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect);
3637 paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1);
3641 // Move to the next position.
3642 LayoutUnit blockDelta = isHorizontal ? colRect.height() : colRect.width();
3643 if (columnBlock->style()->isFlippedBlocksWritingMode())
3644 currLogicalTopOffset += blockDelta;
3646 currLogicalTopOffset -= blockDelta;
3650 static inline LayoutRect frameVisibleRect(RenderObject* renderer)
3652 FrameView* frameView = renderer->document()->view();
3654 return LayoutRect();
3656 return frameView->visibleContentRect();
3659 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
3661 return hitTest(request, result.hitTestLocation(), result);
3664 bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result)
3666 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
3668 renderer()->document()->updateLayout();
3670 LayoutRect hitTestArea = renderer()->isRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
3671 if (!request.ignoreClipping())
3672 hitTestArea.intersect(frameVisibleRect(renderer()));
3674 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false);
3676 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
3677 // return ourselves. We do this so mouse events continue getting delivered after a drag has
3678 // exited the WebView, and so hit testing over a scrollbar hits the content document.
3679 if ((request.active() || request.release()) && isRootLayer()) {
3680 renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
3685 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
3686 Node* node = result.innerNode();
3687 if (node && !result.URLElement())
3688 result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
3690 // Now return whether we were inside this layer (this will always be true for the root
3695 Node* RenderLayer::enclosingElement() const
3697 for (RenderObject* r = renderer(); r; r = r->parent()) {
3698 if (Node* e = r->node())
3701 ASSERT_NOT_REACHED();
3705 #if ENABLE(DIALOG_ELEMENT)
3706 bool RenderLayer::isInTopLayer() const
3708 Node* node = renderer()->node();
3709 return node && node->isElementNode() && toElement(node)->isInTopLayer();
3712 bool RenderLayer::isInTopLayerSubtree() const
3714 for (const RenderLayer* layer = this; layer; layer = layer->parent()) {
3715 if (layer->isInTopLayer())
3722 // Compute the z-offset of the point in the transformState.
3723 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
3724 // ray intersects target, and computing the z delta between those two points.
3725 static double computeZOffset(const HitTestingTransformState& transformState)
3727 // We got an affine transform, so no z-offset
3728 if (transformState.m_accumulatedTransform.isAffine())
3731 // Flatten the point into the target plane
3732 FloatPoint targetPoint = transformState.mappedPoint();
3734 // Now map the point back through the transform, which computes Z.
3735 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
3736 return backmappedPoint.z();
3739 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
3740 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
3741 const HitTestingTransformState* containerTransformState) const
3743 RefPtr<HitTestingTransformState> transformState;
3745 if (containerTransformState) {
3746 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
3747 transformState = HitTestingTransformState::create(*containerTransformState);
3748 convertToLayerCoords(containerLayer, offset);
3750 // If this is the first time we need to make transform state, then base it off of hitTestLocation,
3751 // which is relative to rootLayer.
3752 transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
3753 convertToLayerCoords(rootLayer, offset);
3756 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
3757 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
3758 TransformationMatrix containerTransform;
3759 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
3760 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
3762 transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
3765 return transformState;
3769 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
3774 // The hit layer is depth-sorting with other layers, so just say that it was hit.
3778 // We need to look at z-depth to decide if this layer was hit.
3780 ASSERT(transformState);
3781 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
3782 double childZOffset = computeZOffset(*transformState);
3783 if (childZOffset > *zOffset) {
3784 *zOffset = childZOffset;
3793 // hitTestLocation and hitTestRect are relative to rootLayer.
3794 // A 'flattening' layer is one preserves3D() == false.
3795 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
3796 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer.
3797 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
3799 // If zOffset is non-null (which indicates that the caller wants z offset information),
3800 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
3801 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
3802 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
3803 const HitTestingTransformState* transformState, double* zOffset)
3805 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
3808 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
3810 // Apply a transform if we have one.
3811 if (transform() && !appliedTransform) {
3812 // Make sure the parent's clip rects have been calculated.
3814 ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
3815 ClipRect clipRect = backgroundClipRect(clipRectsContext);
3816 // Go ahead and test the enclosing clip now.
3817 if (!clipRect.intersects(hitTestLocation))
3821 // Create a transform state to accumulate this transform.
3822 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
3824 // If the transform can't be inverted, then don't hit test this layer at all.
3825 if (!newTransformState->m_accumulatedTransform.isInvertible())
3828 // Compute the point and the hit test rect in the coords of this layer by using the values
3829 // from the transformState, which store the point and quad in the coords of the last flattened
3830 // layer, and the accumulated transform which lets up map through preserve-3d layers.
3832 // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
3833 // by our container.
3834 FloatPoint localPoint = newTransformState->mappedPoint();
3835 FloatQuad localPointQuad = newTransformState->mappedQuad();
3836 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
3837 HitTestLocation newHitTestLocation;
3838 if (hitTestLocation.isRectBasedTest())
3839 newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
3841 newHitTestLocation = HitTestLocation(localPoint);
3843 // Now do a hit test with the root layer shifted to be us.
3844 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
3847 // Ensure our lists and 3d status are up-to-date.
3848 updateCompositingAndLayerListsIfNeeded();
3849 update3DTransformedDescendantStatus();
3851 RefPtr<HitTestingTransformState> localTransformState;
3852 if (appliedTransform) {
3853 // We computed the correct state in the caller (above code), so just reference it.
3854 ASSERT(transformState);
3855 localTransformState = const_cast<HitTestingTransformState*>(transformState);
3856 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
3857 // We need transform state for the first time, or to offset the container state, so create it here.
3858 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
3861 // Check for hit test on backface if backface-visibility is 'hidden'
3862 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
3863 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
3864 // If the z-vector of the matrix is negative, the back is facing towards the viewer.
3865 if (invertedMatrix.m33() < 0)
3869 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
3870 if (localTransformState && !preserves3D()) {
3871 // Keep a copy of the pre-flattening state, for computing z-offsets for the container
3872 unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
3873 // This layer is flattening, so flatten the state passed to descendants.
3874 localTransformState->flatten();
3877 // Calculate the clip rects we should use.
3878 LayoutRect layerBounds;
3881 ClipRect outlineRect;
3883 ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
3884 calculateRects(clipRectsContext, hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
3886 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
3888 double localZOffset = -numeric_limits<double>::infinity();
3889 double* zOffsetForDescendantsPtr = 0;
3890 double* zOffsetForContentsPtr = 0;
3892 bool depthSortDescendants = false;
3893 if (preserves3D()) {
3894 depthSortDescendants = true;
3895 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
3896 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3897 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3898 } else if (m_has3DTransformedDescendant) {
3899 // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground.
3900 depthSortDescendants = true;
3901 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3902 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3903 } else if (zOffset) {
3904 zOffsetForDescendantsPtr = 0;
3905 // Container needs us to give back a z offset for the hit layer.
3906 zOffsetForContentsPtr = zOffset;
3909 // This variable tracks which layer the mouse ends up being inside.
3910 RenderLayer* candidateLayer = 0;
3912 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
3913 RenderLayer* hitLayer = hitTestList(posZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation,
3914 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3916 if (!depthSortDescendants)
3918 candidateLayer = hitLayer;
3921 // Now check our overflow objects.