This source file includes following definitions.
- m_blendInfo
- debugName
- compositor
- contentChanged
- canRender3DTransforms
- paintsWithFilters
- requiresFullLayerImageForFilters
- subpixelAccumulation
- setSubpixelAccumulation
- computeOffsetFromRoot
- updateLayerPositionsAfterLayout
- updateLayerPositions
- setAncestorChainHasSelfPaintingLayerDescendant
- dirtyAncestorChainHasSelfPaintingLayerDescendantStatus
- setAncestorChainHasOutOfFlowPositionedDescendant
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus
- scrollsWithRespectTo
- updateLayerPositionsAfterDocumentScroll
- updateLayerPositionsAfterOverflowScroll
- updateLayerPositionsAfterScroll
- updateTransform
- enclosingLayerForContainingBlock
- renderingContextRoot
- currentTransform
- renderableTransform
- enclosingOverflowClipLayer
- checkContainingBlockChainForPagination
- useRegionBasedColumns
- updatePagination
- setHasVisibleContent
- dirtyVisibleContentStatus
- dirtyAncestorChainVisibleDescendantStatus
- setAncestorChainHasVisibleDescendant
- updateHasUnclippedDescendant
- updateHasVisibleNonLayerContent
- subtreeContainsOutOfFlowPositionedLayer
- updateDescendantDependentFlags
- dirty3DTransformedDescendantStatus
- update3DTransformedDescendantStatus
- updateLayerPosition
- perspectiveTransform
- perspectiveOrigin
- isFixedPositionedContainer
- enclosingPositionedAncestor
- enclosingTransformedAncestor
- compositingContainer
- enclosingCompositingLayer
- enclosingCompositingLayerForRepaint
- clearAncestorDependentPropertyCache
- ensureAncestorDependentPropertyCache
- ancestorCompositedScrollingLayer
- ancestorScrollingLayer
- enclosingFilterLayer
- setNeedsToUpdateAncestorDependentProperties
- updateAncestorDependentProperties
- clearChildNeedsToUpdateAncestorDependantProperties
- setCompositingReasons
- hasAncestorWithFilterOutsets
- cannotBlitToWindow
- isTransparent
- transparentPaintingAncestor
- expandClipRectForDescendantsAndReflection
- transparencyClipBox
- paintingExtent
- beginTransparencyLayers
- addChild
- removeChild
- removeOnlyThisLayer
- insertOnlyThisLayer
- convertToPixelSnappedLayerCoords
- convertToPixelSnappedLayerCoords
- accumulateOffsetTowardsAncestor
- convertToLayerCoords
- convertToLayerCoords
- scrollParent
- clipParent
- didUpdateNeedsCompositedScrolling
- updateReflectionInfo
- updateStackingNode
- updateScrollableArea
- collectTrackedRepaintRects
- hasOverflowControls
- paint
- paintOverlayScrollbars
- inContainingBlockChain
- clipToRect
- restoreClip
- performOverlapTests
- shouldDoSoftwarePaint
- shouldSuppressPaintingLayer
- paintForFixedRootBackground
- paintLayer
- paintLayerContentsAndReflection
- paintLayerContents
- paintLayerByApplyingTransform
- paintChildren
- collectFragments
- updatePaintingInfoForFragments
- paintTransformedLayerIntoFragments
- subPixelAccumulationIfNeeded
- paintBackgroundForFragments
- paintForegroundForFragments
- paintForegroundForFragmentsWithPhase
- paintOutlineForFragments
- paintMaskForFragments
- paintChildClippingMaskForFragments
- paintOverflowControlsForFragments
- paintPaginatedChildLayer
- paintChildLayerIntoColumns
- frameVisibleRect
- hitTest
- hitTest
- enclosingElement
- isInTopLayer
- isInTopLayerSubtree
- computeZOffset
- createLocalTransformState
- isHitCandidate
- hitTestLayer
- hitTestContentsForFragments
- hitTestTransformedLayerInFragments
- hitTestLayerByApplyingTransform
- hitTestContents
- hitTestChildren
- hitTestPaginatedChildLayer
- hitTestChildLayerColumns
- addBlockSelectionGapsBounds
- clearBlockSelectionGapsBounds
- repaintBlockSelectionGaps
- hasBlockSelectionGapBounds
- intersectsDamageRect
- logicalBoundingBox
- physicalBoundingBox
- calculateLayerBounds
- compositingState
- isAllowedToQueryCompositingState
- isInCompositingUpdate
- compositedLayerMapping
- ensureCompositedLayerMapping
- clearCompositedLayerMapping
- setGroupedMapping
- hasCompositedMask
- hasCompositedClippingMask
- clipsCompositingDescendantsWithBorderRadius
- paintsWithTransform
- paintsWithBlendMode
- backgroundIsKnownToBeOpaqueInRect
- childBackgroundIsKnownToBeOpaqueInRect
- setParent
- shouldBeSelfPaintingLayer
- updateSelfPaintingLayer
- hasNonEmptyChildRenderers
- hasBoxDecorations
- hasBoxDecorationsOrBackground
- hasVisibleBoxDecorations
- isVisuallyNonEmpty
- updateOutOfFlowPositioned
- hasOrHadFilters
- needsCompositingLayersRebuiltForClip
- needsCompositingLayersRebuiltForOverflow
- needsCompositingLayersRebuiltForFilters
- needsCompositingLayersRebuiltForBlending
- updateFilters
- styleChanged
- scrollsOverflow
- computeFilterOperations
- updateOrRemoveFilterClients
- updateOrRemoveFilterEffectRenderer
- filterNeedsRepaint
- addLayerHitTestRects
- computeSelfHitTestRects
- m_scrollParentDirty
- scrollParent
- setScrollParent
- ancestorCompositedScrollingLayer
- setAncestorCompositedScrollingLayer
- showLayerTree
- showLayerTree
#include "config.h"
#include "core/rendering/RenderLayer.h"
#include "CSSPropertyNames.h"
#include "HTMLNames.h"
#include "RuntimeEnabledFeatures.h"
#include "SVGNames.h"
#include "core/animation/ActiveAnimations.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/frame/Settings.h"
#include "core/html/HTMLFrameElement.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/HitTestRequest.h"
#include "core/rendering/HitTestResult.h"
#include "core/rendering/HitTestingTransformState.h"
#include "core/rendering/LayoutRectRecorder.h"
#include "core/rendering/RenderFlowThread.h"
#include "core/rendering/RenderGeometryMap.h"
#include "core/rendering/RenderInline.h"
#include "core/rendering/RenderReplica.h"
#include "core/rendering/RenderScrollbar.h"
#include "core/rendering/RenderScrollbarPart.h"
#include "core/rendering/RenderTreeAsText.h"
#include "core/rendering/RenderView.h"
#include "core/rendering/compositing/CompositedLayerMapping.h"
#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "core/rendering/svg/ReferenceFilterBuilder.h"
#include "core/rendering/svg/RenderSVGResourceClipper.h"
#include "platform/LengthFunctions.h"
#include "platform/Partitions.h"
#include "platform/TraceEvent.h"
#include "platform/geometry/FloatPoint3D.h"
#include "platform/geometry/FloatRect.h"
#include "platform/graphics/GraphicsContextStateSaver.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"
using namespace std;
namespace WebCore {
namespace {
static CompositingQueryMode gCompositingQueryMode =
CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases;
}
using namespace HTMLNames;
RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type)
: m_layerType(type)
, m_hasSelfPaintingLayerDescendant(false)
, m_hasSelfPaintingLayerDescendantDirty(false)
, m_hasOutOfFlowPositionedDescendant(false)
, m_hasOutOfFlowPositionedDescendantDirty(true)
, m_hasUnclippedDescendant(false)
, m_isUnclippedDescendant(false)
, m_isRootLayer(renderer->isRenderView())
, m_usedTransparency(false)
, m_visibleContentStatusDirty(true)
, m_hasVisibleContent(false)
, m_visibleDescendantStatusDirty(false)
, m_hasVisibleDescendant(false)
, m_hasVisibleNonLayerContent(false)
, m_isPaginated(false)
, m_3DTransformedDescendantStatusDirty(true)
, m_has3DTransformedDescendant(false)
, m_containsDirtyOverlayScrollbars(false)
, m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell())
, m_hasFilterInfo(false)
, m_needsToUpdateAncestorDependentProperties(true)
, m_childNeedsToUpdateAncestorDependantProperties(true)
, 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_groupedMapping(0)
, m_repainter(renderer)
, m_clipper(renderer)
, m_blendInfo(renderer)
{
updateStackingNode();
m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
if (!renderer->firstChild() && renderer->style()) {
m_visibleContentStatusDirty = false;
m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
}
updateScrollableArea();
}
RenderLayer::~RenderLayer()
{
if (!m_renderer->documentBeingDestroyed())
compositor()->removeOutOfFlowPositionedLayer(this);
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);
}
clearCompositedLayerMapping(true);
}
String RenderLayer::debugName() const
{
if (isReflection()) {
ASSERT(m_reflectionInfo);
return m_reflectionInfo->debugName();
}
return renderer()->debugName();
}
RenderLayerCompositor* RenderLayer::compositor() const
{
if (!renderer()->view())
return 0;
return renderer()->view()->compositor();
}
void RenderLayer::contentChanged(ContentChangeType changeType)
{
DisableCompositingQueryAsserts disabler;
if (changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged)
compositor()->updateLayerCompositingState(this);
if (changeType == CanvasContextChanged)
compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCanvasContextChange);
if (m_compositedLayerMapping)
m_compositedLayerMapping->contentChanged(changeType);
}
bool RenderLayer::canRender3DTransforms() const
{
return compositor()->canRender3DTransforms();
}
bool RenderLayer::paintsWithFilters() const
{
if (!renderer()->hasFilter())
return false;
DisableCompositingQueryAsserts disabler;
if (!m_compositedLayerMapping
|| compositingState() != PaintsIntoOwnBacking
|| !m_compositedLayerMapping->canCompositeFilters())
return true;
return false;
}
bool RenderLayer::requiresFullLayerImageForFilters() const
{
if (!paintsWithFilters())
return false;
FilterEffectRenderer* filter = filterRenderer();
return filter ? filter->hasFilterThatMovesPixels() : false;
}
LayoutSize RenderLayer::subpixelAccumulation() const
{
return m_subpixelAccumulation;
}
void RenderLayer::setSubpixelAccumulation(const LayoutSize& size)
{
m_subpixelAccumulation = size;
}
LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
{
hasLayerOffset = true;
if (!parent())
return LayoutPoint();
const RenderLayer* rootLayer = 0;
for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
if (!hasLayerOffset)
return LayoutPoint();
}
ASSERT(rootLayer == root());
LayoutPoint offset;
parent()->convertToLayerCoords(rootLayer, offset);
return offset;
}
void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
{
TRACE_EVENT0("blink_rendering", "RenderLayer::updateLayerPositionsAfterLayout");
DisableCompositingQueryAsserts disabler;
RenderGeometryMap geometryMap(UseTransforms);
if (this != rootLayer)
geometryMap.pushMappingsToAncestor(parent(), 0);
updateLayerPositions(&geometryMap, flags);
}
void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
{
updateLayerPosition();
if (geometryMap)
geometryMap->pushMappingsToAncestor(this, parent());
m_clipper.clearClipRects();
if (hasOverflowControls()) {
LayoutPoint offsetFromRoot;
if (geometryMap)
offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint()));
else {
convertToLayerCoords(root(), offsetFromRoot);
}
scrollableArea()->positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
}
updateDescendantDependentFlags();
if (flags & UpdatePagination)
updatePagination();
else {
m_isPaginated = false;
m_enclosingPaginationLayer = 0;
}
repainter().repaintAfterLayout(geometryMap, flags & CheckForRepaint);
if (m_reflectionInfo)
m_reflectionInfo->reflection()->layout();
if (useRegionBasedColumns() && renderer()->isInFlowRenderFlowThread()) {
updatePagination();
flags |= UpdatePagination;
}
if (renderer()->hasColumns())
flags |= UpdatePagination;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(geometryMap, flags);
if ((flags & NeedsFullRepaintInBacking) && hasCompositedLayerMapping() && !compositedLayerMapping()->paintsIntoCompositedAncestor())
compositedLayerMapping()->setContentsNeedDisplay();
if (geometryMap)
geometryMap->popMappingsToAncestor(parent());
}
void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
break;
layer->m_hasSelfPaintingLayerDescendantDirty = false;
layer->m_hasSelfPaintingLayerDescendant = true;
}
}
void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
layer->m_hasSelfPaintingLayerDescendantDirty = true;
if (layer->isSelfPaintingLayer()) {
ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->hasSelfPaintingLayerDescendant());
break;
}
}
}
void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
if (!layer->m_hasOutOfFlowPositionedDescendantDirty && layer->hasOutOfFlowPositionedDescendant())
break;
layer->setHasOutOfFlowPositionedDescendantDirty(false);
layer->setHasOutOfFlowPositionedDescendant(true);
}
}
void RenderLayer::dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
layer->setHasOutOfFlowPositionedDescendantDirty(true);
layer->setHasUnclippedDescendant(false);
if (layer->renderer()->isOutOfFlowPositioned()) {
ASSERT(!parent() || parent()->m_hasOutOfFlowPositionedDescendantDirty || parent()->hasOutOfFlowPositionedDescendant());
break;
}
}
}
bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const
{
const EPosition position = renderer()->style()->position();
const EPosition otherPosition = other->renderer()->style()->position();
const RenderObject* containingBlock = renderer()->containingBlock();
const RenderObject* otherContainingBlock = other->renderer()->containingBlock();
const RenderLayer* rootLayer = renderer()->view()->compositor()->rootRenderLayer();
const bool isRootFixedPos = position == FixedPosition && containingBlock->enclosingLayer() == rootLayer;
const bool otherIsRootFixedPos = otherPosition == FixedPosition && otherContainingBlock->enclosingLayer() == rootLayer;
if (isRootFixedPos && otherIsRootFixedPos)
return false;
if (isRootFixedPos || otherIsRootFixedPos)
return true;
if (containingBlock == otherContainingBlock)
return false;
HashSet<const RenderObject*> containingBlocks;
while (containingBlock) {
if (containingBlock->enclosingLayer()->scrollsOverflow())
break;
containingBlocks.add(containingBlock);
containingBlock = containingBlock->containingBlock();
}
while (otherContainingBlock) {
if (containingBlocks.contains(otherContainingBlock))
return false;
if (otherContainingBlock->enclosingLayer()->scrollsOverflow())
break;
otherContainingBlock = otherContainingBlock->containingBlock();
}
return true;
}
void RenderLayer::updateLayerPositionsAfterDocumentScroll()
{
ASSERT(this == renderer()->view()->layer());
RenderGeometryMap geometryMap(UseTransforms);
updateLayerPositionsAfterScroll(&geometryMap);
}
void RenderLayer::updateLayerPositionsAfterOverflowScroll()
{
RenderGeometryMap geometryMap(UseTransforms);
RenderView* view = renderer()->view();
if (this != view->layer())
geometryMap.pushMappingsToAncestor(parent(), 0);
updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
}
void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
{
updateDescendantDependentFlags();
if (subtreeIsInvisible())
return;
bool positionChanged = updateLayerPosition();
if (positionChanged)
flags |= HasChangedAncestor;
if (geometryMap)
geometryMap->pushMappingsToAncestor(this, parent());
if ((flags & HasChangedAncestor) || (flags & HasSeenViewportConstrainedAncestor) || (flags & IsOverflowScroll))
m_clipper.clearClipRects();
if (renderer()->style()->hasViewportConstrainedPosition())
flags |= HasSeenViewportConstrainedAncestor;
if (renderer()->hasOverflowClip())
flags |= HasSeenAncestorWithOverflowClip;
if ((flags & IsOverflowScroll) && (flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) {
LayoutRectRecorder recorder(*m_renderer);
repainter().computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
} else {
}
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositionsAfterScroll(geometryMap, flags);
if (geometryMap)
geometryMap->popMappingsToAncestor(parent());
}
void RenderLayer::updateTransform()
{
bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
bool had3DTransform = has3DTransform();
bool hadTransform = m_transform;
if (hasTransform != hadTransform) {
if (hasTransform)
m_transform = adoptPtr(new TransformationMatrix);
else
m_transform.clear();
m_clipper.clearClipRectsIncludingDescendants();
}
if (hasTransform) {
RenderBox* box = renderBox();
ASSERT(box);
m_transform->makeIdentity();
box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
makeMatrixRenderable(*m_transform, canRender3DTransforms());
}
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();
if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
RenderBox* box = renderBox();
TransformationMatrix currTransform;
box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
makeMatrixRenderable(currTransform, canRender3DTransforms());
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 );
return matrix;
}
return *m_transform;
}
RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSelf) const
{
const RenderLayer* layer = (includeSelf == IncludeSelf) ? this : parent();
while (layer) {
if (layer->renderer()->hasOverflowClip())
return const_cast<RenderLayer*>(layer);
layer = layer->parent();
}
return 0;
}
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 (containingBlock != ancestorColumnsRenderer)
return false;
if (prevBlock->isOutOfFlowPositioned())
return false;
return true;
}
bool RenderLayer::useRegionBasedColumns() const
{
return renderer()->document().regionBasedColumnsEnabled();
}
void RenderLayer::updatePagination()
{
m_isPaginated = false;
m_enclosingPaginationLayer = 0;
if (hasCompositedLayerMapping() || !parent())
return;
bool regionBasedColumnsUsed = useRegionBasedColumns();
if (regionBasedColumnsUsed && renderer()->isInFlowRenderFlowThread()) {
m_enclosingPaginationLayer = this;
return;
}
if (m_stackingNode->isNormalFlowOnly()) {
if (regionBasedColumnsUsed) {
m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
m_enclosingPaginationLayer = 0;
} else
m_isPaginated = parent()->renderer()->hasColumns();
return;
}
if (regionBasedColumnsUsed) {
RenderView* view = renderer()->view();
RenderBlock* containingBlock;
for (containingBlock = renderer()->containingBlock();
containingBlock && containingBlock != view;
containingBlock = containingBlock->containingBlock()) {
if (containingBlock->hasLayer()) {
m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
m_enclosingPaginationLayer = 0;
return;
}
}
return;
}
RenderLayerStackingNode* ancestorStackingContainerNode = m_stackingNode->ancestorStackingContainerNode();
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns()) {
m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
return;
}
if (curr->stackingNode() == ancestorStackingContainerNode)
return;
}
}
void RenderLayer::setHasVisibleContent()
{
if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
ASSERT(!parent() || parent()->hasVisibleDescendant());
return;
}
m_hasVisibleContent = true;
m_visibleContentStatusDirty = false;
setNeedsToUpdateAncestorDependentProperties();
repainter().computeRepaintRects(renderer()->containerForRepaint());
if (!m_stackingNode->isNormalFlowOnly()) {
for (RenderLayerStackingNode* sc = m_stackingNode->ancestorStackingContainerNode(); sc; sc = sc->ancestorStackingContainerNode()) {
sc->dirtyZOrderLists();
if (sc->layer()->hasVisibleContent())
break;
}
}
if (parent())
parent()->setAncestorChainHasVisibleDescendant();
}
void RenderLayer::dirtyVisibleContentStatus()
{
m_visibleContentStatusDirty = true;
if (parent())
parent()->dirtyAncestorChainVisibleDescendantStatus();
}
void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
if (layer->m_visibleDescendantStatusDirty)
break;
layer->m_visibleDescendantStatusDirty = true;
}
}
void RenderLayer::setAncestorChainHasVisibleDescendant()
{
for (RenderLayer* layer = this; layer; layer = layer->parent()) {
if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
break;
layer->m_hasVisibleDescendant = true;
layer->m_visibleDescendantStatusDirty = false;
}
}
void RenderLayer::updateHasUnclippedDescendant()
{
TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasUnclippedDescendant");
ASSERT(renderer()->isOutOfFlowPositioned());
if (!m_hasVisibleContent && !m_hasVisibleDescendant)
return;
FrameView* frameView = renderer()->view()->frameView();
if (!frameView)
return;
const RenderObject* containingBlock = renderer()->containingBlock();
setIsUnclippedDescendant(false);
for (RenderLayer* ancestor = parent(); ancestor && ancestor->renderer() != containingBlock; ancestor = ancestor->parent()) {
if (ancestor->scrollsOverflow())
setIsUnclippedDescendant(true);
ancestor->setHasUnclippedDescendant(true);
}
}
void RenderLayer::updateHasVisibleNonLayerContent()
{
TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasVisibleNonLayerContent");
m_hasVisibleNonLayerContent = false;
for (RenderObject* r = renderer()->firstChild(); r; r = r->nextSibling()) {
if (!r->hasLayer()) {
m_hasVisibleNonLayerContent = true;
break;
}
}
}
static bool subtreeContainsOutOfFlowPositionedLayer(const RenderLayer* subtreeRoot)
{
return (subtreeRoot->renderer() && subtreeRoot->renderer()->isOutOfFlowPositioned()) || subtreeRoot->hasOutOfFlowPositionedDescendant();
}
void RenderLayer::updateDescendantDependentFlags()
{
if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
m_hasVisibleDescendant = false;
m_hasSelfPaintingLayerDescendant = false;
m_hasOutOfFlowPositionedDescendant = false;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
child->updateDescendantDependentFlags();
bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
bool hasOutOfFlowPositionedDescendant = subtreeContainsOutOfFlowPositionedLayer(child);
m_hasVisibleDescendant |= hasVisibleDescendant;
m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant;
if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant)
break;
}
m_visibleDescendantStatusDirty = false;
m_hasSelfPaintingLayerDescendantDirty = false;
m_hasOutOfFlowPositionedDescendantDirty = false;
}
if (m_blendInfo.childLayerHasBlendModeStatusDirty()) {
m_blendInfo.setChildLayerHasBlendMode(false);
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
if (!child->stackingNode()->isStackingContext())
child->updateDescendantDependentFlags();
bool childLayerHadBlendMode = child->blendInfo().childLayerHasBlendModeWhileDirty();
bool childLayerHasBlendMode = childLayerHadBlendMode || child->blendInfo().hasBlendMode();
m_blendInfo.setChildLayerHasBlendMode(childLayerHasBlendMode);
if (childLayerHasBlendMode)
break;
}
m_blendInfo.setChildLayerHasBlendModeStatusDirty(false);
}
if (m_visibleContentStatusDirty) {
bool previouslyHasVisibleContent = m_hasVisibleContent;
if (renderer()->style()->visibility() == VISIBLE)
m_hasVisibleContent = true;
else {
m_hasVisibleContent = false;
RenderObject* r = renderer()->firstChild();
while (r) {
if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
m_hasVisibleContent = true;
break;
}
if (r->firstChild() && !r->hasLayer())
r = r->firstChild();
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)
setNeedsToUpdateAncestorDependentProperties();
}
}
void RenderLayer::dirty3DTransformedDescendantStatus()
{
RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContainerNode();
if (!stackingNode)
return;
stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
while (stackingNode && stackingNode->layer()->preserves3D()) {
stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
stackingNode = stackingNode->ancestorStackingContainerNode();
}
}
bool RenderLayer::update3DTransformedDescendantStatus()
{
if (m_3DTransformedDescendantStatusDirty) {
m_has3DTransformedDescendant = false;
m_stackingNode->updateZOrderLists();
RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), PositiveZOrderChildren | NegativeZOrderChildren);
while (RenderLayerStackingNode* node = iterator.next())
m_has3DTransformedDescendant |= node->layer()->update3DTransformedDescendantStatus();
m_3DTransformedDescendantStatusDirty = false;
}
if (preserves3D())
return has3DTransform() || m_has3DTransformedDescendant;
return has3DTransform();
}
bool RenderLayer::updateLayerPosition()
{
LayoutPoint localPoint;
LayoutSize inlineBoundingBoxOffset;
LayoutRectRecorder recorder(*m_renderer);
if (renderer()->isInline() && renderer()->isRenderInline()) {
RenderInline* inlineFlow = toRenderInline(renderer());
IntRect lineBox = inlineFlow->linesBoundingBox();
setSize(lineBox.size());
inlineBoundingBoxOffset = toSize(lineBox.location());
localPoint += inlineBoundingBoxOffset;
} else if (RenderBox* box = renderBox()) {
setSize(pixelSnappedIntSize(box->size(), box->location()));
localPoint += box->topLeftLocationOffset();
}
if (!renderer()->isOutOfFlowPositioned() && renderer()->parent()) {
RenderObject* curr = renderer()->parent();
while (curr && !curr->hasLayer()) {
if (curr->isBox() && !curr->isTableRow()) {
localPoint += toRenderBox(curr)->topLeftLocationOffset();
}
curr = curr->parent();
}
if (curr->isBox() && curr->isTableRow()) {
localPoint -= toRenderBox(curr)->topLeftLocationOffset();
}
}
if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
RenderLayer* positionedParent = enclosingPositionedAncestor();
if (positionedParent->renderer()->hasOverflowClip()) {
LayoutSize offset = positionedParent->renderBox()->scrolledContentOffset();
localPoint -= offset;
}
if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) {
LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(*toRenderBox(renderer()));
localPoint += offset;
}
} else if (parent()) {
if (hasCompositedLayerMapping()) {
LayoutSize columnOffset;
if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns())
renderer()->view()->adjustForColumns(columnOffset, localPoint);
else
parent()->renderer()->adjustForColumns(columnOffset, localPoint);
localPoint += columnOffset;
}
if (parent()->renderer()->hasOverflowClip()) {
IntSize scrollOffset = parent()->renderBox()->scrolledContentOffset();
localPoint -= scrollOffset;
}
}
bool positionOrOffsetChanged = false;
if (renderer()->isInFlowPositioned()) {
LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFlowPosition();
positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
m_offsetForInFlowPosition = newOffset;
localPoint.move(m_offsetForInFlowPosition);
} else {
m_offsetForInFlowPosition = LayoutSize();
}
localPoint -= inlineBoundingBoxOffset;
positionOrOffsetChanged |= location() != localPoint;
setLocation(localPoint);
return positionOrOffsetChanged;
}
TransformationMatrix RenderLayer::perspectiveTransform() const
{
if (!renderer()->hasTransform())
return TransformationMatrix();
RenderStyle* style = renderer()->style();
if (!style->hasPerspective())
return TransformationMatrix();
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);
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()->hasTransform())
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->hasTransform();
}
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->transform())
curr = curr->parent();
return curr;
}
const RenderLayer* RenderLayer::compositingContainer() const
{
if (stackingNode()->isNormalFlowOnly())
return parent();
if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestorStackingContainerNode())
return ancestorStackingNode->layer();
return 0;
}
RenderLayer* RenderLayer::enclosingCompositingLayer(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;
}
RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
{
ASSERT(isAllowedToQueryCompositingState());
if ((includeSelf == IncludeSelf) && (compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking))
return const_cast<RenderLayer*>(this);
for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
if (curr->compositingState() == PaintsIntoOwnBacking || curr->compositingState() == PaintsIntoGroupedBacking)
return const_cast<RenderLayer*>(curr);
}
return 0;
}
void RenderLayer::clearAncestorDependentPropertyCache()
{
ASSERT(isInCompositingUpdate());
m_ancestorDependentPropertyCache.clear();
}
void RenderLayer::ensureAncestorDependentPropertyCache() const
{
ASSERT(isInCompositingUpdate());
if (m_ancestorDependentPropertyCache)
return;
m_ancestorDependentPropertyCache = adoptPtr(new AncestorDependentPropertyCache());
}
RenderLayer* RenderLayer::ancestorCompositedScrollingLayer() const
{
if (!renderer()->acceleratedCompositingForOverflowScrollEnabled())
return 0;
ASSERT(isInCompositingUpdate() || !m_ancestorDependentPropertyCache);
if (m_ancestorDependentPropertyCache && !m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayerDirty())
return m_ancestorDependentPropertyCache->ancestorCompositedScrollingLayer();
RenderObject* containingBlock = renderer()->containingBlock();
if (!containingBlock)
return 0;
if (isInCompositingUpdate())
ensureAncestorDependentPropertyCache();
RenderLayer* ancestorCompositedScrollingLayer = 0;
for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
if (ancestorLayer->needsCompositedScrolling()) {
ancestorCompositedScrollingLayer = ancestorLayer;
break;
}
}
if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setAncestorCompositedScrollingLayer(ancestorCompositedScrollingLayer);
return ancestorCompositedScrollingLayer;
}
RenderLayer* RenderLayer::ancestorScrollingLayer() const
{
RenderObject* containingBlock = renderer()->containingBlock();
if (!containingBlock)
return 0;
for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
if (ancestorLayer->scrollsOverflow())
return ancestorLayer;
}
return 0;
}
RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
{
const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
for (; curr; curr = curr->parent()) {
if (curr->requiresFullLayerImageForFilters())
return const_cast<RenderLayer*>(curr);
}
return 0;
}
void RenderLayer::setNeedsToUpdateAncestorDependentProperties()
{
m_needsToUpdateAncestorDependentProperties = true;
for (RenderLayer* current = this; current && !current->m_childNeedsToUpdateAncestorDependantProperties; current = current->parent())
current->m_childNeedsToUpdateAncestorDependantProperties = true;
}
void RenderLayer::updateAncestorDependentProperties(const AncestorDependentProperties& ancestorDependentProperties)
{
m_ancestorDependentProperties = ancestorDependentProperties;
m_needsToUpdateAncestorDependentProperties = false;
}
void RenderLayer::clearChildNeedsToUpdateAncestorDependantProperties()
{
ASSERT(!m_needsToUpdateAncestorDependentProperties);
m_childNeedsToUpdateAncestorDependantProperties = false;
}
void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask)
{
ASSERT(reasons == (reasons & mask));
if ((m_compositingProperties.compositingReasons & mask) == (reasons & mask))
return;
m_compositingProperties.compositingReasons = (reasons & mask) | (m_compositingProperties.compositingReasons & ~mask);
m_clipper.setCompositingClipRectsDirty();
}
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;
}
bool RenderLayer::cannotBlitToWindow() const
{
if (isTransparent() || m_reflectionInfo || hasTransform())
return true;
if (!parent())
return false;
return parent()->cannotBlitToWindow();
}
bool RenderLayer::isTransparent() const
{
if (renderer()->node() && renderer()->node()->isSVGElement())
return false;
return renderer()->isTransparent() || renderer()->hasMask();
}
RenderLayer* RenderLayer::transparentPaintingAncestor()
{
if (hasCompositedLayerMapping())
return 0;
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
if (curr->hasCompositedLayerMapping())
return 0;
if (curr->isTransparent())
return curr;
}
return 0;
}
enum TransparencyClipBoxBehavior {
PaintingTransparencyClipBox,
HitTestingTransparencyClipBox
};
enum TransparencyClipBoxMode {
DescendantsOfTransparencyClipBox,
RootOfTransparencyClipBox
};
static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, const LayoutSize& subPixelAccumulation, PaintBehavior = 0);
static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
TransparencyClipBoxBehavior transparencyBehavior, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
if (!layer->renderer()->hasMask()) {
for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionLayer() != curr)
clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, subPixelAccumulation, paintBehavior));
}
}
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);
}
}
static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
|| (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
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();
LayoutRect clipRect = layer->physicalBoundingBox(layer);
expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, subPixelAccumulation, paintBehavior);
layer->renderer()->style()->filterOutsets().expandRect(clipRect);
LayoutRect result = transform.mapRect(clipRect);
if (!paginationLayer)
return result;
RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
result = enclosingFlowThread->fragmentsBoundingBox(result);
LayoutPoint rootLayerDelta;
paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
result.moveBy(rootLayerDelta);
return result;
}
LayoutRect clipRect = layer->physicalBoundingBox(rootLayer);
expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, subPixelAccumulation, paintBehavior);
layer->renderer()->style()->filterOutsets().expandRect(clipRect);
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::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && m_blendInfo.childLayerHasBlendMode();
if (context->paintingDisabled() || ((paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency))
return;
RenderLayer* ancestor = transparentPaintingAncestor();
if (ancestor)
ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
if (paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) {
m_usedTransparency = true;
context->save();
LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
context->clip(clipRect);
if (paintsWithBlendMode())
context->setCompositeOperation(context->compositeOperation(), m_blendInfo.blendMode());
context->beginTransparencyLayer(renderer()->opacity());
if (paintsWithBlendMode())
context->setCompositeOperation(context->compositeOperation(), blink::WebBlendModeNormal);
#ifdef REVEAL_TRANSPARENCY_LAYERS
context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
context->fillRect(clipRect);
#endif
}
}
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->setParent(this);
setNeedsToUpdateAncestorDependentProperties();
if (child->stackingNode()->isNormalFlowOnly())
m_stackingNode->dirtyNormalFlowList();
if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) {
child->stackingNode()->dirtyStackingContainerZOrderLists();
}
child->updateDescendantDependentFlags();
if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
setAncestorChainHasVisibleDescendant();
if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
setAncestorChainHasSelfPaintingLayerDescendant();
if (child->blendInfo().hasBlendMode() || child->blendInfo().childLayerHasBlendMode())
m_blendInfo.setAncestorChainBlendedDescendant();
if (subtreeContainsOutOfFlowPositionedLayer(child)) {
compositor()->setNeedsUpdateCompositingRequirementsState();
setAncestorChainHasOutOfFlowPositionedDescendant();
}
child->stackingNode()->setDescendantsAreContiguousInStackingOrderDirty(true);
compositor()->layerWasAdded(this, child);
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
if (!renderer()->documentBeingDestroyed())
compositor()->layerWillBeRemoved(this, 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()) {
oldChild->stackingNode()->dirtyStackingContainerZOrderLists();
}
if (renderer()->style()->visibility() != VISIBLE)
dirtyVisibleContentStatus();
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
oldChild->setParent(0);
oldChild->updateDescendantDependentFlags();
if (subtreeContainsOutOfFlowPositionedLayer(oldChild)) {
compositor()->setNeedsUpdateCompositingRequirementsState();
dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
}
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
dirtyAncestorChainVisibleDescendantStatus();
if (oldChild->m_blendInfo.hasBlendMode() || oldChild->blendInfo().childLayerHasBlendMode())
m_blendInfo.dirtyAncestorChainBlendedDescendantStatus();
if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
return oldChild;
}
void RenderLayer::removeOnlyThisLayer()
{
if (!m_parent)
return;
compositor()->layerWillBeRemoved(m_parent, this);
m_clipper.clearClipRectsIncludingDescendants();
RenderLayer* nextSib = nextSibling();
if (m_reflectionInfo)
removeChild(m_reflectionInfo->reflectionLayer());
RenderLayer* current = m_first;
while (current) {
RenderLayer* next = current->nextSibling();
removeChild(current);
m_parent->addChild(current, nextSib);
if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
current->renderer()->setShouldDoFullRepaintAfterLayout(true);
else
current->repainter().setRepaintStatus(NeedsFullRepaint);
DisableCompositingQueryAsserts disabler;
current->updateLayerPositions(0);
current = next;
}
m_parent->removeChild(this);
m_renderer->destroyLayer();
}
void RenderLayer::insertOnlyThisLayer()
{
if (!m_parent && renderer()->parent()) {
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);
}
for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
m_clipper.clearClipRectsIncludingDescendants();
}
void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation) const
{
LayoutPoint location = roundedLocation;
convertToLayerCoords(ancestorLayer, location);
roundedLocation = roundedIntPoint(location);
}
void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect) const
{
LayoutRect rect = roundedRect;
convertToLayerCoords(ancestorLayer, rect);
roundedRect = pixelSnappedIntRect(rect);
}
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();
RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer->flowThreadContainingBlock() : 0;
if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
fixedFlowThreadContainer = 0;
if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed);
location += LayoutSize(absPos.x(), absPos.y());
return ancestorLayer;
}
if (position == FixedPosition && !fixedFlowThreadContainer) {
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);
if (fixedPositionContainerLayer != ancestorLayer) {
LayoutPoint fixedContainerCoords;
layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
LayoutPoint ancestorCoords;
ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
location += (fixedContainerCoords - ancestorCoords);
} else {
location += toSize(layer->location());
}
return ancestorLayer;
}
RenderLayer* parentLayer;
if (position == AbsolutePosition || position == FixedPosition) {
parentLayer = layer->parent();
bool foundAncestorFirst = false;
while (parentLayer) {
if (parentLayer->isPositionedContainer())
break;
if (parentLayer == ancestorLayer) {
foundAncestorFirst = true;
break;
}
parentLayer = parentLayer->parent();
}
if (renderer->flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
ASSERT(parentLayer != renderer->view()->layer());
if (foundAncestorFirst) {
RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
LayoutPoint thisCoords;
layer->convertToLayerCoords(positionedAncestor, thisCoords);
LayoutPoint ancestorCoords;
ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
location += (thisCoords - ancestorCoords);
return ancestorLayer;
}
} else
parentLayer = layer->parent();
if (!parentLayer)
return 0;
location += toSize(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.move(-delta.x(), -delta.y());
}
RenderLayer* RenderLayer::scrollParent() const
{
ASSERT(renderer()->compositorDrivenAcceleratedScrollingEnabled());
if (stackingNode()->isNormalFlowOnly())
return 0;
ASSERT(isInCompositingUpdate() || !m_ancestorDependentPropertyCache);
if (m_ancestorDependentPropertyCache && !m_ancestorDependentPropertyCache->scrollParentDirty())
return m_ancestorDependentPropertyCache->scrollParent();
RenderLayer* scrollParent = ancestorCompositedScrollingLayer();
if (!scrollParent || scrollParent->stackingNode()->isStackingContainer()) {
if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setScrollParent(0);
return 0;
}
for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) {
if (ancestor->stackingNode()->isStackingContainer()) {
scrollParent = 0;
break;
}
if (!isInCompositingUpdate())
continue;
if (AncestorDependentPropertyCache* ancestorCache = ancestor->m_ancestorDependentPropertyCache.get()) {
if (!ancestorCache->ancestorCompositedScrollingLayerDirty() && ancestorCache->ancestorCompositedScrollingLayer() == scrollParent) {
scrollParent = ancestorCache->scrollParent();
break;
}
}
}
if (m_ancestorDependentPropertyCache)
m_ancestorDependentPropertyCache->setScrollParent(scrollParent);
return scrollParent;
}
RenderLayer* RenderLayer::clipParent() const
{
if (compositingReasons() & CompositingReasonOutOfFlowClipping && !compositor()->clippedByAncestor(this)) {
if (RenderObject* containingBlock = renderer()->containingBlock())
return containingBlock->enclosingLayer()->enclosingCompositingLayer();
}
return 0;
}
void RenderLayer::didUpdateNeedsCompositedScrolling()
{
m_stackingNode->updateIsNormalFlowOnly();
updateSelfPaintingLayer();
if (m_stackingNode->isStackingContainer())
m_stackingNode->dirtyZOrderLists();
else
m_stackingNode->clearZOrderLists();
m_stackingNode->dirtyStackingContainerZOrderLists();
compositor()->setNeedsToRecomputeCompositingRequirements();
compositor()->setCompositingLayersNeedRebuild();
}
void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle)
{
ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle));
if (renderer()->hasReflection()) {
if (!m_reflectionInfo)
m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(toRenderBox(renderer())));
m_reflectionInfo->updateAfterStyleChange(oldStyle);
} else if (m_reflectionInfo) {
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(renderBox()));
else
m_scrollableArea = nullptr;
}
PassOwnPtr<Vector<FloatRect> > RenderLayer::collectTrackedRepaintRects() const
{
if (hasCompositedLayerMapping())
return compositedLayerMapping()->collectTrackedRepaintRects();
return nullptr;
}
bool RenderLayer::hasOverflowControls() const
{
return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollableArea->hasScrollCorner() || renderer()->style()->resize() != RESIZE_NONE);
}
void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, PaintLayerFlags paintFlags)
{
OverlapTestRequestMap overlapTestRequests;
LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, &overlapTestRequests);
paintLayer(context, paintingInfo, paintFlags);
OverlapTestRequestMap::iterator end = overlapTestRequests.end();
for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
it->key->setIsOverlapped(false);
}
void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
{
if (!m_containsDirtyOverlayScrollbars)
return;
LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
paintLayer(context, paintingInfo, PaintLayerPaintingOverlayScrollbars);
m_containsDirtyOverlayScrollbars = false;
}
static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLayer)
{
if (startLayer == endLayer)
return true;
RenderView* view = startLayer->renderer()->view();
for (RenderBlock* currentBlock = startLayer->renderer()->containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) {
if (currentBlock->layer() == endLayer)
return true;
}
return false;
}
void RenderLayer::clipToRect(const LayerPaintingInfo& localPaintingInfo, GraphicsContext* context, const ClipRect& clipRect,
BorderRadiusClippingRule rule)
{
if (clipRect.rect() == localPaintingInfo.paintDirtyRect && !clipRect.hasRadius())
return;
context->save();
context->clip(pixelSnappedIntRect(clipRect.rect()));
if (!clipRect.hasRadius())
return;
for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
LayoutPoint delta;
layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta);
context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
}
if (layer == localPaintingInfo.rootLayer)
break;
}
}
void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
{
if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius())
return;
context->restore();
}
static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
{
Vector<RenderWidget*> overlappedRequestClients;
OverlapTestRequestMap::iterator end = overlapTestRequests.end();
LayoutRect boundingBox = layer->physicalBoundingBox(rootLayer);
for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
if (!boundingBox.intersects(it->value))
continue;
it->key->setIsOverlapped(true);
overlappedRequestClients.append(it->key);
}
for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
overlapTestRequests.remove(overlappedRequestClients[i]);
}
static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
{
return paintingReflection && !layer->has3DTransform();
}
static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
{
if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isRoot())
return true;
return false;
}
static bool paintForFixedRootBackground(const RenderLayer* layer, PaintLayerFlags paintFlags)
{
return layer->renderer()->isRoot() && (paintFlags & PaintLayerPaintingRootBackgroundOnly);
}
void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
DisableCompositingQueryAsserts disabler;
if (compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking) {
if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)) {
paintFlags |= PaintLayerTemporaryClipRects;
} else if (!compositedLayerMapping()->paintsIntoCompositedAncestor()
&& !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)
&& !paintForFixedRootBackground(this, paintFlags)) {
return;
}
} else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) {
return;
}
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
return;
if (shouldSuppressPaintingLayer(this))
return;
if (!renderer()->opacity())
return;
if (paintsWithTransparency(paintingInfo.paintBehavior))
paintFlags |= PaintLayerHaveTransparency;
if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
if (!layerTransform.isInvertible())
return;
if (paintFlags & PaintLayerHaveTransparency) {
if (parent())
parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
else
beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
}
if (enclosingPaginationLayer()) {
paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags);
return;
}
ClipRect clipRect = paintingInfo.paintDirtyRect;
if (parent()) {
ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
clipRect = clipper().backgroundClipRect(clipRectsContext);
clipRect.intersect(paintingInfo.paintDirtyRect);
parent()->clipToRect(paintingInfo, context, clipRect);
}
paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
if (parent())
parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
return;
}
paintLayerContentsAndReflection(context, paintingInfo, paintFlags);
}
void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
PaintLayerFlags localPaintFlags = paintFlags & ~(PaintLayerAppliedTransform);
if (m_reflectionInfo)
m_reflectionInfo->paint(context, paintingInfo, localPaintFlags | PaintLayerPaintingReflection);
localPaintFlags |= PaintLayerPaintingCompositingAllPhases;
paintLayerContents(context, paintingInfo, localPaintFlags);
}
void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
ASSERT(!(paintFlags & PaintLayerAppliedTransform));
bool haveTransparency = paintFlags & PaintLayerHaveTransparency;
bool isSelfPaintingLayer = this->isSelfPaintingLayer();
bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase;
bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase;
bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase;
bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents;
bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars
&& ((isPaintingScrollingContent && isPaintingCompositedBackground)
|| (!isPaintingScrollingContent && isPaintingCompositedForeground));
bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
float deviceScaleFactor = WebCore::deviceScaleFactor(renderer()->frame());
context->setUseHighResMarkers(deviceScaleFactor > 1.5f);
GraphicsContext* transparencyLayerContext = context;
if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot())
return;
m_stackingNode->updateLayerListsIfNeeded();
LayoutPoint offsetFromRoot;
convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
if (compositingState() == PaintsIntoOwnBacking)
offsetFromRoot.move(subpixelAccumulation());
LayoutRect rootRelativeBounds;
bool rootRelativeBoundsComputed = false;
bool hasClipPath = false;
RenderStyle* style = renderer()->style();
RenderSVGResourceClipper* resourceClipper = 0;
ClipperContext clipperContext;
if (renderer()->hasClipPath() && !context->paintingDisabled() && style) {
ASSERT(style->clipPath());
if (style->clipPath()->type() == ClipPathOperation::SHAPE) {
hasClipPath = true;
context->save();
ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style->clipPath());
if (!rootRelativeBoundsComputed) {
rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
rootRelativeBoundsComputed = true;
}
context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
} else if (style->clipPath()->type() == ClipPathOperation::REFERENCE) {
ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style->clipPath());
Document& document = renderer()->document();
Element* element = document.getElementById(referenceClipPathOperation->fragment());
if (isSVGClipPathElement(element) && element->renderer()) {
if (!rootRelativeBoundsComputed) {
rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
rootRelativeBoundsComputed = true;
}
resourceClipper = toRenderSVGResourceClipper(toRenderSVGResourceContainer(element->renderer()));
if (!resourceClipper->applyClippingToContext(renderer(), rootRelativeBounds,
paintingInfo.paintDirtyRect, context, clipperContext)) {
resourceClipper = 0;
}
}
}
}
bool createTransparencyLayerForBlendMode = !renderer()->isRoot() && m_stackingNode->isStackingContext() && m_blendInfo.childLayerHasBlendMode();
if (createTransparencyLayerForBlendMode)
beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
LayerPaintingInfo localPaintingInfo(paintingInfo);
FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters());
if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) {
RenderLayerFilterInfo* filterInfo = this->filterInfo();
ASSERT(filterInfo);
LayoutRect filterRepaintRect = filterInfo->dirtySourceRect();
filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y());
if (!rootRelativeBoundsComputed)
rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
filterInfo->resetDirtySourceRect();
context = filterPainter.beginFilterEffect(context);
if (filterPainter.hasStartedFilterEffect()) {
localPaintingInfo.paintDirtyRect = filterPainter.repaintRect();
localPaintingInfo.clipToDirtyRect = !filterRenderer()->hasFilterThatMovesPixels();
}
}
}
if (filterPainter.hasStartedFilterEffect() && haveTransparency) {
beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
}
RenderObject* paintingRootForRenderer = 0;
if (localPaintingInfo.paintingRoot && !renderer()->isDescendantOf(localPaintingInfo.paintingRoot))
paintingRootForRenderer = localPaintingInfo.paintingRoot;
if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText;
bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly;
bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground);
bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent;
bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground;
bool shouldPaintOverlayScrollbars = isPaintingOverlayScrollbars;
bool shouldPaintMask = (paintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly;
bool shouldPaintClippingMask = (paintFlags & PaintLayerPaintingChildClippingMaskPhase) && shouldPaintContent && !selectionOnly;
PaintBehavior paintBehavior = PaintBehaviorNormal;
if (paintFlags & PaintLayerPaintingSkipRootBackground)
paintBehavior |= PaintBehaviorSkipRootBackground;
else if (paintFlags & PaintLayerPaintingRootBackgroundOnly)
paintBehavior |= PaintBehaviorRootBackgroundOnly;
LayerFragments layerFragments;
if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect,
(paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
(isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation);
updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot);
}
if (shouldPaintBackground)
paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
localPaintingInfo, paintBehavior, paintingRootForRenderer);
if (shouldPaintNegZOrderList)
paintChildren(NegativeZOrderChildren, context, localPaintingInfo, paintFlags);
if (shouldPaintOwnContents)
paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, forceBlackText);
if (shouldPaintOutline)
paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer);
if (shouldPaintNormalFlowAndPosZOrderLists)
paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, localPaintingInfo, paintFlags);
if (shouldPaintOverlayScrollbars)
paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo);
if (filterPainter.hasStartedFilterEffect()) {
ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
clipToRect(localPaintingInfo, transparencyLayerContext, backgroundRect);
context = filterPainter.applyFilterEffect();
restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect);
}
ASSERT(transparencyLayerContext == context);
if (shouldPaintMask)
paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer);
if (shouldPaintClippingMask) {
paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer);
}
if ((haveTransparency || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency && !(m_reflectionInfo && m_reflectionInfo->isPaintingInsideReflection())) {
context->endLayer();
context->restore();
m_usedTransparency = false;
}
if (resourceClipper)
resourceClipper->postApplyStatefulResource(renderer(), context, clipperContext);
if (hasClipPath)
context->restore();
}
void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
{
LayoutPoint delta;
convertToLayerCoords(paintingInfo.rootLayer, delta);
delta.moveBy(translationOffset);
TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
IntPoint roundedDelta = roundedIntPoint(delta);
transform.translateRight(roundedDelta.x(), roundedDelta.y());
LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
GraphicsContextStateSaver stateSaver(*context, false);
if (!transform.isIdentity()) {
stateSaver.save();
context->concatCTM(transform.toAffineTransform());
}
LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior,
adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.overlapTestRequests);
paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
}
void RenderLayer::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
if (!hasSelfPaintingLayerDescendant())
return;
#if !ASSERT_DISABLED
LayerListMutationDetector mutationChecker(m_stackingNode.get());
#endif
RenderLayerStackingNodeIterator iterator(*m_stackingNode, childrenToVisit);
while (RenderLayerStackingNode* child = iterator.next()) {
RenderLayer* childLayer = child->layer();
if (childLayer->compositingState() == PaintsIntoGroupedBacking)
continue;
if (!childLayer->isPaginated())
childLayer->paintLayer(context, paintingInfo, paintFlags);
else
paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags);
}
}
void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect,
ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox)
{
if (!enclosingPaginationLayer() || hasTransform()) {
LayerFragment fragment;
ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip, subPixelAccumulation);
clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
fragments.append(fragment);
return;
}
LayoutPoint offsetWithinPaginatedLayer;
convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer);
ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
LayoutRect layerBoundsInFlowThread;
ClipRect backgroundRectInFlowThread;
ClipRect foregroundRectInFlowThread;
ClipRect outlineRectInFlowThread;
clipper().calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
outlineRectInFlowThread, &offsetWithinPaginatedLayer);
LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer);
layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
LayoutPoint offsetOfPaginationLayerFromRoot;
enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
LayoutRect dirtyRectInFlowThread(dirtyRect);
dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot);
RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
if (fragments.isEmpty())
return;
ClipRect ancestorClipRect = dirtyRect;
if (enclosingPaginationLayer()->parent()) {
ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext);
ancestorClipRect.intersect(dirtyRect);
}
for (size_t i = 0; i < fragments.size(); ++i) {
LayerFragment& fragment = fragments.at(i);
fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread);
fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
fragment.intersect(ancestorClipRect.rect());
fragment.intersect(fragment.paginationClip);
}
}
void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags localPaintFlags,
bool shouldPaintContent, const LayoutPoint* offsetFromRoot)
{
ASSERT(offsetFromRoot);
for (size_t i = 0; i < fragments.size(); ++i) {
LayerFragment& fragment = fragments.at(i);
fragment.shouldPaintContent = shouldPaintContent;
if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) {
LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset;
fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot);
}
}
}
void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
LayerFragments enclosingPaginationFragments;
LayoutPoint offsetOfPaginationLayerFromRoot;
LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect,
(paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
(paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, paintingInfo.subPixelAccumulation, &transformedExtent);
for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
const LayerFragment& fragment = enclosingPaginationFragments.at(i);
LayoutRect clipRect = fragment.backgroundRect.rect();
if (parent() != enclosingPaginationLayer()) {
enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot);
ClipRectsContext clipRectsContext(enclosingPaginationLayer(), (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).rect();
parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
clipRect.intersect(parentClipRect);
}
parent()->clipToRect(paintingInfo, context, clipRect);
paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
}
}
static inline LayoutSize subPixelAccumulationIfNeeded(const LayoutSize& subPixelAccumulation, CompositingState compositingState)
{
if (compositingState == PaintsIntoOwnBacking)
return LayoutSize();
return subPixelAccumulation;
}
void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
RenderObject* paintingRootForRenderer)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (!fragment.shouldPaintContent)
continue;
if (haveTransparency || paintsWithBlendMode())
beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
if (localPaintingInfo.clipToDirtyRect) {
clipToRect(localPaintingInfo, context, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius);
}
PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer());
renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
if (localPaintingInfo.clipToDirtyRect)
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
}
}
void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
RenderObject* paintingRootForRenderer, bool selectionOnly, bool forceBlackText)
{
if (haveTransparency || paintsWithBlendMode()) {
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
break;
}
}
}
PaintBehavior localPaintBehavior = forceBlackText ? (PaintBehavior)PaintBehaviorForceBlackText : paintBehavior;
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
if (shouldClip)
clipToRect(localPaintingInfo, context, layerFragments[0].foregroundRect);
paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments,
context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
if (!selectionOnly) {
paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
}
if (shouldClip)
restoreClip(context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect);
}
void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context,
const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer)
{
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty())
continue;
if (shouldClip)
clipToRect(localPaintingInfo, context, fragment.foregroundRect);
PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer());
if (phase == PaintPhaseForeground)
paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
if (shouldClip)
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
}
}
void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (fragment.outlineRect.isEmpty())
continue;
PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer());
clipToRect(localPaintingInfo, context, fragment.outlineRect, DoNotIncludeSelfForBorderRadius);
renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect);
}
}
void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
RenderObject* paintingRootForRenderer)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (!fragment.shouldPaintContent)
continue;
if (localPaintingInfo.clipToDirtyRect)
clipToRect(localPaintingInfo, context, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius);
PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer());
renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
if (localPaintingInfo.clipToDirtyRect)
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
}
}
void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
RenderObject* paintingRootForRenderer)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
if (!fragment.shouldPaintContent)
continue;
if (localPaintingInfo.clipToDirtyRect)
clipToRect(localPaintingInfo, context, fragment.foregroundRect, IncludeSelfForBorderRadius);
PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, 0, 0, localPaintingInfo.rootLayer->renderer());
renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState())));
if (localPaintingInfo.clipToDirtyRect)
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
}
}
void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
clipToRect(localPaintingInfo, context, fragment.backgroundRect);
if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea())
scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))), pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
}
}
void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
Vector<RenderLayer*> columnLayers;
RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContainerNode();
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;
}
if (!columnLayers.size())
return;
paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1);
}
void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo,
PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
{
RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
ASSERT(columnBlock && columnBlock->hasColumns());
if (!columnBlock || !columnBlock->hasColumns())
return;
LayoutPoint layerOffset;
columnBlock->layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset);
bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
ColumnInfo* colInfo = columnBlock->columnInfo();
unsigned colCount = columnBlock->columnCount(colInfo);
LayoutUnit currLogicalTopOffset = 0;
for (unsigned i = 0; i < colCount; i++) {
LayoutRect colRect = columnBlock->columnRectAt(colInfo, i);
columnBlock->flipForWritingMode(colRect);
LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
LayoutSize offset;
if (isHorizontal) {
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset = LayoutSize(logicalLeftOffset, currLogicalTopOffset);
else
offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - columnBlock->borderTop() - columnBlock->paddingTop());
} else {
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset = LayoutSize(currLogicalTopOffset, logicalLeftOffset);
else
offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnBlock->borderLeft() - columnBlock->paddingLeft(), 0);
}
colRect.moveBy(layerOffset);
LayoutRect localDirtyRect(paintingInfo.paintDirtyRect);
localDirtyRect.intersect(colRect);
if (!localDirtyRect.isEmpty()) {
GraphicsContextStateSaver stateSaver(*context);
context->clip(pixelSnappedIntRect(colRect));
if (!colIndex) {
TransformationMatrix oldTransform;
bool oldHasTransform = childLayer->transform();
if (oldHasTransform)
oldTransform = *childLayer->transform();
TransformationMatrix newTransform(oldTransform);
newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height()));
childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
LayerPaintingInfo localPaintingInfo(paintingInfo);
localPaintingInfo.paintDirtyRect = localDirtyRect;
childLayer->paintLayer(context, localPaintingInfo, paintFlags);
if (oldHasTransform)
childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
else
childLayer->m_transform.clear();
} else {
LayoutPoint childOffset;
columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset);
TransformationMatrix transform;
transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height()));
context->concatCTM(transform.toAffineTransform());
LayerPaintingInfo columnPaintingInfo(paintingInfo);
columnPaintingInfo.rootLayer = columnLayers[colIndex - 1];
columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect);
paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1);
}
}
LayoutUnit blockDelta = isHorizontal ? colRect.height() : colRect.width();
if (columnBlock->style()->isFlippedBlocksWritingMode())
currLogicalTopOffset += blockDelta;
else
currLogicalTopOffset -= blockDelta;
}
}
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());
ASSERT(!renderer()->frame()->view()->layoutPending());
ASSERT(!renderer()->document().renderer()->needsLayout());
LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
if (!request.ignoreClipping())
hitTestArea.intersect(frameVisibleRect(renderer()));
RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false);
if (!insideLayer) {
if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) {
renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
insideLayer = this;
}
}
Node* node = result.innerNode();
if (node && !result.URLElement())
result.setURLElement(toElement(node->enclosingLinkEventParentOrSelf()));
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();
}
bool RenderLayer::isInTopLayerSubtree() const
{
for (const RenderLayer* layer = this; layer; layer = layer->parent()) {
if (layer->isInTopLayer())
return true;
}
return false;
}
static double computeZOffset(const HitTestingTransformState& transformState)
{
if (transformState.m_accumulatedTransform.isAffine())
return 0;
FloatPoint targetPoint = transformState.mappedPoint();
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) {
transformState = HitTestingTransformState::create(*containerTransformState);
convertToLayerCoords(containerLayer, offset);
} else {
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;
if (canDepthSort)
return true;
if (zOffset) {
ASSERT(transformState);
double childZOffset = computeZOffset(*transformState);
if (childZOffset > *zOffset) {
*zOffset = childZOffset;
return true;
}
return false;
}
return true;
}
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;
if (transform() && !appliedTransform) {
if (enclosingPaginationLayer())
return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
if (parent()) {
ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
ClipRect clipRect = clipper().backgroundClipRect(clipRectsContext);
if (!clipRect.intersects(hitTestLocation))
return 0;
}
return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
}
m_stackingNode->updateLayerListsIfNeeded();
update3DTransformedDescendantStatus();
RefPtr<HitTestingTransformState> localTransformState;
if (appliedTransform) {
ASSERT(transformState);
localTransformState = const_cast<HitTestingTransformState*>(transformState);
} else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
}
if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
if (invertedMatrix.m33() < 0)
return 0;
}
RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
if (localTransformState && !preserves3D()) {
unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
localTransformState->flatten();
}
double localZOffset = -numeric_limits<double>::infinity();
double* zOffsetForDescendantsPtr = 0;
double* zOffsetForContentsPtr = 0;
bool depthSortDescendants = false;
if (preserves3D()) {
depthSortDescendants = true;
zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
} else if (m_has3DTransformedDescendant) {
depthSortDescendants = true;
zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
} else if (zOffset) {
zOffsetForDescendantsPtr = 0;
zOffsetForContentsPtr = zOffset;
}
RenderLayer* candidateLayer = 0;
RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
return hitLayer;
candidateLayer = hitLayer;
}
hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
return hitLayer;
candidateLayer = hitLayer;
}
LayerFragments layerFragments;
collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) {
renderer()->updateHitTestResult(result, hitTestLocation.point());
return this;
}
if (isSelfPaintingLayer()) {
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;
candidateLayer = this;
} else if (insideFragmentForegroundRect && result.isRectBasedTest())
result.append(tempResult);
}
hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
return hitLayer;
candidateLayer = hitLayer;
}
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;
LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, 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);
LayoutRect clipRect = fragment.backgroundRect.rect();
if (parent() != enclosingPaginationLayer()) {
enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
ClipRectsContext clipRectsContext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).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)
{
RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
if (!newTransformState->m_accumulatedTransform.isInvertible())
return 0;
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);
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)) {
ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
return false;
}
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 (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->ancestorStackingContainerNode();
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);
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--) {
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) {
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 {
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::addBlockSelectionGapsBounds(const LayoutRect& bounds)
{
m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds));
}
void RenderLayer::clearBlockSelectionGapsBounds()
{
m_blockSelectionGapsBounds = IntRect();
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->clearBlockSelectionGapsBounds();
}
void RenderLayer::repaintBlockSelectionGaps()
{
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->repaintBlockSelectionGaps();
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()->repaintRectangle(rect);
}
bool RenderLayer::hasBlockSelectionGapBounds() const
{
return !m_blockSelectionGapsBounds.isEmpty();
}
bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const
{
if (isRootLayer() || renderer()->isRoot())
return true;
RenderView* view = renderer()->view();
ASSERT(view);
if (view && !renderer()->isRenderInline()) {
if (layerBounds.intersects(damageRect))
return true;
}
return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
}
LayoutRect RenderLayer::logicalBoundingBox() const
{
LayoutRect result;
if (renderer()->isInline() && renderer()->isRenderInline()) {
result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
} else if (renderer()->isTableRow()) {
for (RenderObject* child = renderer()->firstChild(); 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;
}
LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const
{
LayoutRect result = logicalBoundingBox();
if (m_renderer->isBox())
renderBox()->flipForWritingMode(result);
else
m_renderer->containingBlock()->flipForWritingMode(result);
LayoutPoint delta;
if (offsetFromRoot)
delta = *offsetFromRoot;
else
convertToLayerCoords(ancestorLayer, delta);
result.moveBy(delta);
return result;
}
LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
{
if (!isSelfPaintingLayer())
return LayoutRect();
if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
return LayoutRect();
RenderLayerModelObject* renderer = this->renderer();
if (isRootLayer()) {
return renderer->view()->unscaledDocumentRect();
}
LayoutRect boundingBoxRect = logicalBoundingBox();
if (renderer->isBox())
toRenderBox(renderer)->flipForWritingMode(boundingBoxRect);
else
renderer->containingBlock()->flipForWritingMode(boundingBoxRect);
LayoutRect unionBounds = boundingBoxRect;
bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (transform() && flags & PretendLayerHasOwnBacking);
if (flags & UseLocalClipRectIfPossible) {
LayoutRect localClipRect = clipper().localClipRect();
if (localClipRect != PaintInfo::infiniteRect()) {
if ((flags & IncludeSelfTransform) && shouldIncludeTransform)
localClipRect = transform()->mapRect(localClipRect);
LayoutPoint ancestorRelOffset;
convertToLayerCoords(ancestorLayer, ancestorRelOffset);
localClipRect.moveBy(ancestorRelOffset);
return localClipRect;
}
}
CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants);
const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
if (m_reflectionInfo) {
RenderLayer* reflectionLayer = m_reflectionInfo->reflectionLayer();
if (!reflectionLayer->hasCompositedLayerMapping()) {
LayoutRect childUnionBounds = reflectionLayer->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
ASSERT(m_stackingNode->isStackingContainer() || !m_stackingNode->hasPositiveZOrderList());
#if !ASSERT_DISABLED
LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)->stackingNode());
#endif
RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), AllChildren);
while (RenderLayerStackingNode* node = iterator.next()) {
if (node->layer()->hasCompositedLayerMapping()) {
RenderLayer* enclosingCompositingLayer = node->layer()->enclosingCompositingLayer(ExcludeSelf);
node->layer()->compositedLayerMapping()->updateRequiresOwnBackingStoreForAncestorReasons(enclosingCompositingLayer);
}
if (flags & IncludeCompositedDescendants || !node->layer()->hasCompositedLayerMapping()) {
LayoutRect childUnionBounds = node->layer()->calculateLayerBounds(this, 0, descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
if (flags & IncludeLayerFilterOutsets)
renderer->style()->filterOutsets().expandRect(unionBounds);
if ((flags & IncludeSelfTransform) && shouldIncludeTransform) {
TransformationMatrix* affineTrans = transform();
boundingBoxRect = affineTrans->mapRect(boundingBoxRect);
unionBounds = affineTrans->mapRect(unionBounds);
}
LayoutPoint ancestorRelOffset;
if (offsetFromRoot)
ancestorRelOffset = *offsetFromRoot;
else
convertToLayerCoords(ancestorLayer, ancestorRelOffset);
unionBounds.moveBy(ancestorRelOffset);
return unionBounds;
}
CompositingState RenderLayer::compositingState() const
{
ASSERT(isAllowedToQueryCompositingState());
if (m_groupedMapping) {
ASSERT(compositor()->layerSquashingEnabled());
ASSERT(!m_compositedLayerMapping);
return PaintsIntoGroupedBacking;
}
if (!m_compositedLayerMapping)
return NotComposited;
if (compositedLayerMapping()->paintsIntoCompositedAncestor())
return HasOwnBackingButPaintsIntoAncestor;
return PaintsIntoOwnBacking;
}
bool RenderLayer::isAllowedToQueryCompositingState() const
{
if (gCompositingQueryMode == CompositingQueriesAreAllowed)
return true;
return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
}
bool RenderLayer::isInCompositingUpdate() const
{
return renderer()->document().lifecycle().state() == DocumentLifecycle::InCompositingUpdate;
}
CompositedLayerMappingPtr RenderLayer::compositedLayerMapping() const
{
ASSERT(isAllowedToQueryCompositingState());
return m_compositedLayerMapping.get();
}
CompositedLayerMappingPtr RenderLayer::ensureCompositedLayerMapping()
{
if (!m_compositedLayerMapping) {
m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this));
m_compositedLayerMapping->setNeedsGraphicsLayerUpdate();
updateOrRemoveFilterEffectRenderer();
if (RuntimeEnabledFeatures::cssCompositingEnabled())
compositedLayerMapping()->setBlendMode(m_blendInfo.blendMode());
}
return m_compositedLayerMapping.get();
}
void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed)
{
if (!layerBeingDestroyed) {
if (RenderLayer* compositingParent = enclosingCompositingLayer(ExcludeSelf))
compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUpdate();
}
m_compositedLayerMapping.clear();
if (!layerBeingDestroyed)
updateOrRemoveFilterEffectRenderer();
}
void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed)
{
if (!layerBeingDestroyed && m_groupedMapping)
m_groupedMapping->setNeedsGraphicsLayerUpdate();
m_groupedMapping = groupedMapping;
if (!layerBeingDestroyed && m_groupedMapping)
m_groupedMapping->setNeedsGraphicsLayerUpdate();
}
bool RenderLayer::hasCompositedMask() const
{
return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer();
}
bool RenderLayer::hasCompositedClippingMask() const
{
return m_compositedLayerMapping && m_compositedLayerMapping->hasChildClippingMaskLayer();
}
bool RenderLayer::clipsCompositingDescendantsWithBorderRadius() const
{
RenderStyle* style = renderer()->style();
if (!style)
return false;
return compositor()->clipsCompositingDescendants(this) && style->hasBorderRadius();
}
bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
{
return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || compositingState() != PaintsIntoOwnBacking);
}
bool RenderLayer::paintsWithBlendMode() const
{
return m_blendInfo.hasBlendMode() && compositingState() != PaintsIntoOwnBacking;
}
bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
{
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
return false;
if (paintsWithTransparency(PaintBehaviorNormal))
return false;
if (renderer()->style()->visibility() != VISIBLE)
return false;
if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffectsOpacity())
return false;
if (paintsWithTransform(PaintBehaviorNormal))
return false;
if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirty())
return false;
if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect))
return true;
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();
if (childLayer->hasCompositedLayerMapping())
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;
}
void RenderLayer::setParent(RenderLayer* parent)
{
if (parent == m_parent)
return;
if (m_parent && !renderer()->documentBeingDestroyed())
compositor()->layerWillBeRemoved(m_parent, this);
m_parent = parent;
if (m_parent && !renderer()->documentBeingDestroyed())
compositor()->layerWasAdded(m_parent, this);
}
bool RenderLayer::shouldBeSelfPaintingLayer() const
{
return m_layerType == NormalLayer
|| (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars())
|| needsCompositedScrolling();
}
void RenderLayer::updateSelfPaintingLayer()
{
bool isSelfPaintingLayer = this->shouldBeSelfPaintingLayer();
if (this->isSelfPaintingLayer() == isSelfPaintingLayer)
return;
m_isSelfPaintingLayer = isSelfPaintingLayer;
if (!parent())
return;
if (isSelfPaintingLayer)
parent()->setAncestorChainHasSelfPaintingLayerDescendant();
else
parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
}
bool RenderLayer::hasNonEmptyChildRenderers() const
{
for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
if (!child->hasLayer()) {
if (child->isRenderInline() || !child->isBox())
return true;
if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
return true;
}
}
return false;
}
static bool hasBoxDecorations(const RenderStyle* style)
{
return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter();
}
bool RenderLayer::hasBoxDecorationsOrBackground() const
{
return hasBoxDecorations(renderer()->style()) || renderer()->hasBackground();
}
bool RenderLayer::hasVisibleBoxDecorations() const
{
if (!hasVisibleContent())
return false;
return hasBoxDecorationsOrBackground() || hasOverflowControls();
}
bool RenderLayer::isVisuallyNonEmpty() const
{
ASSERT(!m_visibleDescendantStatusDirty);
if (hasVisibleContent() && hasNonEmptyChildRenderers())
return true;
if (renderer()->isReplaced() || renderer()->hasMask())
return true;
if (hasVisibleBoxDecorations())
return true;
return false;
}
void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
{
ASSERT(!oldStyle || renderer()->style()->position() != oldStyle->position());
bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned();
if (!wasOutOfFlowPositioned && !isOutOfFlowPositioned)
return;
for (RenderLayer* ancestor = parent(); ancestor; ancestor = ancestor->parent())
ancestor->setHasUnclippedDescendant(false);
compositor()->setNeedsUpdateCompositingRequirementsState();
if (wasOutOfFlowPositioned && isOutOfFlowPositioned)
return;
if (isOutOfFlowPositioned) {
setAncestorChainHasOutOfFlowPositionedDescendant();
compositor()->addOutOfFlowPositionedLayer(this);
} else {
dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
compositor()->removeOutOfFlowPositionedLayer(this);
setIsUnclippedDescendant(false);
}
}
static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
{
ASSERT(newStyle);
return (oldStyle && oldStyle->hasFilter()) || newStyle->hasFilter();
}
inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
{
ASSERT(newStyle);
return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip());
}
inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
{
ASSERT(newStyle);
if (hasCompositedLayerMapping())
return false;
if (!oldStyle)
return false;
if (oldStyle->overflowX() == newStyle->overflowX())
return false;
RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContainerNode();
return stackingNode && stackingNode->layer()->hasCompositingDescendant();
}
inline bool RenderLayer::needsCompositingLayersRebuiltForFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle, bool didPaintWithFilters) const
{
if (!hasOrHadFilters(oldStyle, newStyle))
return false;
if (hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyWebkitFilter)) {
return false;
}
FilterOutsets newOutsets = newStyle->filterOutsets();
if (oldStyle && (oldStyle->filterOutsets() != newOutsets)) {
return true;
}
return false;
}
inline bool RenderLayer::needsCompositingLayersRebuiltForBlending(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
{
ASSERT(newStyle);
if (!hasCompositedLayerMapping())
return false;
return (shouldIsolateCompositedDescendants() && !stackingNode()->isStackingContext())
|| (oldStyle && (oldStyle->hasBlendMode() != newStyle->hasBlendMode()));
}
void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
{
if (!hasOrHadFilters(oldStyle, newStyle))
return;
updateOrRemoveFilterClients();
if (hasCompositedLayerMapping() && !hasActiveAnimationsOnCompositor(*renderer(), CSSPropertyWebkitFilter))
compositedLayerMapping()->updateFilters(renderer()->style());
updateOrRemoveFilterEffectRenderer();
}
void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
{
m_stackingNode->updateIsNormalFlowOnly();
m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
if (m_scrollableArea)
m_scrollableArea->updateAfterStyleChange(oldStyle);
if (!oldStyle || oldStyle->visibility() != renderer()->style()->visibility()) {
ASSERT(!oldStyle || diff >= StyleDifferenceRepaint);
compositor()->setNeedsUpdateCompositingRequirementsState();
}
updateSelfPaintingLayer();
if (!oldStyle || renderer()->style()->position() != oldStyle->position()) {
ASSERT(!oldStyle || diff >= StyleDifferenceLayout);
updateOutOfFlowPositioned(oldStyle);
}
if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) {
ASSERT(!oldStyle || diff >= StyleDifferenceLayout);
updateReflectionInfo(oldStyle);
}
if (RuntimeEnabledFeatures::cssCompositingEnabled())
m_blendInfo.updateBlendMode();
updateDescendantDependentFlags();
if (!oldStyle || !renderer()->style()->transformDataEquivalent(*oldStyle))
updateTransform();
bool didPaintWithFilters = false;
{
DisableCompositingQueryAsserts disabler;
if (paintsWithFilters())
didPaintWithFilters = true;
updateFilters(oldStyle, renderer()->style());
}
compositor()->updateStyleDeterminedCompositingReasons(this);
setNeedsToUpdateAncestorDependentProperties();
DisableCompositingQueryAsserts disabler;
const RenderStyle* newStyle = renderer()->style();
compositor()->updateLayerCompositingState(this, RenderLayerCompositor::UseChickenEggHacks);
if (needsCompositingLayersRebuiltForClip(oldStyle, newStyle)
|| needsCompositingLayersRebuiltForOverflow(oldStyle, newStyle)
|| needsCompositingLayersRebuiltForFilters(oldStyle, newStyle, didPaintWithFilters)
|| needsCompositingLayersRebuiltForBlending(oldStyle, newStyle)) {
compositor()->setCompositingLayersNeedRebuild();
}
}
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);
RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create();
#ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME
float zoom = style->effectiveZoom() * WebCore::deviceScaleFactor(renderer()->frame());
#else
float zoom = style->effectiveZoom();
#endif
referenceFilter->setAbsoluteTransform(AffineTransform().scale(zoom, zoom));
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()
{
if (!paintsWithFilters()) {
if (RenderLayerFilterInfo* filterInfo = this->filterInfo())
filterInfo->setRenderer(nullptr);
return;
}
RenderLayerFilterInfo* filterInfo = ensureFilterInfo();
if (!filterInfo->renderer()) {
RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create();
filterInfo->setRenderer(filterRenderer.release());
renderer()->document().view()->setHasSoftwareFilters(true);
}
if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
filterInfo->setRenderer(nullptr);
}
void RenderLayer::filterNeedsRepaint()
{
{
DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().lifecycle());
toElement(renderer()->node())->scheduleLayerUpdate();
}
if (renderer()->view()) {
if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && renderer()->frameView()->isInPerformLayout())
renderer()->setShouldDoFullRepaintAfterLayout(true);
else
renderer()->repaint();
}
}
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()) {
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);
}
}
}
DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
: m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { }
COMPILE_ASSERT(1 << RenderLayer::ViewportConstrainedNotCompositedReasonBits >= RenderLayer::NumNotCompositedReasons, too_many_viewport_constrained_not_compositing_reasons);
RenderLayer::AncestorDependentPropertyCache::AncestorDependentPropertyCache()
: m_ancestorCompositedScrollingLayer(0)
, m_scrollParent(0)
, m_ancestorCompositedScrollingLayerDirty(true)
, m_scrollParentDirty(true) { }
RenderLayer* RenderLayer::AncestorDependentPropertyCache::scrollParent() const
{
ASSERT(!m_scrollParentDirty);
return m_scrollParent;
}
void RenderLayer::AncestorDependentPropertyCache::setScrollParent(RenderLayer* scrollParent)
{
m_scrollParent = scrollParent;
m_scrollParentDirty = false;
}
RenderLayer* RenderLayer::AncestorDependentPropertyCache::ancestorCompositedScrollingLayer() const
{
ASSERT(!m_ancestorCompositedScrollingLayerDirty);
return m_ancestorCompositedScrollingLayer;
}
void RenderLayer::AncestorDependentPropertyCache::setAncestorCompositedScrollingLayer(RenderLayer* layer)
{
m_ancestorCompositedScrollingLayer = layer;
m_ancestorCompositedScrollingLayerDirty = false;
}
}
#ifndef NDEBUG
void showLayerTree(const WebCore::RenderLayer* layer)
{
if (!layer)
return;
if (WebCore::LocalFrame* frame = layer->renderer()->frame()) {
WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState);
fprintf(stderr, "%s\n", output.utf8().data());
}
}
void showLayerTree(const WebCore::RenderObject* renderer)
{
if (!renderer)
return;
showLayerTree(renderer->enclosingLayer());
}
#endif