| 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
|
|
|