Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1644)

Unified Diff: Source/core/rendering/RenderLayer.cpp

Issue 898783003: Move rendering/RenderLayer* to layout/ (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | Source/core/rendering/RenderLayerClipper.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderLayer.cpp
diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp
deleted file mode 100644
index 585336ca6bd21e49a3714fc8b50d998f5fde9823..0000000000000000000000000000000000000000
--- a/Source/core/rendering/RenderLayer.cpp
+++ /dev/null
@@ -1,2935 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
- *
- * Portions are Copyright (C) 1998 Netscape Communications Corporation.
- *
- * Other contributors:
- * Robert O'Callahan <roc+@cs.cmu.edu>
- * David Baron <dbaron@fas.harvard.edu>
- * Christian Biesinger <cbiesinger@web.de>
- * Randall Jesup <rjesup@wgate.com>
- * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
- * Josh Soref <timeless@mac.com>
- * Boris Zbarsky <bzbarsky@mit.edu>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Alternatively, the contents of this file may be used under the terms
- * of either the Mozilla Public License Version 1.1, found at
- * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
- * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
- * (the "GPL"), in which case the provisions of the MPL or the GPL are
- * applicable instead of those above. If you wish to allow use of your
- * version of this file only under the terms of one of those two
- * licenses (the MPL or the GPL) and not to allow others to use your
- * version of this file under the LGPL, indicate your decision by
- * deletingthe provisions above and replace them with the notice and
- * other provisions required by the MPL or the GPL, as the case may be.
- * If you do not delete the provisions above, a recipient may use your
- * version of this file under any of the LGPL, the MPL or the GPL.
- */
-
-#include "config.h"
-#include "core/rendering/RenderLayer.h"
-
-#include "core/CSSPropertyNames.h"
-#include "core/HTMLNames.h"
-#include "core/css/PseudoStyleRequest.h"
-#include "core/dom/Document.h"
-#include "core/dom/shadow/ShadowRoot.h"
-#include "core/frame/DeprecatedScheduleStyleRecalcDuringLayout.h"
-#include "core/frame/FrameView.h"
-#include "core/frame/LocalFrame.h"
-#include "core/html/HTMLFrameElement.h"
-#include "core/layout/HitTestRequest.h"
-#include "core/layout/HitTestResult.h"
-#include "core/layout/HitTestingTransformState.h"
-#include "core/layout/LayoutTreeAsText.h"
-#include "core/layout/compositing/CompositedLayerMapping.h"
-#include "core/layout/compositing/RenderLayerCompositor.h"
-#include "core/page/Page.h"
-#include "core/page/scrolling/ScrollingCoordinator.h"
-#include "core/rendering/ColumnInfo.h"
-#include "core/rendering/FilterEffectRenderer.h"
-#include "core/rendering/RenderFlowThread.h"
-#include "core/rendering/RenderGeometryMap.h"
-#include "core/rendering/RenderInline.h"
-#include "core/rendering/RenderPart.h"
-#include "core/rendering/RenderReplica.h"
-#include "core/rendering/RenderScrollbar.h"
-#include "core/rendering/RenderScrollbarPart.h"
-#include "core/rendering/RenderView.h"
-#include "core/rendering/svg/ReferenceFilterBuilder.h"
-#include "core/rendering/svg/RenderSVGRoot.h"
-#include "platform/LengthFunctions.h"
-#include "platform/Partitions.h"
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/TraceEvent.h"
-#include "platform/geometry/FloatPoint3D.h"
-#include "platform/geometry/FloatRect.h"
-#include "platform/geometry/TransformState.h"
-#include "platform/graphics/filters/ReferenceFilter.h"
-#include "platform/graphics/filters/SourceGraphic.h"
-#include "platform/transforms/ScaleTransformOperation.h"
-#include "platform/transforms/TransformationMatrix.h"
-#include "platform/transforms/TranslateTransformOperation.h"
-#include "public/platform/Platform.h"
-#include "wtf/StdLibExtras.h"
-#include "wtf/text/CString.h"
-
-namespace blink {
-
-namespace {
-
-static CompositingQueryMode gCompositingQueryMode =
- CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases;
-
-} // namespace
-
-using namespace HTMLNames;
-
-RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type)
- : m_layerType(type)
- , m_hasSelfPaintingLayerDescendant(false)
- , m_hasSelfPaintingLayerDescendantDirty(false)
- , m_isRootLayer(renderer->isRenderView())
- , m_visibleContentStatusDirty(true)
- , m_hasVisibleContent(false)
- , m_visibleDescendantStatusDirty(false)
- , m_hasVisibleDescendant(false)
- , m_hasVisibleNonLayerContent(false)
- , m_isPaginated(false)
-#if ENABLE(ASSERT)
- , m_needsPositionUpdate(true)
-#endif
- , m_3DTransformedDescendantStatusDirty(true)
- , m_has3DTransformedDescendant(false)
- , m_containsDirtyOverlayScrollbars(false)
- , m_hasFilterInfo(false)
- , m_needsAncestorDependentCompositingInputsUpdate(true)
- , m_needsDescendantDependentCompositingInputsUpdate(true)
- , m_childNeedsCompositingInputsUpdate(true)
- , m_hasCompositingDescendant(false)
- , m_hasNonCompositedChild(false)
- , m_shouldIsolateCompositedDescendants(false)
- , m_lostGroupedMapping(false)
- , m_renderer(renderer)
- , m_parent(0)
- , m_previous(0)
- , m_next(0)
- , m_first(0)
- , m_last(0)
- , m_staticInlinePosition(0)
- , m_staticBlockPosition(0)
- , m_enclosingPaginationLayer(0)
- , m_potentialCompositingReasonsFromStyle(CompositingReasonNone)
- , m_compositingReasons(CompositingReasonNone)
- , m_groupedMapping(0)
- , m_clipper(*renderer)
-{
- updateStackingNode();
-
- m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
-
- if (!renderer->slowFirstChild() && renderer->style()) {
- m_visibleContentStatusDirty = false;
- m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
- }
-
- updateScrollableArea();
-}
-
-RenderLayer::~RenderLayer()
-{
- if (renderer()->frame() && renderer()->frame()->page()) {
- if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->page()->scrollingCoordinator())
- scrollingCoordinator->willDestroyRenderLayer(this);
- }
-
- removeFilterInfoIfNeeded();
-
- if (groupedMapping()) {
- DisableCompositingQueryAsserts disabler;
- groupedMapping()->removeRenderLayerFromSquashingGraphicsLayer(this);
- setGroupedMapping(0);
- }
-
- // Child layers will be deleted by their corresponding render objects, so
- // we don't need to delete them ourselves.
-
- clearCompositedLayerMapping(true);
-
- if (m_reflectionInfo)
- m_reflectionInfo->destroy();
-}
-
-String RenderLayer::debugName() const
-{
- if (isReflection()) {
- return renderer()->parent()->debugName() + " (reflection)";
- }
- return renderer()->debugName();
-}
-
-RenderLayerCompositor* RenderLayer::compositor() const
-{
- if (!renderer()->view())
- return 0;
- return renderer()->view()->compositor();
-}
-
-void RenderLayer::contentChanged(ContentChangeType changeType)
-{
- // updateLayerCompositingState will query compositingReasons for accelerated overflow scrolling.
- // This is tripped by LayoutTests/compositing/content-changed-chicken-egg.html
- DisableCompositingQueryAsserts disabler;
-
- if (changeType == CanvasChanged)
- compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
-
- if (changeType == CanvasContextChanged) {
- compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
-
- // Although we're missing test coverage, we need to call
- // GraphicsLayer::setContentsToPlatformLayer with the new platform
- // layer for this canvas.
- // See http://crbug.com/349195
- if (hasCompositedLayerMapping())
- compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
- }
-
- if (m_compositedLayerMapping)
- m_compositedLayerMapping->contentChanged(changeType);
-}
-
-bool RenderLayer::paintsWithFilters() const
-{
- if (!renderer()->hasFilter())
- return false;
-
- // https://code.google.com/p/chromium/issues/detail?id=343759
- DisableCompositingQueryAsserts disabler;
- return !m_compositedLayerMapping || compositingState() != PaintsIntoOwnBacking;
-}
-
-LayoutSize RenderLayer::subpixelAccumulation() const
-{
- return m_subpixelAccumulation;
-}
-
-void RenderLayer::setSubpixelAccumulation(const LayoutSize& size)
-{
- m_subpixelAccumulation = size;
-}
-
-void RenderLayer::updateLayerPositionsAfterLayout()
-{
- TRACE_EVENT0("blink,benchmark", "RenderLayer::updateLayerPositionsAfterLayout");
-
- m_clipper.clearClipRectsIncludingDescendants();
- updateLayerPositionRecursive();
-
- {
- // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
- // https://code.google.com/p/chromium/issues/detail?id=343756
- DisableCompositingQueryAsserts disabler;
- bool needsPaginationUpdate = isPaginated() || enclosingPaginationLayer();
- updatePaginationRecursive(needsPaginationUpdate);
- }
-}
-
-void RenderLayer::updateLayerPositionRecursive()
-{
- updateLayerPosition();
-
- if (m_reflectionInfo)
- m_reflectionInfo->reflection()->layout();
-
- // FIXME: We should be able to remove this call because we don't care about
- // any descendant-dependent flags, but code somewhere else is reading these
- // flags and depending on us to update them.
- updateDescendantDependentFlags();
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateLayerPositionRecursive();
-}
-
-void RenderLayer::updateHasSelfPaintingLayerDescendant() const
-{
- ASSERT(m_hasSelfPaintingLayerDescendantDirty);
-
- m_hasSelfPaintingLayerDescendant = false;
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) {
- m_hasSelfPaintingLayerDescendant = true;
- break;
- }
- }
-
- m_hasSelfPaintingLayerDescendantDirty = false;
-}
-
-void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
-{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- layer->m_hasSelfPaintingLayerDescendantDirty = true;
- // If we have reached a self-painting layer, we know our parent should have a self-painting descendant
- // in this case, there is no need to dirty our ancestors further.
- if (layer->isSelfPaintingLayer()) {
- ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->m_hasSelfPaintingLayerDescendant);
- break;
- }
- }
-}
-
-bool RenderLayer::scrollsWithViewport() const
-{
- return renderer()->style()->position() == FixedPosition && renderer()->containerForFixedPosition() == renderer()->view();
-}
-
-bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const
-{
- if (scrollsWithViewport() != other->scrollsWithViewport())
- return true;
- return ancestorScrollingLayer() != other->ancestorScrollingLayer();
-}
-
-void RenderLayer::updateLayerPositionsAfterOverflowScroll()
-{
- m_clipper.clearClipRectsIncludingDescendants();
- updateLayerPositionsAfterScrollRecursive();
-}
-
-void RenderLayer::updateLayerPositionsAfterScrollRecursive()
-{
- if (updateLayerPosition())
- m_renderer->setPreviousPaintInvalidationRect(m_renderer->boundsRectForPaintInvalidation(m_renderer->containerForPaintInvalidation()));
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateLayerPositionsAfterScrollRecursive();
-}
-
-void RenderLayer::updateTransformationMatrix()
-{
- if (m_transform) {
- RenderBox* box = renderBox();
- ASSERT(box);
- m_transform->makeIdentity();
- box->style()->applyTransform(*m_transform, LayoutSize(box->pixelSnappedSize()), RenderStyle::IncludeTransformOrigin);
- makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositing());
- }
-}
-
-void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle)
-{
- if (oldStyle && newStyle->transformDataEquivalent(*oldStyle))
- return;
-
- // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
- // so check style too.
- bool hasTransform = renderer()->hasTransformRelatedProperty() && newStyle->hasTransform();
- bool had3DTransform = has3DTransform();
-
- bool hadTransform = m_transform;
- if (hasTransform != hadTransform) {
- if (hasTransform)
- m_transform = adoptPtr(new TransformationMatrix);
- else
- m_transform.clear();
-
- // Layers with transforms act as clip rects roots, so clear the cached clip rects here.
- m_clipper.clearClipRectsIncludingDescendants();
- } else if (hasTransform) {
- m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects);
- }
-
- updateTransformationMatrix();
-
- if (had3DTransform != has3DTransform())
- dirty3DTransformedDescendantStatus();
-}
-
-static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer)
-{
- if (RenderObject* containingBlock = layer->renderer()->containingBlock())
- return containingBlock->enclosingLayer();
- return 0;
-}
-
-RenderLayer* RenderLayer::renderingContextRoot()
-{
- RenderLayer* renderingContext = 0;
-
- if (shouldPreserve3D())
- renderingContext = this;
-
- for (RenderLayer* current = enclosingLayerForContainingBlock(this); current && current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(current))
- renderingContext = current;
-
- return renderingContext;
-}
-
-TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
-{
- if (!m_transform)
- return TransformationMatrix();
-
- // m_transform includes transform-origin, so we need to recompute the transform here.
- if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
- RenderBox* box = renderBox();
- TransformationMatrix currTransform;
- box->style()->applyTransform(currTransform, LayoutSize(box->pixelSnappedSize()), RenderStyle::ExcludeTransformOrigin);
- makeMatrixRenderable(currTransform, compositor()->hasAcceleratedCompositing());
- return currTransform;
- }
-
- return *m_transform;
-}
-
-TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
-{
- if (!m_transform)
- return TransformationMatrix();
-
- if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
- TransformationMatrix matrix = *m_transform;
- makeMatrixRenderable(matrix, false /* flatten 3d */);
- return matrix;
- }
-
- return *m_transform;
-}
-
-static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
-{
- RenderView* view = renderer->view();
- RenderLayerModelObject* prevBlock = renderer;
- RenderBlock* containingBlock;
- for (containingBlock = renderer->containingBlock();
- containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
- containingBlock = containingBlock->containingBlock())
- prevBlock = containingBlock;
-
- // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
- if (containingBlock != ancestorColumnsRenderer)
- return false;
-
- // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
- if (prevBlock->isOutOfFlowPositioned())
- return false;
-
- // Otherwise we are paginated by the columns block.
- return true;
-}
-
-// Convert a bounding box from flow thread coordinates, relative to |layer|, to visual coordinates, relative to |ancestorLayer|.
-// See http://www.chromium.org/developers/design-documents/multi-column-layout for more info on these coordinate types.
-static void convertFromFlowThreadToVisualBoundingBoxInAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutRect& rect)
-{
- RenderLayer* paginationLayer = layer->enclosingPaginationLayer();
- ASSERT(paginationLayer);
- RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer());
-
- // First make the flow thread rectangle relative to the flow thread, not to |layer|.
- LayoutPoint offsetWithinPaginationLayer;
- layer->convertToLayerCoords(paginationLayer, offsetWithinPaginationLayer);
- rect.moveBy(offsetWithinPaginationLayer);
-
- // Then make the rectangle visual, relative to the fragmentation context. Split our box up into
- // the actual fragment boxes that render in the columns/pages and unite those together to get
- // our true bounding box.
- rect = flowThread->fragmentsBoundingBox(rect);
-
- // Finally, make the visual rectangle relative to |ancestorLayer|.
- if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) {
- rect.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer));
- return;
- }
- // The ancestor layer is inside the same pagination layer as |layer|, so we need to subtract
- // the visual distance from the ancestor layer to the pagination layer.
- rect.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer));
-}
-
-bool RenderLayer::useRegionBasedColumns() const
-{
- return renderer()->document().regionBasedColumnsEnabled();
-}
-
-void RenderLayer::updatePaginationRecursive(bool needsPaginationUpdate)
-{
- m_isPaginated = false;
- m_enclosingPaginationLayer = 0;
-
- if (useRegionBasedColumns() && renderer()->isRenderFlowThread())
- needsPaginationUpdate = true;
-
- if (needsPaginationUpdate)
- updatePagination();
-
- if (renderer()->hasColumns())
- needsPaginationUpdate = true;
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updatePaginationRecursive(needsPaginationUpdate);
-}
-
-void RenderLayer::updatePagination()
-{
- bool usesRegionBasedColumns = useRegionBasedColumns();
- if ((!usesRegionBasedColumns && compositingState() != NotComposited) || !parent())
- return; // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
-
- // The main difference between the paginated booleans for the old column code and the new column code
- // is that each paginated layer has to paint on its own with the new code. There is no
- // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on
- // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and
- // genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
- // layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
- // to that layer easily.
- if (usesRegionBasedColumns && renderer()->isRenderFlowThread()) {
- m_enclosingPaginationLayer = this;
- return;
- }
-
- if (m_stackingNode->isNormalFlowOnly()) {
- if (usesRegionBasedColumns) {
- // Content inside a transform is not considered to be paginated, since we simply
- // paint the transform multiple times in each column, so we don't have to use
- // fragments for the transformed content.
- m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
- if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransformRelatedProperty())
- m_enclosingPaginationLayer = 0;
- } else {
- m_isPaginated = parent()->renderer()->hasColumns();
- }
- return;
- }
-
- // For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
- // we find one, then we just check its pagination status.
- if (usesRegionBasedColumns) {
- RenderView* view = renderer()->view();
- RenderBlock* containingBlock;
- for (containingBlock = renderer()->containingBlock();
- containingBlock && containingBlock != view;
- containingBlock = containingBlock->containingBlock()) {
- if (containingBlock->hasLayer()) {
- // Content inside a transform is not considered to be paginated, since we simply
- // paint the transform multiple times in each column, so we don't have to use
- // fragments for the transformed content.
- m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
- if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransformRelatedProperty())
- m_enclosingPaginationLayer = 0;
- return;
- }
- }
- return;
- }
-
- // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
- RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ancestorStackingContextNode();
- for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
- if (curr->renderer()->hasColumns()) {
- m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
- return;
- }
- if (curr->stackingNode() == ancestorStackingContextNode)
- return;
- }
-}
-
-void RenderLayer::clearPaginationRecursive()
-{
- m_enclosingPaginationLayer = 0;
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->clearPaginationRecursive();
-}
-
-LayoutPoint RenderLayer::positionFromPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
-{
- FloatPoint point = renderObject->localToContainerPoint(FloatPoint(), paintInvalidationContainer, 0, 0, paintInvalidationState);
-
- // FIXME: Eventually we are going to unify coordinates in GraphicsLayer space.
- if (paintInvalidationContainer && paintInvalidationContainer->layer()->groupedMapping())
- mapPointToPaintBackingCoordinates(paintInvalidationContainer, point);
-
- return LayoutPoint(point);
-}
-
-void RenderLayer::mapPointToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, FloatPoint& point)
-{
- RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
- if (!paintInvalidationLayer->groupedMapping()) {
- point.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
- return;
- }
-
- RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
- if (!transformedAncestor)
- return;
-
- // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
- // transformed ancestor.
- point = paintInvalidationContainer->localToContainerPoint(point, transformedAncestor);
-
- point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
-}
-
-void RenderLayer::mapRectToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect)
-{
- RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
- if (!paintInvalidationLayer->groupedMapping()) {
- rect.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
- return;
- }
-
- RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
- if (!transformedAncestor)
- return;
-
- // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
- // transformed ancestor.
- rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect(rect), transformedAncestor).boundingBox());
-
- rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
-}
-
-void RenderLayer::mapRectToPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState)
-{
- if (!paintInvalidationContainer->layer()->groupedMapping()) {
- renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
- return;
- }
-
- // This code adjusts the paint invalidation rectangle to be in the space of the transformed ancestor of the grouped (i.e. squashed)
- // layer. This is because all layers that squash together need to issue paint invalidations w.r.t. a single container that is
- // an ancestor of all of them, in order to properly take into account any local transforms etc.
- // FIXME: remove this special-case code that works around the paint invalidation code structure.
- renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
-
- mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
-}
-
-LayoutRect RenderLayer::computePaintInvalidationRect(const RenderObject* renderObject, const RenderLayer* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
-{
- if (!paintInvalidationContainer->groupedMapping())
- return renderObject->computePaintInvalidationRect(paintInvalidationContainer->renderer(), paintInvalidationState);
-
- LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer->renderer(), paintInvalidationState);
- mapRectToPaintBackingCoordinates(paintInvalidationContainer->renderer(), rect);
- return rect;
-}
-
-void RenderLayer::dirtyVisibleContentStatus()
-{
- m_visibleContentStatusDirty = true;
- if (parent())
- parent()->dirtyAncestorChainVisibleDescendantStatus();
-}
-
-void RenderLayer::potentiallyDirtyVisibleContentStatus(EVisibility visibility)
-{
- if (m_visibleContentStatusDirty)
- return;
- if (hasVisibleContent() == (visibility == VISIBLE))
- return;
- dirtyVisibleContentStatus();
-}
-
-void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
-{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (layer->m_visibleDescendantStatusDirty)
- break;
-
- layer->m_visibleDescendantStatusDirty = true;
- }
-}
-
-// FIXME: this is quite brute-force. We could be more efficient if we were to
-// track state and update it as appropriate as changes are made in the Render tree.
-void RenderLayer::updateScrollingStateAfterCompositingChange()
-{
- TRACE_EVENT0("blink", "RenderLayer::updateScrollingStateAfterCompositingChange");
- m_hasVisibleNonLayerContent = false;
- for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()) {
- if (!r->hasLayer()) {
- m_hasVisibleNonLayerContent = true;
- break;
- }
- }
-
- m_hasNonCompositedChild = false;
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- if (child->compositingState() == NotComposited) {
- m_hasNonCompositedChild = true;
- return;
- }
- }
-}
-
-// The descendant-dependent flags system is badly broken because we clean dirty
-// bits in upward tree walks, which means we need to call updateDescendantDependentFlags
-// at every node in the tree to fully clean all the dirty bits. While we'll in
-// the process of fixing this issue, updateDescendantDependentFlagsForEntireSubtree
-// provides a big hammer for actually cleaning all the dirty bits in a subtree.
-//
-// FIXME: Remove this function once the descendant-dependent flags system keeps
-// its dirty bits scoped to subtrees.
-void RenderLayer::updateDescendantDependentFlagsForEntireSubtree()
-{
- updateDescendantDependentFlags();
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateDescendantDependentFlagsForEntireSubtree();
-}
-
-void RenderLayer::updateDescendantDependentFlags()
-{
- if (m_visibleDescendantStatusDirty) {
- m_hasVisibleDescendant = false;
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- child->updateDescendantDependentFlags();
-
- if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
- m_hasVisibleDescendant = true;
- break;
- }
- }
-
- m_visibleDescendantStatusDirty = false;
- }
-
- if (m_visibleContentStatusDirty) {
- bool previouslyHasVisibleContent = m_hasVisibleContent;
- if (renderer()->style()->visibility() == VISIBLE)
- m_hasVisibleContent = true;
- else {
- // layer may be hidden but still have some visible content, check for this
- m_hasVisibleContent = false;
- RenderObject* r = renderer()->slowFirstChild();
- while (r) {
- if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
- m_hasVisibleContent = true;
- break;
- }
- RenderObject* rendererFirstChild = r->slowFirstChild();
- if (rendererFirstChild && !r->hasLayer())
- r = rendererFirstChild;
- else if (r->nextSibling())
- r = r->nextSibling();
- else {
- do {
- r = r->parent();
- if (r == renderer())
- r = 0;
- } while (r && !r->nextSibling());
- if (r)
- r = r->nextSibling();
- }
- }
- }
- m_visibleContentStatusDirty = false;
-
- if (hasVisibleContent() != previouslyHasVisibleContent) {
- setNeedsCompositingInputsUpdate();
- // We need to tell m_renderer to recheck its rect because we
- // pretend that invisible RenderObjects have 0x0 rects. Changing
- // visibility therefore changes our rect and we need to visit
- // this RenderObject during the invalidateTreeIfNeeded walk.
- m_renderer->setMayNeedPaintInvalidation();
- }
- }
-}
-
-void RenderLayer::dirty3DTransformedDescendantStatus()
-{
- RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContextNode();
- if (!stackingNode)
- return;
-
- stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
-
- // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
- // Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
- while (stackingNode && stackingNode->layer()->preserves3D()) {
- stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
- stackingNode = stackingNode->ancestorStackingContextNode();
- }
-}
-
-// Return true if this layer or any preserve-3d descendants have 3d.
-bool RenderLayer::update3DTransformedDescendantStatus()
-{
- if (m_3DTransformedDescendantStatusDirty) {
- m_has3DTransformedDescendant = false;
-
- m_stackingNode->updateZOrderLists();
-
- // Transformed or preserve-3d descendants can only be in the z-order lists, not
- // in the normal flow list, so we only need to check those.
- RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), PositiveZOrderChildren | NegativeZOrderChildren);
- while (RenderLayerStackingNode* node = iterator.next())
- m_has3DTransformedDescendant |= node->layer()->update3DTransformedDescendantStatus();
-
- m_3DTransformedDescendantStatusDirty = false;
- }
-
- // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
- // the m_has3DTransformedDescendant set.
- if (preserves3D())
- return has3DTransform() || m_has3DTransformedDescendant;
-
- return has3DTransform();
-}
-
-bool RenderLayer::updateLayerPosition()
-{
- LayoutPoint localPoint;
- LayoutPoint inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
-
- if (renderer()->isInline() && renderer()->isRenderInline()) {
- RenderInline* inlineFlow = toRenderInline(renderer());
- IntRect lineBox = inlineFlow->linesBoundingBox();
- m_size = lineBox.size();
- inlineBoundingBoxOffset = lineBox.location();
- localPoint.moveBy(inlineBoundingBoxOffset);
- } else if (RenderBox* box = renderBox()) {
- m_size = pixelSnappedIntSize(box->size(), box->location());
- localPoint.moveBy(box->topLeftLocation());
- }
-
- if (!renderer()->isOutOfFlowPositioned() && !renderer()->isColumnSpanAll() && renderer()->parent()) {
- // We must adjust our position by walking up the render tree looking for the
- // nearest enclosing object with a layer.
- RenderObject* curr = renderer()->parent();
- while (curr && !curr->hasLayer()) {
- if (curr->isBox() && !curr->isTableRow()) {
- // Rows and cells share the same coordinate space (that of the section).
- // Omit them when computing our xpos/ypos.
- localPoint.moveBy(toRenderBox(curr)->topLeftLocation());
- }
- curr = curr->parent();
- }
- if (curr->isBox() && curr->isTableRow()) {
- // Put ourselves into the row coordinate space.
- localPoint.moveBy(-toRenderBox(curr)->topLeftLocation());
- }
- }
-
- // Subtract our parent's scroll offset.
- if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
- RenderLayer* positionedParent = enclosingPositionedAncestor();
-
- // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
- if (positionedParent->renderer()->hasOverflowClip()) {
- IntSize offset = positionedParent->renderBox()->scrolledContentOffset();
- localPoint -= offset;
- }
-
- if (positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
- LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(*toRenderBox(renderer()));
- localPoint += offset;
- }
- } else if (parent()) {
- // FIXME: This code is very wrong, but luckily only needed in the old/current multicol
- // implementation. The compositing system doesn't understand columns and we're hacking
- // around that fact by faking the position of the RenderLayers when we think we'll end up
- // being composited.
- if (hasStyleDeterminedDirectCompositingReasons() && !useRegionBasedColumns()) {
- // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
- // They won't split across columns properly.
- if (!parent()->renderer()->hasColumns() && parent()->renderer()->isDocumentElement() && renderer()->view()->hasColumns())
- localPoint += renderer()->view()->columnOffset(localPoint);
- else
- localPoint += parent()->renderer()->columnOffset(localPoint);
- }
-
- if (parent()->renderer()->hasOverflowClip()) {
- IntSize scrollOffset = parent()->renderBox()->scrolledContentOffset();
- localPoint -= scrollOffset;
- }
- }
-
- bool positionOrOffsetChanged = false;
- if (renderer()->isRelPositioned()) {
- LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFlowPosition();
- positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
- m_offsetForInFlowPosition = newOffset;
- localPoint.move(m_offsetForInFlowPosition);
- } else {
- m_offsetForInFlowPosition = LayoutSize();
- }
-
- // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
- localPoint.moveBy(-inlineBoundingBoxOffset);
-
- if (m_location != localPoint)
- positionOrOffsetChanged = true;
- m_location = localPoint;
-
-#if ENABLE(ASSERT)
- m_needsPositionUpdate = false;
-#endif
- return positionOrOffsetChanged;
-}
-
-TransformationMatrix RenderLayer::perspectiveTransform() const
-{
- if (!renderer()->hasTransformRelatedProperty())
- return TransformationMatrix();
-
- RenderStyle* style = renderer()->style();
- if (!style->hasPerspective())
- return TransformationMatrix();
-
- // Maybe fetch the perspective from the backing?
- const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect();
- const float boxWidth = borderBox.width();
- const float boxHeight = borderBox.height();
-
- float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth);
- float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight);
-
- // A perspective origin of 0,0 makes the vanishing point in the center of the element.
- // We want it to be in the top-left, so subtract half the height and width.
- perspectiveOriginX -= boxWidth / 2.0f;
- perspectiveOriginY -= boxHeight / 2.0f;
-
- TransformationMatrix t;
- t.translate(perspectiveOriginX, perspectiveOriginY);
- t.applyPerspective(style->perspective());
- t.translate(-perspectiveOriginX, -perspectiveOriginY);
-
- return t;
-}
-
-FloatPoint RenderLayer::perspectiveOrigin() const
-{
- if (!renderer()->hasTransformRelatedProperty())
- return FloatPoint();
-
- const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
- RenderStyle* style = renderer()->style();
-
- return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.height().toFloat()));
-}
-
-static inline bool isFixedPositionedContainer(RenderLayer* layer)
-{
- return layer->isRootLayer() || layer->hasTransformRelatedProperty();
-}
-
-RenderLayer* RenderLayer::enclosingPositionedAncestor() const
-{
- RenderLayer* curr = parent();
- while (curr && !curr->isPositionedContainer())
- curr = curr->parent();
-
- return curr;
-}
-
-RenderLayer* RenderLayer::enclosingTransformedAncestor() const
-{
- RenderLayer* curr = parent();
- while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransformRelatedProperty())
- curr = curr->parent();
-
- return curr;
-}
-
-LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const
-{
- const AncestorDependentCompositingInputs& properties = ancestorDependentCompositingInputs();
-
- TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
- // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip are correct.
- renderer()->mapLocalToContainer(properties.transformAncestor ? properties.transformAncestor->renderer() : 0, transformState, ApplyContainerFlip);
- transformState.flatten();
- return LayoutPoint(transformState.lastPlanarPoint());
-}
-
-const RenderLayer* RenderLayer::compositingContainer() const
-{
- if (stackingNode()->isNormalFlowOnly())
- return parent();
- if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestorStackingContextNode())
- return ancestorStackingNode->layer();
- return 0;
-}
-
-bool RenderLayer::isPaintInvalidationContainer() const
-{
- return compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking;
-}
-
-// Note: enclosingCompositingLayer does not include squashed layers. Compositing stacking children of squashed layers
-// receive graphics layers that are parented to the compositing ancestor of the squashed layer.
-RenderLayer* RenderLayer::enclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot includeSelf) const
-{
- ASSERT(isAllowedToQueryCompositingState());
-
- if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking)
- return const_cast<RenderLayer*>(this);
-
- for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
- if (curr->compositingState() != NotComposited && curr->compositingState() != PaintsIntoGroupedBacking)
- return const_cast<RenderLayer*>(curr);
- }
-
- return 0;
-}
-
-// Return the enclosingCompositedLayerForPaintInvalidation for the given RenderLayer
-// including crossing frame boundaries.
-RenderLayer* RenderLayer::enclosingLayerForPaintInvalidationCrossingFrameBoundaries() const
-{
- const RenderLayer* layer = this;
- RenderLayer* compositedLayer = 0;
- while (!compositedLayer) {
- compositedLayer = layer->enclosingLayerForPaintInvalidation();
- if (!compositedLayer) {
- RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
- if (!owner)
- break;
- layer = owner->enclosingLayer();
- }
- }
- return compositedLayer;
-}
-
-RenderLayer* RenderLayer::enclosingLayerForPaintInvalidation() const
-{
- ASSERT(isAllowedToQueryCompositingState());
-
- if (isPaintInvalidationContainer())
- return const_cast<RenderLayer*>(this);
-
- for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
- if (curr->isPaintInvalidationContainer())
- return const_cast<RenderLayer*>(curr);
- }
-
- return 0;
-}
-
-void RenderLayer::setNeedsCompositingInputsUpdate()
-{
- m_needsAncestorDependentCompositingInputsUpdate = true;
- m_needsDescendantDependentCompositingInputsUpdate = true;
-
- for (RenderLayer* current = this; current && !current->m_childNeedsCompositingInputsUpdate; current = current->parent())
- current->m_childNeedsCompositingInputsUpdate = true;
-
- compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
-}
-
-void RenderLayer::updateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs& compositingInputs)
-{
- m_ancestorDependentCompositingInputs = compositingInputs;
- m_needsAncestorDependentCompositingInputsUpdate = false;
-}
-
-void RenderLayer::updateDescendantDependentCompositingInputs(const DescendantDependentCompositingInputs& compositingInputs)
-{
- m_descendantDependentCompositingInputs = compositingInputs;
- m_needsDescendantDependentCompositingInputsUpdate = false;
-}
-
-void RenderLayer::didUpdateCompositingInputs()
-{
- ASSERT(!needsCompositingInputsUpdate());
- m_childNeedsCompositingInputsUpdate = false;
- if (m_scrollableArea)
- m_scrollableArea->updateNeedsCompositedScrolling();
-}
-
-bool RenderLayer::hasNonIsolatedDescendantWithBlendMode() const
-{
- if (descendantDependentCompositingInputs().hasNonIsolatedDescendantWithBlendMode)
- return true;
- if (renderer()->isSVGRoot())
- return toRenderSVGRoot(renderer())->hasNonIsolatedBlendingDescendants();
- return false;
-}
-
-void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask)
-{
- if ((compositingReasons() & mask) == (reasons & mask))
- return;
- m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask);
-}
-
-void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant)
-{
- if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescendant))
- return;
-
- m_hasCompositingDescendant = hasCompositingDescendant;
-
- if (hasCompositedLayerMapping())
- compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
-}
-
-void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompositedDescendants)
-{
- if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsolateCompositedDescendants))
- return;
-
- m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants;
-
- if (hasCompositedLayerMapping())
- compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
-}
-
-bool RenderLayer::hasAncestorWithFilterOutsets() const
-{
- for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
- RenderLayerModelObject* renderer = curr->renderer();
- if (renderer->style()->hasFilterOutsets())
- return true;
- }
- return false;
-}
-
-static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
- RenderLayer::TransparencyClipBoxBehavior transparencyBehavior, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
-{
- // If we have a mask, then the clip is limited to the border box area (and there is
- // no need to examine child layers).
- if (!layer->renderer()->hasMask()) {
- // Note: we don't have to walk z-order lists since transparent elements always establish
- // a stacking container. This means we can just walk the layer tree directly.
- for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
- if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionLayer() != curr)
- clipRect.unite(RenderLayer::transparencyClipBox(curr, rootLayer, transparencyBehavior, RenderLayer::DescendantsOfTransparencyClipBox, subPixelAccumulation, paintBehavior));
- }
- }
-
- // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
- // current transparencyClipBox to catch all child layers.
- // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
- // size into the parent layer.
- if (layer->renderer()->hasReflection()) {
- LayoutPoint delta;
- layer->convertToLayerCoords(rootLayer, delta);
- clipRect.move(-delta.x(), -delta.y());
- clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
- clipRect.moveBy(delta);
- }
-}
-
-LayoutRect RenderLayer::transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
- TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
-{
- // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
- // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
- // would be better to respect clips.
-
- if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
- || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransformRelatedProperty()))) {
- // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
- // the transformed layer and all of its children.
- const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
- const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
- LayoutPoint delta;
- layer->convertToLayerCoords(rootLayerForTransform, delta);
-
- delta.move(subPixelAccumulation);
- IntPoint pixelSnappedDelta = roundedIntPoint(delta);
- TransformationMatrix transform;
- transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y());
- transform = transform * *layer->transform();
-
- // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
- // paints unfragmented.
- LayoutRect clipRect = layer->physicalBoundingBox(layer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, subPixelAccumulation, paintBehavior);
- clipRect.expand(layer->renderer()->style()->filterOutsets());
- LayoutRect result = transform.mapRect(clipRect);
- if (!paginationLayer)
- return result;
-
- // We have to break up the transformed extent across our columns.
- // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
- // get our true bounding box.
- RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
- result = enclosingFlowThread->fragmentsBoundingBox(result);
-
- LayoutPoint rootLayerDelta;
- paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
- result.moveBy(rootLayerDelta);
- return result;
- }
-
- LayoutRect clipRect = layer->fragmentsBoundingBox(rootLayer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, subPixelAccumulation, paintBehavior);
- clipRect.expand(layer->renderer()->style()->filterOutsets());
- clipRect.move(subPixelAccumulation);
- return clipRect;
-}
-
-LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
-{
- return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paintDirtyRect);
-}
-
-void* RenderLayer::operator new(size_t sz)
-{
- return partitionAlloc(Partitions::getRenderingPartition(), sz);
-}
-
-void RenderLayer::operator delete(void* ptr)
-{
- partitionFree(ptr);
-}
-
-void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
-{
- RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
- if (prevSibling) {
- child->setPreviousSibling(prevSibling);
- prevSibling->setNextSibling(child);
- ASSERT(prevSibling != child);
- } else
- setFirstChild(child);
-
- if (beforeChild) {
- beforeChild->setPreviousSibling(child);
- child->setNextSibling(beforeChild);
- ASSERT(beforeChild != child);
- } else
- setLastChild(child);
-
- child->m_parent = this;
-
- setNeedsCompositingInputsUpdate();
-
- if (child->stackingNode()->isNormalFlowOnly())
- m_stackingNode->dirtyNormalFlowList();
-
- if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) {
- // Dirty the z-order list in which we are contained. The ancestorStackingContextNode() can be null in the
- // case where we're building up generated content layers. This is ok, since the lists will start
- // off dirty in that case anyway.
- child->stackingNode()->dirtyStackingContextZOrderLists();
- }
-
- dirtyAncestorChainVisibleDescendantStatus();
- dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
-
- child->updateDescendantDependentFlags();
-}
-
-RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
-{
- if (oldChild->previousSibling())
- oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
- if (oldChild->nextSibling())
- oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
-
- if (m_first == oldChild)
- m_first = oldChild->nextSibling();
- if (m_last == oldChild)
- m_last = oldChild->previousSibling();
-
- if (oldChild->stackingNode()->isNormalFlowOnly())
- m_stackingNode->dirtyNormalFlowList();
- if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild()) {
- // Dirty the z-order list in which we are contained. When called via the
- // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
- // from the main layer tree, so we need to null-check the
- // |stackingContext| value.
- oldChild->stackingNode()->dirtyStackingContextZOrderLists();
- }
-
- if (renderer()->style()->visibility() != VISIBLE)
- dirtyVisibleContentStatus();
-
- oldChild->setPreviousSibling(0);
- oldChild->setNextSibling(0);
- oldChild->m_parent = 0;
-
- dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
-
- oldChild->updateDescendantDependentFlags();
-
- if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
- dirtyAncestorChainVisibleDescendantStatus();
-
- if (oldChild->enclosingPaginationLayer())
- oldChild->clearPaginationRecursive();
-
- return oldChild;
-}
-
-void RenderLayer::removeOnlyThisLayer()
-{
- if (!m_parent)
- return;
-
- {
- DisableCompositingQueryAsserts disabler; // We need the current compositing status.
- if (isPaintInvalidationContainer()) {
- // Our children will be reparented and contained by a new paint invalidation container,
- // so need paint invalidation. CompositingUpdate can't see this layer (which has been
- // removed) so won't do this for us.
- setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
- }
- }
-
- m_clipper.clearClipRectsIncludingDescendants();
-
- RenderLayer* nextSib = nextSibling();
-
- // Remove the child reflection layer before moving other child layers.
- // The reflection layer should not be moved to the parent.
- if (m_reflectionInfo)
- removeChild(m_reflectionInfo->reflectionLayer());
-
- // Now walk our kids and reattach them to our parent.
- RenderLayer* current = m_first;
- while (current) {
- RenderLayer* next = current->nextSibling();
- removeChild(current);
- m_parent->addChild(current, nextSib);
-
- // FIXME: We should call a specialized version of this function.
- current->updateLayerPositionsAfterLayout();
- current = next;
- }
-
- // Remove us from the parent.
- m_parent->removeChild(this);
- m_renderer->destroyLayer();
-}
-
-void RenderLayer::insertOnlyThisLayer()
-{
- if (!m_parent && renderer()->parent()) {
- // We need to connect ourselves when our renderer() has a parent.
- // Find our enclosingLayer and add ourselves.
- RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
- ASSERT(parentLayer);
- RenderLayer* beforeChild = !parentLayer->reflectionInfo() || parentLayer->reflectionInfo()->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
- parentLayer->addChild(this, beforeChild);
- }
-
- // Remove all descendant layers from the hierarchy and add them to the new position.
- for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->nextSibling())
- curr->moveLayers(m_parent, this);
-
- // Clear out all the clip rects.
- m_clipper.clearClipRectsIncludingDescendants();
-}
-
-// Returns the layer reached on the walk up towards the ancestor.
-static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location)
-{
- ASSERT(ancestorLayer != layer);
-
- const RenderLayerModelObject* renderer = layer->renderer();
- EPosition position = renderer->style()->position();
-
- // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
- // may need to be revisited in a future patch.
- // If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
- // since localToAbsolute maps the coordinates from flow thread to regions coordinates and regions can be
- // positioned in a completely different place in the viewport (RenderView).
- if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
- // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
- // localToAbsolute() on the RenderView.
- FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed);
- location += LayoutSize(absPos.x(), absPos.y());
- return ancestorLayer;
- }
-
- // For the fixed positioned elements inside a render flow thread, we should also skip the code path below
- // Otherwise, for the case of ancestorLayer == rootLayer and fixed positioned element child of a transformed
- // element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
- if (position == FixedPosition) {
- // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
- // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
- // so we should always find the ancestor at or before we find the fixed position container.
- RenderLayer* fixedPositionContainerLayer = 0;
- bool foundAncestor = false;
- for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
- if (currLayer == ancestorLayer)
- foundAncestor = true;
-
- if (isFixedPositionedContainer(currLayer)) {
- fixedPositionContainerLayer = currLayer;
- ASSERT_UNUSED(foundAncestor, foundAncestor);
- break;
- }
- }
-
- ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
-
- if (fixedPositionContainerLayer != ancestorLayer) {
- LayoutPoint fixedContainerCoords;
- layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
-
- LayoutPoint ancestorCoords;
- ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
-
- location += (fixedContainerCoords - ancestorCoords);
- } else {
- // RenderView has been handled in the first top-level 'if' block above.
- ASSERT(ancestorLayer != renderer->view()->layer());
- ASSERT(ancestorLayer->hasTransformRelatedProperty());
-
- location += layer->location();
-
- // The spec (http://dev.w3.org/csswg/css-transforms/#transform-rendering) doesn't say if a
- // fixed-position element under a scrollable transformed element should scroll. However,
- // other parts of blink scroll the fixed-position element, and the following keeps the consistency.
- if (RenderLayerScrollableArea* scrollableArea = ancestorLayer->scrollableArea())
- location -= LayoutSize(scrollableArea->scrollOffset());
- }
- return ancestorLayer;
- }
-
- RenderLayer* parentLayer;
- if (position == AbsolutePosition) {
- // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
- parentLayer = layer->parent();
- bool foundAncestorFirst = false;
- while (parentLayer) {
- // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
- // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
- // we are bailing out before reaching root layer.
- if (parentLayer->isPositionedContainer())
- break;
-
- if (parentLayer == ancestorLayer) {
- foundAncestorFirst = true;
- break;
- }
-
- parentLayer = parentLayer->parent();
- }
-
- // We should not reach RenderView layer past the RenderFlowThread layer for any
- // children of the RenderFlowThread.
- ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer->view()->layer());
-
- if (foundAncestorFirst) {
- // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
- // to enclosingPositionedAncestor and subtract.
- RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
-
- LayoutPoint thisCoords;
- layer->convertToLayerCoords(positionedAncestor, thisCoords);
-
- LayoutPoint ancestorCoords;
- ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
-
- location += (thisCoords - ancestorCoords);
- return ancestorLayer;
- }
- } else if (renderer->isColumnSpanAll()) {
- RenderBlock* multicolContainer = renderer->containingBlock();
- ASSERT(toRenderBlockFlow(multicolContainer)->multiColumnFlowThread());
- parentLayer = multicolContainer->layer();
- ASSERT(parentLayer);
- } else {
- parentLayer = layer->parent();
- }
-
- if (!parentLayer)
- return 0;
-
- location += layer->location();
- return parentLayer;
-}
-
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const
-{
- if (ancestorLayer == this)
- return;
-
- const RenderLayer* currLayer = this;
- while (currLayer && currLayer != ancestorLayer)
- currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location);
-}
-
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect) const
-{
- LayoutPoint delta;
- convertToLayerCoords(ancestorLayer, delta);
- rect.moveBy(delta);
-}
-
-LayoutPoint RenderLayer::visualOffsetFromAncestor(const RenderLayer* ancestorLayer) const
-{
- LayoutPoint offset;
- if (ancestorLayer == this)
- return offset;
- RenderLayer* paginationLayer = enclosingPaginationLayer();
- if (paginationLayer == this)
- paginationLayer = parent()->enclosingPaginationLayer();
- if (!paginationLayer) {
- convertToLayerCoords(ancestorLayer, offset);
- return offset;
- }
-
- RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer());
- convertToLayerCoords(paginationLayer, offset);
- offset = flowThread->flowThreadPointToVisualPoint(offset);
- if (ancestorLayer == paginationLayer)
- return offset;
-
- if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) {
- offset.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer));
- } else {
- // The ancestor layer is also inside the pagination layer, so we need to subtract the visual
- // distance from the ancestor layer to the pagination layer.
- offset.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer));
- }
- return offset;
-}
-
-void RenderLayer::didUpdateNeedsCompositedScrolling()
-{
- updateSelfPaintingLayer();
-}
-
-void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle)
-{
- ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle));
- if (renderer()->hasReflection()) {
- if (!m_reflectionInfo)
- m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(*renderBox()));
- m_reflectionInfo->updateAfterStyleChange(oldStyle);
- } else if (m_reflectionInfo) {
- m_reflectionInfo->destroy();
- m_reflectionInfo = nullptr;
- }
-}
-
-void RenderLayer::updateStackingNode()
-{
- if (requiresStackingNode())
- m_stackingNode = adoptPtr(new RenderLayerStackingNode(this));
- else
- m_stackingNode = nullptr;
-}
-
-void RenderLayer::updateScrollableArea()
-{
- if (requiresScrollableArea())
- m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this));
- else
- m_scrollableArea = nullptr;
-}
-
-bool RenderLayer::hasOverflowControls() const
-{
- return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollableArea->scrollCorner() || renderer()->style()->resize() != RESIZE_NONE);
-}
-
-void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect,
- ClipRectsCacheSlot clipRectsCacheSlot, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
- const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox)
-{
- if (!enclosingPaginationLayer() || hasTransformRelatedProperty()) {
- // For unpaginated layers, there is only one fragment.
- LayerFragment fragment;
- ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy, subPixelAccumulation);
- if (respectOverflowClip == IgnoreOverflowClip)
- clipRectsContext.setIgnoreOverflowClip();
- clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
- fragments.append(fragment);
- return;
- }
-
- // Compute our offset within the enclosing pagination layer.
- LayoutPoint offsetWithinPaginatedLayer;
- convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer);
-
- // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
- // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
- ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
- if (respectOverflowClip == IgnoreOverflowClip)
- paginationClipRectsContext.setIgnoreOverflowClip();
- LayoutRect layerBoundsInFlowThread;
- ClipRect backgroundRectInFlowThread;
- ClipRect foregroundRectInFlowThread;
- ClipRect outlineRectInFlowThread;
- clipper().calculateRects(paginationClipRectsContext, LayoutRect::infiniteIntRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
- outlineRectInFlowThread, &offsetWithinPaginatedLayer);
-
- // Take our bounding box within the flow thread and clip it.
- LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer);
- layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
-
- // Make the dirty rect relative to the fragmentation context (multicol container, etc.).
- RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
- LayoutPoint offsetOfPaginationLayerFromRoot; // Visual offset from the root layer to the nearest fragmentation context.
- bool rootLayerIsInsidePaginationLayer = rootLayer->enclosingPaginationLayer() == enclosingPaginationLayer();
- if (rootLayerIsInsidePaginationLayer) {
- // The root layer is in the same fragmentation context as this layer, so we need to look
- // inside it and subtract the offset between the fragmentation context and the root layer.
- offsetOfPaginationLayerFromRoot = -rootLayer->visualOffsetFromAncestor(enclosingPaginationLayer());
- } else {
- offsetOfPaginationLayerFromRoot = enclosingPaginationLayer()->visualOffsetFromAncestor(rootLayer);
- }
- LayoutRect dirtyRectInFlowThread(dirtyRect);
- dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot);
-
- // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
- // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
- enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
-
- if (fragments.isEmpty())
- return;
-
- // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
- ClipRect ancestorClipRect = dirtyRect;
- if (const RenderLayer* paginationParentLayer = enclosingPaginationLayer()->parent()) {
- const RenderLayer* ancestorLayer = rootLayerIsInsidePaginationLayer ? paginationParentLayer : rootLayer;
- ClipRectsContext clipRectsContext(ancestorLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
- if (respectOverflowClip == IgnoreOverflowClip)
- clipRectsContext.setIgnoreOverflowClip();
- ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext);
- if (rootLayerIsInsidePaginationLayer)
- ancestorClipRect.moveBy(-rootLayer->visualOffsetFromAncestor(ancestorLayer));
- ancestorClipRect.intersect(dirtyRect);
- }
-
- for (size_t i = 0; i < fragments.size(); ++i) {
- LayerFragment& fragment = fragments.at(i);
-
- // Set our four rects with all clipping applied that was internal to the flow thread.
- fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread);
-
- // Shift to the root-relative physical position used when painting the flow thread in this fragment.
- fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
-
- // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
- // properly clipped by the overflow.
- fragment.intersect(ancestorClipRect.rect());
-
- // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
- // clip, so the column clip ends up being all we apply.
- fragment.intersect(fragment.paginationClip);
- }
-}
-
-static inline LayoutRect frameVisibleRect(RenderObject* renderer)
-{
- FrameView* frameView = renderer->document().view();
- if (!frameView)
- return LayoutRect();
-
- return frameView->visibleContentRect();
-}
-
-bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
-{
- return hitTest(request, result.hitTestLocation(), result);
-}
-
-bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result)
-{
- ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
-
- // RenderView should make sure to update layout before entering hit testing
- ASSERT(!renderer()->frame()->view()->layoutPending());
- ASSERT(!renderer()->document().renderView()->needsLayout());
-
- // Start with frameVisibleRect to ensure we include the scrollbars.
- LayoutRect hitTestArea = frameVisibleRect(renderer());
- if (request.ignoreClipping())
- hitTestArea.unite(renderer()->view()->documentRect());
-
- RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false);
- if (!insideLayer) {
- // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
- // return ourselves. We do this so mouse events continue getting delivered after a drag has
- // exited the WebView, and so hit testing over a scrollbar hits the content document.
- // In addtion, it is possible for the mouse to stay in the document but there is no element.
- // At that time, the events of the mouse should be fired.
- LayoutPoint hitPoint = hitTestLocation.point();
- if (!request.isChildFrameHitTest() && ((request.active() || request.release()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y()))) && isRootLayer()) {
- renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
- insideLayer = this;
- }
- }
-
- // Now determine if the result is inside an anchor - if the urlElement isn't already set.
- Node* node = result.innerNode();
- if (node && !result.URLElement())
- result.setURLElement(node->enclosingLinkEventParentOrSelf());
-
- // Now return whether we were inside this layer (this will always be true for the root
- // layer).
- return insideLayer;
-}
-
-Node* RenderLayer::enclosingElement() const
-{
- for (RenderObject* r = renderer(); r; r = r->parent()) {
- if (Node* e = r->node())
- return e;
- }
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-bool RenderLayer::isInTopLayer() const
-{
- Node* node = renderer()->node();
- return node && node->isElementNode() && toElement(node)->isInTopLayer();
-}
-
-// Compute the z-offset of the point in the transformState.
-// This is effectively projecting a ray normal to the plane of ancestor, finding where that
-// ray intersects target, and computing the z delta between those two points.
-static double computeZOffset(const HitTestingTransformState& transformState)
-{
- // We got an affine transform, so no z-offset
- if (transformState.m_accumulatedTransform.isAffine())
- return 0;
-
- // Flatten the point into the target plane
- FloatPoint targetPoint = transformState.mappedPoint();
-
- // Now map the point back through the transform, which computes Z.
- FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
- return backmappedPoint.z();
-}
-
-PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* containerTransformState,
- const LayoutPoint& translationOffset) const
-{
- RefPtr<HitTestingTransformState> transformState;
- LayoutPoint offset;
- if (containerTransformState) {
- // If we're already computing transform state, then it's relative to the container (which we know is non-null).
- transformState = HitTestingTransformState::create(*containerTransformState);
- convertToLayerCoords(containerLayer, offset);
- } else {
- // If this is the first time we need to make transform state, then base it off of hitTestLocation,
- // which is relative to rootLayer.
- transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
- convertToLayerCoords(rootLayer, offset);
- }
- offset.moveBy(translationOffset);
-
- RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
- if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
- TransformationMatrix containerTransform;
- renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
- transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
- } else {
- transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
- }
-
- return transformState;
-}
-
-
-static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
-{
- if (!hitLayer)
- return false;
-
- // The hit layer is depth-sorting with other layers, so just say that it was hit.
- if (canDepthSort)
- return true;
-
- // We need to look at z-depth to decide if this layer was hit.
- if (zOffset) {
- ASSERT(transformState);
- // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
- double childZOffset = computeZOffset(*transformState);
- if (childZOffset > *zOffset) {
- *zOffset = childZOffset;
- return true;
- }
- return false;
- }
-
- return true;
-}
-
-// hitTestLocation and hitTestRect are relative to rootLayer.
-// A 'flattening' layer is one preserves3D() == false.
-// transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
-// transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer.
-// transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
-//
-// If zOffset is non-null (which indicates that the caller wants z offset information),
-// *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
-RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
- const HitTestingTransformState* transformState, double* zOffset)
-{
- if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
- return 0;
-
- // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
-
- // Apply a transform if we have one.
- if (transform() && !appliedTransform) {
- if (enclosingPaginationLayer())
- return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
-
- // Make sure the parent's clip rects have been calculated.
- if (parent()) {
- ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize));
- // Go ahead and test the enclosing clip now.
- if (!clipRect.intersects(hitTestLocation))
- return 0;
- }
-
- return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
- }
-
- // Ensure our lists and 3d status are up-to-date.
- m_stackingNode->updateLayerListsIfNeeded();
- update3DTransformedDescendantStatus();
-
- RefPtr<HitTestingTransformState> localTransformState;
- if (appliedTransform) {
- // We computed the correct state in the caller (above code), so just reference it.
- ASSERT(transformState);
- localTransformState = const_cast<HitTestingTransformState*>(transformState);
- } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
- // We need transform state for the first time, or to offset the container state, so create it here.
- localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
- }
-
- // Check for hit test on backface if backface-visibility is 'hidden'
- if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
- TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
- // If the z-vector of the matrix is negative, the back is facing towards the viewer.
- if (invertedMatrix.m33() < 0)
- return 0;
- }
-
- RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
- if (localTransformState && !preserves3D()) {
- // Keep a copy of the pre-flattening state, for computing z-offsets for the container
- unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
- // This layer is flattening, so flatten the state passed to descendants.
- localTransformState->flatten();
- }
-
- // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
- // descendants.
- double localZOffset = -std::numeric_limits<double>::infinity();
- double* zOffsetForDescendantsPtr = 0;
- double* zOffsetForContentsPtr = 0;
-
- bool depthSortDescendants = false;
- if (preserves3D()) {
- depthSortDescendants = true;
- // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
- zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
- zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
- } else if (zOffset) {
- zOffsetForDescendantsPtr = 0;
- // Container needs us to give back a z offset for the hit layer.
- zOffsetForContentsPtr = zOffset;
- }
-
- // This variable tracks which layer the mouse ends up being inside.
- RenderLayer* candidateLayer = 0;
-
- // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
- RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
- if (hitLayer) {
- if (!depthSortDescendants)
- return hitLayer;
- candidateLayer = hitLayer;
- }
-
- // Now check our overflow objects.
- hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
- if (hitLayer) {
- if (!depthSortDescendants)
- return hitLayer;
- candidateLayer = hitLayer;
- }
-
- // Collect the fragments. This will compute the clip rectangles for each layer fragment.
- LayerFragments layerFragments;
- collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
-
- if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) {
- renderer()->updateHitTestResult(result, hitTestLocation.point());
- return this;
- }
-
- // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check
- // every fragment in reverse order.
- if (isSelfPaintingLayer()) {
- // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
- HitTestResult tempResult(result.hitTestLocation());
- bool insideFragmentForegroundRect = false;
- if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect)
- && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
- if (result.isRectBasedTest())
- result.append(tempResult);
- else
- result = tempResult;
- if (!depthSortDescendants)
- return this;
- // Foreground can depth-sort with descendant layers, so keep this as a candidate.
- candidateLayer = this;
- } else if (insideFragmentForegroundRect && result.isRectBasedTest())
- result.append(tempResult);
- }
-
- // Now check our negative z-index children.
- hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
- if (hitLayer) {
- if (!depthSortDescendants)
- return hitLayer;
- candidateLayer = hitLayer;
- }
-
- // If we found a layer, return. Child layers, and foreground always render in front of background.
- if (candidateLayer)
- return candidateLayer;
-
- if (isSelfPaintingLayer()) {
- HitTestResult tempResult(result.hitTestLocation());
- bool insideFragmentBackgroundRect = false;
- if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect)
- && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
- if (result.isRectBasedTest())
- result.append(tempResult);
- else
- result = tempResult;
- return this;
- }
- if (insideFragmentBackgroundRect && result.isRectBasedTest())
- result.append(tempResult);
- }
-
- return 0;
-}
-
-bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result,
- const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& insideClipRect) const
-{
- if (layerFragments.isEmpty())
- return false;
-
- for (int i = layerFragments.size() - 1; i >= 0; --i) {
- const LayerFragment& fragment = layerFragments.at(i);
- if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects(hitTestLocation))
- || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.intersects(hitTestLocation)))
- continue;
- insideClipRect = true;
- if (hitTestContents(request, result, fragment.layerBounds, hitTestLocation, hitTestFilter))
- return true;
- }
-
- return false;
-}
-
-RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
-{
- LayerFragments enclosingPaginationFragments;
- LayoutPoint offsetOfPaginationLayerFromRoot;
- // FIXME: We're missing a sub-pixel offset here crbug.com/348728
- LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RenderLayer::RootOfTransparencyClipBox, LayoutSize());
- enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestRect,
- RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent);
-
- for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
- const LayerFragment& fragment = enclosingPaginationFragments.at(i);
-
- // Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
- // the enclosing pagination layer.
- LayoutRect clipRect = fragment.backgroundRect.rect();
-
- // Now compute the clips within a given fragment
- if (parent() != enclosingPaginationLayer()) {
- enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
- LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsContext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbarSize)).rect();
- parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
- clipRect.intersect(parentClipRect);
- }
-
- if (!hitTestLocation.intersects(clipRect))
- continue;
-
- RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation,
- transformState, zOffset, fragment.paginationOffset);
- if (hitLayer)
- return hitLayer;
- }
-
- return 0;
-}
-
-RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
- const LayoutPoint& translationOffset)
-{
- // Create a transform state to accumulate this transform.
- RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
-
- // If the transform can't be inverted, then don't hit test this layer at all.
- if (!newTransformState->m_accumulatedTransform.isInvertible())
- return 0;
-
- // Compute the point and the hit test rect in the coords of this layer by using the values
- // from the transformState, which store the point and quad in the coords of the last flattened
- // layer, and the accumulated transform which lets up map through preserve-3d layers.
- //
- // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
- // by our container.
- FloatPoint localPoint = newTransformState->mappedPoint();
- FloatQuad localPointQuad = newTransformState->mappedQuad();
- LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea();
- HitTestLocation newHitTestLocation;
- if (hitTestLocation.isRectBasedTest())
- newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
- else
- newHitTestLocation = HitTestLocation(localPoint);
-
- // Now do a hit test with the root layer shifted to be us.
- return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
-}
-
-bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const
-{
- ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
-
- if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) {
- // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
- // a rect-based test.
- ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
- return false;
- }
-
- // For positioned generated content, we might still not have a
- // node by the time we get to the layer level, since none of
- // the content in the layer has an element. So just walk up
- // the tree.
- if (!result.innerNode() || !result.innerNonSharedNode()) {
- Node* e = enclosingElement();
- if (!result.innerNode())
- result.setInnerNode(e);
- if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(e);
- }
-
- return true;
-}
-
-RenderLayer* RenderLayer::hitTestChildren(ChildrenIteration childrentoVisit, RenderLayer* rootLayer,
- const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* transformState,
- double* zOffsetForDescendants, double* zOffset,
- const HitTestingTransformState* unflattenedTransformState,
- bool depthSortDescendants)
-{
- if (!hasSelfPaintingLayerDescendant())
- return 0;
-
- RenderLayer* resultLayer = 0;
- RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoVisit);
- while (RenderLayerStackingNode* child = iterator.next()) {
- RenderLayer* childLayer = child->layer();
- RenderLayer* hitLayer = 0;
- HitTestResult tempResult(result.hitTestLocation());
- if (childLayer->isPaginated())
- hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants);
- else
- hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
-
- // If it a rect-based test, we can safely append the temporary result since it might had hit
- // nodes but not necesserily had hitLayer set.
- if (result.isRectBasedTest())
- result.append(tempResult);
-
- if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
- resultLayer = hitLayer;
- if (!result.isRectBasedTest())
- result = tempResult;
- if (!depthSortDescendants)
- break;
- }
- }
-
- return resultLayer;
-}
-
-RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
-{
- Vector<RenderLayer*> columnLayers;
- RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode();
- for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
- if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
- columnLayers.append(curr);
- if (curr->stackingNode() == ancestorNode)
- break;
- }
-
- ASSERT(columnLayers.size());
- return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset,
- columnLayers, columnLayers.size() - 1);
-}
-
-RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
- const Vector<RenderLayer*>& columnLayers, size_t columnIndex)
-{
- RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer());
-
- ASSERT(columnBlock && columnBlock->hasColumns());
- if (!columnBlock || !columnBlock->hasColumns())
- return 0;
-
- LayoutPoint layerOffset;
- columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset);
-
- ColumnInfo* colInfo = columnBlock->columnInfo();
- int colCount = columnBlock->columnCount(colInfo);
-
- // We have to go backwards from the last column to the first.
- bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
- LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent();
- LayoutUnit currLogicalTopOffset = 0;
- int i;
- for (i = 0; i < colCount; i++) {
- LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
- LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
- if (columnBlock->style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset += blockDelta;
- else
- currLogicalTopOffset -= blockDelta;
- }
- for (i = colCount - 1; i >= 0; i--) {
- // For each rect, we clip to the rect, and then we adjust our coords.
- LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
- columnBlock->flipForWritingMode(colRect);
- LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
- LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.width());
- if (columnBlock->style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset -= blockDelta;
- else
- currLogicalTopOffset += blockDelta;
-
- LayoutSize offset;
- if (isHorizontal) {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset);
- else
- offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
- } else {
- if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
- offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
- else
- offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
- }
-
- colRect.moveBy(layerOffset);
-
- LayoutRect localClipRect(hitTestRect);
- localClipRect.intersect(colRect);
-
- if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect)) {
- RenderLayer* hitLayer = 0;
- if (!columnIndex) {
- // Apply a translation transform to change where the layer paints.
- TransformationMatrix oldTransform;
- bool oldHasTransform = childLayer->transform();
- if (oldHasTransform)
- oldTransform = *childLayer->transform();
- TransformationMatrix newTransform(oldTransform);
- newTransform.translateRight(offset.width(), offset.height());
-
- childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
- hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset);
- if (oldHasTransform)
- childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
- else
- childLayer->m_transform.clear();
- } else {
- // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space.
- // This involves subtracting out the position of the layer in our current coordinate space.
- RenderLayer* nextLayer = columnLayers[columnIndex - 1];
- RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState);
- newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
- FloatPoint localPoint = newTransformState->mappedPoint();
- FloatQuad localPointQuad = newTransformState->mappedQuad();
- LayoutRect localHitTestRect = newTransformState->mappedArea().enclosingBoundingBox();
- HitTestLocation newHitTestLocation;
- if (hitTestLocation.isRectBasedTest())
- newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
- else
- newHitTestLocation = HitTestLocation(localPoint);
- newTransformState->flatten();
-
- hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestLocation,
- newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
- }
-
- if (hitLayer)
- return hitLayer;
- }
- }
-
- return 0;
-}
-
-void RenderLayer::blockSelectionGapsBoundsChanged()
-{
- setNeedsCompositingInputsUpdate();
-}
-
-void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds)
-{
- m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds));
- blockSelectionGapsBoundsChanged();
-}
-
-void RenderLayer::clearBlockSelectionGapsBounds()
-{
- m_blockSelectionGapsBounds = IntRect();
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->clearBlockSelectionGapsBounds();
- blockSelectionGapsBoundsChanged();
-}
-
-void RenderLayer::invalidatePaintForBlockSelectionGaps()
-{
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->invalidatePaintForBlockSelectionGaps();
-
- if (m_blockSelectionGapsBounds.isEmpty())
- return;
-
- LayoutRect rect = m_blockSelectionGapsBounds;
- if (renderer()->hasOverflowClip()) {
- RenderBox* box = renderBox();
- rect.move(-box->scrolledContentOffset());
- if (!scrollableArea()->usesCompositedScrolling())
- rect.intersect(box->overflowClipRect(LayoutPoint()));
- }
- if (renderer()->hasClip())
- rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint()));
- if (!rect.isEmpty())
- renderer()->invalidatePaintRectangle(rect);
-}
-
-IntRect RenderLayer::blockSelectionGapsBounds() const
-{
- if (!renderer()->isRenderBlockFlow())
- return IntRect();
-
- RenderBlockFlow* renderBlockFlow = toRenderBlockFlow(renderer());
- LayoutRect gapRects = renderBlockFlow->selectionGapRectsForPaintInvalidation(renderBlockFlow);
-
- return pixelSnappedIntRect(gapRects);
-}
-
-bool RenderLayer::hasBlockSelectionGapBounds() const
-{
- // FIXME: it would be more accurate to return !blockSelectionGapsBounds().isEmpty(), but this is impossible
- // at the moment because it causes invalid queries to layout-dependent code (crbug.com/372802).
- // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::LayoutClean);
-
- if (!renderer()->isRenderBlock())
- return false;
-
- return toRenderBlock(renderer())->shouldPaintSelectionGaps();
-}
-
-bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const
-{
- // Always examine the canvas and the root.
- // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
- // paints the root's background.
- if (isRootLayer() || renderer()->isDocumentElement())
- return true;
-
- // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
- // can go ahead and return true.
- RenderView* view = renderer()->view();
- ASSERT(view);
- if (view && !renderer()->isRenderInline()) {
- if (layerBounds.intersects(damageRect))
- return true;
- }
-
- // Otherwise we need to compute the bounding box of this single layer and see if it intersects
- // the damage rect.
- return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
-}
-
-LayoutRect RenderLayer::logicalBoundingBox() const
-{
- // There are three special cases we need to consider.
- // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
- // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
- // line boxes of all three lines (including overflow on those lines).
- // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
- // overflow, we have to create a bounding box that will extend to include this overflow.
- // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
- // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
- // floats.
- LayoutRect result;
- if (renderer()->isInline() && renderer()->isRenderInline()) {
- result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
- } else if (renderer()->isTableRow()) {
- // Our bounding box is just the union of all of our cells' border/overflow rects.
- for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
- if (child->isTableCell()) {
- LayoutRect bbox = toRenderBox(child)->borderBoxRect();
- result.unite(bbox);
- LayoutRect overflowRect = renderBox()->visualOverflowRect();
- if (bbox != overflowRect)
- result.unite(overflowRect);
- }
- }
- } else {
- RenderBox* box = renderBox();
- ASSERT(box);
- result = box->borderBoxRect();
- result.unite(box->visualOverflowRect());
- }
-
- ASSERT(renderer()->view());
- return result;
-}
-
-static inline LayoutRect flippedLogicalBoundingBox(LayoutRect boundingBox, RenderObject* renderer)
-{
- LayoutRect result = boundingBox;
- if (renderer->isBox())
- toRenderBox(renderer)->flipForWritingMode(result);
- else
- renderer->containingBlock()->flipForWritingMode(result);
- return result;
-}
-
-LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const
-{
- LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer());
- if (offsetFromRoot)
- result.moveBy(*offsetFromRoot);
- else
- convertToLayerCoords(ancestorLayer, result);
- return result;
-}
-
-LayoutRect RenderLayer::fragmentsBoundingBox(const RenderLayer* ancestorLayer) const
-{
- if (!enclosingPaginationLayer())
- return physicalBoundingBox(ancestorLayer);
-
- LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer());
- convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer, result);
- return result;
-}
-
-LayoutRect RenderLayer::boundingBoxForCompositingOverlapTest() const
-{
- return overlapBoundsIncludeChildren() ? boundingBoxForCompositing() : fragmentsBoundingBox(this);
-}
-
-static void expandRectForReflectionAndStackingChildren(const RenderLayer* ancestorLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result)
-{
- if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping())
- result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundingBoxForCompositing(ancestorLayer));
-
- ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer->stackingNode()->hasPositiveZOrderList());
-
-#if ENABLE(ASSERT)
- LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(ancestorLayer)->stackingNode());
-#endif
-
- RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), AllChildren);
- while (RenderLayerStackingNode* node = iterator.next()) {
- // Here we exclude both directly composited layers and squashing layers
- // because those RenderLayers don't paint into the graphics layer
- // for this RenderLayer. For example, the bounds of squashed RenderLayers
- // will be included in the computation of the appropriate squashing
- // GraphicsLayer.
- if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()->compositingState() != NotComposited)
- continue;
- result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, options));
- }
-}
-
-LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const
-{
- LayoutPoint origin;
- LayoutRect result = physicalBoundingBox(ancestorLayer, &origin);
-
- const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
-
- expandRectForReflectionAndStackingChildren(this, DoNotApplyBoundsChickenEggHacks, result);
-
- result.moveBy(offsetFromRoot);
- return result;
-}
-
-LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLayer, CalculateBoundsOptions options) const
-{
- if (!isSelfPaintingLayer())
- return LayoutRect();
-
- if (!ancestorLayer)
- ancestorLayer = this;
-
- // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
- if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
- return LayoutRect();
-
- // The root layer is always just the size of the document.
- if (isRootLayer())
- return m_renderer->view()->unscaledDocumentRect();
-
- // The layer created for the RenderFlowThread is just a helper for painting and hit-testing,
- // and should not contribute to the bounding box. The RenderMultiColumnSets will contribute
- // the correct size for the rendered content of the multicol container.
- if (useRegionBasedColumns() && renderer()->isRenderFlowThread())
- return LayoutRect();
-
- LayoutRect result = clipper().localClipRect();
- if (result == LayoutRect::infiniteIntRect()) {
- LayoutPoint origin;
- result = physicalBoundingBox(ancestorLayer, &origin);
-
- const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
-
- // Reflections are implemented with RenderLayers that hang off of the reflected layer. However,
- // the reflection layer subtree does not include the subtree of the parent RenderLayer, so
- // a recursive computation of stacking children yields no results. This breaks cases when there are stacking
- // children of the parent, that need to be included in reflected composited bounds.
- // Fix this by including composited bounds of stacking children of the reflected RenderLayer.
- if (hasCompositedLayerMapping() && parent() && parent()->reflectionInfo() && parent()->reflectionInfo()->reflectionLayer() == this)
- expandRectForReflectionAndStackingChildren(parent(), options, result);
- else
- expandRectForReflectionAndStackingChildren(this, options, result);
-
- // FIXME: We can optimize the size of the composited layers, by not enlarging
- // filtered areas with the outsets if we know that the filter is going to render in hardware.
- // https://bugs.webkit.org/show_bug.cgi?id=81239
- result.expand(m_renderer->style()->filterOutsets());
- }
-
- if (paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChickenEggHacks && transform()))
- result = transform()->mapRect(result);
-
- if (enclosingPaginationLayer()) {
- convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer, result);
- return result;
- }
- LayoutPoint delta;
- convertToLayerCoords(ancestorLayer, delta);
- result.moveBy(delta);
- return result;
-}
-
-CompositingState RenderLayer::compositingState() const
-{
- ASSERT(isAllowedToQueryCompositingState());
-
- // This is computed procedurally so there is no redundant state variable that
- // can get out of sync from the real actual compositing state.
-
- if (m_groupedMapping) {
- ASSERT(!m_compositedLayerMapping);
- return PaintsIntoGroupedBacking;
- }
-
- if (!m_compositedLayerMapping)
- return NotComposited;
-
- return PaintsIntoOwnBacking;
-}
-
-bool RenderLayer::isAllowedToQueryCompositingState() const
-{
- if (gCompositingQueryMode == CompositingQueriesAreAllowed)
- return true;
- return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
-}
-
-CompositedLayerMapping* RenderLayer::compositedLayerMapping() const
-{
- ASSERT(isAllowedToQueryCompositingState());
- return m_compositedLayerMapping.get();
-}
-
-GraphicsLayer* RenderLayer::graphicsLayerBacking() const
-{
- switch (compositingState()) {
- case NotComposited:
- return 0;
- case PaintsIntoGroupedBacking:
- return groupedMapping()->squashingLayer();
- default:
- return compositedLayerMapping()->mainGraphicsLayer();
- }
-}
-
-GraphicsLayer* RenderLayer::graphicsLayerBackingForScrolling() const
-{
- switch (compositingState()) {
- case NotComposited:
- return 0;
- case PaintsIntoGroupedBacking:
- return groupedMapping()->squashingLayer();
- default:
- return compositedLayerMapping()->scrollingContentsLayer() ? compositedLayerMapping()->scrollingContentsLayer() : compositedLayerMapping()->mainGraphicsLayer();
- }
-}
-
-void RenderLayer::ensureCompositedLayerMapping()
-{
- if (m_compositedLayerMapping)
- return;
-
- m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this));
- m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
-
- updateOrRemoveFilterEffectRenderer();
-}
-
-void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed)
-{
- if (!layerBeingDestroyed) {
- // We need to make sure our decendants get a geometry update. In principle,
- // we could call setNeedsGraphicsLayerUpdate on our children, but that would
- // require walking the z-order lists to find them. Instead, we over-invalidate
- // by marking our parent as needing a geometry update.
- if (RenderLayer* compositingParent = enclosingLayerWithCompositedLayerMapping(ExcludeSelf))
- compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
- }
-
- m_compositedLayerMapping.clear();
-
- if (!layerBeingDestroyed)
- updateOrRemoveFilterEffectRenderer();
-}
-
-void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed)
-{
- if (groupedMapping == m_groupedMapping)
- return;
-
- if (!layerBeingDestroyed && m_groupedMapping) {
- m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
- m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this);
- }
- m_groupedMapping = groupedMapping;
- if (!layerBeingDestroyed && m_groupedMapping)
- m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
-}
-
-bool RenderLayer::hasCompositedMask() const
-{
- return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer();
-}
-
-bool RenderLayer::hasCompositedClippingMask() const
-{
- return m_compositedLayerMapping && m_compositedLayerMapping->hasChildClippingMaskLayer();
-}
-
-bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
-{
- return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || compositingState() != PaintsIntoOwnBacking);
-}
-
-bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
-{
- if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
- return false;
-
- if (paintsWithTransparency(PaintBehaviorNormal))
- return false;
-
- // We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child
- // is visible and that child doesn't cover the entire rect.
- if (renderer()->style()->visibility() != VISIBLE)
- return false;
-
- if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffectsOpacity())
- return false;
-
- // FIXME: Handle simple transforms.
- if (paintsWithTransform(PaintBehaviorNormal))
- return false;
-
- // FIXME: Remove this check.
- // This function should not be called when layer-lists are dirty.
- // It is somehow getting triggered during style update.
- if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirty())
- return false;
-
- // FIXME: We currently only check the immediate renderer,
- // which will miss many cases.
- if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect))
- return true;
-
- // We can't consult child layers if we clip, since they might cover
- // parts of the rect that are clipped out.
- if (renderer()->hasOverflowClip())
- return false;
-
- return childBackgroundIsKnownToBeOpaqueInRect(localRect);
-}
-
-bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
-{
- RenderLayerStackingNodeReverseIterator revertseIterator(*m_stackingNode, PositiveZOrderChildren | NormalFlowChildren | NegativeZOrderChildren);
- while (RenderLayerStackingNode* child = revertseIterator.next()) {
- const RenderLayer* childLayer = child->layer();
- // Stop at composited paint boundaries.
- if (childLayer->isPaintInvalidationContainer())
- continue;
-
- if (!childLayer->canUseConvertToLayerCoords())
- continue;
-
- LayoutPoint childOffset;
- LayoutRect childLocalRect(localRect);
- childLayer->convertToLayerCoords(this, childOffset);
- childLocalRect.moveBy(-childOffset);
-
- if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
- return true;
- }
- return false;
-}
-
-bool RenderLayer::shouldBeSelfPaintingLayer() const
-{
- if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAcceleratedCompositing())
- return true;
- return m_layerType == NormalLayer
- || (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars())
- || needsCompositedScrolling();
-}
-
-void RenderLayer::updateSelfPaintingLayer()
-{
- bool isSelfPaintingLayer = shouldBeSelfPaintingLayer();
- if (this->isSelfPaintingLayer() == isSelfPaintingLayer)
- return;
-
- m_isSelfPaintingLayer = isSelfPaintingLayer;
-
- if (parent())
- parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
-}
-
-bool RenderLayer::hasNonEmptyChildRenderers() const
-{
- // Some HTML can cause whitespace text nodes to have renderers, like:
- // <div>
- // <img src=...>
- // </div>
- // so test for 0x0 RenderTexts here
- for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
- if (!child->hasLayer()) {
- if (child->isRenderInline() || !child->isBox())
- return true;
-
- if (!toRenderBox(child)->size().isEmpty())
- return true;
- }
- }
- return false;
-}
-
-bool RenderLayer::hasBoxDecorationsOrBackground() const
-{
- return renderer()->style()->hasBoxDecorations() || renderer()->style()->hasBackground();
-}
-
-bool RenderLayer::hasVisibleBoxDecorations() const
-{
- if (!hasVisibleContent())
- return false;
-
- return hasBoxDecorationsOrBackground() || hasOverflowControls();
-}
-
-void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
-{
- if (!newStyle->hasFilter() && (!oldStyle || !oldStyle->hasFilter()))
- return;
-
- updateOrRemoveFilterClients();
- updateOrRemoveFilterEffectRenderer();
-}
-
-bool RenderLayer::attemptDirectCompositingUpdate(StyleDifference diff, const RenderStyle* oldStyle)
-{
- CompositingReasons oldPotentialCompositingReasonsFromStyle = m_potentialCompositingReasonsFromStyle;
- compositor()->updatePotentialCompositingReasonsFromStyle(this);
-
- // This function implements an optimization for transforms and opacity.
- // A common pattern is for a touchmove handler to update the transform
- // and/or an opacity of an element every frame while the user moves their
- // finger across the screen. The conditions below recognize when the
- // compositing state is set up to receive a direct transform or opacity
- // update.
-
- if (!diff.hasAtMostPropertySpecificDifferences(StyleDifference::TransformChanged | StyleDifference::OpacityChanged))
- return false;
- // The potentialCompositingReasonsFromStyle could have changed without
- // a corresponding StyleDifference if an animation started or ended.
- if (m_potentialCompositingReasonsFromStyle != oldPotentialCompositingReasonsFromStyle)
- return false;
- // We could add support for reflections if we updated the transform on
- // the reflection layers.
- if (renderer()->hasReflection())
- return false;
- // If we're unwinding a scheduleSVGFilterLayerUpdateHack(), then we can't
- // perform a direct compositing update because the filters code is going
- // to produce different output this time around. We can remove this code
- // once we fix the chicken/egg bugs in the filters code and delete the
- // scheduleSVGFilterLayerUpdateHack().
- if (renderer()->node() && renderer()->node()->svgFilterNeedsLayerUpdate())
- return false;
- if (!m_compositedLayerMapping)
- return false;
-
- // To cut off almost all the work in the compositing update for
- // this case, we treat inline transforms has having assumed overlap
- // (similar to how we treat animated transforms). Notice that we read
- // CompositingReasonInlineTransform from the m_compositingReasons, which
- // means that the inline transform actually triggered assumed overlap in
- // the overlap map.
- if (diff.transformChanged() && !(m_compositingReasons & CompositingReasonInlineTransform))
- return false;
-
- // We composite transparent RenderLayers differently from non-transparent
- // RenderLayers even when the non-transparent RenderLayers are already a
- // stacking context.
- if (diff.opacityChanged() && m_renderer->style()->hasOpacity() != oldStyle->hasOpacity())
- return false;
-
- updateTransform(oldStyle, renderer()->style());
-
- // FIXME: Consider introducing a smaller graphics layer update scope
- // that just handles transforms and opacity. GraphicsLayerUpdateLocal
- // will also program bounds, clips, and many other properties that could
- // not possibly have changed.
- m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
- compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange);
- return true;
-}
-
-void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
-{
- if (attemptDirectCompositingUpdate(diff, oldStyle))
- return;
-
- m_stackingNode->updateIsNormalFlowOnly();
- m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
-
- if (m_scrollableArea)
- m_scrollableArea->updateAfterStyleChange(oldStyle);
-
- // Overlay scrollbars can make this layer self-painting so we need
- // to recompute the bit once scrollbars have been updated.
- updateSelfPaintingLayer();
-
- if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) {
- ASSERT(!oldStyle || diff.needsFullLayout());
- updateReflectionInfo(oldStyle);
- }
-
- updateDescendantDependentFlags();
-
- updateTransform(oldStyle, renderer()->style());
- updateFilters(oldStyle, renderer()->style());
-
- setNeedsCompositingInputsUpdate();
-}
-
-bool RenderLayer::scrollsOverflow() const
-{
- if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea())
- return scrollableArea->scrollsOverflow();
-
- return false;
-}
-
-FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style)
-{
- const FilterOperations& filters = style->filter();
- if (filters.hasReferenceFilter()) {
- for (size_t i = 0; i < filters.size(); ++i) {
- FilterOperation* filterOperation = filters.operations().at(i).get();
- if (filterOperation->type() != FilterOperation::REFERENCE)
- continue;
- ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
- // FIXME: Cache the ReferenceFilter if it didn't change.
- RefPtrWillBeRawPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create(style->effectiveZoom());
- referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referenceFilter.get(), renderer(), referenceFilter->sourceGraphic(),
- referenceOperation));
- referenceOperation->setFilter(referenceFilter.release());
- }
- }
-
- return filters;
-}
-
-void RenderLayer::updateOrRemoveFilterClients()
-{
- if (!hasFilter()) {
- removeFilterInfoIfNeeded();
- return;
- }
-
- if (renderer()->style()->filter().hasReferenceFilter())
- ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->filter());
- else if (hasFilterInfo())
- filterInfo()->removeReferenceFilterClients();
-}
-
-void RenderLayer::updateOrRemoveFilterEffectRenderer()
-{
- // FilterEffectRenderer is only used to render the filters in software mode,
- // so we always need to run updateOrRemoveFilterEffectRenderer after the composited
- // mode might have changed for this layer.
- if (!paintsWithFilters()) {
- // Don't delete the whole filter info here, because we might use it
- // for loading CSS shader files.
- if (RenderLayerFilterInfo* filterInfo = this->filterInfo())
- filterInfo->setRenderer(nullptr);
-
- return;
- }
-
- RenderLayerFilterInfo* filterInfo = ensureFilterInfo();
- if (!filterInfo->renderer()) {
- RefPtrWillBeRawPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create();
- filterInfo->setRenderer(filterRenderer.release());
- }
-
- // If the filter fails to build, remove it from the layer. It will still attempt to
- // go through regular processing (e.g. compositing), but never apply anything.
- if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
- filterInfo->setRenderer(nullptr);
-}
-
-void RenderLayer::filterNeedsPaintInvalidation()
-{
- {
- DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().lifecycle());
- // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a style recalc, which
- // is a problem because this function can be called while performing layout.
- // Presumably this represents an illegal data flow of layout or compositing
- // information into the style system.
- toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack();
- }
-
- renderer()->setShouldDoFullPaintInvalidation();
-}
-
-void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const
-{
- computeSelfHitTestRects(rects);
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->addLayerHitTestRects(rects);
-}
-
-void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const
-{
- if (!size().isEmpty()) {
- Vector<LayoutRect> rect;
-
- if (renderBox() && renderBox()->scrollsOverflow()) {
- // For scrolling layers, rects are taken to be in the space of the contents.
- // We need to include the bounding box of the layer in the space of its parent
- // (eg. for border / scroll bars) and if it's composited then the entire contents
- // as well as they may be on another composited layer. Skip reporting contents
- // for non-composited layers as they'll get projected to the same layer as the
- // bounding box.
- if (compositingState() != NotComposited)
- rect.append(m_scrollableArea->overflowRect());
-
- rects.set(this, rect);
- if (const RenderLayer* parentLayer = parent()) {
- LayerHitTestRects::iterator iter = rects.find(parentLayer);
- if (iter == rects.end()) {
- rects.add(parentLayer, Vector<LayoutRect>()).storedValue->value.append(physicalBoundingBox(parentLayer));
- } else {
- iter->value.append(physicalBoundingBox(parentLayer));
- }
- }
- } else {
- rect.append(logicalBoundingBox());
- rects.set(this, rect);
- }
- }
-}
-
-void RenderLayer::setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()
-{
- renderer()->setShouldDoFullPaintInvalidation();
-
- // Disable for reading compositingState() in isPaintInvalidationContainer() below.
- DisableCompositingQueryAsserts disabler;
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->isPaintInvalidationContainer())
- child->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
- }
-}
-
-DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
- : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { }
-
-} // namespace blink
-
-#ifndef NDEBUG
-void showLayerTree(const blink::RenderLayer* layer)
-{
- if (!layer)
- return;
-
- if (blink::LocalFrame* frame = layer->renderer()->frame()) {
- WTF::String output = externalRepresentation(frame, blink::LayoutAsTextShowAllLayers | blink::LayoutAsTextShowLayerNesting | blink::LayoutAsTextShowCompositedLayers | blink::LayoutAsTextShowAddresses | blink::LayoutAsTextShowIDAndClass | blink::LayoutAsTextDontUpdateLayout | blink::LayoutAsTextShowLayoutState);
- fprintf(stderr, "%s\n", output.utf8().data());
- }
-}
-
-void showLayerTree(const blink::RenderObject* renderer)
-{
- if (!renderer)
- return;
- showLayerTree(renderer->enclosingLayer());
-}
-#endif
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | Source/core/rendering/RenderLayerClipper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698