2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 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"
49 #include "CSSStyleDeclaration.h"
50 #include "CSSStyleSelector.h"
53 #include "EventHandler.h"
54 #include "EventQueue.h"
55 #include "FloatPoint3D.h"
56 #include "FloatRect.h"
57 #include "FocusController.h"
59 #include "FrameSelection.h"
60 #include "FrameTree.h"
61 #include "FrameView.h"
63 #include "GraphicsContext.h"
64 #include "HTMLFrameOwnerElement.h"
65 #include "HTMLNames.h"
66 #include "HitTestingTransformState.h"
67 #include "HitTestRequest.h"
68 #include "HitTestResult.h"
69 #include "OverflowEvent.h"
70 #include "OverlapTestRequestClient.h"
72 #include "PlatformMouseEvent.h"
73 #include "RenderArena.h"
74 #include "RenderInline.h"
75 #include "RenderMarquee.h"
76 #include "RenderReplica.h"
77 #include "RenderScrollbar.h"
78 #include "RenderScrollbarPart.h"
79 #include "RenderTheme.h"
80 #include "RenderTreeAsText.h"
81 #include "RenderView.h"
82 #include "ScaleTransformOperation.h"
83 #include "Scrollbar.h"
84 #include "ScrollbarTheme.h"
85 #include "TextStream.h"
86 #include "TransformationMatrix.h"
87 #include "TranslateTransformOperation.h"
88 #include <wtf/StdLibExtras.h>
89 #include <wtf/UnusedParam.h>
90 #include <wtf/text/CString.h>
92 #if USE(ACCELERATED_COMPOSITING)
93 #include "RenderLayerBacking.h"
94 #include "RenderLayerCompositor.h"
101 #define MIN_INTERSECT_FOR_REVEAL 32
107 using namespace HTMLNames;
109 const int MinimumWidthWhileResizing = 100;
110 const int MinimumHeightWhileResizing = 40;
112 void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
114 return renderArena->allocate(sz);
117 void ClipRects::operator delete(void* ptr, size_t sz)
119 // Stash size where destroy can find it.
123 void ClipRects::destroy(RenderArena* renderArena)
127 // Recover the size left there for us by operator delete and free the memory.
128 renderArena->free(*(size_t *)this, this);
131 RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
132 : m_renderer(renderer)
140 , m_normalFlowList(0)
145 , m_inResizeMode(false)
146 , m_scrollDimensionsDirty(true)
147 , m_zOrderListsDirty(true)
148 , m_normalFlowListDirty(true)
149 , m_isNormalFlowOnly(shouldBeNormalFlowOnly())
150 , m_usedTransparency(false)
151 , m_paintingInsideReflection(false)
152 , m_inOverflowRelayout(false)
153 , m_needsFullRepaint(false)
154 , m_overflowStatusDirty(true)
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_mustOverlapCompositedLayers(false)
166 , m_containsDirtyOverlayScrollbars(false)
168 , m_staticInlinePosition(0)
169 , m_staticBlockPosition(0)
173 , m_scrollableAreaPage(0)
175 ScrollableArea::setConstrainsScrollingToContentEdge(false);
177 if (!renderer->firstChild() && renderer->style()) {
178 m_visibleContentStatusDirty = false;
179 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
183 RenderLayer::~RenderLayer()
185 if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
186 if (Frame* frame = renderer()->frame())
187 frame->eventHandler()->resizeLayerDestroyed();
190 if (m_scrollableAreaPage)
191 m_scrollableAreaPage->removeScrollableArea(this);
193 destroyScrollbar(HorizontalScrollbar);
194 destroyScrollbar(VerticalScrollbar);
199 // Child layers will be deleted by their corresponding render objects, so
200 // we don't need to delete them ourselves.
202 delete m_posZOrderList;
203 delete m_negZOrderList;
204 delete m_normalFlowList;
207 #if USE(ACCELERATED_COMPOSITING)
211 // Make sure we have no lingering clip rects.
212 ASSERT(!m_clipRects);
215 m_scrollCorner->destroy();
217 m_resizer->destroy();
220 #if USE(ACCELERATED_COMPOSITING)
221 RenderLayerCompositor* RenderLayer::compositor() const
223 ASSERT(renderer()->view());
224 return renderer()->view()->compositor();
227 void RenderLayer::contentChanged(ContentChangeType changeType)
229 // This can get called when video becomes accelerated, so the layers may change.
230 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this))
231 compositor()->setCompositingLayersNeedRebuild();
234 m_backing->contentChanged(changeType);
236 #endif // USE(ACCELERATED_COMPOSITING)
238 bool RenderLayer::hasAcceleratedCompositing() const
240 #if USE(ACCELERATED_COMPOSITING)
241 return compositor()->hasAcceleratedCompositing();
247 bool RenderLayer::canRender3DTransforms() const
249 #if USE(ACCELERATED_COMPOSITING)
250 return compositor()->canRender3DTransforms();
256 LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
258 hasLayerOffset = true;
261 return LayoutPoint();
263 // This is similar to root() but we check if an ancestor layer would
264 // prevent the optimization from working.
265 const RenderLayer* rootLayer = 0;
266 for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
267 hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
269 return LayoutPoint();
271 ASSERT(rootLayer == root());
274 parent()->convertToLayerCoords(rootLayer, offset);
278 void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerPositionsFlags flags)
281 if (offsetFromRoot) {
283 LayoutPoint computedOffsetFromRoot = computeOffsetFromRoot(hasLayerOffset);
284 ASSERT(hasLayerOffset);
285 ASSERT(*offsetFromRoot == computedOffsetFromRoot);
289 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
290 // we need to keep in sync, since we may have shifted relative
291 // to our parent layer.
292 LayoutPoint oldOffsetFromRoot;
293 if (offsetFromRoot) {
294 // We can't cache our offset to the repaint container if the mapping is anything more complex than a simple translation
295 if (!canUseConvertToLayerCoords())
296 offsetFromRoot = 0; // If our cached offset is invalid make sure it's not passed to any of our children
298 oldOffsetFromRoot = *offsetFromRoot;
299 // Frequently our parent layer's renderer will be the same as our renderer's containing block. In that case,
300 // we just update the cache using our offset to our parent (which is m_topLeft). Otherwise, regenerated cached
301 // offsets to the root from the render tree.
302 if (!m_parent || m_parent->renderer() == renderer()->containingBlock())
303 offsetFromRoot->move(m_topLeft.x(), m_topLeft.y()); // Fast case
306 convertToLayerCoords(root(), offset);
307 *offsetFromRoot = offset;
313 if (offsetFromRoot) {
314 offset = *offsetFromRoot;
316 LayoutPoint computedOffsetFromRoot;
317 convertToLayerCoords(root(), computedOffsetFromRoot);
318 ASSERT(offset == computedOffsetFromRoot);
321 // FIXME: It looks suspicious to call convertToLayerCoords here
322 // as canUseConvertToLayerCoords may be true for an ancestor layer.
323 convertToLayerCoords(root(), offset);
325 positionOverflowControls(toSize(offset));
327 updateVisibilityStatus();
329 if (flags & UpdatePagination)
332 m_isPaginated = false;
334 if (m_hasVisibleContent) {
335 RenderView* view = renderer()->view();
337 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
338 // mapping between them and the RenderObjects. It would be neat to enable
339 // LayoutState outside the layout() phase and use it here.
340 ASSERT(!view->layoutStateEnabled());
342 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
343 IntRect oldRepaintRect = m_repaintRect;
344 IntRect oldOutlineBox = m_outlineBox;
345 computeRepaintRects(offsetFromRoot);
346 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
347 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
348 if (flags & CheckForRepaint) {
349 if (view && !view->printing()) {
350 if (m_needsFullRepaint) {
351 renderer()->repaintUsingContainer(repaintContainer, oldRepaintRect);
352 if (m_repaintRect != oldRepaintRect)
353 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
355 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
361 m_needsFullRepaint = false;
363 // Go ahead and update the reflection's position and size.
365 m_reflection->layout();
367 #if USE(ACCELERATED_COMPOSITING)
368 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
369 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
371 flags &= ~IsCompositingUpdateRoot;
374 if (renderer()->hasColumns())
375 flags |= UpdatePagination;
377 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
378 child->updateLayerPositions(offsetFromRoot, flags);
380 #if USE(ACCELERATED_COMPOSITING)
381 if ((flags & UpdateCompositingLayers) && isComposited())
382 backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
385 // With all our children positioned, now update our marquee if we need to.
387 m_marquee->updateMarqueePosition();
390 *offsetFromRoot = oldOffsetFromRoot;
393 LayoutRect RenderLayer::repaintRectIncludingDescendants() const
395 LayoutRect repaintRect = m_repaintRect;
396 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
397 repaintRect.unite(child->repaintRectIncludingDescendants());
401 void RenderLayer::computeRepaintRects(IntPoint* offsetFromRoot)
403 ASSERT(m_hasVisibleContent);
404 ASSERT(!m_visibleContentStatusDirty);
406 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
407 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
408 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, offsetFromRoot);
411 void RenderLayer::clearRepaintRects()
413 ASSERT(!m_hasVisibleContent);
414 ASSERT(!m_visibleContentStatusDirty);
416 m_repaintRect = IntRect();
417 m_outlineBox = IntRect();
420 void RenderLayer::updateLayerPositionsAfterScroll(bool fixed)
422 ASSERT(!m_visibleContentStatusDirty);
424 // If we have no visible content, there is no point recomputing our rectangles as
425 // they will be empty. If our visibility changes, we are expected to recompute all
426 // our positions anyway.
427 if (!m_hasVisibleContent)
430 updateLayerPosition();
432 if (fixed || renderer()->style()->position() == FixedPosition) {
433 // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions?
434 computeRepaintRects();
436 } else if (renderer()->hasTransform() && !renderer()->isRenderView()) {
437 // Transforms act as fixed position containers, so nothing inside a
438 // transformed element can be fixed relative to the viewport if the
439 // transformed element is not fixed itself or child of a fixed element.
443 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
444 child->updateLayerPositionsAfterScroll(fixed);
446 // We don't update our reflection as scrolling is a translation which does not change the size()
447 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
451 m_marquee->updateMarqueePosition();
454 void RenderLayer::updateTransform()
456 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
457 // so check style too.
458 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
459 bool had3DTransform = has3DTransform();
461 bool hadTransform = m_transform;
462 if (hasTransform != hadTransform) {
464 m_transform = adoptPtr(new TransformationMatrix);
470 RenderBox* box = renderBox();
472 m_transform->makeIdentity();
473 box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
474 makeMatrixRenderable(*m_transform, canRender3DTransforms());
477 if (had3DTransform != has3DTransform())
478 dirty3DTransformedDescendantStatus();
481 TransformationMatrix RenderLayer::currentTransform() const
484 return TransformationMatrix();
486 #if USE(ACCELERATED_COMPOSITING)
487 if (renderer()->style()->isRunningAcceleratedAnimation()) {
488 TransformationMatrix currTransform;
489 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
490 style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
491 makeMatrixRenderable(currTransform, canRender3DTransforms());
492 return currTransform;
499 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
502 return TransformationMatrix();
504 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
505 TransformationMatrix matrix = *m_transform;
506 makeMatrixRenderable(matrix, false /* flatten 3d */);
513 static bool checkContainingBlockChainForPagination(RenderBoxModelObject* renderer, RenderBox* ancestorColumnsRenderer)
515 RenderView* view = renderer->view();
516 RenderBoxModelObject* prevBlock = renderer;
517 RenderBlock* containingBlock;
518 for (containingBlock = renderer->containingBlock();
519 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
520 containingBlock = containingBlock->containingBlock())
521 prevBlock = containingBlock;
523 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
524 if (containingBlock != ancestorColumnsRenderer)
527 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
528 if (prevBlock->isPositioned())
531 // Otherwise we are paginated by the columns block.
535 void RenderLayer::updatePagination()
537 m_isPaginated = false;
538 if (isComposited() || !parent())
539 return; // FIXME: We will have to deal with paginated compositing layers someday.
540 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
542 if (isNormalFlowOnly()) {
543 m_isPaginated = parent()->renderer()->hasColumns();
547 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context.
548 RenderLayer* ancestorStackingContext = stackingContext();
549 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
550 if (curr->renderer()->hasColumns()) {
551 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
554 if (curr == ancestorStackingContext)
559 void RenderLayer::setHasVisibleContent(bool b)
561 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
563 m_visibleContentStatusDirty = false;
564 m_hasVisibleContent = b;
565 if (m_hasVisibleContent) {
566 computeRepaintRects();
567 if (!isNormalFlowOnly()) {
568 for (RenderLayer* sc = stackingContext(); sc; sc = sc->stackingContext()) {
569 sc->dirtyZOrderLists();
570 if (sc->hasVisibleContent())
576 parent()->childVisibilityChanged(m_hasVisibleContent);
579 void RenderLayer::dirtyVisibleContentStatus()
581 m_visibleContentStatusDirty = true;
583 parent()->dirtyVisibleDescendantStatus();
586 void RenderLayer::childVisibilityChanged(bool newVisibility)
588 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
591 RenderLayer* l = this;
592 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
593 l->m_hasVisibleDescendant = true;
597 dirtyVisibleDescendantStatus();
600 void RenderLayer::dirtyVisibleDescendantStatus()
602 RenderLayer* l = this;
603 while (l && !l->m_visibleDescendantStatusDirty) {
604 l->m_visibleDescendantStatusDirty = true;
609 void RenderLayer::updateVisibilityStatus()
611 if (m_visibleDescendantStatusDirty) {
612 m_hasVisibleDescendant = false;
613 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
614 child->updateVisibilityStatus();
615 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
616 m_hasVisibleDescendant = true;
620 m_visibleDescendantStatusDirty = false;
623 if (m_visibleContentStatusDirty) {
624 if (renderer()->style()->visibility() == VISIBLE)
625 m_hasVisibleContent = true;
627 // layer may be hidden but still have some visible content, check for this
628 m_hasVisibleContent = false;
629 RenderObject* r = renderer()->firstChild();
631 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
632 m_hasVisibleContent = true;
635 if (r->firstChild() && !r->hasLayer())
637 else if (r->nextSibling())
638 r = r->nextSibling();
644 } while (r && !r->nextSibling());
646 r = r->nextSibling();
650 m_visibleContentStatusDirty = false;
654 void RenderLayer::dirty3DTransformedDescendantStatus()
656 RenderLayer* curr = stackingContext();
658 curr->m_3DTransformedDescendantStatusDirty = true;
660 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
661 // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
662 while (curr && curr->preserves3D()) {
663 curr->m_3DTransformedDescendantStatusDirty = true;
664 curr = curr->stackingContext();
668 // Return true if this layer or any preserve-3d descendants have 3d.
669 bool RenderLayer::update3DTransformedDescendantStatus()
671 if (m_3DTransformedDescendantStatusDirty) {
672 m_has3DTransformedDescendant = false;
674 // Transformed or preserve-3d descendants can only be in the z-order lists, not
675 // in the normal flow list, so we only need to check those.
676 if (m_posZOrderList) {
677 for (unsigned i = 0; i < m_posZOrderList->size(); ++i)
678 m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus();
681 // Now check our negative z-index children.
682 if (m_negZOrderList) {
683 for (unsigned i = 0; i < m_negZOrderList->size(); ++i)
684 m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus();
687 m_3DTransformedDescendantStatusDirty = false;
690 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
691 // the m_has3DTransformedDescendant set.
693 return has3DTransform() || m_has3DTransformedDescendant;
695 return has3DTransform();
698 void RenderLayer::updateLayerPosition()
700 LayoutPoint localPoint;
701 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
702 if (renderer()->isRenderInline()) {
703 RenderInline* inlineFlow = toRenderInline(renderer());
704 LayoutRect lineBox = inlineFlow->linesBoundingBox();
705 setSize(lineBox.size());
706 inlineBoundingBoxOffset = toSize(lineBox.location());
707 localPoint += inlineBoundingBoxOffset;
708 } else if (RenderBox* box = renderBox()) {
709 setSize(box->size());
710 localPoint += box->locationOffsetIncludingFlipping();
713 // Clear our cached clip rect information.
716 if (!renderer()->isPositioned() && renderer()->parent()) {
717 // We must adjust our position by walking up the render tree looking for the
718 // nearest enclosing object with a layer.
719 RenderObject* curr = renderer()->parent();
720 while (curr && !curr->hasLayer()) {
721 if (curr->isBox() && !curr->isTableRow()) {
722 // Rows and cells share the same coordinate space (that of the section).
723 // Omit them when computing our xpos/ypos.
724 localPoint += toRenderBox(curr)->locationOffsetIncludingFlipping();
726 curr = curr->parent();
728 if (curr->isBox() && curr->isTableRow()) {
729 // Put ourselves into the row coordinate space.
730 localPoint -= toRenderBox(curr)->locationOffsetIncludingFlipping();
734 // Subtract our parent's scroll offset.
735 if (renderer()->isPositioned() && enclosingPositionedAncestor()) {
736 RenderLayer* positionedParent = enclosingPositionedAncestor();
738 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
739 LayoutSize offset = positionedParent->scrolledContentOffset();
740 localPoint -= offset;
742 if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
743 LayoutSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer()));
744 localPoint += offset;
746 } else if (parent()) {
747 if (isComposited()) {
748 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
749 // They won't split across columns properly.
750 LayoutSize columnOffset;
751 parent()->renderer()->adjustForColumns(columnOffset, localPoint);
752 localPoint += columnOffset;
755 LayoutSize scrollOffset = parent()->scrolledContentOffset();
756 localPoint -= scrollOffset;
759 if (renderer()->isRelPositioned()) {
760 m_relativeOffset = renderer()->relativePositionOffset();
761 localPoint.move(m_relativeOffset);
763 m_relativeOffset = LayoutSize();
766 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
767 localPoint -= inlineBoundingBoxOffset;
768 setLocation(localPoint.x(), localPoint.y());
771 TransformationMatrix RenderLayer::perspectiveTransform() const
773 if (!renderer()->hasTransform())
774 return TransformationMatrix();
776 RenderStyle* style = renderer()->style();
777 if (!style->hasPerspective())
778 return TransformationMatrix();
780 // Maybe fetch the perspective from the backing?
781 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
782 const float boxWidth = borderBox.width();
783 const float boxHeight = borderBox.height();
785 float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth);
786 float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight);
788 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
789 // We want it to be in the top-left, so subtract half the height and width.
790 perspectiveOriginX -= boxWidth / 2.0f;
791 perspectiveOriginY -= boxHeight / 2.0f;
793 TransformationMatrix t;
794 t.translate(perspectiveOriginX, perspectiveOriginY);
795 t.applyPerspective(style->perspective());
796 t.translate(-perspectiveOriginX, -perspectiveOriginY);
801 FloatPoint RenderLayer::perspectiveOrigin() const
803 if (!renderer()->hasTransform())
806 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
807 RenderStyle* style = renderer()->style();
809 return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()),
810 style->perspectiveOriginY().calcFloatValue(borderBox.height()));
813 RenderLayer* RenderLayer::stackingContext() const
815 RenderLayer* layer = parent();
816 while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
817 layer = layer->parent();
821 static inline bool isPositionedContainer(RenderLayer* layer)
823 RenderObject* o = layer->renderer();
824 return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
827 static inline bool isFixedPositionedContainer(RenderLayer* layer)
829 RenderObject* o = layer->renderer();
830 return o->isRenderView() || layer->hasTransform();
833 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
835 RenderLayer* curr = parent();
836 while (curr && !isPositionedContainer(curr))
837 curr = curr->parent();
842 RenderLayer* RenderLayer::enclosingScrollableLayer() const
844 for (RenderObject* nextRenderer = renderer()->parent(); nextRenderer; nextRenderer = nextRenderer->parent()) {
845 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea())
846 return nextRenderer->enclosingLayer();
852 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
854 RenderLayer* curr = parent();
855 while (curr && !curr->renderer()->isRenderView() && !curr->transform())
856 curr = curr->parent();
861 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
863 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
866 #if USE(ACCELERATED_COMPOSITING)
867 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
869 if (includeSelf && isComposited())
870 return const_cast<RenderLayer*>(this);
872 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
873 if (curr->isComposited())
874 return const_cast<RenderLayer*>(curr);
881 RenderLayer* RenderLayer::clippingRoot() const
883 #if USE(ACCELERATED_COMPOSITING)
885 return const_cast<RenderLayer*>(this);
888 const RenderLayer* current = this;
890 if (current->renderer()->isRenderView())
891 return const_cast<RenderLayer*>(current);
893 current = compositingContainer(current);
895 if (current->transform()
896 #if USE(ACCELERATED_COMPOSITING)
897 || current->isComposited()
900 return const_cast<RenderLayer*>(current);
903 ASSERT_NOT_REACHED();
907 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
909 // We don't use convertToLayerCoords because it doesn't know about transforms
910 return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, false, true));
913 bool RenderLayer::cannotBlitToWindow() const
915 if (isTransparent() || hasReflection() || hasTransform())
919 return parent()->cannotBlitToWindow();
922 bool RenderLayer::isTransparent() const
925 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
928 return renderer()->isTransparent() || renderer()->hasMask();
931 RenderLayer* RenderLayer::transparentPaintingAncestor()
936 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
937 if (curr->isComposited())
939 if (curr->isTransparent())
945 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, PaintBehavior);
947 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
949 // If we have a mask, then the clip is limited to the border box area (and there is
950 // no need to examine child layers).
951 if (!layer->renderer()->hasMask()) {
952 // Note: we don't have to walk z-order lists since transparent elements always establish
953 // a stacking context. This means we can just walk the layer tree directly.
954 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
955 if (!layer->reflection() || layer->reflectionLayer() != curr)
956 clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
960 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
961 // current transparencyClipBox to catch all child layers.
962 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
963 // size into the parent layer.
964 if (layer->renderer()->hasReflection()) {
966 layer->convertToLayerCoords(rootLayer, delta);
967 clipRect.move(-delta.x(), -delta.y());
968 clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
969 clipRect.moveBy(delta);
973 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
975 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
976 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
977 // would be better to respect clips.
979 if (rootLayer != layer && layer->paintsWithTransform(paintBehavior)) {
980 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
981 // the transformed layer and all of its children.
983 layer->convertToLayerCoords(rootLayer, delta);
985 TransformationMatrix transform;
986 transform.translate(delta.x(), delta.y());
987 transform = transform * *layer->transform();
989 LayoutRect clipRect = layer->boundingBox(layer);
990 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, paintBehavior);
991 return transform.mapRect(clipRect);
994 LayoutRect clipRect = layer->boundingBox(rootLayer);
995 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, paintBehavior);
999 void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
1001 if (p->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
1004 RenderLayer* ancestor = transparentPaintingAncestor();
1006 ancestor->beginTransparencyLayers(p, rootLayer, paintBehavior);
1008 if (paintsWithTransparency(paintBehavior)) {
1009 m_usedTransparency = true;
1011 LayoutRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior);
1013 p->beginTransparencyLayer(renderer()->opacity());
1014 #ifdef REVEAL_TRANSPARENCY_LAYERS
1015 p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
1016 p->fillRect(clipRect);
1021 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
1023 return renderArena->allocate(sz);
1026 void RenderLayer::operator delete(void* ptr, size_t sz)
1028 // Stash size where destroy can find it.
1029 *(size_t *)ptr = sz;
1032 void RenderLayer::destroy(RenderArena* renderArena)
1036 // Recover the size left there for us by operator delete and free the memory.
1037 renderArena->free(*(size_t *)this, this);
1040 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1042 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1044 child->setPreviousSibling(prevSibling);
1045 prevSibling->setNextSibling(child);
1046 ASSERT(prevSibling != child);
1048 setFirstChild(child);
1051 beforeChild->setPreviousSibling(child);
1052 child->setNextSibling(beforeChild);
1053 ASSERT(beforeChild != child);
1055 setLastChild(child);
1057 child->setParent(this);
1059 if (child->isNormalFlowOnly())
1060 dirtyNormalFlowList();
1062 if (!child->isNormalFlowOnly() || child->firstChild()) {
1063 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
1064 // case where we're building up generated content layers. This is ok, since the lists will start
1065 // off dirty in that case anyway.
1066 child->dirtyStackingContextZOrderLists();
1069 child->updateVisibilityStatus();
1070 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1071 childVisibilityChanged(true);
1073 #if USE(ACCELERATED_COMPOSITING)
1074 compositor()->layerWasAdded(this, child);
1078 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1080 #if USE(ACCELERATED_COMPOSITING)
1081 if (!renderer()->documentBeingDestroyed())
1082 compositor()->layerWillBeRemoved(this, oldChild);
1086 if (oldChild->previousSibling())
1087 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1088 if (oldChild->nextSibling())
1089 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1091 if (m_first == oldChild)
1092 m_first = oldChild->nextSibling();
1093 if (m_last == oldChild)
1094 m_last = oldChild->previousSibling();
1096 if (oldChild->isNormalFlowOnly())
1097 dirtyNormalFlowList();
1098 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1099 // Dirty the z-order list in which we are contained. When called via the
1100 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1101 // from the main layer tree, so we need to null-check the |stackingContext| value.
1102 oldChild->dirtyStackingContextZOrderLists();
1105 oldChild->setPreviousSibling(0);
1106 oldChild->setNextSibling(0);
1107 oldChild->setParent(0);
1109 oldChild->updateVisibilityStatus();
1110 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1111 childVisibilityChanged(false);
1116 void RenderLayer::removeOnlyThisLayer()
1121 // Mark that we are about to lose our layer. This makes render tree
1122 // walks ignore this layer while we're removing it.
1123 m_renderer->setHasLayer(false);
1125 #if USE(ACCELERATED_COMPOSITING)
1126 compositor()->layerWillBeRemoved(m_parent, this);
1129 // Dirty the clip rects.
1130 clearClipRectsIncludingDescendants();
1132 // Remove us from the parent.
1133 RenderLayer* parent = m_parent;
1134 RenderLayer* nextSib = nextSibling();
1135 bool hasLayerOffset;
1136 const LayoutPoint offsetFromRootBeforeMove = computeOffsetFromRoot(hasLayerOffset);
1137 parent->removeChild(this);
1140 removeChild(reflectionLayer());
1142 // Now walk our kids and reattach them to our parent.
1143 RenderLayer* current = m_first;
1145 RenderLayer* next = current->nextSibling();
1146 removeChild(current);
1147 parent->addChild(current, nextSib);
1148 current->setNeedsFullRepaint();
1149 LayoutPoint offsetFromRoot = offsetFromRootBeforeMove;
1150 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1151 ASSERT(!renderer()->hasLayer());
1152 current->updateLayerPositions(hasLayerOffset ? &offsetFromRoot : 0);
1156 m_renderer->destroyLayer();
1159 void RenderLayer::insertOnlyThisLayer()
1161 if (!m_parent && renderer()->parent()) {
1162 // We need to connect ourselves when our renderer() has a parent.
1163 // Find our enclosingLayer and add ourselves.
1164 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
1165 ASSERT(parentLayer);
1166 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
1167 parentLayer->addChild(this, beforeChild);
1170 // Remove all descendant layers from the hierarchy and add them to the new position.
1171 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
1172 curr->moveLayers(m_parent, this);
1174 // Clear out all the clip rects.
1175 clearClipRectsIncludingDescendants();
1179 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
1181 if (ancestorLayer == this)
1184 EPosition position = renderer()->style()->position();
1185 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) {
1186 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1187 // localToAbsolute() on the RenderView.
1188 FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
1189 location += flooredLayoutSize(absPos);
1193 if (position == FixedPosition) {
1194 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1195 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1196 // so we should always find the ancestor at or before we find the fixed position container.
1197 RenderLayer* fixedPositionContainerLayer = 0;
1198 bool foundAncestor = false;
1199 for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) {
1200 if (currLayer == ancestorLayer)
1201 foundAncestor = true;
1203 if (isFixedPositionedContainer(currLayer)) {
1204 fixedPositionContainerLayer = currLayer;
1205 ASSERT_UNUSED(foundAncestor, foundAncestor);
1210 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1212 if (fixedPositionContainerLayer != ancestorLayer) {
1213 LayoutPoint fixedContainerCoords;
1214 convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
1216 LayoutPoint ancestorCoords;
1217 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
1219 location += (fixedContainerCoords - ancestorCoords);
1224 RenderLayer* parentLayer;
1225 if (position == AbsolutePosition || position == FixedPosition) {
1226 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1227 parentLayer = parent();
1228 bool foundAncestorFirst = false;
1229 while (parentLayer) {
1230 if (isPositionedContainer(parentLayer))
1233 if (parentLayer == ancestorLayer) {
1234 foundAncestorFirst = true;
1238 parentLayer = parentLayer->parent();
1241 if (foundAncestorFirst) {
1242 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1243 // to enclosingPositionedAncestor and subtract.
1244 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1246 LayoutPoint thisCoords;
1247 convertToLayerCoords(positionedAncestor, thisCoords);
1249 LayoutPoint ancestorCoords;
1250 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
1252 location += (thisCoords - ancestorCoords);
1256 parentLayer = parent();
1261 parentLayer->convertToLayerCoords(ancestorLayer, location);
1263 location += toSize(m_topLeft);
1267 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
1270 convertToLayerCoords(ancestorLayer, delta);
1271 rect.move(-delta.x(), -delta.y());
1274 static inline int adjustedScrollDelta(int beginningDelta) {
1275 // This implemention matches Firefox's.
1276 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
1277 const int speedReducer = 12;
1279 int adjustedDelta = beginningDelta / speedReducer;
1280 if (adjustedDelta > 1)
1281 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
1282 else if (adjustedDelta < -1)
1283 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
1285 return adjustedDelta;
1288 void RenderLayer::panScrollFromPoint(const LayoutPoint& sourcePoint)
1290 Frame* frame = renderer()->frame();
1294 LayoutPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
1296 // 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
1297 static LayoutPoint previousMousePosition;
1298 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
1299 currentMousePosition = previousMousePosition;
1301 previousMousePosition = currentMousePosition;
1303 LayoutUnit xDelta = currentMousePosition.x() - sourcePoint.x();
1304 LayoutUnit yDelta = currentMousePosition.y() - sourcePoint.y();
1306 if (abs(xDelta) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
1308 if (abs(yDelta) <= ScrollView::noPanScrollRadius)
1311 scrollByRecursively(adjustedScrollDelta(xDelta), adjustedScrollDelta(yDelta), ScrollOffsetClamped);
1314 void RenderLayer::scrollByRecursively(LayoutUnit xDelta, LayoutUnit yDelta, ScrollOffsetClamping clamp)
1316 if (!xDelta && !yDelta)
1319 bool restrictedByLineClamp = false;
1320 if (renderer()->parent())
1321 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1323 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1324 LayoutUnit newOffsetX = scrollXOffset() + xDelta;
1325 LayoutUnit newOffsetY = scrollYOffset() + yDelta;
1326 scrollToOffset(newOffsetX, newOffsetY, clamp);
1328 // If this layer can't do the scroll we ask the next layer up that can scroll to try
1329 LayoutUnit leftToScrollX = newOffsetX - scrollXOffset();
1330 LayoutUnit leftToScrollY = newOffsetY - scrollYOffset();
1331 if ((leftToScrollX || leftToScrollY) && renderer()->parent()) {
1332 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
1333 scrollableLayer->scrollByRecursively(leftToScrollX, leftToScrollY);
1335 Frame* frame = renderer()->frame();
1337 frame->eventHandler()->updateAutoscrollRenderer();
1339 } else if (renderer()->view()->frameView()) {
1340 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
1341 // have an overflow clip. Which means that it is a document node that can be scrolled.
1342 renderer()->view()->frameView()->scrollBy(LayoutSize(xDelta, yDelta));
1343 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
1344 // https://bugs.webkit.org/show_bug.cgi?id=28237
1348 void RenderLayer::scrollToOffset(LayoutUnit x, LayoutUnit y, ScrollOffsetClamping clamp)
1350 if (clamp == ScrollOffsetClamped) {
1351 RenderBox* box = renderBox();
1355 LayoutUnit maxX = scrollWidth() - box->clientWidth();
1356 LayoutUnit maxY = scrollHeight() - box->clientHeight();
1358 x = min(max<LayoutUnit>(x, 0), maxX);
1359 y = min(max<LayoutUnit>(y, 0), maxY);
1362 ScrollableArea::scrollToOffsetWithoutAnimation(LayoutPoint(x, y));
1365 void RenderLayer::scrollTo(LayoutUnit x, LayoutUnit y)
1367 RenderBox* box = renderBox();
1371 if (box->style()->overflowX() != OMARQUEE) {
1372 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
1373 if (m_scrollDimensionsDirty)
1374 computeScrollDimensions();
1377 // FIXME: Eventually, we will want to perform a blit. For now never
1378 // blit, since the check for blitting is going to be very
1379 // complicated (since it will involve testing whether our layer
1380 // is either occluded by another layer or clipped by an enclosing
1381 // layer or contains fixed backgrounds, etc.).
1382 LayoutSize newScrollOffset = LayoutSize(x - m_scrollOrigin.x(), y - m_scrollOrigin.y());
1383 if (m_scrollOffset == newScrollOffset)
1385 m_scrollOffset = newScrollOffset;
1387 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
1388 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
1389 updateLayerPositionsAfterScroll();
1391 RenderView* view = renderer()->view();
1393 // We should have a RenderView if we're trying to scroll.
1396 #if ENABLE(DASHBOARD_SUPPORT)
1397 // Update dashboard regions, scrolling may change the clip of a
1398 // particular region.
1399 view->frameView()->updateDashboardRegions();
1402 view->updateWidgetPositions();
1405 #if USE(ACCELERATED_COMPOSITING)
1406 if (compositor()->inCompositingMode()) {
1407 // Our stacking context is guaranteed to contain all of our descendants that may need
1408 // repositioning, so update compositing layers from there.
1409 if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) {
1410 if (compositor()->compositingConsultsOverlap())
1411 compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
1413 bool isUpdateRoot = true;
1414 compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
1420 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
1422 Frame* frame = renderer()->frame();
1424 // The caret rect needs to be invalidated after scrolling
1425 frame->selection()->setCaretRectNeedsUpdate();
1427 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
1428 if (repaintContainer)
1429 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
1430 frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
1433 // Just schedule a full repaint of our object.
1435 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
1437 // Schedule the scroll DOM event.
1438 if (renderer()->node())
1439 renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget);
1442 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1444 RenderLayer* parentLayer = 0;
1445 LayoutRect newRect = rect;
1447 // We may end up propagating a scroll event. It is important that we suspend events until
1448 // the end of the function since they could delete the layer or the layer's renderer().
1449 FrameView* frameView = renderer()->document()->view();
1451 frameView->pauseScheduledEvents();
1453 bool restrictedByLineClamp = false;
1454 if (renderer()->parent()) {
1455 parentLayer = renderer()->parent()->enclosingLayer();
1456 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1459 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1460 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
1461 // This will prevent us from revealing text hidden by the slider in Safari RSS.
1462 RenderBox* box = renderBox();
1464 FloatPoint absPos = box->localToAbsolute();
1465 absPos.move(box->borderLeft(), box->borderTop());
1467 LayoutRect layerBounds = LayoutRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
1468 LayoutRect exposeRect = LayoutRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
1469 LayoutRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
1471 LayoutUnit xOffset = r.x() - absPos.x();
1472 LayoutUnit yOffset = r.y() - absPos.y();
1473 // Adjust offsets if they're outside of the allowable range.
1474 xOffset = max<LayoutUnit>(0, min(scrollWidth() - layerBounds.width(), xOffset));
1475 yOffset = max<LayoutUnit>(0, min(scrollHeight() - layerBounds.height(), yOffset));
1477 if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
1478 LayoutUnit diffX = scrollXOffset();
1479 LayoutUnit diffY = scrollYOffset();
1480 scrollToOffset(xOffset, yOffset);
1481 diffX = scrollXOffset() - diffX;
1482 diffY = scrollYOffset() - diffY;
1483 newRect.setX(rect.x() - diffX);
1484 newRect.setY(rect.y() - diffY);
1486 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled()) {
1488 if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) {
1489 LayoutRect viewRect = frameView->visibleContentRect();
1490 LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1492 LayoutUnit xOffset = r.x();
1493 LayoutUnit yOffset = r.y();
1494 // Adjust offsets if they're outside of the allowable range.
1495 xOffset = max<LayoutUnit>(0, min(frameView->contentsWidth(), xOffset));
1496 yOffset = max<LayoutUnit>(0, min(frameView->contentsHeight(), yOffset));
1498 frameView->setScrollPosition(LayoutPoint(xOffset, yOffset));
1499 parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer();
1500 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
1501 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
1503 LayoutRect viewRect = frameView->visibleContentRect();
1504 LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1506 frameView->setScrollPosition(r.location());
1508 // This is the outermost view of a web page, so after scrolling this view we
1509 // scroll its container by calling Page::scrollRectIntoView.
1510 // This only has an effect on the Mac platform in applications
1511 // that put web views into scrolling containers, such as Mac OS X Mail.
1512 // The canAutoscroll function in EventHandler also knows about this.
1513 if (Frame* frame = frameView->frame()) {
1514 if (Page* page = frame->page())
1515 page->chrome()->scrollRectIntoView(rect);
1522 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
1525 frameView->resumeScheduledEvents();
1528 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1530 // Determine the appropriate X behavior.
1531 ScrollBehavior scrollX;
1532 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
1533 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
1534 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
1535 // If the rectangle is fully visible, use the specified visible behavior.
1536 // If the rectangle is partially visible, but over a certain threshold,
1537 // then treat it as fully visible to avoid unnecessary horizontal scrolling
1538 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1539 else if (intersectWidth == visibleRect.width()) {
1540 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1541 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1542 if (scrollX == alignCenter)
1544 } else if (intersectWidth > 0)
1545 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
1546 scrollX = ScrollAlignment::getPartialBehavior(alignX);
1548 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
1549 // If we're trying to align to the closest edge, and the exposeRect is further right
1550 // than the visibleRect, and not bigger than the visible area, then align with the right.
1551 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
1552 scrollX = alignRight;
1554 // Given the X behavior, compute the X coordinate.
1556 if (scrollX == noScroll)
1557 x = visibleRect.x();
1558 else if (scrollX == alignRight)
1559 x = exposeRect.maxX() - visibleRect.width();
1560 else if (scrollX == alignCenter)
1561 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
1565 // Determine the appropriate Y behavior.
1566 ScrollBehavior scrollY;
1567 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
1568 LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
1569 if (intersectHeight == exposeRect.height())
1570 // If the rectangle is fully visible, use the specified visible behavior.
1571 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1572 else if (intersectHeight == visibleRect.height()) {
1573 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1574 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1575 if (scrollY == alignCenter)
1577 } else if (intersectHeight > 0)
1578 // If the rectangle is partially visible, use the specified partial behavior
1579 scrollY = ScrollAlignment::getPartialBehavior(alignY);
1581 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
1582 // If we're trying to align to the closest edge, and the exposeRect is further down
1583 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
1584 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
1585 scrollY = alignBottom;
1587 // Given the Y behavior, compute the Y coordinate.
1589 if (scrollY == noScroll)
1590 y = visibleRect.y();
1591 else if (scrollY == alignBottom)
1592 y = exposeRect.maxY() - visibleRect.height();
1593 else if (scrollY == alignCenter)
1594 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
1598 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
1601 void RenderLayer::autoscroll()
1603 Frame* frame = renderer()->frame();
1607 FrameView* frameView = frame->view();
1611 #if ENABLE(DRAG_SUPPORT)
1612 frame->eventHandler()->updateSelectionForMouseDrag();
1615 LayoutPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
1616 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
1619 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
1621 // FIXME: This should be possible on generated content but is not right now.
1622 if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
1625 // Set the width and height of the shadow ancestor node if there is one.
1626 // This is necessary for textarea elements since the resizable layer is in the shadow content.
1627 Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode());
1628 RenderBox* renderer = toRenderBox(element->renderer());
1630 EResize resize = renderer->style()->resize();
1631 if (resize == RESIZE_NONE)
1634 Document* document = element->document();
1635 if (!document->frame()->eventHandler()->mousePressed())
1638 float zoomFactor = renderer->style()->effectiveZoom();
1640 LayoutSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos()));
1641 newOffset.setWidth(newOffset.width() / zoomFactor);
1642 newOffset.setHeight(newOffset.height() / zoomFactor);
1644 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
1645 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
1646 element->setMinimumSizeForResizing(minimumSize);
1648 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
1650 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
1652 CSSStyleDeclaration* style = element->style();
1653 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
1657 if (resize != RESIZE_VERTICAL && difference.width()) {
1658 if (element->isFormControlElement()) {
1659 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1660 style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec);
1661 style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec);
1663 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingWidth());
1664 baseWidth = baseWidth / zoomFactor;
1665 style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec);
1668 if (resize != RESIZE_HORIZONTAL && difference.height()) {
1669 if (element->isFormControlElement()) {
1670 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1671 style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec);
1672 style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec);
1674 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingHeight());
1675 baseHeight = baseHeight / zoomFactor;
1676 style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec);
1679 document->updateLayout();
1681 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
1684 LayoutUnit RenderLayer::scrollSize(ScrollbarOrientation orientation) const
1686 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
1687 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
1690 void RenderLayer::setScrollOffset(const LayoutPoint& offset)
1692 scrollTo(offset.x(), offset.y());
1695 LayoutUnit RenderLayer::scrollPosition(Scrollbar* scrollbar) const
1697 if (scrollbar->orientation() == HorizontalScrollbar)
1698 return scrollXOffset();
1699 if (scrollbar->orientation() == VerticalScrollbar)
1700 return scrollYOffset();
1704 LayoutPoint RenderLayer::scrollPosition() const
1706 return m_scrollOrigin + m_scrollOffset;
1709 LayoutPoint RenderLayer::minimumScrollPosition() const
1711 return m_scrollOrigin;
1714 LayoutPoint RenderLayer::maximumScrollPosition() const
1716 // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
1717 return m_scrollOrigin + m_scrollSize - visibleContentRect(true).size();
1720 LayoutRect RenderLayer::visibleContentRect(bool includeScrollbars) const
1722 LayoutUnit verticalScrollbarWidth = 0;
1723 LayoutUnit horizontalScrollbarHeight = 0;
1724 if (includeScrollbars) {
1725 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
1726 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
1729 return LayoutRect(LayoutPoint(scrollXOffset(), scrollYOffset()),
1730 LayoutSize(max<LayoutUnit>(0, m_layerSize.width() - verticalScrollbarWidth),
1731 max<LayoutUnit>(0, m_layerSize.height() - horizontalScrollbarHeight)));
1734 LayoutSize RenderLayer::overhangAmount() const
1736 return LayoutSize();
1739 void RenderLayer::didCompleteRubberBand(const LayoutSize&) const
1743 bool RenderLayer::isActive() const
1745 Page* page = renderer()->frame()->page();
1746 return page && page->focusController()->isActive();
1749 static LayoutRect cornerRect(const RenderLayer* layer, const LayoutRect& bounds)
1751 int horizontalThickness;
1752 int verticalThickness;
1753 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1754 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
1755 // even when they don't exist in order to set the resizer square size properly.
1756 horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
1757 verticalThickness = horizontalThickness;
1758 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1759 horizontalThickness = layer->verticalScrollbar()->width();
1760 verticalThickness = horizontalThickness;
1761 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
1762 verticalThickness = layer->horizontalScrollbar()->height();
1763 horizontalThickness = verticalThickness;
1765 horizontalThickness = layer->verticalScrollbar()->width();
1766 verticalThickness = layer->horizontalScrollbar()->height();
1768 return LayoutRect(bounds.maxX() - horizontalThickness - layer->renderer()->style()->borderRightWidth(),
1769 bounds.maxY() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
1770 horizontalThickness, verticalThickness);
1773 LayoutRect RenderLayer::scrollCornerRect() const
1775 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
1776 // This happens when:
1777 // (a) A resizer is present and at least one scrollbar is present
1778 // (b) Both scrollbars are present.
1779 bool hasHorizontalBar = horizontalScrollbar();
1780 bool hasVerticalBar = verticalScrollbar();
1781 bool hasResizer = renderer()->style()->resize() != RESIZE_NONE;
1782 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
1783 return cornerRect(this, renderBox()->borderBoxRect());
1784 return LayoutRect();
1787 static LayoutRect resizerCornerRect(const RenderLayer* layer, const LayoutRect& bounds)
1789 ASSERT(layer->renderer()->isBox());
1790 if (layer->renderer()->style()->resize() == RESIZE_NONE)
1791 return LayoutRect();
1792 return cornerRect(layer, bounds);
1795 LayoutRect RenderLayer::scrollCornerAndResizerRect() const
1797 RenderBox* box = renderBox();
1799 return LayoutRect();
1800 LayoutRect scrollCornerAndResizer = scrollCornerRect();
1801 if (scrollCornerAndResizer.isEmpty())
1802 scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect());
1803 return scrollCornerAndResizer;
1806 bool RenderLayer::isScrollCornerVisible() const
1808 ASSERT(renderer()->isBox());
1809 return !scrollCornerRect().isEmpty();
1812 LayoutRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const LayoutRect& scrollbarRect) const
1814 RenderView* view = renderer()->view();
1816 return scrollbarRect;
1818 LayoutRect rect = scrollbarRect;
1819 rect.move(scrollbarOffset(scrollbar));
1821 return view->frameView()->convertFromRenderer(renderer(), rect);
1824 LayoutRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const LayoutRect& parentRect) const
1826 RenderView* view = renderer()->view();
1830 LayoutRect rect = view->frameView()->convertToRenderer(renderer(), parentRect);
1831 rect.move(-scrollbarOffset(scrollbar));
1835 LayoutPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const LayoutPoint& scrollbarPoint) const
1837 RenderView* view = renderer()->view();
1839 return scrollbarPoint;
1841 LayoutPoint point = scrollbarPoint;
1842 point.move(scrollbarOffset(scrollbar));
1843 return view->frameView()->convertFromRenderer(renderer(), point);
1846 LayoutPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const LayoutPoint& parentPoint) const
1848 RenderView* view = renderer()->view();
1852 LayoutPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint);
1854 point.move(-scrollbarOffset(scrollbar));
1858 LayoutSize RenderLayer::contentsSize() const
1860 return LayoutSize(const_cast<RenderLayer*>(this)->scrollWidth(), const_cast<RenderLayer*>(this)->scrollHeight());
1863 LayoutUnit RenderLayer::visibleHeight() const
1865 return m_layerSize.height();
1868 LayoutUnit RenderLayer::visibleWidth() const
1870 return m_layerSize.width();
1873 bool RenderLayer::shouldSuspendScrollAnimations() const
1875 RenderView* view = renderer()->view();
1878 return view->frameView()->shouldSuspendScrollAnimations();
1881 bool RenderLayer::isOnActivePage() const
1883 return !m_renderer->document()->inPageCache();
1886 LayoutPoint RenderLayer::currentMousePosition() const
1888 return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : LayoutPoint();
1891 LayoutSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
1893 RenderBox* box = renderBox();
1895 if (scrollbar == m_vBar.get())
1896 return LayoutSize(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
1898 if (scrollbar == m_hBar.get())
1899 return LayoutSize(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
1901 ASSERT_NOT_REACHED();
1902 return LayoutSize();
1905 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const LayoutRect& rect)
1907 #if USE(ACCELERATED_COMPOSITING)
1908 if (scrollbar == m_vBar.get()) {
1909 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
1910 layer->setNeedsDisplayInRect(rect);
1914 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
1915 layer->setNeedsDisplayInRect(rect);
1920 LayoutRect scrollRect = rect;
1921 RenderBox* box = renderBox();
1923 if (scrollbar == m_vBar.get())
1924 scrollRect.move(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
1926 scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
1927 renderer()->repaintRectangle(scrollRect);
1930 void RenderLayer::invalidateScrollCornerRect(const LayoutRect& rect)
1932 #if USE(ACCELERATED_COMPOSITING)
1933 if (GraphicsLayer* layer = layerForScrollCorner()) {
1934 layer->setNeedsDisplayInRect(rect);
1939 m_scrollCorner->repaintRectangle(rect);
1941 m_resizer->repaintRectangle(rect);
1944 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
1946 RefPtr<Scrollbar> widget;
1947 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
1948 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
1949 if (hasCustomScrollbarStyle)
1950 widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer));
1952 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
1953 if (orientation == HorizontalScrollbar)
1954 didAddHorizontalScrollbar(widget.get());
1956 didAddVerticalScrollbar(widget.get());
1958 renderer()->document()->view()->addChild(widget.get());
1959 return widget.release();
1962 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
1964 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
1966 if (scrollbar->isCustomScrollbar())
1967 toRenderScrollbar(scrollbar.get())->clearOwningRenderer();
1969 if (orientation == HorizontalScrollbar)
1970 willRemoveHorizontalScrollbar(scrollbar.get());
1972 willRemoveVerticalScrollbar(scrollbar.get());
1975 scrollbar->removeFromParent();
1976 scrollbar->disconnectFromScrollableArea();
1981 bool RenderLayer::scrollsOverflow() const
1983 if (!renderer()->isBox())
1986 return toRenderBox(renderer())->scrollsOverflow();
1989 bool RenderLayer::allowsScrolling() const
1991 return (m_hBar && m_hBar->enabled()) || (m_vBar && m_vBar->enabled());
1994 void RenderLayer::didAddHorizontalScrollbar(Scrollbar* scrollbar)
1996 m_renderer->document()->didAddWheelEventHandler();
1997 ScrollableArea::didAddHorizontalScrollbar(scrollbar);
2000 void RenderLayer::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
2002 ScrollableArea::willRemoveHorizontalScrollbar(scrollbar);
2003 // FIXME: maybe need a separate ScrollableArea::didRemoveHorizontalScrollbar callback?
2004 m_renderer->document()->didRemoveWheelEventHandler();
2007 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
2009 if (hasScrollbar == (m_hBar != 0))
2013 m_hBar = createScrollbar(HorizontalScrollbar);
2015 destroyScrollbar(HorizontalScrollbar);
2017 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2019 m_hBar->styleChanged();
2021 m_vBar->styleChanged();
2023 #if ENABLE(DASHBOARD_SUPPORT)
2024 // Force an update since we know the scrollbars have changed things.
2025 if (renderer()->document()->hasDashboardRegions())
2026 renderer()->document()->setDashboardRegionsDirty(true);
2030 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
2032 if (hasScrollbar == (m_vBar != 0))
2036 m_vBar = createScrollbar(VerticalScrollbar);
2038 destroyScrollbar(VerticalScrollbar);
2040 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2042 m_hBar->styleChanged();
2044 m_vBar->styleChanged();
2046 #if ENABLE(DASHBOARD_SUPPORT)
2047 // Force an update since we know the scrollbars have changed things.
2048 if (renderer()->document()->hasDashboardRegions())
2049 renderer()->document()->setDashboardRegionsDirty(true);
2053 ScrollableArea* RenderLayer::enclosingScrollableArea() const
2055 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2056 return scrollableLayer;
2058 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
2059 // if the frame view isn't scrollable.
2063 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
2065 if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2067 return m_vBar->width();
2070 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
2072 if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2074 return m_hBar->height();
2077 LayoutSize RenderLayer::offsetFromResizeCorner(const LayoutPoint& absolutePoint) const
2079 // Currently the resize corner is always the bottom right corner
2080 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
2081 LayoutPoint bottomRight = toPoint(size());
2082 LayoutPoint localPoint = absoluteToContents(absolutePoint);
2083 return localPoint - bottomRight;
2086 bool RenderLayer::hasOverflowControls() const
2088 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
2091 void RenderLayer::positionOverflowControls(const LayoutSize& offsetFromLayer)
2093 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2096 RenderBox* box = renderBox();
2100 const LayoutRect& borderBox = box->borderBoxRect();
2101 const LayoutRect& scrollCorner = scrollCornerRect();
2102 LayoutRect absBounds(borderBox.location() + offsetFromLayer, borderBox.size());
2104 m_vBar->setFrameRect(LayoutRect(absBounds.maxX() - box->borderRight() - m_vBar->width(),
2105 absBounds.y() + box->borderTop(),
2107 absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
2110 m_hBar->setFrameRect(LayoutRect(absBounds.x() + box->borderLeft(),
2111 absBounds.maxY() - box->borderBottom() - m_hBar->height(),
2112 absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2115 #if USE(ACCELERATED_COMPOSITING)
2116 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2118 layer->setPosition(m_hBar->frameRect().location() - offsetFromLayer);
2119 layer->setSize(m_hBar->frameRect().size());
2121 layer->setDrawsContent(m_hBar);
2123 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2125 layer->setPosition(m_vBar->frameRect().location() - offsetFromLayer);
2126 layer->setSize(m_vBar->frameRect().size());
2128 layer->setDrawsContent(m_vBar);
2131 if (GraphicsLayer* layer = layerForScrollCorner()) {
2132 const LayoutRect& scrollCornerAndResizer = scrollCornerAndResizerRect();
2133 layer->setPosition(scrollCornerAndResizer.location());
2134 layer->setSize(scrollCornerAndResizer.size());
2135 layer->setDrawsContent(!scrollCornerAndResizer.isEmpty());
2140 m_scrollCorner->setFrameRect(scrollCorner);
2142 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
2145 LayoutUnit RenderLayer::scrollWidth()
2147 if (m_scrollDimensionsDirty)
2148 computeScrollDimensions();
2149 return m_scrollSize.width();
2152 LayoutUnit RenderLayer::scrollHeight()
2154 if (m_scrollDimensionsDirty)
2155 computeScrollDimensions();
2156 return m_scrollSize.height();
2159 LayoutUnit RenderLayer::overflowTop() const
2161 RenderBox* box = renderBox();
2162 LayoutRect overflowRect(box->layoutOverflowRect());
2163 box->flipForWritingMode(overflowRect);
2164 return overflowRect.y();
2167 LayoutUnit RenderLayer::overflowBottom() const
2169 RenderBox* box = renderBox();
2170 LayoutRect overflowRect(box->layoutOverflowRect());
2171 box->flipForWritingMode(overflowRect);
2172 return overflowRect.maxY();
2175 LayoutUnit RenderLayer::overflowLeft() const
2177 RenderBox* box = renderBox();
2178 LayoutRect overflowRect(box->layoutOverflowRect());
2179 box->flipForWritingMode(overflowRect);
2180 return overflowRect.x();
2183 LayoutUnit RenderLayer::overflowRight() const
2185 RenderBox* box = renderBox();
2186 LayoutRect overflowRect(box->layoutOverflowRect());
2187 box->flipForWritingMode(overflowRect);
2188 return overflowRect.maxX();
2191 void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
2193 RenderBox* box = renderBox();
2196 m_scrollDimensionsDirty = false;
2198 m_scrollOverflow.setWidth(overflowLeft() - box->borderLeft());
2199 m_scrollOverflow.setHeight(overflowTop() - box->borderTop());
2201 m_scrollSize.setWidth(overflowRight() - overflowLeft());
2202 m_scrollSize.setHeight(overflowBottom() - overflowTop());
2204 m_scrollOrigin = LayoutPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height());
2207 *needHBar = m_scrollSize.width() > box->clientWidth();
2209 *needVBar = m_scrollSize.height() > box->clientHeight();
2212 void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2214 if (m_overflowStatusDirty) {
2215 m_horizontalOverflow = horizontalOverflow;
2216 m_verticalOverflow = verticalOverflow;
2217 m_overflowStatusDirty = false;
2221 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2222 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2224 if (horizontalOverflowChanged || verticalOverflowChanged) {
2225 m_horizontalOverflow = horizontalOverflow;
2226 m_verticalOverflow = verticalOverflow;
2228 if (FrameView* frameView = renderer()->document()->view()) {
2229 frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
2230 renderer()->node());
2235 void RenderLayer::updateScrollInfoAfterLayout()
2237 RenderBox* box = renderBox();
2241 m_scrollDimensionsDirty = true;
2243 bool horizontalOverflow, verticalOverflow;
2244 computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
2246 if (box->style()->overflowX() != OMARQUEE) {
2247 // Layout may cause us to be in an invalid scroll position. In this case we need
2248 // to pull our scroll offsets back to the max (or push them up to the min).
2249 LayoutUnit newX = max<LayoutUnit>(0, min(scrollXOffset(), scrollWidth() - box->clientWidth()));
2250 LayoutUnit newY = max<LayoutUnit>(0, min(scrollYOffset(), scrollHeight() - box->clientHeight()));
2251 if (newX != scrollXOffset() || newY != scrollYOffset())
2252 scrollToOffset(newX, newY);
2255 bool haveHorizontalBar = m_hBar;
2256 bool haveVerticalBar = m_vBar;
2258 // overflow:scroll should just enable/disable.
2259 if (renderer()->style()->overflowX() == OSCROLL)
2260 m_hBar->setEnabled(horizontalOverflow);
2261 if (renderer()->style()->overflowY() == OSCROLL)
2262 m_vBar->setEnabled(verticalOverflow);
2264 // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any
2265 // scrollbars that may be present.
2266 if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar)
2267 setHasHorizontalScrollbar(false);
2268 if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar)
2269 setHasVerticalScrollbar(false);
2271 // overflow:auto may need to lay out again if scrollbars got added/removed.
2272 bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
2273 (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
2274 if (scrollbarsChanged) {
2275 if (box->hasAutoHorizontalScrollbar())
2276 setHasHorizontalScrollbar(horizontalOverflow);
2277 if (box->hasAutoVerticalScrollbar())
2278 setHasVerticalScrollbar(verticalOverflow);
2280 #if ENABLE(DASHBOARD_SUPPORT)
2281 // Force an update since we know the scrollbars have changed things.
2282 if (renderer()->document()->hasDashboardRegions())
2283 renderer()->document()->setDashboardRegionsDirty(true);
2286 renderer()->repaint();
2288 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) {
2289 if (!m_inOverflowRelayout) {
2290 // Our proprietary overflow: overlay value doesn't trigger a layout.
2291 m_inOverflowRelayout = true;
2292 renderer()->setNeedsLayout(true, false);
2293 if (renderer()->isRenderBlock()) {
2294 RenderBlock* block = toRenderBlock(renderer());
2295 block->scrollbarsChanged(box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow,
2296 box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
2297 block->layoutBlock(true); // FIXME: Need to handle positioned floats triggering extra relayouts.
2299 renderer()->layout();
2300 m_inOverflowRelayout = false;
2305 // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
2306 if (m_hBar && box->hasAutoHorizontalScrollbar())
2307 m_hBar->setEnabled(true);
2308 if (m_vBar && box->hasAutoVerticalScrollbar())
2309 m_vBar->setEnabled(true);
2311 // Set up the range (and page step/line step).
2313 LayoutUnit clientWidth = box->clientWidth();
2314 LayoutUnit pageStep = max<LayoutUnit>(max<LayoutUnit>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
2315 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2316 m_hBar->setProportion(clientWidth, m_scrollSize.width());
2319 LayoutUnit clientHeight = box->clientHeight();
2320 LayoutUnit pageStep = max<LayoutUnit>(max<LayoutUnit>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
2321 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2322 m_vBar->setProportion(clientHeight, m_scrollSize.height());
2325 scrollToOffset(scrollXOffset(), scrollYOffset());
2327 if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
2328 updateOverflowStatus(horizontalOverflow, verticalOverflow);
2331 void RenderLayer::paintOverflowControls(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& damageRect, bool paintingOverlayControls)
2333 // Don't do anything if we have no overflow.
2334 if (!renderer()->hasOverflowClip())
2337 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
2338 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
2339 // will be false, and we should just tell the root layer that there are overlay scrollbars
2340 // that need to be painted. That will cause the second pass through the layer tree to run,
2341 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
2342 // second pass doesn't need to re-enter the RenderTree to get it right.
2343 if (hasOverlayScrollbars() && !paintingOverlayControls) {
2344 RenderView* renderView = renderer()->view();
2345 renderView->layer()->setContainsDirtyOverlayScrollbars(true);
2346 m_cachedOverlayScrollbarOffset = paintOffset;
2347 renderView->frameView()->setContainsScrollableAreaWithOverlayScrollbars(true);
2351 // This check is required to avoid painting custom CSS scrollbars twice.
2352 if (paintingOverlayControls && !hasOverlayScrollbars())
2355 LayoutPoint adjustedPaintOffset = paintOffset;
2356 if (paintingOverlayControls)
2357 adjustedPaintOffset = m_cachedOverlayScrollbarOffset;
2359 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
2360 // widgets can move without layout occurring (most notably when you scroll a document that
2361 // contains fixed positioned elements).
2362 positionOverflowControls(toSize(adjustedPaintOffset));
2364 // Now that we're sure the scrollbars are in the right place, paint them.
2366 #if USE(ACCELERATED_COMPOSITING)
2367 && !layerForHorizontalScrollbar()
2370 m_hBar->paint(context, damageRect);
2372 #if USE(ACCELERATED_COMPOSITING)
2373 && !layerForVerticalScrollbar()
2376 m_vBar->paint(context, damageRect);
2378 #if USE(ACCELERATED_COMPOSITING)
2379 if (layerForScrollCorner())
2383 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
2385 paintScrollCorner(context, adjustedPaintOffset, damageRect);
2387 // Paint our resizer last, since it sits on top of the scroll corner.
2388 paintResizer(context, adjustedPaintOffset, damageRect);
2391 void RenderLayer::paintScrollCorner(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& damageRect)
2393 RenderBox* box = renderBox();
2396 LayoutRect absRect = scrollCornerRect();
2397 absRect.moveBy(paintOffset);
2398 if (!absRect.intersects(damageRect))
2401 if (context->updatingControlTints()) {
2402 updateScrollCornerStyle();
2406 if (m_scrollCorner) {
2407 m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
2411 // We don't want to paint white if we have overlay scrollbars, since we need
2412 // to see what is behind it.
2413 if (!hasOverlayScrollbars())
2414 context->fillRect(absRect, Color::white, box->style()->colorSpace());
2417 void RenderLayer::drawPlatformResizerImage(GraphicsContext* context, LayoutRect resizerCornerRect)
2419 float deviceScaleFactor = Page::deviceScaleFactor(renderer()->frame());
2421 RefPtr<Image> resizeCornerImage;
2422 IntSize cornerResizerSize;
2423 if (deviceScaleFactor >= 2) {
2424 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef()));
2425 resizeCornerImage = resizeCornerImageHiRes;
2426 cornerResizerSize = resizeCornerImage->size();
2427 cornerResizerSize.scale(0.5f);
2429 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner").leakRef()));
2430 resizeCornerImage = resizeCornerImageLoRes;
2431 cornerResizerSize = resizeCornerImage->size();
2434 IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
2435 context->drawImage(resizeCornerImage.get(), renderer()->style()->colorSpace(), imageRect);
2438 void RenderLayer::paintResizer(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& damageRect)
2440 if (renderer()->style()->resize() == RESIZE_NONE)
2443 RenderBox* box = renderBox();
2446 LayoutRect absRect = resizerCornerRect(this, box->borderBoxRect());
2447 absRect.moveBy(paintOffset);
2448 if (!absRect.intersects(damageRect))
2451 if (context->updatingControlTints()) {
2452 updateResizerStyle();
2457 m_resizer->paintIntoRect(context, paintOffset, absRect);
2461 drawPlatformResizerImage(context, absRect);
2463 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
2464 // Clipping will exclude the right and bottom edges of this frame.
2465 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
2466 GraphicsContextStateSaver stateSaver(*context);
2467 context->clip(absRect);
2468 LayoutRect largerCorner = absRect;
2469 largerCorner.setSize(LayoutSize(largerCorner.width() + 1, largerCorner.height() + 1));
2470 context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
2471 context->setStrokeThickness(1.0f);
2472 context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
2473 context->drawRect(largerCorner);
2477 bool RenderLayer::isPointInResizeControl(const LayoutPoint& absolutePoint) const
2479 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
2482 RenderBox* box = renderBox();
2485 LayoutPoint localPoint = absoluteToContents(absolutePoint);
2487 LayoutRect localBounds(0, 0, box->width(), box->height());
2488 return resizerCornerRect(this, localBounds).contains(localPoint);
2491 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const LayoutPoint& localPoint)
2493 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2496 RenderBox* box = renderBox();
2499 LayoutRect resizeControlRect;
2500 if (renderer()->style()->resize() != RESIZE_NONE) {
2501 resizeControlRect = resizerCornerRect(this, box->borderBoxRect());
2502 if (resizeControlRect.contains(localPoint))
2506 LayoutUnit resizeControlSize = max<LayoutUnit>(resizeControlRect.height(), 0);
2509 LayoutRect vBarRect(box->width() - box->borderRight() - m_vBar->width(),
2512 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
2513 if (vBarRect.contains(localPoint)) {
2514 result.setScrollbar(m_vBar.get());
2519 resizeControlSize = max<LayoutUnit>(resizeControlRect.width(), 0);
2521 LayoutRect hBarRect(box->borderLeft(),
2522 box->height() - box->borderBottom() - m_hBar->height(),
2523 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
2525 if (hBarRect.contains(localPoint)) {
2526 result.setScrollbar(m_hBar.get());
2534 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
2536 return ScrollableArea::scroll(direction, granularity, multiplier);
2539 void RenderLayer::paint(GraphicsContext* p, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
2541 OverlapTestRequestMap overlapTestRequests;
2542 paintLayer(this, p, damageRect, paintBehavior, paintingRoot, &overlapTestRequests);
2543 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2544 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
2545 it->first->setOverlapTestResult(false);
2548 void RenderLayer::paintOverlayScrollbars(GraphicsContext* p, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
2550 if (!m_containsDirtyOverlayScrollbars)
2552 paintLayer(this, p, damageRect, paintBehavior, paintingRoot, 0, PaintLayerHaveTransparency | PaintLayerTemporaryClipRects
2553 | PaintLayerPaintingOverlayScrollbars);
2554 m_containsDirtyOverlayScrollbars = false;
2557 static void setClip(GraphicsContext* p, const LayoutRect& paintDirtyRect, const LayoutRect& clipRect)
2559 if (paintDirtyRect == clipRect)
2565 static void restoreClip(GraphicsContext* p, const LayoutRect& paintDirtyRect, const LayoutRect& clipRect)
2567 if (paintDirtyRect == clipRect)
2572 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
2574 Vector<OverlapTestRequestClient*> overlappedRequestClients;
2575 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2576 LayoutRect boundingBox = layer->boundingBox(rootLayer);
2577 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
2578 if (!boundingBox.intersects(it->second))
2581 it->first->setOverlapTestResult(true);
2582 overlappedRequestClients.append(it->first);
2584 for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
2585 overlapTestRequests.remove(overlappedRequestClients[i]);
2588 #if USE(ACCELERATED_COMPOSITING)
2589 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
2591 return paintingReflection && !layer->has3DTransform();
2595 void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
2596 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2597 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2598 PaintLayerFlags paintFlags)
2600 #if USE(ACCELERATED_COMPOSITING)
2601 if (isComposited()) {
2602 // The updatingControlTints() painting pass goes through compositing layers,
2603 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
2604 if (p->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
2605 paintFlags |= PaintLayerTemporaryClipRects;
2606 else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
2607 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
2613 // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC.
2614 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2615 // will do a full repaint().
2616 if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
2619 // If this layer is totally invisible then there is nothing to paint.
2620 if (!renderer()->opacity())
2623 if (paintsWithTransparency(paintBehavior))
2624 paintFlags |= PaintLayerHaveTransparency;
2626 // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
2627 if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
2628 TransformationMatrix layerTransform = renderableTransform(paintBehavior);
2629 // If the transform can't be inverted, then don't paint anything.
2630 if (!layerTransform.isInvertible())
2633 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
2634 // layer from the parent now, assuming there is a parent
2635 if (paintFlags & PaintLayerHaveTransparency) {
2637 parent()->beginTransparencyLayers(p, rootLayer, paintBehavior);
2639 beginTransparencyLayers(p, rootLayer, paintBehavior);
2642 // Make sure the parent's clip rects have been calculated.
2643 LayoutRect clipRect = paintDirtyRect;
2645 clipRect = backgroundClipRect(rootLayer, paintFlags & PaintLayerTemporaryClipRects);
2646 clipRect.intersect(paintDirtyRect);
2649 // Push the parent coordinate space's clip.
2650 setClip(p, paintDirtyRect, clipRect);
2652 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2653 // This involves subtracting out the position of the layer in our current coordinate space.
2655 convertToLayerCoords(rootLayer, delta);
2656 TransformationMatrix transform(layerTransform);
2657 transform.translateRight(delta.x(), delta.y());
2659 // Apply the transform.
2661 GraphicsContextStateSaver stateSaver(*p);
2662 p->concatCTM(transform.toAffineTransform());
2664 // Now do a paint with the root layer shifted to be us.
2665 paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform);
2668 // Restore the clip.
2669 restoreClip(p, paintDirtyRect, clipRect);
2674 PaintLayerFlags localPaintFlags = paintFlags & ~PaintLayerAppliedTransform;
2675 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
2677 // Paint the reflection first if we have one.
2678 if (m_reflection && !m_paintingInsideReflection) {
2679 // Mark that we are now inside replica painting.
2680 m_paintingInsideReflection = true;
2681 reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection);
2682 m_paintingInsideReflection = false;
2685 // Calculate the clip rects we should use.
2686 LayoutRect layerBounds, damageRect, clipRectToApply, outlineRect;
2687 calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects);
2688 LayoutPoint paintOffset = toPoint(layerBounds.location() - renderBoxLocation());
2690 // Ensure our lists are up-to-date.
2691 updateCompositingAndLayerListsIfNeeded();
2693 bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText;
2694 bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly;
2696 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
2697 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
2698 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
2699 // so it will be tested against as we descend through the renderers.
2700 RenderObject* paintingRootForRenderer = 0;
2701 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
2702 paintingRootForRenderer = paintingRoot;
2704 if (overlapTestRequests && isSelfPaintingLayer())
2705 performOverlapTests(*overlapTestRequests, rootLayer, this);
2707 bool paintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
2709 // We want to paint our layer, but only if we intersect the damage rect.
2710 bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent && isSelfPaintingLayer();
2711 if (shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
2712 // Begin transparency layers lazily now that we know we have to paint something.
2713 if (haveTransparency)
2714 beginTransparencyLayers(p, rootLayer, paintBehavior);
2716 // Paint our background first, before painting any child layers.
2717 // Establish the clip used to paint our background.
2718 setClip(p, paintDirtyRect, damageRect);
2720 // Paint the background.
2721 PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
2722 renderer()->paint(paintInfo, paintOffset);
2724 // Restore the clip.
2725 restoreClip(p, paintDirtyRect, damageRect);
2728 // Now walk the sorted list of children with negative z-indices.
2729 paintList(m_negZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2731 // Now establish the appropriate clip and paint our child RenderObjects.
2732 if (shouldPaint && !clipRectToApply.isEmpty() && !paintingOverlayScrollbars) {
2733 // Begin transparency layers lazily now that we know we have to paint something.
2734 if (haveTransparency)
2735 beginTransparencyLayers(p, rootLayer, paintBehavior);
2737 // Set up the clip used when painting our children.
2738 setClip(p, paintDirtyRect, clipRectToApply);
2739 PaintInfo paintInfo(p, clipRectToApply,
2740 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
2741 forceBlackText, paintingRootForRenderer, 0);
2742 renderer()->paint(paintInfo, paintOffset);
2743 if (!selectionOnly) {
2744 paintInfo.phase = PaintPhaseFloat;
2745 renderer()->paint(paintInfo, paintOffset);
2746 paintInfo.phase = PaintPhaseForeground;
2747 paintInfo.overlapTestRequests = overlapTestRequests;
2748 renderer()->paint(paintInfo, paintOffset);
2749 paintInfo.phase = PaintPhaseChildOutlines;
2750 renderer()->paint(paintInfo, paintOffset);
2753 // Now restore our clip.
2754 restoreClip(p, paintDirtyRect, clipRectToApply);
2757 if (!outlineRect.isEmpty() && isSelfPaintingLayer() && !paintingOverlayScrollbars) {
2758 // Paint our own outline
2759 PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
2760 setClip(p, paintDirtyRect, outlineRect);
2761 renderer()->paint(paintInfo, paintOffset);
2762 restoreClip(p, paintDirtyRect, outlineRect);
2765 // Paint any child layers that have overflow.
2766 paintList(m_normalFlowList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2768 // Now walk the sorted list of children with positive z-indices.
2769 paintList(m_posZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2771 if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
2772 setClip(p, paintDirtyRect, damageRect);
2775 PaintInfo paintInfo(p, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0);
2776 renderer()->paint(paintInfo, paintOffset);
2778 // Restore the clip.
2779 restoreClip(p, paintDirtyRect, damageRect);
2782 if (paintingOverlayScrollbars) {
2783 setClip(p, paintDirtyRect, damageRect);
2784 paintOverflowControls(p, paintOffset, damageRect, true);
2785 restoreClip(p, paintDirtyRect, damageRect);
2788 // End our transparency layer
2789 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
2790 p->endTransparencyLayer();
2792 m_usedTransparency = false;
2796 void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* p,
2797 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2798 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2799 PaintLayerFlags paintFlags)
2804 for (size_t i = 0; i < list->size(); ++i) {
2805 RenderLayer* childLayer = list->at(i);
2806 if (!childLayer->isPaginated())
2807 childLayer->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2809 paintPaginatedChildLayer(childLayer, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2813 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
2814 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2815 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2816 PaintLayerFlags paintFlags)
2818 // We need to do multiple passes, breaking up our child layer into strips.
2819 Vector<RenderLayer*> columnLayers;
2820 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
2821 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
2822 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
2823 columnLayers.append(curr);
2824 if (curr == ancestorLayer)
2828 ASSERT(columnLayers.size());
2830 paintChildLayerIntoColumns(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags, columnLayers, columnLayers.size() - 1);
2833 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
2834 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2835 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2836 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
2838 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
2840 ASSERT(columnBlock && columnBlock->hasColumns());
2841 if (!columnBlock || !columnBlock->hasColumns())
2844 LayoutPoint layerOffset;
2845 // FIXME: It looks suspicious to call convertToLayerCoords here
2846 // as canUseConvertToLayerCoords is true for this layer.
2847 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset);
2849 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
2851 ColumnInfo* colInfo = columnBlock->columnInfo();
2852 unsigned colCount = columnBlock->columnCount(colInfo);
2853 int currLogicalTopOffset = 0;
2854 for (unsigned i = 0; i < colCount; i++) {
2855 // For each rect, we clip to the rect, and then we adjust our coords.
2856 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
2857 columnBlock->flipForWritingMode(colRect);
2858 int logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
2859 LayoutSize offset = isHorizontal ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2861 colRect.moveBy(layerOffset);
2863 LayoutRect localDirtyRect(paintDirtyRect);
2864 localDirtyRect.intersect(colRect);
2866 if (!localDirtyRect.isEmpty()) {
2867 GraphicsContextStateSaver stateSaver(*context);
2869 // Each strip pushes a clip, since column boxes are specified as being
2870 // like overflow:hidden.
2871 context->clip(colRect);
2874 // Apply a translation transform to change where the layer paints.
2875 TransformationMatrix oldTransform;
2876 bool oldHasTransform = childLayer->transform();
2877 if (oldHasTransform)
2878 oldTransform = *childLayer->transform();
2879 TransformationMatrix newTransform(oldTransform);
2880 newTransform.translateRight(offset.width(), offset.height());
2882 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
2883 childLayer->paintLayer(rootLayer, context, localDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2884 if (oldHasTransform)
2885 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
2887 childLayer->m_transform.clear();
2889 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2890 // This involves subtracting out the position of the layer in our current coordinate space.
2891 LayoutPoint childOffset;
2892 columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childOffset);
2893 TransformationMatrix transform;
2894 transform.translateRight(childOffset.x() + offset.width(), childOffset.y() + offset.height());
2896 // Apply the transform.
2897 context->concatCTM(transform.toAffineTransform());
2899 // Now do a paint with the root layer shifted to be the next multicol block.
2900 paintChildLayerIntoColumns(childLayer, columnLayers[colIndex - 1], context, transform.inverse().mapRect(localDirtyRect), paintBehavior,
2901 paintingRoot, overlapTestRequests, paintFlags,
2902 columnLayers, colIndex - 1);
2906 // Move to the next position.
2907 int blockDelta = isHorizontal ? colRect.height() : colRect.width();
2908 if (columnBlock->style()->isFlippedBlocksWritingMode())
2909 currLogicalTopOffset += blockDelta;
2911 currLogicalTopOffset -= blockDelta;
2915 static inline LayoutRect frameVisibleRect(RenderObject* renderer)
2917 FrameView* frameView = renderer->document()->view();
2919 return LayoutRect();
2921 return frameView->visibleContentRect();
2924 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
2926 renderer()->document()->updateLayout();
2928 LayoutRect hitTestArea = renderer()->view()->documentRect();
2929 if (!request.ignoreClipping())
2930 hitTestArea.intersect(frameVisibleRect(renderer()));
2932 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, result.point(), false);
2934 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
2935 // return ourselves. We do this so mouse events continue getting delivered after a drag has
2936 // exited the WebView, and so hit testing over a scrollbar hits the content document.
2937 if ((request.active() || request.mouseUp()) && renderer()->isRenderView()) {
2938 renderer()->updateHitTestResult(result, result.point());
2943 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
2944 Node* node = result.innerNode();
2945 if (node && !result.URLElement())
2946 result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
2948 // Next set up the correct :hover/:active state along the new chain.
2949 updateHoverActiveState(request, result);
2951 // Now return whether we were inside this layer (this will always be true for the root
2956 Node* RenderLayer::enclosingElement() const
2958 for (RenderObject* r = renderer(); r; r = r->parent()) {
2959 if (Node* e = r->node())
2962 ASSERT_NOT_REACHED();
2966 // Compute the z-offset of the point in the transformState.
2967 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
2968 // ray intersects target, and computing the z delta between those two points.
2969 static double computeZOffset(const HitTestingTransformState& transformState)
2971 // We got an affine transform, so no z-offset
2972 if (transformState.m_accumulatedTransform.isAffine())
2975 // Flatten the point into the target plane
2976 FloatPoint targetPoint = transformState.mappedPoint();
2978 // Now map the point back through the transform, which computes Z.
2979 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
2980 return backmappedPoint.z();
2983 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
2984 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint,
2985 const HitTestingTransformState* containerTransformState) const
2987 RefPtr<HitTestingTransformState> transformState;
2989 if (containerTransformState) {
2990 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
2991 transformState = HitTestingTransformState::create(*containerTransformState);
2992 convertToLayerCoords(containerLayer, offset);
2994 // If this is the first time we need to make transform state, then base it off of hitTestPoint,
2995 // which is relative to rootLayer.
2996 transformState = HitTestingTransformState::create(hitTestPoint, FloatQuad(hitTestRect));
2997 convertToLayerCoords(rootLayer, offset);
3000 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
3001 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
3002 TransformationMatrix containerTransform;
3003 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
3004 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
3006 transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
3009 return transformState;
3013 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
3018 // The hit layer is depth-sorting with other layers, so just say that it was hit.
3022 // We need to look at z-depth to decide if this layer was hit.
3024 ASSERT(transformState);
3025 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
3026 double childZOffset = computeZOffset(*transformState);
3027 if (childZOffset > *zOffset) {
3028 *zOffset = childZOffset;
3037 // hitTestPoint and hitTestRect are relative to rootLayer.
3038 // A 'flattening' layer is one preserves3D() == false.
3039 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
3040 // transformState.m_lastPlanarPoint is the hitTestPoint in the plane of the containing flattening layer.
3041 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
3043 // If zOffset is non-null (which indicates that the caller wants z offset information),
3044 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
3045 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
3046 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint, bool appliedTransform,
3047 const HitTestingTransformState* transformState, double* zOffset)
3049 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
3051 bool useTemporaryClipRects = false;
3052 #if USE(ACCELERATED_COMPOSITING)
3053 useTemporaryClipRects = compositor()->inCompositingMode();
3055 useTemporaryClipRects |= renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars();
3057 LayoutRect hitTestArea = result.rectForPoint(hitTestPoint);
3059 // Apply a transform if we have one.
3060 if (transform() && !appliedTransform) {
3061 // Make sure the parent's clip rects have been calculated.
3063 LayoutRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects, IncludeOverlayScrollbarSize);
3064 // Go ahead and test the enclosing clip now.
3065 if (!clipRect.intersects(hitTestArea))
3069 // Create a transform state to accumulate this transform.
3070 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState);
3072 // If the transform can't be inverted, then don't hit test this layer at all.
3073 if (!newTransformState->m_accumulatedTransform.isInvertible())
3076 // Compute the point and the hit test rect in the coords of this layer by using the values
3077 // from the transformState, which store the point and quad in the coords of the last flattened
3078 // layer, and the accumulated transform which lets up map through preserve-3d layers.
3080 // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z)
3081 // by our container.
3082 LayoutPoint localPoint = roundedLayoutPoint(newTransformState->mappedPoint());
3083 LayoutRect localHitTestRect;
3084 #if USE(ACCELERATED_COMPOSITING)
3085 if (isComposited()) {
3086 // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting.
3087 localHitTestRect = backing()->compositedBounds();
3090 localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
3092 // Now do a hit test with the root layer shifted to be us.
3093 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset);
3096 // Ensure our lists and 3d status are up-to-date.
3097 updateCompositingAndLayerListsIfNeeded();
3098 update3DTransformedDescendantStatus();
3100 RefPtr<HitTestingTransformState> localTransformState;
3101 if (appliedTransform) {
3102 // We computed the correct state in the caller (above code), so just reference it.
3103 ASSERT(transformState);
3104 localTransformState = const_cast<HitTestingTransformState*>(transformState);
3105 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
3106 // We need transform state for the first time, or to offset the container state, so create it here.
3107 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState);
3110 // Check for hit test on backface if backface-visibility is 'hidden'
3111 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
3112 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
3113 // If the z-vector of the matrix is negative, the back is facing towards the viewer.
3114 if (invertedMatrix.m33() < 0)
3118 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
3119 if (localTransformState && !preserves3D()) {
3120 // Keep a copy of the pre-flattening state, for computing z-offsets for the container
3121 unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
3122 // This layer is flattening, so flatten the state passed to descendants.
3123 localTransformState->flatten();
3126 // Calculate the clip rects we should use.
3127 LayoutRect layerBounds;
3130 LayoutRect outlineRect;
3131 calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects, IncludeOverlayScrollbarSize);
3133 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
3135 double localZOffset = -numeric_limits<double>::infinity();
3136 double* zOffsetForDescendantsPtr = 0;
3137 double* zOffsetForContentsPtr = 0;
3139 bool depthSortDescendants = false;
3140 if (preserves3D()) {
3141 depthSortDescendants = true;
3142 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
3143 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3144 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3145 } else if (m_has3DTransformedDescendant) {
3146 // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground.
3147 depthSortDescendants = true;
3148 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3149 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3150 } else if (zOffset) {
3151 zOffsetForDescendantsPtr = 0;
3152 // Container needs us to give back a z offset for the hit layer.
3153 zOffsetForContentsPtr = zOffset;
3156 // This variable tracks which layer the mouse ends up being inside.
3157 RenderLayer* candidateLayer = 0;
3159 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
3160 RenderLayer* hitLayer = hitTestList(m_posZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint,
3161 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3163 if (!depthSortDescendants)
3165 candidateLayer = hitLayer;
3168 // Now check our overflow objects.
3169 hitLayer = hitTestList(m_normalFlowList, rootLayer, request, result, hitTestRect, hitTestPoint,
3170 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3172 if (!depthSortDescendants)
3174 candidateLayer = hitLayer;
3177 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
3178 if (fgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
3179 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
3180 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3181 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
3182 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
3183 if (result.isRectBasedTest())
3184 result.append(tempResult);
3186 result = tempResult;
3187 if (!depthSortDescendants)
3189 // Foreground can depth-sort with descendant layers, so keep this as a candidate.
3190 candidateLayer = this;
3191 } else if (result.isRectBasedTest())
3192 result.append(tempResult);
3195 // Now check our negative z-index children.
3196 hitLayer = hitTestList(m_negZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint,
3197 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3199 if (!depthSortDescendants)
3201 candidateLayer = hitLayer;
3204 // If we found a layer, return. Child layers, and foreground always render in front of background.
3206 return candidateLayer;
3208 if (bgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
3209 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3210 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) &&
3211 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
3212 if (result.isRectBasedTest())
3213 result.append(tempResult);
3215 result = tempResult;
3217 } else if (result.isRectBasedTest())
3218 result.append(tempResult);
3224 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const LayoutPoint& hitTestPoint, HitTestFilter hitTestFilter) const
3226 if (!renderer()->hitTest(request, result, hitTestPoint,
3227 toPoint(layerBounds.location() - renderBoxLocation()),
3229 // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
3230 // a rect-based test.
3231 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
3235 // For positioned generated content, we might still not have a
3236 // node by the time we get to the layer level, since none of
3237 // the content in the layer has an element. So just walk up
3239 if (!result.innerNode() || !result.innerNonSharedNode()) {
3240 Node* e = enclosingElement();
3241 if (!result.innerNode())
3242 result.setInnerNode(e);
3243 if (!result.innerNonSharedNode())
3244 result.setInnerNonSharedNode(e);
3250 RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* rootLayer,
3251 const HitTestRequest& request, HitTestResult& result,
3252 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint,
3253 const HitTestingTransformState* transformState,
3254 double* zOffsetForDescendants, double* zOffset,
3255 const HitTestingTransformState* unflattenedTransformState,
3256 bool depthSortDescendants)
3261 RenderLayer* resultLayer = 0;
3262 for (int i = list->size() - 1; i >= 0; --i) {
3263 RenderLayer* childLayer = list->at(i);
3264 RenderLayer* hitLayer = 0;
3265 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3266 if (childLayer->isPaginated())
3267 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants);
3269 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, transformState, zOffsetForDescendants);
3271 // If it a rect-based test, we can safely append the temporary result since it might had hit
3272 // nodes but not necesserily had hitLayer set.
3273 if (result.isRectBasedTest())
3274 result.append(tempResult);
3276 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
3277 resultLayer = hitLayer;
3278 if (!result.isRectBasedTest())
3279 result = tempResult;
3280 if (!depthSortDescendants)
3288 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
3289 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset)
3291 Vector<RenderLayer*> columnLayers;
3292 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
3293 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
3294 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
3295 columnLayers.append(curr);
3296 if (curr == ancestorLayer)
3300 ASSERT(columnLayers.size());
3301 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestPoint, transformState, zOffset,
3302 columnLayers, columnLayers.size() - 1);
3305 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
3306 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset,
3307 const Vector<RenderLayer*>& columnLayers, size_t columnIndex)
3309 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer());
3311 ASSERT(columnBlock && columnBlock->hasColumns());
3312 if (!columnBlock || !columnBlock->hasColumns())
3315 LayoutPoint layerOffset;
3316 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset);
3318 ColumnInfo* colInfo = columnBlock->columnInfo();
3319 int colCount = columnBlock->columnCount(colInfo);
3321 // We have to go backwards from the last column to the first.
3322 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
3323 LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent();
3324 LayoutUnit currLogicalTopOffset = 0;
3326 for (i = 0; i < colCount; i++) {
3327 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
3328 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
3329 if (columnBlock->style()->isFlippedBlocksWritingMode())
3330 currLogicalTopOffset += blockDelta;
3332 currLogicalTopOffset -= blockDelta;
3334 for (i = colCount - 1; i >= 0; i--) {
3335 // For each rect, we clip to the rect, and then we adjust our coords.
3336 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
3337 columnBlock->flipForWritingMode(colRect);
3338 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
3339 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
3340 if (columnBlock->style()->isFlippedBlocksWritingMode())
3341 currLogicalTopOffset -= blockDelta;
3343 currLogicalTopOffset += blockDelta;
3344 colRect.moveBy(layerOffset);
3346 LayoutRect localClipRect(hitTestRect);
3347 localClipRect.intersect(colRect);
3349 LayoutSize offset = isHorizontal ? LayoutSize(currLogicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
3351 if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectForPoint(hitTestPoint))) {
3352 RenderLayer* hitLayer = 0;
3354 // Apply a translation transform to change where the layer paints.
3355 TransformationMatrix oldTransform;
3356 bool oldHasTransform = childLayer->transform();
3357 if (oldHasTransform)
3358 oldTransform = *childLayer->transform();
3359 TransformationMatrix newTransform(oldTransform);
3360 newTransform.translateRight(offset.width(), offset.height());
3362 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
3363 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestPoint, false, transformState, zOffset);
3364 if (oldHasTransform)
3365 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
3367 childLayer->m_transform.clear();
3369 // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space.
3370 // This involves subtracting out the position of the layer in our current coordinate space.
3371 RenderLayer* nextLayer = columnLayers[columnIndex - 1];
3372 RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestPoint, transformState);
3373 newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
3374 LayoutPoint localPoint = roundedLayoutPoint(newTransformState->mappedPoint());
3375 LayoutRect localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
3376 newTransformState->flatten();
3378 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, localPoint,
3379 newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
3390 void RenderLayer::updateClipRects(const RenderLayer* rootLayer, OverlayScrollbarSizeRelevancy relevancy)
3393 ASSERT(rootLayer == m_clipRectsRoot);
3394 return; // We have the correct cached value.
3397 // For transformed layers, the root layer was shifted to be us, so there is no need to
3398 // examine the parent. We want to cache clip rects with us as the root.
3399 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
3401 parentLayer->updateClipRects(rootLayer, relevancy);
3403 ClipRects clipRects;
3404 calculateClipRects(rootLayer, clipRects, true, relevancy);
3406 if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects())
3407 m_clipRects = parentLayer->clipRects();
3409 m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects);
3412 m_clipRectsRoot = rootLayer;
3416 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached, OverlayScrollbarSizeRelevancy relevancy) const
3419 // The root layer's clip rect is always infinite.
3420 clipRects.reset(PaintInfo::infiniteRect());
3424 // For transformed layers, the root layer was shifted to be us, so there is no need to
3425 // examine the parent. We want to cache clip rects with us as the root.
3426 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
3428 // Ensure that our parent's clip has been calculated so that we can examine the values.
3430 if (useCached && parentLayer->clipRects())
3431 clipRects = *parentLayer->clipRects();
3433 parentLayer->calculateClipRects(rootLayer, clipRects);
3436 clipRects.reset(PaintInfo::infiniteRect());
3438 // A fixed object is essentially the root of its containing block hierarchy, so when
3439 // we encounter such an object, we reset our clip rects to the fixedClipRect.
3440 if (renderer()->style()->position() == FixedPosition) {
3441 clipRects.setPosClipRect(clipRects.fixedClipRect());
3442 clipRects.setOverflowClipRect(clipRects.fixedClipRect());
3443 clipRects.setFixed(true);
3445 else if (renderer()->style()->position() == RelativePosition)
3446 clipRects.setPosClipRect(clipRects.overflowClipRect());
3447 else if (renderer()->style()->position() == AbsolutePosition)
3448 clipRects.setOverflowClipRect(clipRects.posClipRect());
3450 // Update the clip rects that will be passed to child layers.
3451 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
3452 // This layer establishes a clip of some kind.
3454 convertToLayerCoords(rootLayer, offset);
3455 RenderView* view = renderer()->view();
3457 if (view && clipRects.fixed() && rootLayer->renderer() == view) {
3458 offset -= view->frameView()->scrollOffsetForFixedPosition();
3461 if (renderer()->hasOverflowClip()) {
3462 LayoutRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(offset, relevancy);
3463 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
3464 if (renderer()->isPositioned() || renderer()->isRelPositioned())
3465 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
3467 if (renderer()->hasClip()) {
3468 LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset);
3469 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
3470 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
3471 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
3476 void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
3479 if (temporaryClipRects) {
3480 parent()->calculateClipRects(rootLayer, clipRects, false, relevancy);
3484 parent()->updateClipRects(rootLayer, relevancy);
3485 clipRects = *parent()->clipRects();
3488 LayoutRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
3490 LayoutRect backgroundRect;
3492 ClipRects parentRects;
3493 parentClipRects(rootLayer, parentRects, temporaryClipRects, relevancy);
3494 backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() :
3495 (renderer()->isPositioned() ? parentRects.posClipRect() :
3496 parentRects.overflowClipRect());
3497 RenderView* view = renderer()->view();
3499 if (view && parentRects.fixed() && rootLayer->renderer() == view)
3500 backgroundRect.move(view->frameView()->scrollXForFixedPosition(), view->frameView()->scrollYForFixedPosition());
3502 return backgroundRect;
3505 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
3506 LayoutRect& backgroundRect, LayoutRect& foregroundRect, LayoutRect& outlineRect, bool temporaryClipRects,
3507 OverlayScrollbarSizeRelevancy relevancy) const
3509 if (rootLayer != this && parent()) {
3510 backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects, relevancy);
3511 backgroundRect.intersect(paintDirtyRect);
3513 backgroundRect = paintDirtyRect;
3515 foregroundRect = backgroundRect;
3516 outlineRect = backgroundRect;
3519 convertToLayerCoords(rootLayer, offset);
3520 layerBounds = LayoutRect(offset, size());
3522 // Update the clip rects that will be passed to child layers.
3523 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
3524 // This layer establishes a clip of some kind.
3525 if (renderer()->hasOverflowClip())
3526 foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, relevancy));
3527 if (renderer()->hasClip()) {
3528 // Clip applies to *us* as well, so go ahead and update the damageRect.
3529 LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset);
3530 backgroundRect.intersect(newPosClip);
3531 foregroundRect.intersect(newPosClip);
3532 outlineRect.intersect(newPosClip);
3535 // If we establish a clip at all, then go ahead and make sure our background
3536 // rect is intersected with our layer's bounds including our visual overflow,
3537 // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden.
3538 LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect();
3539 renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped.
3540 layerBoundsWithVisualOverflow.moveBy(offset);
3541 backgroundRect.intersect(layerBoundsWithVisualOverflow);
3545 LayoutRect RenderLayer::childrenClipRect() const
3547 RenderView* renderView = renderer()->view();
3548 RenderLayer* clippingRootLayer = clippingRoot();
3549 LayoutRect layerBounds, backgroundRect, foregroundRect, outlineRect;
3550 calculateRects(clippingRootLayer, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
3551 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect)).enclosingBoundingBox();
3554 LayoutRect RenderLayer::selfClipRect() const
3556 RenderView* renderView = renderer()->view();
3557 RenderLayer* clippingRootLayer = clippingRoot();
3558 LayoutRect layerBounds, backgroundRect, foregroundRect, outlineRect;
3559 calculateRects(clippingRootLayer, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
3560 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect)).enclosingBoundingBox();
3563 void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds)
3565 m_blockSelectionGapsBounds.unite(bounds);
3568 void RenderLayer::clearBlockSelectionGapsBounds()
3570 m_blockSelectionGapsBounds = LayoutRect();
3571 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3572 child->clearBlockSelectionGapsBounds();
3575 void RenderLayer::repaintBlockSelectionGaps()
3577 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3578 child->repaintBlockSelectionGaps();
3580 if (m_blockSelectionGapsBounds.isEmpty())
3583 LayoutRect rect = m_blockSelectionGapsBounds;
3584 rect.move(-scrolledContentOffset());
3585 if (renderer()->hasOverflowClip())
3586 rect.intersect(toRenderBox(renderer())->overflowClipRect(LayoutPoint()));
3587 if (renderer()->hasClip())
3588 rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint()));
3589 if (!rect.isEmpty())
3590 renderer()->repaintRectangle(rect);
3593 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer) const
3595 // Always examine the canvas and the root.
3596 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
3597 // paints the root's background.
3598 if (renderer()->isRenderView() || renderer()->isRoot())
3601 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
3602 // can go ahead and return true.
3603 RenderView* view = renderer()->view();
3605 if (view && !renderer()->isRenderInline()) {
3606 LayoutRect b = layerBounds;
3607 b.inflate(view->maximalOutlineSize());
3608 if (b.intersects(damageRect))
3612 // Otherwise we need to compute the bounding box of this single layer and see if it intersects
3614 return boundingBox(rootLayer).intersects(damageRect);
3617 LayoutRect RenderLayer::localBoundingBox() const
3619 // There are three special cases we need to consider.
3620 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
3621 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
3622 // line boxes of all three lines (including overflow on those lines).
3623 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
3624 // overflow, we have to create a bounding box that will extend to include this overflow.
3625 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
3626 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
3629 if (renderer()->isRenderInline())
3630 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
3631 else if (renderer()->isTableRow()) {
3632 // Our bounding box is just the union of all of our cells' border/overflow rects.
3633 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
3634 if (child->isTableCell()) {
3635 LayoutRect bbox = toRenderBox(child)->borderBoxRect();
3637 LayoutRect overflowRect = renderBox()->visualOverflowRect();
3638 if (bbox != overflowRect)
3639 result.unite(overflowRect);
3643 RenderBox* box = renderBox();
3645 if (box->hasMask()) {
3646 result = box->maskClipRect();
3647 box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not.
3649 LayoutRect bbox = box->borderBoxRect();
3651 LayoutRect overflowRect = box->visualOverflowRect();
3652 if (bbox != overflowRect)
3653 result.unite(overflowRect);
3657 RenderView* view = renderer()->view();
3660 result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
3665 LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const
3667 LayoutRect result = localBoundingBox();
3668 if (renderer()->isBox())
3669 renderBox()->flipForWritingMode(result);
3671 renderer()->containingBlock()->flipForWritingMode(result);
3673 convertToLayerCoords(ancestorLayer, delta);
3674 result.moveBy(delta);
3678 LayoutRect RenderLayer::absoluteBoundingBox() const
3680 return boundingBox(root());
3683 void RenderLayer::clearClipRectsIncludingDescendants()
3690 for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
3691 l->clearClipRectsIncludingDescendants();
3694 void RenderLayer::clearClipRects()
3697 m_clipRects->deref(renderer()->renderArena());
3700 m_clipRectsRoot = 0;
3705 #if USE(ACCELERATED_COMPOSITING)
3706 RenderLayerBacking* RenderLayer::ensureBacking()
3709 m_backing = adoptPtr(new RenderLayerBacking(this));
3710 return m_backing.get();
3713 void RenderLayer::clearBacking()
3718 bool RenderLayer::hasCompositedMask() const
3720 return m_backing && m_backing->hasMaskLayer();
3723 GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const
3725 return m_backing ? m_backing->layerForHorizontalScrollbar() : 0;
3728 GraphicsLayer* RenderLayer::layerForVerticalScrollbar() const
3730 return m_backing ? m_backing->layerForVerticalScrollbar() : 0;
3733 GraphicsLayer* RenderLayer::layerForScrollCorner() const
3735 return m_backing ? m_backing->layerForScrollCorner() : 0;
3739 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
3741 #if USE(ACCELERATED_COMPOSITING)
3742 bool paintsToWindow = !isComposited() || backing()->paintingGoesToWindow();
3744 bool paintsToWindow = true;
3746 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || paintsToWindow);
3749 void RenderLayer::setParent(RenderLayer* parent)
3751 if (parent == m_parent)
3754 #if USE(ACCELERATED_COMPOSITING)
3755 if (m_parent && !renderer()->documentBeingDestroyed())
3756 compositor()->layerWillBeRemoved(m_parent, this);
3761 #if USE(ACCELERATED_COMPOSITING)
3762 if (m_parent && !renderer()->documentBeingDestroyed())
3763 compositor()->layerWasAdded(m_parent, this);
3767 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
3772 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
3773 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
3774 if (currObj1 == currObj2)
3780 void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
3782 // We don't update :hover/:active state when the result is marked as readOnly.
3783 if (request.readOnly())
3786 Document* doc = renderer()->document();
3788 Node* activeNode = doc->activeNode();
3789 if (activeNode && !request.active()) {
3790 // We are clearing the :active chain because the mouse has been released.
3791 for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
3792 if (curr->node() && !curr->isText())
3793 curr->node()->clearInActiveChain();
3795 doc->setActiveNode(0);
3797 Node* newActiveNode = result.innerNode();
3798 if (!activeNode && newActiveNode && request.active()) {
3799 // We are setting the :active chain and freezing it. If future moves happen, they
3800 // will need to reference this chain.
3801 for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
3802 if (curr->node() && !curr->isText()) {
3803 curr->node()->setInActiveChain();
3806 doc->setActiveNode(newActiveNode);
3810 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
3811 // :hover/:active to only apply to elements that are in the :active chain that we froze
3812 // at the time the mouse went down.
3813 bool mustBeInActiveChain = request.active() && request.mouseMove();
3815 // Check to see if the hovered node has changed. If not, then we don't need to
3817 RefPtr<Node> oldHoverNode = doc->hoverNode();
3818 Node* newHoverNode = result.innerNode();
3820 // Update our current hover node.
3821 doc->setHoverNode(newHoverNode);
3823 // We have two different objects. Fetch their renderers.
3824 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
3825 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
3827 // Locate the common ancestor render object for the two renderers.
3828 RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
3830 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
3831 Vector<RefPtr<Node>, 32> nodesToAddToChain;
3833 if (oldHoverObj != newHoverObj) {
3834 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
3835 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
3836 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
3837 nodesToRemoveFromChain.append(curr->node());
3841 // Now set the hover state for our new object up to the root.
3842 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
3843 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
3844 nodesToAddToChain.append(curr->node());
3847 size_t removeCount = nodesToRemoveFromChain.size();
3848 for (size_t i = 0; i < removeCount; ++i) {
3849 nodesToRemoveFromChain[i]->setActive(false);
3850 nodesToRemoveFromChain[i]->setHovered(false);
3853 size_t addCount = nodesToAddToChain.size();
3854 for (size_t i = 0; i < addCount; ++i) {
3855 nodesToAddToChain[i]->setActive(request.active());
3856 nodesToAddToChain[i]->setHovered(true);
3860 // Helper for the sorting of layers by z-index.
3861 static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
3863 return first->zIndex() < second->zIndex();
3866 void RenderLayer::dirtyZOrderLists()
3868 if (m_posZOrderList)
3869 m_posZOrderList->clear();
3870 if (m_negZOrderList)
3871 m_negZOrderList->clear();
3872 m_zOrderListsDirty = true;
3874 #if USE(ACCELERATED_COMPOSITING)
3875 if (!renderer()->documentBeingDestroyed())
3876 compositor()->setCompositingLayersNeedRebuild();
3880 void RenderLayer::dirtyStackingContextZOrderLists()
3882 RenderLayer* sc = stackingContext();
3884 sc->dirtyZOrderLists();
3887 void RenderLayer::dirtyNormalFlowList()
3889 if (m_normalFlowList)
3890 m_normalFlowList->clear();
3891 m_normalFlowListDirty = true;
3893 #if USE(ACCELERATED_COMPOSITING)
3894 if (!renderer()->documentBeingDestroyed())
3895 compositor()->setCompositingLayersNeedRebuild();
3899 void RenderLayer::updateZOrderLists()
3901 if (!isStackingContext() || !m_zOrderListsDirty)
3904 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3905 if (!m_reflection || reflectionLayer() != child)
3906 child->collectLayers(m_posZOrderList, m_negZOrderList);
3908 // Sort the two lists.
3909 if (m_posZOrderList)
3910 std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
3912 if (m_negZOrderList)
3913 std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
3915 m_zOrderListsDirty = false;
3918 void RenderLayer::updateNormalFlowList()
3920 if (!m_normalFlowListDirty)
3923 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
3924 // Ignore non-overflow layers and reflections.
3925 if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) {
3926 if (!m_normalFlowList)
3927 m_normalFlowList = new Vector<RenderLayer*>;
3928 m_normalFlowList->append(child);
3932 m_normalFlowListDirty = false;
3935 void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
3937 updateVisibilityStatus();
3939 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
3940 if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isNormalFlowOnly() && !renderer()->isRenderFlowThread()) {
3941 // Determine which buffer the child should be in.
3942 Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
3944 // Create the buffer if it doesn't exist yet.
3946 buffer = new Vector<RenderLayer*>;
3948 // Append ourselves at the end of the appropriate buffer.
3949 buffer->append(this);
3952 // Recur into our children to collect more layers, but only if we don't establish
3953 // a stacking context.
3954 if (m_hasVisibleDescendant && !isStackingContext()) {
3955 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
3956 // Ignore reflections.
3957 if (!m_reflection || reflectionLayer() != child)
3958 child->collectLayers(posBuffer, negBuffer);
3963 void RenderLayer::updateLayerListsIfNeeded()
3965 updateZOrderLists();
3966 updateNormalFlowList();
3969 void RenderLayer::updateCompositingAndLayerListsIfNeeded()
3971 #if USE(ACCELERATED_COMPOSITING)
3972 if (compositor()->inCompositingMode()) {
3973 if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty)
3974 compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this);
3978 updateLayerListsIfNeeded();
3981 void RenderLayer::repaintIncludingDescendants()
3983 renderer()->repaint();
3984 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
3985 curr->repaintIncludingDescendants();
3988 #if USE(ACCELERATED_COMPOSITING)
3989 void RenderLayer::setBackingNeedsRepaint()
3991 ASSERT(isComposited());
3992 if (backing()->paintingGoesToWindow()) {
3993 // If we're trying to repaint the placeholder document layer, propagate the
3994 // repaint to the native view system.
3995 RenderView* view = renderer()->view();
3997 view->repaintViewRectangle(absoluteBoundingBox());
3999 backing()->setContentsNeedDisplay();
4002 void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r)
4004 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here,
4005 // so assert but check that the layer is composited.
4006 ASSERT(isComposited());
4007 if (!isComposited() || backing()->paintingGoesToWindow()) {
4008 // If we're trying to repaint the placeholder document layer, propagate the
4009 // repaint to the native view system.
4010 LayoutRect absRect(r);
4012 convertToLayerCoords(root(), delta);
4013 absRect.moveBy(delta);
4015 RenderView* view = renderer()->view();
4017 view->repaintViewRectangle(absRect);
4019 backing()->setContentsNeedDisplayInRect(r);
4022 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
4023 void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer)
4025 renderer()->repaintUsingContainer(repaintContainer, renderer()->clippedOverflowRectForRepaint(repaintContainer));
4027 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
4028 if (!curr->isComposited())
4029 curr->repaintIncludingNonCompositingDescendants(repaintContainer);
4034 bool RenderLayer::shouldBeNormalFlowOnly() const
4036 return (renderer()->hasOverflowClip()
4037 || renderer()->hasReflection()
4038 || renderer()->hasMask()
4039 || renderer()->isCanvas()
4040 || renderer()->isVideo()
4041 || renderer()->isEmbeddedObject()
4042 || renderer()->isApplet()
4043 || renderer()->isRenderIFrame()
4044 || renderer()->style()->specifiesColumns())
4045 && !renderer()->isPositioned()
4046 && !renderer()->isRelPositioned()
4047 && !renderer()->hasTransform()
4048 && !isTransparent();
4051 bool RenderLayer::isSelfPaintingLayer() const
4053 return !isNormalFlowOnly()
4054 || renderer()->hasReflection()
4055 || renderer()->hasMask()
4056 || renderer()->isTableRow()
4057 || renderer()->isCanvas()
4058 || renderer()->isVideo()
4059 || renderer()->isEmbeddedObject()
4060 || renderer()->isApplet()
4061 || renderer()->isRenderIFrame();
4064 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
4066 bool isNormalFlowOnly = shouldBeNormalFlowOnly();
4067 if (isNormalFlowOnly != m_isNormalFlowOnly) {
4068 m_isNormalFlowOnly = isNormalFlowOnly;
4069 RenderLayer* p = parent();
4071 p->dirtyNormalFlowList();
4072 dirtyStackingContextZOrderLists();
4075 if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) {
4077 m_marquee = new RenderMarquee(this);
4078 m_marquee->updateMarqueeStyle();
4080 else if (m_marquee) {
4085 if (!hasReflection() && m_reflection)
4087 else if (hasReflection()) {
4090 updateReflectionStyle();
4093 if (scrollsOverflow()) {
4094 if (!m_scrollableAreaPage) {
4095 if (Frame* frame = renderer()->frame()) {
4096 if (Page* page = frame->page()) {
4097 m_scrollableAreaPage = page;
4098 m_scrollableAreaPage->addScrollableArea(this);
4102 } else if (m_scrollableAreaPage) {
4103 m_scrollableAreaPage->removeScrollableArea(this);
4104 m_scrollableAreaPage = 0;
4107 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
4109 m_hBar->styleChanged();
4111 m_vBar->styleChanged();
4113 updateScrollCornerStyle();
4114 updateResizerStyle();
4116 #if USE(ACCELERATED_COMPOSITING)
4119 if (compositor()->updateLayerCompositingState(this))
4120 compositor()->setCompositingLayersNeedRebuild();
4122 m_backing->updateGraphicsLayerGeometry();
4123 else if (oldStyle && oldStyle->overflowX() != renderer()->style()->overflowX()) {
4124 if (stackingContext()->hasCompositingDescendant())
4125 compositor()->setCompositingLayersNeedRebuild();
4128 if (m_backing && diff >= StyleDifferenceRepaint)
4129 m_backing->setContentsNeedDisplay();
4135 void RenderLayer::updateScrollCornerStyle()
4137 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
4138 RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
4140 if (!m_scrollCorner) {
4141 m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
4142 m_scrollCorner->setParent(renderer());
4144 m_scrollCorner->setStyle(corner.release());
4145 } else if (m_scrollCorner) {
4146 m_scrollCorner->destroy();
4151 void RenderLayer::updateResizerStyle()
4153 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
4154 RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
4157 m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
4158 m_resizer->setParent(renderer());
4160 m_resizer->setStyle(resizer.release());
4161 } else if (m_resizer) {
4162 m_resizer->destroy();
4167 RenderLayer* RenderLayer::reflectionLayer() const
4169 return m_reflection ? m_reflection->layer() : 0;
4172 void RenderLayer::createReflection()
4174 ASSERT(!m_reflection);
4175 m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document());
4176 m_reflection->setParent(renderer()); // We create a 1-way connection.
4179 void RenderLayer::removeReflection()
4181 if (!m_reflection->documentBeingDestroyed())
4182 m_reflection->removeLayers(this);
4184 m_reflection->setParent(0);
4185 m_reflection->destroy();
4189 void RenderLayer::updateReflectionStyle()
4191 RefPtr<RenderStyle> newStyle = RenderStyle::create();
4192 newStyle->inheritFrom(renderer()->style());
4194 // Map in our transform.
4195 TransformOperations transform;
4196 switch (renderer()->style()->boxReflect()->direction()) {
4197 case ReflectionBelow:
4198 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
4199 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
4200 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
4202 case ReflectionAbove:
4203 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
4204 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
4205 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
4207 case ReflectionRight:
4208 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
4209 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
4210 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
4212 case ReflectionLeft:
4213 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
4214 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
4215 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
4218 newStyle->setTransform(transform);
4221 newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask());
4223 m_reflection->setStyle(newStyle.release());
4226 } // namespace WebCore
4229 void showLayerTree(const WebCore::RenderLayer* layer)
4234 if (WebCore::Frame* frame = layer->renderer()->frame()) {
4235 WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState);
4236 fprintf(stderr, "%s\n", output.utf8().data());
4240 void showLayerTree(const WebCore::RenderObject* renderer)
4244 showLayerTree(renderer->enclosingLayer());