2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 "CSSStyleSelector.h"
52 #include "DocumentEventQueue.h"
53 #include "EventHandler.h"
54 #if ENABLE(CSS_FILTERS)
55 #include "FEColorMatrix.h"
57 #include "FilterEffectRenderer.h"
59 #include "FloatConversion.h"
60 #include "FloatPoint3D.h"
61 #include "FloatRect.h"
62 #include "FocusController.h"
64 #include "FrameSelection.h"
65 #include "FrameTree.h"
66 #include "FrameView.h"
68 #include "GraphicsContext.h"
69 #include "HTMLFrameElement.h"
70 #include "HTMLFrameOwnerElement.h"
71 #include "HTMLNames.h"
72 #include "HitTestingTransformState.h"
73 #include "HitTestRequest.h"
74 #include "HitTestResult.h"
75 #include "OverflowEvent.h"
76 #include "OverlapTestRequestClient.h"
78 #include "PlatformMouseEvent.h"
79 #include "RenderArena.h"
80 #include "RenderFlowThread.h"
81 #include "RenderInline.h"
82 #include "RenderMarquee.h"
83 #include "RenderReplica.h"
84 #include "RenderScrollbar.h"
85 #include "RenderScrollbarPart.h"
86 #include "RenderTheme.h"
87 #include "RenderTreeAsText.h"
88 #include "RenderView.h"
89 #include "ScaleTransformOperation.h"
90 #include "Scrollbar.h"
91 #include "ScrollbarTheme.h"
93 #include "SourceGraphic.h"
94 #include "StylePropertySet.h"
95 #include "TextStream.h"
96 #include "TransformationMatrix.h"
97 #include "TranslateTransformOperation.h"
98 #include <wtf/StdLibExtras.h>
99 #include <wtf/UnusedParam.h>
100 #include <wtf/text/CString.h>
102 #if USE(ACCELERATED_COMPOSITING)
103 #include "RenderLayerBacking.h"
104 #include "RenderLayerCompositor.h"
108 #include "SVGNames.h"
111 #if PLATFORM(CHROMIUM) || PLATFORM(BLACKBERRY)
112 // FIXME: border radius clipping triggers too-slow path on Chromium
113 // https://bugs.webkit.org/show_bug.cgi?id=69866
114 #define DISABLE_ROUNDED_CORNER_CLIPPING
117 #define MIN_INTERSECT_FOR_REVEAL 32
123 using namespace HTMLNames;
125 const int MinimumWidthWhileResizing = 100;
126 const int MinimumHeightWhileResizing = 40;
128 void* ClipRects::operator new(size_t sz, RenderArena* renderArena)
130 return renderArena->allocate(sz);
133 void ClipRects::operator delete(void* ptr, size_t sz)
135 // Stash size where destroy can find it.
139 void ClipRects::destroy(RenderArena* renderArena)
143 // Recover the size left there for us by operator delete and free the memory.
144 renderArena->free(*(size_t *)this, this);
147 RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
148 : m_inResizeMode(false)
149 , m_scrollDimensionsDirty(true)
150 , m_zOrderListsDirty(true)
151 , m_normalFlowListDirty(true)
152 , m_usedTransparency(false)
153 , m_paintingInsideReflection(false)
154 , m_inOverflowRelayout(false)
155 , m_repaintStatus(NeedsNormalRepaint)
156 , m_visibleContentStatusDirty(true)
157 , m_hasVisibleContent(false)
158 , m_visibleDescendantStatusDirty(false)
159 , m_hasVisibleDescendant(false)
160 , m_isPaginated(false)
161 , m_3DTransformedDescendantStatusDirty(true)
162 , m_has3DTransformedDescendant(false)
163 #if USE(ACCELERATED_COMPOSITING)
164 , m_hasCompositingDescendant(false)
165 , m_mustOverlapCompositedLayers(false)
167 , m_containsDirtyOverlayScrollbars(false)
169 , m_layerListMutationAllowed(true)
171 , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell())
172 , m_renderer(renderer)
180 , m_normalFlowList(0)
186 , m_staticInlinePosition(0)
187 , m_staticBlockPosition(0)
192 m_isNormalFlowOnly = shouldBeNormalFlowOnly();
194 ScrollableArea::setConstrainsScrollingToContentEdge(false);
196 if (!renderer->firstChild() && renderer->style()) {
197 m_visibleContentStatusDirty = false;
198 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
201 Node* node = renderer->node();
202 if (node && node->isElementNode()) {
203 // We save and restore only the scrollOffset as the other scroll values are recalculated.
204 Element* element = toElement(node);
205 m_scrollOffset = element->savedLayerScrollOffset();
206 element->setSavedLayerScrollOffset(IntSize());
210 RenderLayer::~RenderLayer()
212 if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
213 if (Frame* frame = renderer()->frame())
214 frame->eventHandler()->resizeLayerDestroyed();
217 if (Frame* frame = renderer()->frame()) {
218 if (FrameView* frameView = frame->view())
219 frameView->removeScrollableArea(this);
222 if (!m_renderer->documentBeingDestroyed()) {
223 Node* node = m_renderer->node();
224 if (node && node->isElementNode())
225 toElement(node)->setSavedLayerScrollOffset(m_scrollOffset);
228 destroyScrollbar(HorizontalScrollbar);
229 destroyScrollbar(VerticalScrollbar);
234 // Child layers will be deleted by their corresponding render objects, so
235 // we don't need to delete them ourselves.
237 delete m_posZOrderList;
238 delete m_negZOrderList;
239 delete m_normalFlowList;
242 #if USE(ACCELERATED_COMPOSITING)
246 // Make sure we have no lingering clip rects.
247 ASSERT(!m_clipRects);
250 m_scrollCorner->destroy();
252 m_resizer->destroy();
255 #if USE(ACCELERATED_COMPOSITING)
256 RenderLayerCompositor* RenderLayer::compositor() const
258 ASSERT(renderer()->view());
259 return renderer()->view()->compositor();
262 void RenderLayer::contentChanged(ContentChangeType changeType)
264 // This can get called when video becomes accelerated, so the layers may change.
265 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this))
266 compositor()->setCompositingLayersNeedRebuild();
269 m_backing->contentChanged(changeType);
271 #endif // USE(ACCELERATED_COMPOSITING)
273 bool RenderLayer::canRender3DTransforms() const
275 #if USE(ACCELERATED_COMPOSITING)
276 return compositor()->canRender3DTransforms();
282 #if ENABLE(CSS_FILTERS)
283 bool RenderLayer::paintsWithFilters() const
285 // FIXME: Eventually there will be more factors than isComposited() to decide whether or not to render the filter
286 if (!renderer()->hasFilter())
292 if (!m_backing || !m_backing->canCompositeFilters())
298 bool RenderLayer::requiresFullLayerImageForFilters() const
300 // FIXME: This can be optimized to enlarge the repaint rect exactly with the amount that is going to be used.
301 // https://bugs.webkit.org/show_bug.cgi?id=81263
302 return paintsWithFilters() && filter() && filter()->hasFilterThatMovesPixels();
306 LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
308 hasLayerOffset = true;
311 return LayoutPoint();
313 // This is similar to root() but we check if an ancestor layer would
314 // prevent the optimization from working.
315 const RenderLayer* rootLayer = 0;
316 for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
317 hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
319 return LayoutPoint();
321 ASSERT(rootLayer == root());
324 parent()->convertToLayerCoords(rootLayer, offset);
328 void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerPositionsFlags flags)
331 if (offsetFromRoot) {
333 LayoutPoint computedOffsetFromRoot = computeOffsetFromRoot(hasLayerOffset);
334 ASSERT(hasLayerOffset);
335 ASSERT(*offsetFromRoot == computedOffsetFromRoot);
339 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
340 // we need to keep in sync, since we may have shifted relative
341 // to our parent layer.
342 LayoutPoint oldOffsetFromRoot;
343 if (offsetFromRoot) {
344 // We can't cache our offset to the repaint container if the mapping is anything more complex than a simple translation
345 if (!canUseConvertToLayerCoords())
346 offsetFromRoot = 0; // If our cached offset is invalid make sure it's not passed to any of our children
348 oldOffsetFromRoot = *offsetFromRoot;
349 // Frequently our parent layer's renderer will be the same as our renderer's containing block. In that case,
350 // we just update the cache using our offset to our parent (which is m_topLeft). Otherwise, regenerated cached
351 // offsets to the root from the render tree.
352 if (!m_parent || m_parent->renderer() == renderer()->containingBlock())
353 offsetFromRoot->move(m_topLeft.x(), m_topLeft.y()); // Fast case
356 convertToLayerCoords(root(), offset);
357 *offsetFromRoot = offset;
363 if (offsetFromRoot) {
364 offset = *offsetFromRoot;
366 LayoutPoint computedOffsetFromRoot;
367 convertToLayerCoords(root(), computedOffsetFromRoot);
368 ASSERT(offset == computedOffsetFromRoot);
371 // FIXME: It looks suspicious to call convertToLayerCoords here
372 // as canUseConvertToLayerCoords may be true for an ancestor layer.
373 convertToLayerCoords(root(), offset);
375 positionOverflowControls(toSize(roundedIntPoint(offset)));
377 updateVisibilityStatus();
379 if (flags & UpdatePagination)
382 m_isPaginated = false;
384 if (m_hasVisibleContent) {
385 RenderView* view = renderer()->view();
387 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
388 // mapping between them and the RenderObjects. It would be neat to enable
389 // LayoutState outside the layout() phase and use it here.
390 ASSERT(!view->layoutStateEnabled());
392 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
393 LayoutRect oldRepaintRect = m_repaintRect;
394 LayoutRect oldOutlineBox = m_outlineBox;
395 computeRepaintRects(offsetFromRoot);
396 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
397 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
398 if (flags & CheckForRepaint) {
399 if (view && !view->printing()) {
400 if (m_repaintStatus & NeedsFullRepaint) {
401 renderer()->repaintUsingContainer(repaintContainer, oldRepaintRect);
402 if (m_repaintRect != oldRepaintRect)
403 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
404 } else if (shouldRepaintAfterLayout())
405 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
411 m_repaintStatus = NeedsNormalRepaint;
413 // Go ahead and update the reflection's position and size.
415 m_reflection->layout();
417 #if USE(ACCELERATED_COMPOSITING)
418 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
419 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
421 flags &= ~IsCompositingUpdateRoot;
424 if (renderer()->hasColumns())
425 flags |= UpdatePagination;
427 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
428 child->updateLayerPositions(offsetFromRoot, flags);
430 #if USE(ACCELERATED_COMPOSITING)
431 if ((flags & UpdateCompositingLayers) && isComposited())
432 backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
435 // With all our children positioned, now update our marquee if we need to.
437 m_marquee->updateMarqueePosition();
440 *offsetFromRoot = oldOffsetFromRoot;
443 LayoutRect RenderLayer::repaintRectIncludingDescendants() const
445 LayoutRect repaintRect = m_repaintRect;
446 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
447 repaintRect.unite(child->repaintRectIncludingDescendants());
451 void RenderLayer::computeRepaintRects(LayoutPoint* offsetFromRoot)
453 ASSERT(!m_visibleContentStatusDirty);
455 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
456 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
457 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, offsetFromRoot);
460 void RenderLayer::clearRepaintRects()
462 ASSERT(!m_hasVisibleContent);
463 ASSERT(!m_visibleContentStatusDirty);
465 m_repaintRect = IntRect();
466 m_outlineBox = IntRect();
469 void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrollFlags flags)
471 // FIXME: This shouldn't be needed, but there are some corner cases where
472 // these flags are still dirty. Update so that the check below is valid.
473 updateVisibilityStatus();
475 // If we have no visible content and no visible descendants, there is no point recomputing
476 // our rectangles as they will be empty. If our visibility changes, we are expected to
477 // recompute all our positions anyway.
478 if (!m_hasVisibleDescendant && !m_hasVisibleContent)
481 updateLayerPosition();
483 if ((flags & HasSeenFixedPositionedAncestor) || renderer()->style()->position() == FixedPosition) {
484 // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions?
485 computeRepaintRects();
486 flags |= HasSeenFixedPositionedAncestor;
487 } else if ((flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) {
488 // If we have seen an overflow clip, we should update our repaint rects as clippedOverflowRectForRepaint
489 // intersects it with our ancestor overflow clip that may have moved.
490 computeRepaintRects();
493 if (renderer()->hasOverflowClip())
494 flags |= HasSeenAncestorWithOverflowClip;
496 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
497 child->updateLayerPositionsAfterScroll(flags);
499 // We don't update our reflection as scrolling is a translation which does not change the size()
500 // of an object, thus RenderReplica will still repaint itself properly as the layer position was
504 m_marquee->updateMarqueePosition();
507 void RenderLayer::updateTransform()
509 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
510 // so check style too.
511 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
512 bool had3DTransform = has3DTransform();
514 bool hadTransform = m_transform;
515 if (hasTransform != hadTransform) {
517 m_transform = adoptPtr(new TransformationMatrix);
523 RenderBox* box = renderBox();
525 m_transform->makeIdentity();
526 box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
527 makeMatrixRenderable(*m_transform, canRender3DTransforms());
530 if (had3DTransform != has3DTransform())
531 dirty3DTransformedDescendantStatus();
534 TransformationMatrix RenderLayer::currentTransform() const
537 return TransformationMatrix();
539 #if USE(ACCELERATED_COMPOSITING)
540 if (renderer()->style()->isRunningAcceleratedAnimation()) {
541 TransformationMatrix currTransform;
542 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
543 style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
544 makeMatrixRenderable(currTransform, canRender3DTransforms());
545 return currTransform;
552 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
555 return TransformationMatrix();
557 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
558 TransformationMatrix matrix = *m_transform;
559 makeMatrixRenderable(matrix, false /* flatten 3d */);
566 static bool checkContainingBlockChainForPagination(RenderBoxModelObject* renderer, RenderBox* ancestorColumnsRenderer)
568 RenderView* view = renderer->view();
569 RenderBoxModelObject* prevBlock = renderer;
570 RenderBlock* containingBlock;
571 for (containingBlock = renderer->containingBlock();
572 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
573 containingBlock = containingBlock->containingBlock())
574 prevBlock = containingBlock;
576 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
577 if (containingBlock != ancestorColumnsRenderer)
580 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
581 if (prevBlock->isPositioned())
584 // Otherwise we are paginated by the columns block.
588 void RenderLayer::updatePagination()
590 m_isPaginated = false;
591 if (isComposited() || !parent())
592 return; // FIXME: We will have to deal with paginated compositing layers someday.
593 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
595 if (isNormalFlowOnly()) {
596 m_isPaginated = parent()->renderer()->hasColumns();
600 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context.
601 RenderLayer* ancestorStackingContext = stackingContext();
602 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
603 if (curr->renderer()->hasColumns()) {
604 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
607 if (curr == ancestorStackingContext)
612 void RenderLayer::setHasVisibleContent(bool b)
614 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
616 m_visibleContentStatusDirty = false;
617 m_hasVisibleContent = b;
618 if (m_hasVisibleContent) {
619 computeRepaintRects();
620 if (!isNormalFlowOnly()) {
621 for (RenderLayer* sc = stackingContext(); sc; sc = sc->stackingContext()) {
622 sc->dirtyZOrderLists();
623 if (sc->hasVisibleContent())
629 parent()->childVisibilityChanged(m_hasVisibleContent);
632 void RenderLayer::dirtyVisibleContentStatus()
634 m_visibleContentStatusDirty = true;
636 parent()->dirtyVisibleDescendantStatus();
639 void RenderLayer::childVisibilityChanged(bool newVisibility)
641 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
644 RenderLayer* l = this;
645 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
646 l->m_hasVisibleDescendant = true;
650 dirtyVisibleDescendantStatus();
653 void RenderLayer::dirtyVisibleDescendantStatus()
655 RenderLayer* l = this;
656 while (l && !l->m_visibleDescendantStatusDirty) {
657 l->m_visibleDescendantStatusDirty = true;
662 void RenderLayer::updateVisibilityStatus()
664 if (m_visibleDescendantStatusDirty) {
665 m_hasVisibleDescendant = false;
666 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
667 child->updateVisibilityStatus();
668 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
669 m_hasVisibleDescendant = true;
673 m_visibleDescendantStatusDirty = false;
676 if (m_visibleContentStatusDirty) {
677 if (renderer()->style()->visibility() == VISIBLE)
678 m_hasVisibleContent = true;
680 // layer may be hidden but still have some visible content, check for this
681 m_hasVisibleContent = false;
682 RenderObject* r = renderer()->firstChild();
684 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
685 m_hasVisibleContent = true;
688 if (r->firstChild() && !r->hasLayer())
690 else if (r->nextSibling())
691 r = r->nextSibling();
697 } while (r && !r->nextSibling());
699 r = r->nextSibling();
703 m_visibleContentStatusDirty = false;
707 void RenderLayer::dirty3DTransformedDescendantStatus()
709 RenderLayer* curr = stackingContext();
711 curr->m_3DTransformedDescendantStatusDirty = true;
713 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
714 // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
715 while (curr && curr->preserves3D()) {
716 curr->m_3DTransformedDescendantStatusDirty = true;
717 curr = curr->stackingContext();
721 // Return true if this layer or any preserve-3d descendants have 3d.
722 bool RenderLayer::update3DTransformedDescendantStatus()
724 if (m_3DTransformedDescendantStatusDirty) {
725 m_has3DTransformedDescendant = false;
727 // Transformed or preserve-3d descendants can only be in the z-order lists, not
728 // in the normal flow list, so we only need to check those.
729 if (m_posZOrderList) {
730 for (unsigned i = 0; i < m_posZOrderList->size(); ++i)
731 m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus();
734 // Now check our negative z-index children.
735 if (m_negZOrderList) {
736 for (unsigned i = 0; i < m_negZOrderList->size(); ++i)
737 m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus();
740 m_3DTransformedDescendantStatusDirty = false;
743 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
744 // the m_has3DTransformedDescendant set.
746 return has3DTransform() || m_has3DTransformedDescendant;
748 return has3DTransform();
751 void RenderLayer::updateLayerPosition()
753 LayoutPoint localPoint;
754 LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
755 if (renderer()->isRenderInline()) {
756 RenderInline* inlineFlow = toRenderInline(renderer());
757 IntRect lineBox = inlineFlow->linesBoundingBox();
758 setSize(lineBox.size());
759 inlineBoundingBoxOffset = toSize(lineBox.location());
760 localPoint += inlineBoundingBoxOffset;
761 } else if (RenderBox* box = renderBox()) {
762 // FIXME: Is snapping the size really needed here for the RenderBox case?
763 setSize(pixelSnappedIntSize(box->size(), box->location()));
764 localPoint += box->topLeftLocationOffset();
767 // Clear our cached clip rect information.
770 if (!renderer()->isPositioned() && renderer()->parent()) {
771 // We must adjust our position by walking up the render tree looking for the
772 // nearest enclosing object with a layer.
773 RenderObject* curr = renderer()->parent();
774 while (curr && !curr->hasLayer()) {
775 if (curr->isBox() && !curr->isTableRow()) {
776 // Rows and cells share the same coordinate space (that of the section).
777 // Omit them when computing our xpos/ypos.
778 localPoint += toRenderBox(curr)->topLeftLocationOffset();
780 curr = curr->parent();
782 if (curr->isBox() && curr->isTableRow()) {
783 // Put ourselves into the row coordinate space.
784 localPoint -= toRenderBox(curr)->topLeftLocationOffset();
788 // Subtract our parent's scroll offset.
789 if (renderer()->isPositioned() && enclosingPositionedAncestor()) {
790 RenderLayer* positionedParent = enclosingPositionedAncestor();
792 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
793 LayoutSize offset = positionedParent->scrolledContentOffset();
794 localPoint -= offset;
796 if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
797 LayoutSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer()));
798 localPoint += offset;
800 } else if (parent()) {
801 if (isComposited()) {
802 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
803 // They won't split across columns properly.
804 LayoutSize columnOffset;
805 parent()->renderer()->adjustForColumns(columnOffset, localPoint);
806 localPoint += columnOffset;
809 LayoutSize scrollOffset = parent()->scrolledContentOffset();
810 localPoint -= scrollOffset;
813 if (renderer()->isRelPositioned()) {
814 m_relativeOffset = renderer()->relativePositionOffset();
815 localPoint.move(m_relativeOffset);
817 m_relativeOffset = LayoutSize();
820 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
821 localPoint -= inlineBoundingBoxOffset;
822 setLocation(localPoint.x(), localPoint.y());
825 TransformationMatrix RenderLayer::perspectiveTransform() const
827 if (!renderer()->hasTransform())
828 return TransformationMatrix();
830 RenderStyle* style = renderer()->style();
831 if (!style->hasPerspective())
832 return TransformationMatrix();
834 // Maybe fetch the perspective from the backing?
835 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
836 const float boxWidth = borderBox.width();
837 const float boxHeight = borderBox.height();
839 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth);
840 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight);
842 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
843 // We want it to be in the top-left, so subtract half the height and width.
844 perspectiveOriginX -= boxWidth / 2.0f;
845 perspectiveOriginY -= boxHeight / 2.0f;
847 TransformationMatrix t;
848 t.translate(perspectiveOriginX, perspectiveOriginY);
849 t.applyPerspective(style->perspective());
850 t.translate(-perspectiveOriginX, -perspectiveOriginY);
855 FloatPoint RenderLayer::perspectiveOrigin() const
857 if (!renderer()->hasTransform())
860 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
861 RenderStyle* style = renderer()->style();
863 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()),
864 floatValueForLength(style->perspectiveOriginY(), borderBox.height()));
867 RenderLayer* RenderLayer::stackingContext() const
869 RenderLayer* layer = parent();
870 while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
871 layer = layer->parent();
875 static inline bool isPositionedContainer(RenderLayer* layer)
877 RenderObject* o = layer->renderer();
878 return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
881 static inline bool isFixedPositionedContainer(RenderLayer* layer)
883 RenderObject* o = layer->renderer();
884 return o->isRenderView() || layer->hasTransform();
887 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
889 RenderLayer* curr = parent();
890 while (curr && !isPositionedContainer(curr))
891 curr = curr->parent();
896 RenderLayer* RenderLayer::enclosingScrollableLayer() const
898 for (RenderObject* nextRenderer = renderer()->parent(); nextRenderer; nextRenderer = nextRenderer->parent()) {
899 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea())
900 return nextRenderer->enclosingLayer();
906 IntRect RenderLayer::scrollableAreaBoundingBox() const
908 return renderer()->absoluteBoundingBoxRect();
911 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
913 RenderLayer* curr = parent();
914 while (curr && !curr->renderer()->isRenderView() && !curr->transform())
915 curr = curr->parent();
920 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
922 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
925 inline bool RenderLayer::shouldRepaintAfterLayout() const
927 #if USE(ACCELERATED_COMPOSITING)
928 if (m_repaintStatus == NeedsNormalRepaint)
931 // Composited layers that were moved during a positioned movement only
932 // layout, don't need to be repainted. They just need to be recomposited.
933 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
934 return !isComposited();
940 #if USE(ACCELERATED_COMPOSITING)
941 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
943 if (includeSelf && isComposited())
944 return const_cast<RenderLayer*>(this);
946 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
947 if (curr->isComposited())
948 return const_cast<RenderLayer*>(curr);
954 RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const
956 if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
957 return const_cast<RenderLayer*>(this);
959 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
960 if (curr->isComposited() && !curr->backing()->paintsIntoCompositedAncestor())
961 return const_cast<RenderLayer*>(curr);
968 #if ENABLE(CSS_FILTERS)
969 RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const
971 const RenderLayer* curr = includeSelf ? this : parent();
972 for (; curr; curr = curr->parent()) {
973 if (curr->requiresFullLayerImageForFilters())
974 return const_cast<RenderLayer*>(curr);
980 RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
982 for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
983 if ((curr != this && curr->requiresFullLayerImageForFilters()) || curr->isComposited() || curr->isRootLayer())
984 return const_cast<RenderLayer*>(curr);
989 void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, bool immediate)
994 LayoutRect rectForRepaint = rect;
996 #if ENABLE(CSS_FILTERS)
997 if (renderer()->style()->hasFilterOutsets()) {
1002 renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset);
1003 rectForRepaint.move(-leftOutset, -topOutset);
1004 rectForRepaint.expand(leftOutset + rightOutset, topOutset + bottomOutset);
1008 m_filterRepaintRect.unite(rectForRepaint);
1010 RenderLayer* parentLayer = enclosingFilterRepaintLayer();
1011 ASSERT(parentLayer);
1012 FloatQuad repaintQuad(rectForRepaint);
1013 LayoutRect parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox();
1015 #if USE(ACCELERATED_COMPOSITING)
1016 if (parentLayer->isComposited()) {
1017 if (!parentLayer->backing()->paintsIntoWindow()) {
1018 parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
1021 // If the painting goes to window, redirect the painting to the parent RenderView.
1022 parentLayer = renderer()->view()->layer();
1023 parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox();
1027 if (parentLayer->paintsWithFilters()) {
1028 parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect, immediate);
1032 if (parentLayer->isRootLayer()) {
1033 RenderView* view = toRenderView(parentLayer->renderer());
1034 view->repaintViewRectangle(parentLayerRect, immediate);
1038 ASSERT_NOT_REACHED();
1042 RenderLayer* RenderLayer::clippingRoot() const
1044 #if USE(ACCELERATED_COMPOSITING)
1046 return const_cast<RenderLayer*>(this);
1049 const RenderLayer* current = this;
1051 if (current->renderer()->isRenderView())
1052 return const_cast<RenderLayer*>(current);
1054 current = compositingContainer(current);
1056 if (current->transform()
1057 #if USE(ACCELERATED_COMPOSITING)
1058 || current->isComposited()
1061 return const_cast<RenderLayer*>(current);
1064 ASSERT_NOT_REACHED();
1068 LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
1070 // We don't use convertToLayerCoords because it doesn't know about transforms
1071 return roundedLayoutPoint(renderer()->absoluteToLocal(absolutePoint, false, true));
1074 bool RenderLayer::cannotBlitToWindow() const
1076 if (isTransparent() || hasReflection() || hasTransform())
1080 return parent()->cannotBlitToWindow();
1083 bool RenderLayer::isTransparent() const
1086 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
1089 return renderer()->isTransparent() || renderer()->hasMask();
1092 RenderLayer* RenderLayer::transparentPaintingAncestor()
1097 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
1098 if (curr->isComposited())
1100 if (curr->isTransparent())
1106 static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, PaintBehavior);
1108 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
1110 // If we have a mask, then the clip is limited to the border box area (and there is
1111 // no need to examine child layers).
1112 if (!layer->renderer()->hasMask()) {
1113 // Note: we don't have to walk z-order lists since transparent elements always establish
1114 // a stacking context. This means we can just walk the layer tree directly.
1115 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
1116 if (!layer->reflection() || layer->reflectionLayer() != curr)
1117 clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
1121 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
1122 // current transparencyClipBox to catch all child layers.
1123 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
1124 // size into the parent layer.
1125 if (layer->renderer()->hasReflection()) {
1127 layer->convertToLayerCoords(rootLayer, delta);
1128 clipRect.move(-delta.x(), -delta.y());
1129 clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
1130 clipRect.moveBy(delta);
1134 static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
1136 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
1137 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
1138 // would be better to respect clips.
1140 if (rootLayer != layer && layer->paintsWithTransform(paintBehavior)) {
1141 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
1142 // the transformed layer and all of its children.
1144 layer->convertToLayerCoords(rootLayer, delta);
1146 TransformationMatrix transform;
1147 transform.translate(delta.x(), delta.y());
1148 transform = transform * *layer->transform();
1150 LayoutRect clipRect = layer->boundingBox(layer);
1151 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, paintBehavior);
1152 return transform.mapRect(clipRect);
1155 LayoutRect clipRect = layer->boundingBox(rootLayer);
1156 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, paintBehavior);
1160 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1162 return intersection(transparencyClipBox(this, rootLayer, paintBehavior), paintDirtyRect);
1165 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
1167 if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
1170 RenderLayer* ancestor = transparentPaintingAncestor();
1172 ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
1174 if (paintsWithTransparency(paintBehavior)) {
1175 m_usedTransparency = true;
1177 LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
1178 context->clip(clipRect);
1179 context->beginTransparencyLayer(renderer()->opacity());
1180 #ifdef REVEAL_TRANSPARENCY_LAYERS
1181 context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
1182 context->fillRect(clipRect);
1187 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena)
1189 return renderArena->allocate(sz);
1192 void RenderLayer::operator delete(void* ptr, size_t sz)
1194 // Stash size where destroy can find it.
1195 *(size_t *)ptr = sz;
1198 void RenderLayer::destroy(RenderArena* renderArena)
1202 // Recover the size left there for us by operator delete and free the memory.
1203 renderArena->free(*(size_t *)this, this);
1206 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1208 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1210 child->setPreviousSibling(prevSibling);
1211 prevSibling->setNextSibling(child);
1212 ASSERT(prevSibling != child);
1214 setFirstChild(child);
1217 beforeChild->setPreviousSibling(child);
1218 child->setNextSibling(beforeChild);
1219 ASSERT(beforeChild != child);
1221 setLastChild(child);
1223 child->setParent(this);
1225 if (child->isNormalFlowOnly())
1226 dirtyNormalFlowList();
1228 if (!child->isNormalFlowOnly() || child->firstChild()) {
1229 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
1230 // case where we're building up generated content layers. This is ok, since the lists will start
1231 // off dirty in that case anyway.
1232 child->dirtyStackingContextZOrderLists();
1235 child->updateVisibilityStatus();
1236 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1237 childVisibilityChanged(true);
1239 #if USE(ACCELERATED_COMPOSITING)
1240 compositor()->layerWasAdded(this, child);
1244 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1246 #if USE(ACCELERATED_COMPOSITING)
1247 if (!renderer()->documentBeingDestroyed())
1248 compositor()->layerWillBeRemoved(this, oldChild);
1252 if (oldChild->previousSibling())
1253 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1254 if (oldChild->nextSibling())
1255 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1257 if (m_first == oldChild)
1258 m_first = oldChild->nextSibling();
1259 if (m_last == oldChild)
1260 m_last = oldChild->previousSibling();
1262 if (oldChild->isNormalFlowOnly())
1263 dirtyNormalFlowList();
1264 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1265 // Dirty the z-order list in which we are contained. When called via the
1266 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1267 // from the main layer tree, so we need to null-check the |stackingContext| value.
1268 oldChild->dirtyStackingContextZOrderLists();
1271 oldChild->setPreviousSibling(0);
1272 oldChild->setNextSibling(0);
1273 oldChild->setParent(0);
1275 oldChild->updateVisibilityStatus();
1276 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1277 childVisibilityChanged(false);
1282 void RenderLayer::removeOnlyThisLayer()
1287 // Mark that we are about to lose our layer. This makes render tree
1288 // walks ignore this layer while we're removing it.
1289 m_renderer->setHasLayer(false);
1291 #if USE(ACCELERATED_COMPOSITING)
1292 compositor()->layerWillBeRemoved(m_parent, this);
1295 // Dirty the clip rects.
1296 clearClipRectsIncludingDescendants();
1298 RenderLayer* nextSib = nextSibling();
1299 bool hasLayerOffset;
1300 const LayoutPoint offsetFromRootBeforeMove = computeOffsetFromRoot(hasLayerOffset);
1302 // Remove the child reflection layer before moving other child layers.
1303 // The reflection layer should not be moved to the parent.
1305 removeChild(reflectionLayer());
1307 // Now walk our kids and reattach them to our parent.
1308 RenderLayer* current = m_first;
1310 RenderLayer* next = current->nextSibling();
1311 removeChild(current);
1312 m_parent->addChild(current, nextSib);
1313 current->setRepaintStatus(NeedsFullRepaint);
1314 LayoutPoint offsetFromRoot = offsetFromRootBeforeMove;
1315 // updateLayerPositions depends on hasLayer() already being false for proper layout.
1316 ASSERT(!renderer()->hasLayer());
1317 current->updateLayerPositions(hasLayerOffset ? &offsetFromRoot : 0);
1321 // Remove us from the parent.
1322 m_parent->removeChild(this);
1323 m_renderer->destroyLayer();
1326 void RenderLayer::insertOnlyThisLayer()
1328 if (!m_parent && renderer()->parent()) {
1329 // We need to connect ourselves when our renderer() has a parent.
1330 // Find our enclosingLayer and add ourselves.
1331 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
1332 ASSERT(parentLayer);
1333 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
1334 parentLayer->addChild(this, beforeChild);
1337 // Remove all descendant layers from the hierarchy and add them to the new position.
1338 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
1339 curr->moveLayers(m_parent, this);
1341 // Clear out all the clip rects.
1342 clearClipRectsIncludingDescendants();
1345 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const
1347 LayoutPoint location = roundedLocation;
1348 convertToLayerCoords(ancestorLayer, location);
1349 roundedLocation = roundedIntPoint(location);
1352 void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const
1354 LayoutRect rect = roundedRect;
1355 convertToLayerCoords(ancestorLayer, rect);
1356 roundedRect = pixelSnappedIntRect(rect);
1359 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
1361 if (ancestorLayer == this)
1364 EPosition position = renderer()->style()->position();
1365 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) {
1366 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1367 // localToAbsolute() on the RenderView.
1368 FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
1369 location += flooredLayoutSize(absPos);
1373 if (position == FixedPosition) {
1374 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1375 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1376 // so we should always find the ancestor at or before we find the fixed position container.
1377 RenderLayer* fixedPositionContainerLayer = 0;
1378 bool foundAncestor = false;
1379 for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) {
1380 if (currLayer == ancestorLayer)
1381 foundAncestor = true;
1383 if (isFixedPositionedContainer(currLayer)) {
1384 fixedPositionContainerLayer = currLayer;
1385 ASSERT_UNUSED(foundAncestor, foundAncestor);
1390 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1392 if (fixedPositionContainerLayer != ancestorLayer) {
1393 LayoutPoint fixedContainerCoords;
1394 convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
1396 LayoutPoint ancestorCoords;
1397 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
1399 location += (fixedContainerCoords - ancestorCoords);
1404 RenderLayer* parentLayer;
1405 if (position == AbsolutePosition || position == FixedPosition) {
1406 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1407 parentLayer = parent();
1408 bool foundAncestorFirst = false;
1409 while (parentLayer) {
1410 if (isPositionedContainer(parentLayer))
1413 if (parentLayer == ancestorLayer) {
1414 foundAncestorFirst = true;
1418 parentLayer = parentLayer->parent();
1421 if (foundAncestorFirst) {
1422 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1423 // to enclosingPositionedAncestor and subtract.
1424 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1426 LayoutPoint thisCoords;
1427 convertToLayerCoords(positionedAncestor, thisCoords);
1429 LayoutPoint ancestorCoords;
1430 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
1432 location += (thisCoords - ancestorCoords);
1436 parentLayer = parent();
1441 parentLayer->convertToLayerCoords(ancestorLayer, location);
1443 location += toSize(m_topLeft);
1446 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
1449 convertToLayerCoords(ancestorLayer, delta);
1450 rect.move(-delta.x(), -delta.y());
1453 static inline int adjustedScrollDelta(int beginningDelta) {
1454 // This implemention matches Firefox's.
1455 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
1456 const int speedReducer = 12;
1458 int adjustedDelta = beginningDelta / speedReducer;
1459 if (adjustedDelta > 1)
1460 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
1461 else if (adjustedDelta < -1)
1462 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
1464 return adjustedDelta;
1467 void RenderLayer::panScrollFromPoint(const LayoutPoint& sourcePoint)
1469 Frame* frame = renderer()->frame();
1473 IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
1475 // 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
1476 static IntPoint previousMousePosition;
1477 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
1478 currentMousePosition = previousMousePosition;
1480 previousMousePosition = currentMousePosition;
1482 int xDelta = currentMousePosition.x() - sourcePoint.x();
1483 int yDelta = currentMousePosition.y() - sourcePoint.y();
1485 if (abs(xDelta) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
1487 if (abs(yDelta) <= ScrollView::noPanScrollRadius)
1490 scrollByRecursively(adjustedScrollDelta(xDelta), adjustedScrollDelta(yDelta), ScrollOffsetClamped);
1493 void RenderLayer::scrollByRecursively(int xDelta, int yDelta, ScrollOffsetClamping clamp)
1495 if (!xDelta && !yDelta)
1498 bool restrictedByLineClamp = false;
1499 if (renderer()->parent())
1500 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1502 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1503 int newOffsetX = scrollXOffset() + xDelta;
1504 int newOffsetY = scrollYOffset() + yDelta;
1505 scrollToOffset(newOffsetX, newOffsetY, clamp);
1507 // If this layer can't do the scroll we ask the next layer up that can scroll to try
1508 int leftToScrollX = newOffsetX - scrollXOffset();
1509 int leftToScrollY = newOffsetY - scrollYOffset();
1510 if ((leftToScrollX || leftToScrollY) && renderer()->parent()) {
1511 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
1512 scrollableLayer->scrollByRecursively(leftToScrollX, leftToScrollY);
1514 Frame* frame = renderer()->frame();
1516 frame->eventHandler()->updateAutoscrollRenderer();
1518 } else if (renderer()->view()->frameView()) {
1519 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
1520 // have an overflow clip. Which means that it is a document node that can be scrolled.
1521 renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
1522 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
1523 // https://bugs.webkit.org/show_bug.cgi?id=28237
1527 void RenderLayer::scrollToOffset(int x, int y, ScrollOffsetClamping clamp)
1529 if (clamp == ScrollOffsetClamped) {
1530 RenderBox* box = renderBox();
1534 int maxX = scrollWidth() - box->clientWidth();
1535 int maxY = scrollHeight() - box->clientHeight();
1537 x = min(max(x, 0), maxX);
1538 y = min(max(y, 0), maxY);
1541 IntPoint newScrollOffset(x, y);
1542 if (newScrollOffset != LayoutPoint(scrollXOffset(), scrollYOffset()))
1543 scrollToOffsetWithoutAnimation(newScrollOffset);
1546 void RenderLayer::scrollTo(int x, int y)
1548 RenderBox* box = renderBox();
1552 if (box->style()->overflowX() != OMARQUEE) {
1553 // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
1554 if (m_scrollDimensionsDirty)
1555 computeScrollDimensions();
1558 // FIXME: Eventually, we will want to perform a blit. For now never
1559 // blit, since the check for blitting is going to be very
1560 // complicated (since it will involve testing whether our layer
1561 // is either occluded by another layer or clipped by an enclosing
1562 // layer or contains fixed backgrounds, etc.).
1563 IntSize newScrollOffset = IntSize(x - scrollOrigin().x(), y - scrollOrigin().y());
1564 if (m_scrollOffset == newScrollOffset)
1566 m_scrollOffset = newScrollOffset;
1568 // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
1569 // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
1570 updateLayerPositionsAfterScroll();
1572 RenderView* view = renderer()->view();
1574 // We should have a RenderView if we're trying to scroll.
1577 #if ENABLE(DASHBOARD_SUPPORT)
1578 // Update dashboard regions, scrolling may change the clip of a
1579 // particular region.
1580 view->frameView()->updateDashboardRegions();
1583 view->updateWidgetPositions();
1586 updateCompositingLayersAfterScroll();
1588 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
1589 Frame* frame = renderer()->frame();
1591 // The caret rect needs to be invalidated after scrolling
1592 frame->selection()->setCaretRectNeedsUpdate();
1594 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
1595 if (repaintContainer)
1596 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
1597 frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
1600 // Just schedule a full repaint of our object.
1602 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
1604 // Schedule the scroll DOM event.
1605 if (renderer()->node())
1606 renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), DocumentEventQueue::ScrollEventElementTarget);
1609 void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1611 RenderLayer* parentLayer = 0;
1612 LayoutRect newRect = rect;
1614 // We may end up propagating a scroll event. It is important that we suspend events until
1615 // the end of the function since they could delete the layer or the layer's renderer().
1616 FrameView* frameView = renderer()->document()->view();
1618 frameView->pauseScheduledEvents();
1620 bool restrictedByLineClamp = false;
1621 if (renderer()->parent()) {
1622 parentLayer = renderer()->parent()->enclosingLayer();
1623 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1626 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1627 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
1628 // This will prevent us from revealing text hidden by the slider in Safari RSS.
1629 RenderBox* box = renderBox();
1631 FloatPoint absPos = box->localToAbsolute();
1632 absPos.move(box->borderLeft(), box->borderTop());
1634 LayoutRect layerBounds = LayoutRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
1635 LayoutRect exposeRect = LayoutRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
1636 LayoutRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
1638 LayoutUnit adjustedX = r.x() - absPos.x();
1639 LayoutUnit adjustedY = r.y() - absPos.y();
1640 // Adjust offsets if they're outside of the allowable range.
1641 adjustedX = max<LayoutUnit>(0, min(scrollWidth() - layerBounds.width(), adjustedX));
1642 adjustedY = max<LayoutUnit>(0, min(scrollHeight() - layerBounds.height(), adjustedY));
1644 int xOffset = roundToInt(adjustedX);
1645 int yOffset = roundToInt(adjustedY);
1647 if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
1648 int diffX = scrollXOffset();
1649 int diffY = scrollYOffset();
1650 scrollToOffset(xOffset, yOffset);
1651 diffX = scrollXOffset() - diffX;
1652 diffY = scrollYOffset() - diffY;
1653 newRect.setX(rect.x() - diffX);
1654 newRect.setY(rect.y() - diffY);
1656 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled()) {
1658 Element* ownerElement = 0;
1659 if (renderer()->document())
1660 ownerElement = renderer()->document()->ownerElement();
1662 if (ownerElement && ownerElement->renderer()) {
1663 HTMLFrameElement* frameElement = 0;
1665 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
1666 frameElement = static_cast<HTMLFrameElement*>(ownerElement);
1668 if (frameElement && frameElement->scrollingMode() != ScrollbarAlwaysOff) {
1669 LayoutRect viewRect = frameView->visibleContentRect();
1670 LayoutRect exposeRect = getRectToExpose(viewRect, rect, alignX, alignY);
1672 int xOffset = roundToInt(exposeRect.x());
1673 int yOffset = roundToInt(exposeRect.y());
1674 // Adjust offsets if they're outside of the allowable range.
1675 xOffset = max(0, min(frameView->contentsWidth(), xOffset));
1676 yOffset = max(0, min(frameView->contentsHeight(), yOffset));
1678 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
1679 if (frameView->safeToPropagateScrollToParent()) {
1680 parentLayer = ownerElement->renderer()->enclosingLayer();
1681 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
1682 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
1687 LayoutRect viewRect = frameView->visibleContentRect();
1688 LayoutRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1690 frameView->setScrollPosition(roundedIntPoint(r.location()));
1692 // This is the outermost view of a web page, so after scrolling this view we
1693 // scroll its container by calling Page::scrollRectIntoView.
1694 // This only has an effect on the Mac platform in applications
1695 // that put web views into scrolling containers, such as Mac OS X Mail.
1696 // The canAutoscroll function in EventHandler also knows about this.
1697 if (Frame* frame = frameView->frame()) {
1698 if (Page* page = frame->page())
1699 page->chrome()->scrollRectIntoView(pixelSnappedIntRect(rect));
1706 parentLayer->scrollRectToVisible(newRect, alignX, alignY);
1709 frameView->resumeScheduledEvents();
1712 void RenderLayer::updateCompositingLayersAfterScroll()
1714 #if USE(ACCELERATED_COMPOSITING)
1715 if (compositor()->inCompositingMode()) {
1716 // Our stacking context is guaranteed to contain all of our descendants that may need
1717 // repositioning, so update compositing layers from there.
1718 if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) {
1719 if (compositor()->compositingConsultsOverlap())
1720 compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
1722 bool isUpdateRoot = true;
1723 compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
1730 LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1732 // Determine the appropriate X behavior.
1733 ScrollBehavior scrollX;
1734 LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
1735 LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
1736 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
1737 // If the rectangle is fully visible, use the specified visible behavior.
1738 // If the rectangle is partially visible, but over a certain threshold,
1739 // then treat it as fully visible to avoid unnecessary horizontal scrolling
1740 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1741 else if (intersectWidth == visibleRect.width()) {
1742 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1743 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1744 if (scrollX == alignCenter)
1746 } else if (intersectWidth > 0)
1747 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
1748 scrollX = ScrollAlignment::getPartialBehavior(alignX);
1750 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
1751 // If we're trying to align to the closest edge, and the exposeRect is further right
1752 // than the visibleRect, and not bigger than the visible area, then align with the right.
1753 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
1754 scrollX = alignRight;
1756 // Given the X behavior, compute the X coordinate.
1758 if (scrollX == noScroll)
1759 x = visibleRect.x();
1760 else if (scrollX == alignRight)
1761 x = exposeRect.maxX() - visibleRect.width();
1762 else if (scrollX == alignCenter)
1763 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
1767 // Determine the appropriate Y behavior.
1768 ScrollBehavior scrollY;
1769 LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
1770 LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
1771 if (intersectHeight == exposeRect.height())
1772 // If the rectangle is fully visible, use the specified visible behavior.
1773 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1774 else if (intersectHeight == visibleRect.height()) {
1775 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1776 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1777 if (scrollY == alignCenter)
1779 } else if (intersectHeight > 0)
1780 // If the rectangle is partially visible, use the specified partial behavior
1781 scrollY = ScrollAlignment::getPartialBehavior(alignY);
1783 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
1784 // If we're trying to align to the closest edge, and the exposeRect is further down
1785 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
1786 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
1787 scrollY = alignBottom;
1789 // Given the Y behavior, compute the Y coordinate.
1791 if (scrollY == noScroll)
1792 y = visibleRect.y();
1793 else if (scrollY == alignBottom)
1794 y = exposeRect.maxY() - visibleRect.height();
1795 else if (scrollY == alignCenter)
1796 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
1800 return LayoutRect(LayoutPoint(x, y), visibleRect.size());
1803 void RenderLayer::autoscroll()
1805 Frame* frame = renderer()->frame();
1809 FrameView* frameView = frame->view();
1813 #if ENABLE(DRAG_SUPPORT)
1814 frame->eventHandler()->updateSelectionForMouseDrag();
1817 IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
1818 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
1821 void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOffset)
1823 // FIXME: This should be possible on generated content but is not right now.
1824 if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
1827 // Set the width and height of the shadow ancestor node if there is one.
1828 // This is necessary for textarea elements since the resizable layer is in the shadow content.
1829 Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode());
1830 RenderBox* renderer = toRenderBox(element->renderer());
1832 EResize resize = renderer->style()->resize();
1833 if (resize == RESIZE_NONE)
1836 Document* document = element->document();
1837 if (!document->frame()->eventHandler()->mousePressed())
1840 float zoomFactor = renderer->style()->effectiveZoom();
1842 LayoutSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.position()));
1843 newOffset.setWidth(newOffset.width() / zoomFactor);
1844 newOffset.setHeight(newOffset.height() / zoomFactor);
1846 LayoutSize currentSize = LayoutSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
1847 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
1848 element->setMinimumSizeForResizing(minimumSize);
1850 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
1851 if (renderer->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
1852 newOffset.setWidth(-newOffset.width());
1853 adjustedOldOffset.setWidth(-adjustedOldOffset.width());
1856 LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
1858 ASSERT(element->isStyledElement());
1859 StyledElement* styledElement = static_cast<StyledElement*>(element);
1860 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
1862 if (resize != RESIZE_VERTICAL && difference.width()) {
1863 if (element->isFormControlElement()) {
1864 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1865 styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false);
1866 styledElement->setInlineStyleProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false);
1868 LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? ZERO_LAYOUT_UNIT : renderer->borderAndPaddingWidth());
1869 baseWidth = baseWidth / zoomFactor;
1870 styledElement->setInlineStyleProperty(CSSPropertyWidth, String::number(roundToInt(baseWidth + difference.width())) + "px", false);
1873 if (resize != RESIZE_HORIZONTAL && difference.height()) {
1874 if (element->isFormControlElement()) {
1875 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1876 styledElement->setInlineStyleProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false);
1877 styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false);
1879 LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? ZERO_LAYOUT_UNIT : renderer->borderAndPaddingHeight());
1880 baseHeight = baseHeight / zoomFactor;
1881 styledElement->setInlineStyleProperty(CSSPropertyHeight, String::number(roundToInt(baseHeight + difference.height())) + "px", false);
1884 document->updateLayout();
1886 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
1889 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
1891 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
1892 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
1895 void RenderLayer::setScrollOffset(const IntPoint& offset)
1897 scrollTo(offset.x(), offset.y());
1900 int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
1902 if (scrollbar->orientation() == HorizontalScrollbar)
1903 return scrollXOffset();
1904 if (scrollbar->orientation() == VerticalScrollbar)
1905 return scrollYOffset();
1909 IntPoint RenderLayer::scrollPosition() const
1911 return scrollOrigin() + m_scrollOffset;
1914 IntPoint RenderLayer::minimumScrollPosition() const
1916 return scrollOrigin();
1919 IntPoint RenderLayer::maximumScrollPosition() const
1921 // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
1922 return scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRect(true).size();
1925 IntRect RenderLayer::visibleContentRect(bool includeScrollbars) const
1927 int verticalScrollbarWidth = 0;
1928 int horizontalScrollbarHeight = 0;
1929 if (includeScrollbars) {
1930 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
1931 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
1934 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
1935 IntSize(max(0, m_layerSize.width() - verticalScrollbarWidth),
1936 max(0, m_layerSize.height() - horizontalScrollbarHeight)));
1939 IntSize RenderLayer::overhangAmount() const
1944 bool RenderLayer::isActive() const
1946 Page* page = renderer()->frame()->page();
1947 return page && page->focusController()->isActive();
1950 static int cornerStart(const RenderLayer* layer, int minX, int maxX, int thickness)
1952 if (layer->renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1953 return minX + layer->renderer()->style()->borderLeftWidth();
1954 return maxX - thickness - layer->renderer()->style()->borderRightWidth();
1957 static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds)
1959 int horizontalThickness;
1960 int verticalThickness;
1961 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1962 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
1963 // even when they don't exist in order to set the resizer square size properly.
1964 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
1965 verticalThickness = horizontalThickness;
1966 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1967 horizontalThickness = layer->verticalScrollbar()->width();
1968 verticalThickness = horizontalThickness;
1969 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
1970 verticalThickness = layer->horizontalScrollbar()->height();
1971 horizontalThickness = verticalThickness;
1973 horizontalThickness = layer->verticalScrollbar()->width();
1974 verticalThickness = layer->horizontalScrollbar()->height();
1976 return IntRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
1977 bounds.maxY() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
1978 horizontalThickness, verticalThickness);
1981 IntRect RenderLayer::scrollCornerRect() const
1983 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
1984 // This happens when:
1985 // (a) A resizer is present and at least one scrollbar is present
1986 // (b) Both scrollbars are present.
1987 bool hasHorizontalBar = horizontalScrollbar();
1988 bool hasVerticalBar = verticalScrollbar();
1989 bool hasResizer = renderer()->style()->resize() != RESIZE_NONE;
1990 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
1991 return cornerRect(this, renderBox()->pixelSnappedBorderBoxRect());
1995 static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
1997 ASSERT(layer->renderer()->isBox());
1998 if (layer->renderer()->style()->resize() == RESIZE_NONE)
2000 return cornerRect(layer, bounds);
2003 IntRect RenderLayer::scrollCornerAndResizerRect() const
2005 RenderBox* box = renderBox();
2008 IntRect scrollCornerAndResizer = scrollCornerRect();
2009 if (scrollCornerAndResizer.isEmpty())
2010 scrollCornerAndResizer = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2011 return scrollCornerAndResizer;
2014 bool RenderLayer::isScrollCornerVisible() const
2016 ASSERT(renderer()->isBox());
2017 return !scrollCornerRect().isEmpty();
2020 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
2022 RenderView* view = renderer()->view();
2024 return scrollbarRect;
2026 IntRect rect = scrollbarRect;
2027 rect.move(scrollbarOffset(scrollbar));
2029 return view->frameView()->convertFromRenderer(renderer(), rect);
2032 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
2034 RenderView* view = renderer()->view();
2038 IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect);
2039 rect.move(-scrollbarOffset(scrollbar));
2043 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
2045 RenderView* view = renderer()->view();
2047 return scrollbarPoint;
2049 IntPoint point = scrollbarPoint;
2050 point.move(scrollbarOffset(scrollbar));
2051 return view->frameView()->convertFromRenderer(renderer(), point);
2054 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
2056 RenderView* view = renderer()->view();
2060 IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint);
2062 point.move(-scrollbarOffset(scrollbar));
2066 IntSize RenderLayer::contentsSize() const
2068 return IntSize(scrollWidth(), scrollHeight());
2071 int RenderLayer::visibleHeight() const
2073 return m_layerSize.height();
2076 int RenderLayer::visibleWidth() const
2078 return m_layerSize.width();
2081 bool RenderLayer::shouldSuspendScrollAnimations() const
2083 RenderView* view = renderer()->view();
2086 return view->frameView()->shouldSuspendScrollAnimations();
2089 bool RenderLayer::isOnActivePage() const
2091 return !m_renderer->document()->inPageCache();
2094 IntPoint RenderLayer::currentMousePosition() const
2096 return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint();
2099 LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
2101 const RenderBox* box = renderBox();
2102 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2103 return minX + box->borderLeft();
2104 return maxX - box->borderRight() - m_vBar->width();
2107 LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
2109 const RenderBox* box = renderBox();
2110 int x = minX + box->borderLeft();
2111 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2112 x += m_vBar ? m_vBar->width() : resizerCornerRect(this, box->pixelSnappedBorderBoxRect()).width();
2116 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
2118 RenderBox* box = renderBox();
2120 if (scrollbar == m_vBar.get())
2121 return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
2123 if (scrollbar == m_hBar.get())
2124 return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2126 ASSERT_NOT_REACHED();
2130 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2132 #if USE(ACCELERATED_COMPOSITING)
2133 if (scrollbar == m_vBar.get()) {
2134 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2135 layer->setNeedsDisplayInRect(rect);
2139 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2140 layer->setNeedsDisplayInRect(rect);
2145 IntRect scrollRect = rect;
2146 RenderBox* box = renderBox();
2148 if (scrollbar == m_vBar.get())
2149 scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
2151 scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
2152 renderer()->repaintRectangle(scrollRect);
2155 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
2157 #if USE(ACCELERATED_COMPOSITING)
2158 if (GraphicsLayer* layer = layerForScrollCorner()) {
2159 layer->setNeedsDisplayInRect(rect);
2164 m_scrollCorner->repaintRectangle(rect);
2166 m_resizer->repaintRectangle(rect);
2169 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
2171 RefPtr<Scrollbar> widget;
2172 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
2173 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
2174 if (hasCustomScrollbarStyle)
2175 widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer));
2177 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
2178 if (orientation == HorizontalScrollbar)
2179 didAddHorizontalScrollbar(widget.get());
2181 didAddVerticalScrollbar(widget.get());
2183 renderer()->document()->view()->addChild(widget.get());
2184 return widget.release();
2187 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
2189 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
2191 if (scrollbar->isCustomScrollbar())
2192 toRenderScrollbar(scrollbar.get())->clearOwningRenderer();
2194 if (orientation == HorizontalScrollbar)
2195 willRemoveHorizontalScrollbar(scrollbar.get());
2197 willRemoveVerticalScrollbar(scrollbar.get());
2200 scrollbar->removeFromParent();
2201 scrollbar->disconnectFromScrollableArea();
2206 bool RenderLayer::scrollsOverflow() const
2208 if (!renderer()->isBox())
2211 return toRenderBox(renderer())->scrollsOverflow();
2214 bool RenderLayer::allowsScrolling() const
2216 return (m_hBar && m_hBar->enabled()) || (m_vBar && m_vBar->enabled());
2219 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
2221 if (hasScrollbar == hasHorizontalScrollbar())
2225 m_hBar = createScrollbar(HorizontalScrollbar);
2227 destroyScrollbar(HorizontalScrollbar);
2229 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2231 m_hBar->styleChanged();
2233 m_vBar->styleChanged();
2235 #if ENABLE(DASHBOARD_SUPPORT)
2236 // Force an update since we know the scrollbars have changed things.
2237 if (renderer()->document()->hasDashboardRegions())
2238 renderer()->document()->setDashboardRegionsDirty(true);
2242 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
2244 if (hasScrollbar == hasVerticalScrollbar())
2248 m_vBar = createScrollbar(VerticalScrollbar);
2250 destroyScrollbar(VerticalScrollbar);
2252 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
2254 m_hBar->styleChanged();
2256 m_vBar->styleChanged();
2258 #if ENABLE(DASHBOARD_SUPPORT)
2259 // Force an update since we know the scrollbars have changed things.
2260 if (renderer()->document()->hasDashboardRegions())
2261 renderer()->document()->setDashboardRegionsDirty(true);
2265 ScrollableArea* RenderLayer::enclosingScrollableArea() const
2267 if (RenderLayer* scrollableLayer = enclosingScrollableLayer())
2268 return scrollableLayer;
2270 // FIXME: We should return the frame view here (or possibly an ancestor frame view,
2271 // if the frame view isn't scrollable.
2275 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
2277 if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2279 return m_vBar->width();
2282 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
2284 if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
2286 return m_hBar->height();
2289 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
2291 // Currently the resize corner is either the bottom right corner or the bottom left corner.
2292 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
2293 IntSize elementSize = size();
2294 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2295 elementSize.setWidth(0);
2296 IntPoint resizerPoint = toPoint(elementSize);
2297 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
2298 return localPoint - resizerPoint;
2301 bool RenderLayer::hasOverflowControls() const
2303 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
2306 void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer)
2308 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2311 RenderBox* box = renderBox();
2315 const IntRect borderBox = box->pixelSnappedBorderBoxRect();
2316 const IntRect& scrollCorner = scrollCornerRect();
2317 IntRect absBounds(borderBox.location() + offsetFromLayer, borderBox.size());
2319 m_vBar->setFrameRect(IntRect(verticalScrollbarStart(absBounds.x(), absBounds.maxX()),
2320 absBounds.y() + box->borderTop(),
2322 absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
2325 m_hBar->setFrameRect(IntRect(horizontalScrollbarStart(absBounds.x()),
2326 absBounds.maxY() - box->borderBottom() - m_hBar->height(),
2327 absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2330 #if USE(ACCELERATED_COMPOSITING)
2331 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2333 layer->setPosition(m_hBar->frameRect().location() - offsetFromLayer);
2334 layer->setSize(m_hBar->frameRect().size());
2336 layer->setDrawsContent(m_hBar);
2338 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2340 layer->setPosition(m_vBar->frameRect().location() - offsetFromLayer);
2341 layer->setSize(m_vBar->frameRect().size());
2343 layer->setDrawsContent(m_vBar);
2346 if (GraphicsLayer* layer = layerForScrollCorner()) {
2347 const LayoutRect& scrollCornerAndResizer = scrollCornerAndResizerRect();
2348 layer->setPosition(scrollCornerAndResizer.location());
2349 layer->setSize(scrollCornerAndResizer.size());
2350 layer->setDrawsContent(!scrollCornerAndResizer.isEmpty());
2355 m_scrollCorner->setFrameRect(scrollCorner);
2357 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
2360 int RenderLayer::scrollWidth() const
2362 ASSERT(renderBox());
2363 if (m_scrollDimensionsDirty)
2364 const_cast<RenderLayer*>(this)->computeScrollDimensions();
2365 return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft());
2368 int RenderLayer::scrollHeight() const
2370 ASSERT(renderBox());
2371 if (m_scrollDimensionsDirty)
2372 const_cast<RenderLayer*>(this)->computeScrollDimensions();
2373 return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop());
2376 LayoutUnit RenderLayer::overflowTop() const
2378 RenderBox* box = renderBox();
2379 LayoutRect overflowRect(box->layoutOverflowRect());
2380 box->flipForWritingMode(overflowRect);
2381 return overflowRect.y();
2384 LayoutUnit RenderLayer::overflowBottom() const
2386 RenderBox* box = renderBox();
2387 LayoutRect overflowRect(box->layoutOverflowRect());
2388 box->flipForWritingMode(overflowRect);
2389 return overflowRect.maxY();
2392 LayoutUnit RenderLayer::overflowLeft() const
2394 RenderBox* box = renderBox();
2395 LayoutRect overflowRect(box->layoutOverflowRect());
2396 box->flipForWritingMode(overflowRect);
2397 return overflowRect.x();
2400 LayoutUnit RenderLayer::overflowRight() const
2402 RenderBox* box = renderBox();
2403 LayoutRect overflowRect(box->layoutOverflowRect());
2404 box->flipForWritingMode(overflowRect);
2405 return overflowRect.maxX();
2408 void RenderLayer::computeScrollDimensions()
2410 RenderBox* box = renderBox();
2413 m_scrollDimensionsDirty = false;
2415 m_scrollOverflow.setWidth(overflowLeft() - box->borderLeft());
2416 m_scrollOverflow.setHeight(overflowTop() - box->borderTop());
2418 m_scrollSize.setWidth(overflowRight() - overflowLeft());
2419 m_scrollSize.setHeight(overflowBottom() - overflowTop());
2421 setScrollOrigin(IntPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height()));
2424 bool RenderLayer::hasHorizontalOverflow() const
2426 ASSERT(!m_scrollDimensionsDirty);
2428 return scrollWidth() > renderBox()->pixelSnappedClientWidth();
2431 bool RenderLayer::hasVerticalOverflow() const
2433 ASSERT(!m_scrollDimensionsDirty);
2435 return scrollHeight() > renderBox()->pixelSnappedClientHeight();
2438 void RenderLayer::updateScrollbarsAfterLayout()
2440 RenderBox* box = renderBox();
2443 bool hasHorizontalOverflow = this->hasHorizontalOverflow();
2444 bool hasVerticalOverflow = this->hasVerticalOverflow();
2446 // overflow:scroll should just enable/disable.
2447 if (m_hBar && renderer()->style()->overflowX() == OSCROLL)
2448 m_hBar->setEnabled(hasHorizontalOverflow);
2449 if (m_vBar && renderer()->style()->overflowY() == OSCROLL)
2450 m_vBar->setEnabled(hasVerticalOverflow);
2452 // overflow:auto may need to lay out again if scrollbars got added/removed.
2453 bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
2454 bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
2456 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
2457 if (box->hasAutoHorizontalScrollbar())
2458 setHasHorizontalScrollbar(hasHorizontalOverflow);
2459 if (box->hasAutoVerticalScrollbar())
2460 setHasVerticalScrollbar(hasVerticalOverflow);
2462 #if ENABLE(DASHBOARD_SUPPORT)
2463 // Force an update since we know the scrollbars have changed things.
2464 if (renderer()->document()->hasDashboardRegions())
2465 renderer()->document()->setDashboardRegionsDirty(true);
2468 renderer()->repaint();
2470 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) {
2471 if (!m_inOverflowRelayout) {
2472 // Our proprietary overflow: overlay value doesn't trigger a layout.
2473 m_inOverflowRelayout = true;
2474 renderer()->setNeedsLayout(true, MarkOnlyThis);
2475 if (renderer()->isRenderBlock()) {
2476 RenderBlock* block = toRenderBlock(renderer());
2477 block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
2478 block->layoutBlock(true); // FIXME: Need to handle positioned floats triggering extra relayouts.
2480 renderer()->layout();
2481 m_inOverflowRelayout = false;
2486 // Set up the range (and page step/line step).
2488 int clientWidth = box->pixelSnappedClientWidth();
2489 int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
2490 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2491 m_hBar->setProportion(clientWidth, m_scrollSize.width());
2494 int clientHeight = box->pixelSnappedClientHeight();
2495 int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
2496 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2497 m_vBar->setProportion(clientHeight, m_scrollSize.height());
2500 updateScrollableAreaSet((hasHorizontalOverflow || hasVerticalOverflow) && scrollsOverflow());
2503 void RenderLayer::updateScrollInfoAfterLayout()
2505 RenderBox* box = renderBox();
2509 m_scrollDimensionsDirty = true;
2510 IntSize scrollOffsetOriginal(scrollXOffset(), scrollYOffset());
2512 computeScrollDimensions();
2514 if (box->style()->overflowX() != OMARQUEE) {
2515 // Layout may cause us to be at an invalid scroll position. In this case we need
2516 // to pull our scroll offsets back to the max (or push them up to the min).
2517 int newX = max(0, min<int>(scrollXOffset(), scrollWidth() - box->clientWidth()));
2518 int newY = max(0, min<int>(scrollYOffset(), scrollHeight() - box->clientHeight()));
2519 if (newX != scrollXOffset() || newY != scrollYOffset())
2520 scrollToOffset(newX, newY);
2523 updateScrollbarsAfterLayout();
2525 if (scrollOffsetOriginal != scrollOffset())
2526 scrollToOffsetWithoutAnimation(IntPoint(scrollXOffset(), scrollYOffset()));
2529 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
2531 // Don't do anything if we have no overflow.
2532 if (!renderer()->hasOverflowClip())
2535 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
2536 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
2537 // will be false, and we should just tell the root layer that there are overlay scrollbars
2538 // that need to be painted. That will cause the second pass through the layer tree to run,
2539 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
2540 // second pass doesn't need to re-enter the RenderTree to get it right.
2541 if (hasOverlayScrollbars() && !paintingOverlayControls) {
2542 RenderView* renderView = renderer()->view();
2543 renderView->layer()->setContainsDirtyOverlayScrollbars(true);
2544 m_cachedOverlayScrollbarOffset = paintOffset;
2545 renderView->frameView()->setContainsScrollableAreaWithOverlayScrollbars(true);
2549 // This check is required to avoid painting custom CSS scrollbars twice.
2550 if (paintingOverlayControls && !hasOverlayScrollbars())
2553 IntPoint adjustedPaintOffset = paintOffset;
2554 if (paintingOverlayControls)
2555 adjustedPaintOffset = m_cachedOverlayScrollbarOffset;
2557 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
2558 // widgets can move without layout occurring (most notably when you scroll a document that
2559 // contains fixed positioned elements).
2560 positionOverflowControls(toSize(adjustedPaintOffset));
2562 // Now that we're sure the scrollbars are in the right place, paint them.
2564 #if USE(ACCELERATED_COMPOSITING)
2565 && !layerForHorizontalScrollbar()
2568 m_hBar->paint(context, damageRect);
2570 #if USE(ACCELERATED_COMPOSITING)
2571 && !layerForVerticalScrollbar()
2574 m_vBar->paint(context, damageRect);
2576 #if USE(ACCELERATED_COMPOSITING)
2577 if (layerForScrollCorner())
2581 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
2583 paintScrollCorner(context, adjustedPaintOffset, damageRect);
2585 // Paint our resizer last, since it sits on top of the scroll corner.
2586 paintResizer(context, adjustedPaintOffset, damageRect);
2589 void RenderLayer::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
2591 RenderBox* box = renderBox();
2594 IntRect absRect = scrollCornerRect();
2595 absRect.moveBy(paintOffset);
2596 if (!absRect.intersects(damageRect))
2599 if (context->updatingControlTints()) {
2600 updateScrollCornerStyle();
2604 if (m_scrollCorner) {
2605 m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
2609 // We don't want to paint white if we have overlay scrollbars, since we need
2610 // to see what is behind it.
2611 if (!hasOverlayScrollbars())
2612 context->fillRect(absRect, Color::white, box->style()->colorSpace());
2615 void RenderLayer::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect)
2617 float deviceScaleFactor = WebCore::deviceScaleFactor(renderer()->frame());
2619 RefPtr<Image> resizeCornerImage;
2620 IntSize cornerResizerSize;
2621 if (deviceScaleFactor >= 2) {
2622 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef()));
2623 resizeCornerImage = resizeCornerImageHiRes;
2624 cornerResizerSize = resizeCornerImage->size();
2625 cornerResizerSize.scale(0.5f);
2627 DEFINE_STATIC_LOCAL(Image*, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner").leakRef()));
2628 resizeCornerImage = resizeCornerImageLoRes;
2629 cornerResizerSize = resizeCornerImage->size();
2632 IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
2633 if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
2635 context->translate(imageRect.x(), imageRect.y());
2638 context->scale(FloatSize(-1.0, 1.0));
2639 context->drawImage(resizeCornerImage.get(), renderer()->style()->colorSpace(), imageRect);
2643 context->drawImage(resizeCornerImage.get(), renderer()->style()->colorSpace(), imageRect);
2646 void RenderLayer::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
2648 if (renderer()->style()->resize() == RESIZE_NONE)
2651 RenderBox* box = renderBox();
2654 IntRect absRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2655 absRect.moveBy(paintOffset);
2656 if (!absRect.intersects(damageRect))
2659 if (context->updatingControlTints()) {
2660 updateResizerStyle();
2665 m_resizer->paintIntoRect(context, paintOffset, absRect);
2669 drawPlatformResizerImage(context, absRect);
2671 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
2672 // Clipping will exclude the right and bottom edges of this frame.
2673 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
2674 GraphicsContextStateSaver stateSaver(*context);
2675 context->clip(absRect);
2676 IntRect largerCorner = absRect;
2677 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
2678 context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
2679 context->setStrokeThickness(1.0f);
2680 context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
2681 context->drawRect(largerCorner);
2685 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
2687 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
2690 RenderBox* box = renderBox();
2693 IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
2695 IntRect localBounds(0, 0, box->pixelSnappedWidth(), box->pixelSnappedHeight());
2696 return resizerCornerRect(this, localBounds).contains(localPoint);
2699 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
2701 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2704 RenderBox* box = renderBox();
2707 IntRect resizeControlRect;
2708 if (renderer()->style()->resize() != RESIZE_NONE) {
2709 resizeControlRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect());
2710 if (resizeControlRect.contains(localPoint))
2714 int resizeControlSize = max(resizeControlRect.height(), 0);
2716 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
2717 LayoutRect vBarRect(verticalScrollbarStart(0, box->width()),
2720 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
2721 if (vBarRect.contains(localPoint)) {
2722 result.setScrollbar(m_vBar.get());
2727 resizeControlSize = max(resizeControlRect.width(), 0);
2728 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
2729 LayoutRect hBarRect(horizontalScrollbarStart(0),
2730 box->height() - box->borderBottom() - m_hBar->height(),
2731 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
2733 if (hBarRect.contains(localPoint)) {
2734 result.setScrollbar(m_hBar.get());
2742 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
2744 return ScrollableArea::scroll(direction, granularity, multiplier);
2747 void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, PaintLayerFlags paintFlags)
2749 OverlapTestRequestMap overlapTestRequests;
2750 paintLayer(this, context, damageRect, paintBehavior, paintingRoot, region, &overlapTestRequests, paintFlags);
2751 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2752 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
2753 it->first->setOverlapTestResult(false);
2756 void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
2758 if (!m_containsDirtyOverlayScrollbars)
2760 paintLayer(this, context, damageRect, paintBehavior, paintingRoot, 0, 0, PaintLayerHaveTransparency | PaintLayerTemporaryClipRects
2761 | PaintLayerPaintingOverlayScrollbars);
2762 m_containsDirtyOverlayScrollbars = false;
2765 #ifndef DISABLE_ROUNDED_CORNER_CLIPPING
2766 static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
2768 if (startLayer == endLayer)
2771 RenderView* view = startLayer->renderer()->view();
2772 for (RenderBlock* currentBlock = startLayer->renderer()->containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) {
2773 if (currentBlock->layer() == endLayer)
2781 void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect,
2782 BorderRadiusClippingRule rule)
2784 if (clipRect.rect() == paintDirtyRect)
2787 context->clip(pixelSnappedIntRect(clipRect.rect()));
2789 if (!clipRect.hasRadius())
2792 #ifndef DISABLE_ROUNDED_CORNER_CLIPPING
2793 // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
2794 // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
2795 // containing block chain so we check that also.
2796 for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
2797 if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
2799 layer->convertToLayerCoords(rootLayer, delta);
2800 context->addRoundedRectClip(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
2803 if (layer == rootLayer)
2809 void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
2811 if (clipRect.rect() == paintDirtyRect)
2816 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
2818 Vector<OverlapTestRequestClient*> overlappedRequestClients;
2819 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2820 LayoutRect boundingBox = layer->boundingBox(rootLayer);
2821 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
2822 if (!boundingBox.intersects(it->second))
2825 it->first->setOverlapTestResult(true);
2826 overlappedRequestClients.append(it->first);
2828 for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
2829 overlapTestRequests.remove(overlappedRequestClients[i]);
2832 #if USE(ACCELERATED_COMPOSITING)
2833 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
2835 return paintingReflection && !layer->has3DTransform();
2839 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
2841 // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
2842 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2843 // will do a full repaint().
2844 if (layer->renderer()->document()->didLayoutWithPendingStylesheets() && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot())
2847 // Avoid painting all layers if the document is in a state where visual updates aren't allowed.
2848 // A full repaint will occur in Document::implicitClose() if painting is suppressed here.
2849 if (!layer->renderer()->document()->visualUpdatesAllowed())
2856 void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context,
2857 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2858 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
2859 PaintLayerFlags paintFlags)
2861 #if USE(ACCELERATED_COMPOSITING)
2862 if (isComposited()) {
2863 // The updatingControlTints() painting pass goes through compositing layers,
2864 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
2865 if (context->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
2866 paintFlags |= PaintLayerTemporaryClipRects;
2867 else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
2868 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
2874 if (shouldSuppressPaintingLayer(this))
2877 // If this layer is totally invisible then there is nothing to paint.
2878 if (!renderer()->opacity())
2881 if (paintsWithTransparency(paintBehavior))
2882 paintFlags |= PaintLayerHaveTransparency;
2884 // PaintLayerAppliedTransform is used in RenderReplica, to avoid applying the transform twice.
2885 if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
2886 TransformationMatrix layerTransform = renderableTransform(paintBehavior);
2887 // If the transform can't be inverted, then don't paint anything.
2888 if (!layerTransform.isInvertible())
2891 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
2892 // layer from the parent now, assuming there is a parent
2893 if (paintFlags & PaintLayerHaveTransparency) {
2895 parent()->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
2897 beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
2900 // Make sure the parent's clip rects have been calculated.
2901 ClipRect clipRect = paintDirtyRect;
2903 clipRect = backgroundClipRect(rootLayer, region, paintFlags & PaintLayerTemporaryClipRects);
2904 clipRect.intersect(paintDirtyRect);
2906 // Push the parent coordinate space's clip.
2907 parent()->clipToRect(rootLayer, context, paintDirtyRect, clipRect);
2910 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2911 // This involves subtracting out the position of the layer in our current coordinate space.
2913 convertToLayerCoords(rootLayer, delta);
2914 TransformationMatrix transform(layerTransform);
2915 transform.translateRight(delta.x(), delta.y());
2917 // Apply the transform.
2919 GraphicsContextStateSaver stateSaver(*context);
2920 context->concatCTM(transform.toAffineTransform());
2922 // Now do a paint with the root layer shifted to be us.
2923 paintLayerContentsAndReflection(this, context, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
2926 // Restore the clip.
2928 parent()->restoreClip(context, paintDirtyRect, clipRect);
2933 paintLayerContentsAndReflection(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
2936 void RenderLayer::paintLayerContentsAndReflection(RenderLayer* rootLayer, GraphicsContext* context,
2937 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
2938 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
2939 PaintLayerFlags paintFlags)
2941 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
2943 // Paint the reflection first if we have one.
2944 if (m_reflection && !m_paintingInsideReflection) {
2945 // Mark that we are now inside replica painting.
2946 m_paintingInsideReflection = true;
2947 reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection);
2948 m_paintingInsideReflection = false;
2951 localPaintFlags |= PaintLayerPaintingCompositingAllPhases;
2952 paintLayerContents(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags);
2955 void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* context,
2956 const LayoutRect& parentPaintDirtyRect, PaintBehavior paintBehavior,
2957 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
2958 PaintLayerFlags paintFlags)
2960 PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
2961 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
2962 bool isSelfPaintingLayer = this->isSelfPaintingLayer();
2963 bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
2964 // Outline always needs to be painted even if we have no visible content.
2965 bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars;
2966 bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
2968 // Calculate the clip rects we should use only when we need them.
2969 LayoutRect layerBounds;
2970 ClipRect damageRect, clipRectToApply, outlineRect;
2971 LayoutPoint paintOffset;
2972 LayoutRect paintDirtyRect = parentPaintDirtyRect;
2974 bool useClipRect = true;
2975 GraphicsContext* transparencyLayerContext = context;
2977 // Ensure our lists are up-to-date.
2978 updateLayerListsIfNeeded();
2980 #if ENABLE(CSS_FILTERS)
2981 FilterEffectRendererHelper filterPainter(filter() && paintsWithFilters());
2982 if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) {
2983 LayoutPoint rootLayerOffset;
2984 convertToLayerCoords(rootLayer, rootLayerOffset);
2985 m_filterRepaintRect.move(rootLayerOffset.x(), rootLayerOffset.y());
2986 if (filterPainter.prepareFilterEffect(this, calculateLayerBounds(this, rootLayer, 0), parentPaintDirtyRect, m_filterRepaintRect)) {
2987 // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
2988 m_filterRepaintRect = IntRect();
2990 // Rewire the old context to a memory buffer, so that we can capture the contents of the layer.
2991 // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer
2992 // on the original context and avoid duplicating "beginFilterEffect" after each transpareny layer call. Also, note that
2993 // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method.
2994 context = filterPainter.beginFilterEffect(context);
2996 // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
2997 if (filterPainter.hasStartedFilterEffect()) {
2998 paintDirtyRect = filterPainter.repaintRect();
2999 // If the filter needs the full source image, we need to avoid using the clip rectangles.
3000 // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
3001 // Note that we will still apply the clipping on the final rendering of the filter.
3002 useClipRect = !filter()->hasFilterThatMovesPixels();
3008 if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
3009 calculateRects(rootLayer, region, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects);
3010 paintOffset = toPoint(layerBounds.location() - renderBoxLocation());
3013 bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText;
3014 bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly;
3016 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
3017 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
3018 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
3019 // so it will be tested against as we descend through the renderers.
3020 RenderObject* paintingRootForRenderer = 0;
3021 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
3022 paintingRootForRenderer = paintingRoot;
3024 if (overlapTestRequests && isSelfPaintingLayer)
3025 performOverlapTests(*overlapTestRequests, rootLayer, this);
3027 // We want to paint our layer, but only if we intersect the damage rect.
3028 shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer);
3030 if (localPaintFlags & PaintLayerPaintingCompositingBackgroundPhase) {
3031 if (shouldPaintContent && !selectionOnly) {
3032 // Begin transparency layers lazily now that we know we have to paint something.
3033 if (haveTransparency)
3034 beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior);
3037 // Paint our background first, before painting any child layers.
3038 // Establish the clip used to paint our background.
3039 clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
3042 // Paint the background.
3043 PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0);
3044 renderer()->paint(paintInfo, paintOffset);
3047 // Restore the clip.
3048 restoreClip(context, paintDirtyRect, damageRect);
3052 // Now walk the sorted list of children with negative z-indices.
3053 paintList(m_negZOrderList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags);
3056 if (localPaintFlags & PaintLayerPaintingCompositingForegroundPhase) {
3057 // Now establish the appropriate clip and paint our child RenderObjects.
3058 if (shouldPaintContent && !clipRectToApply.isEmpty()) {
3059 // Begin transparency layers lazily now that we know we have to paint something.
3060 if (haveTransparency)
3061 beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior);
3064 // Set up the clip used when painting our children.
3065 clipToRect(rootLayer, context, paintDirtyRect, clipRectToApply);
3068 PaintInfo paintInfo(context, pixelSnappedIntRect(clipRectToApply.rect()),
3069 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
3070 forceBlackText, paintingRootForRenderer, region, 0);
3071 renderer()->paint(paintInfo, paintOffset);
3072 if (!selectionOnly) {
3073 paintInfo.phase = PaintPhaseFloat;
3074 renderer()->paint(paintInfo, paintOffset);
3075 paintInfo.phase = PaintPhaseForeground;
3076 paintInfo.overlapTestRequests = overlapTestRequests;
3077 renderer()->paint(paintInfo, paintOffset);
3078 paintInfo.phase = PaintPhaseChildOutlines;
3079 renderer()->paint(paintInfo, paintOffset);
3083 // Now restore our clip.
3084 restoreClip(context, paintDirtyRect, clipRectToApply);
3088 if (shouldPaintOutline && !outlineRect.isEmpty()) {
3089 // Paint our own outline
3090 PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, region, 0);
3091 clipToRect(rootLayer, context, paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius);
3092 renderer()->paint(paintInfo, paintOffset);
3093 restoreClip(context, paintDirtyRect, outlineRect);
3096 // Paint any child layers that have overflow.
3097 paintList(m_normalFlowList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags);
3099 // Now walk the sorted list of children with positive z-indices.
3100 paintList(m_posZOrderList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags);
3103 if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) {
3105 clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
3108 PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, region, 0);
3109 renderer()->paint(paintInfo, paintOffset);
3112 // Restore the clip.
3113 restoreClip(context, paintDirtyRect, damageRect);
3117 if (isPaintingOverlayScrollbars) {
3118 clipToRect(rootLayer, context, paintDirtyRect, damageRect);
3119 paintOverflowControls(context, roundedIntPoint(paintOffset), pixelSnappedIntRect(damageRect.rect()), true);
3120 restoreClip(context, paintDirtyRect, damageRect);
3123 #if ENABLE(CSS_FILTERS)
3124 if (filterPainter.hasStartedFilterEffect()) {
3125 // Apply the correct clipping (ie. overflow: hidden).
3126 clipToRect(rootLayer, transparencyLayerContext, paintDirtyRect, damageRect);
3127 context = filterPainter.applyFilterEffect();
3128 restoreClip(transparencyLayerContext, paintDirtyRect, damageRect);
3132 // Make sure that we now use the original transparency context.
3133 ASSERT(transparencyLayerContext == context);
3135 // End our transparency layer
3136 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
3137 context->endTransparencyLayer();
3139 m_usedTransparency = false;
3143 void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* context,
3144 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
3145 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
3146 PaintLayerFlags paintFlags)
3151 #if !ASSERT_DISABLED
3152 LayerListMutationDetector mutationChecker(this);
3155 for (size_t i = 0; i < list->size(); ++i) {
3156 RenderLayer* childLayer = list->at(i);
3157 if (!childLayer->isPaginated())
3158 childLayer->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
3160 paintPaginatedChildLayer(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
3164 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
3165 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
3166 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
3167 PaintLayerFlags paintFlags)
3169 // We need to do multiple passes, breaking up our child layer into strips.
3170 Vector<RenderLayer*> columnLayers;
3171 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
3172 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
3173 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
3174 columnLayers.append(curr);
3175 if (curr == ancestorLayer)
3179 // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before
3180 // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
3181 // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer.
3182 if (!columnLayers.size())
3185 paintChildLayerIntoColumns(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags, columnLayers, columnLayers.size() - 1);
3188 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
3189 const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior,
3190 RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests,
3191 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
3193 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
3195 ASSERT(columnBlock && columnBlock->hasColumns());
3196 if (!columnBlock || !columnBlock->hasColumns())
3199 LayoutPoint layerOffset;
3200 // FIXME: It looks suspicious to call convertToLayerCoords here
3201 // as canUseConvertToLayerCoords is true for this layer.
3202 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset);
3204 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
3206 ColumnInfo* colInfo = columnBlock->columnInfo();
3207 unsigned colCount = columnBlock->columnCount(colInfo);
3208 int currLogicalTopOffset = 0;
3209 for (unsigned i = 0; i < colCount; i++) {
3210 // For each rect, we clip to the rect, and then we adjust our coords.
3211 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
3212 columnBlock->flipForWritingMode(colRect);
3213 int logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
3216 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3217 offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset);
3219 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
3221 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3222 offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset);
3224 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
3227 colRect.moveBy(layerOffset);
3229 LayoutRect localDirtyRect(paintDirtyRect);
3230 localDirtyRect.intersect(colRect);
3232 if (!localDirtyRect.isEmpty()) {
3233 GraphicsContextStateSaver stateSaver(*context);
3235 // Each strip pushes a clip, since column boxes are specified as being
3236 // like overflow:hidden.
3237 context->clip(colRect);
3240 // Apply a translation transform to change where the layer paints.
3241 TransformationMatrix oldTransform;
3242 bool oldHasTransform = childLayer->transform();
3243 if (oldHasTransform)
3244 oldTransform = *childLayer->transform();
3245 TransformationMatrix newTransform(oldTransform);
3246 newTransform.translateRight(offset.width(), offset.height());
3248 childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
3249 childLayer->paintLayer(rootLayer, context, localDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, paintFlags);
3250 if (oldHasTransform)
3251 childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
3253 childLayer->m_transform.clear();
3255 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
3256 // This involves subtracting out the position of the layer in our current coordinate space.
3257 LayoutPoint childOffset;
3258 columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childOffset);
3259 TransformationMatrix transform;
3260 transform.translateRight(childOffset.x() + offset.width(), childOffset.y() + offset.height());
3262 // Apply the transform.
3263 context->concatCTM(transform.toAffineTransform());
3265 // Now do a paint with the root layer shifted to be the next multicol block.
3266 paintChildLayerIntoColumns(childLayer, columnLayers[colIndex - 1], context, transform.inverse().mapRect(localDirtyRect), paintBehavior,
3267 paintingRoot, region, overlapTestRequests, paintFlags,
3268 columnLayers, colIndex - 1);
3272 // Move to the next position.
3273 int blockDelta = isHorizontal ? colRect.height() : colRect.width();
3274 if (columnBlock->style()->isFlippedBlocksWritingMode())
3275 currLogicalTopOffset += blockDelta;
3277 currLogicalTopOffset -= blockDelta;
3281 static inline LayoutRect frameVisibleRect(RenderObject* renderer)
3283 FrameView* frameView = renderer->document()->view();
3285 return LayoutRect();
3287 return frameView->visibleContentRect();
3290 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
3292 renderer()->document()->updateLayout();
3294 LayoutRect hitTestArea = renderer()->isRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
3295 if (!request.ignoreClipping())
3296 hitTestArea.intersect(frameVisibleRect(renderer()));
3298 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, result.point(), false);
3300 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
3301 // return ourselves. We do this so mouse events continue getting delivered after a drag has
3302 // exited the WebView, and so hit testing over a scrollbar hits the content document.
3303 if ((request.active() || request.release()) && renderer()->isRenderView()) {
3304 renderer()->updateHitTestResult(result, result.point());
3309 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
3310 Node* node = result.innerNode();
3311 if (node && !result.URLElement())
3312 result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
3314 // Next set up the correct :hover/:active state along the new chain.
3315 updateHoverActiveState(request, result);
3317 // Now return whether we were inside this layer (this will always be true for the root
3322 Node* RenderLayer::enclosingElement() const
3324 for (RenderObject* r = renderer(); r; r = r->parent()) {
3325 if (Node* e = r->node())
3328 ASSERT_NOT_REACHED();
3332 // Compute the z-offset of the point in the transformState.
3333 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
3334 // ray intersects target, and computing the z delta between those two points.
3335 static double computeZOffset(const HitTestingTransformState& transformState)
3337 // We got an affine transform, so no z-offset
3338 if (transformState.m_accumulatedTransform.isAffine())
3341 // Flatten the point into the target plane
3342 FloatPoint targetPoint = transformState.mappedPoint();
3344 // Now map the point back through the transform, which computes Z.
3345 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
3346 return backmappedPoint.z();
3349 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
3350 const LayoutRect& hitTestRect, const LayoutPoint& hitTestPoint,
3351 const HitTestingTransformState* containerTransformState) const
3353 RefPtr<HitTestingTransformState> transformState;
3355 if (containerTransformState) {
3356 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
3357 transformState = HitTestingTransformState::create(*containerTransformState);
3358 convertToLayerCoords(containerLayer,