#include "config.h"
#include "core/rendering/RenderLayer.h"
-#include "CSSPropertyNames.h"
-#include "HTMLNames.h"
-#include "RuntimeEnabledFeatures.h"
-#include "SVGNames.h"
+#include "core/CSSPropertyNames.h"
+#include "core/HTMLNames.h"
#include "core/css/PseudoStyleRequest.h"
#include "core/dom/Document.h"
#include "core/dom/shadow/ShadowRoot.h"
-#include "core/html/HTMLFrameElement.h"
-#include "core/frame/Frame.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/Settings.h"
-#include "core/frame/animation/AnimationController.h"
#include "core/page/scrolling/ScrollingCoordinator.h"
-#include "core/platform/graphics/GraphicsContextStateSaver.h"
-#include "core/platform/graphics/filters/ReferenceFilter.h"
-#include "core/platform/graphics/filters/SourceGraphic.h"
-#include "core/platform/graphics/filters/custom/CustomFilterGlobalContext.h"
-#include "core/platform/graphics/filters/custom/CustomFilterOperation.h"
-#include "core/platform/graphics/filters/custom/CustomFilterValidatedProgram.h"
-#include "core/platform/graphics/filters/custom/ValidatedCustomFilterOperation.h"
#include "core/rendering/ColumnInfo.h"
-#include "core/rendering/CompositedLayerMapping.h"
#include "core/rendering/FilterEffectRenderer.h"
#include "core/rendering/HitTestRequest.h"
#include "core/rendering/HitTestResult.h"
#include "core/rendering/HitTestingTransformState.h"
-#include "core/rendering/RenderBox.h"
#include "core/rendering/RenderFlowThread.h"
#include "core/rendering/RenderGeometryMap.h"
#include "core/rendering/RenderInline.h"
-#include "core/rendering/RenderLayerCompositor.h"
-#include "core/rendering/RenderLayerStackingNodeIterator.h"
+#include "core/rendering/RenderPart.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/RuntimeEnabledFeatures.h"
#include "platform/TraceEvent.h"
#include "platform/geometry/FloatPoint3D.h"
#include "platform/geometry/FloatRect.h"
+#include "platform/geometry/TransformState.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/UnusedParam.h"
#include "wtf/text/CString.h"
-using namespace std;
+namespace blink {
+
+namespace {
+
+static CompositingQueryMode gCompositingQueryMode =
+ CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases;
-namespace WebCore {
+} // namespace
using namespace HTMLNames;
-RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
- : m_hasSelfPaintingLayerDescendant(false)
+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_needsCompositedScrolling(false)
, m_isRootLayer(renderer->isRenderView())
, m_usedTransparency(false)
- , m_childLayerHasBlendMode(false)
- , m_childLayerHasBlendModeStatusDirty(false)
, m_visibleContentStatusDirty(true)
, m_hasVisibleContent(false)
, m_visibleDescendantStatusDirty(false)
, m_3DTransformedDescendantStatusDirty(true)
, m_has3DTransformedDescendant(false)
, m_containsDirtyOverlayScrollbars(false)
- , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell())
, m_hasFilterInfo(false)
- , m_blendMode(BlendModeNormal)
+ , m_needsAncestorDependentCompositingInputsUpdate(true)
+ , m_needsDescendantDependentCompositingInputsUpdate(true)
+ , m_childNeedsCompositingInputsUpdate(true)
+ , m_hasCompositingDescendant(false)
+ , m_hasNonCompositedChild(false)
+ , m_shouldIsolateCompositedDescendants(false)
+ , m_lostGroupedMapping(false)
, m_renderer(renderer)
, m_parent(0)
, m_previous(0)
, m_staticInlinePosition(0)
, m_staticBlockPosition(0)
, m_enclosingPaginationLayer(0)
- , m_forceNeedsCompositedScrolling(DoNotForceCompositedScrolling)
- , m_repainter(renderer)
- , m_clipper(renderer)
+ , m_potentialCompositingReasonsFromStyle(CompositingReasonNone)
+ , m_compositingReasons(CompositingReasonNone)
+ , m_groupedMapping(0)
+ , m_clipper(*renderer)
{
updateStackingNode();
m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
- if (!renderer->firstChild() && renderer->style()) {
+ if (!renderer->slowFirstChild() && renderer->style()) {
m_visibleContentStatusDirty = false;
m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
}
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);
+ }
+
// Child layers will be deleted by their corresponding render objects, so
// we don't need to delete them ourselves.
clearCompositedLayerMapping(true);
+
+ if (m_reflectionInfo)
+ m_reflectionInfo->destroy();
}
String RenderLayer::debugName() const
{
- if (isReflection())
- return m_reflectionInfo->debugName();
+ if (isReflection()) {
+ return renderer()->parent()->debugName() + " (reflection)";
+ }
return renderer()->debugName();
}
void RenderLayer::contentChanged(ContentChangeType changeType)
{
- // This can get called when video becomes accelerated, so the layers may change.
- if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this))
- compositor()->setCompositingLayersNeedRebuild();
+ // updateLayerCompositingState will query compositingReasons for accelerated overflow scrolling.
+ // This is tripped by LayoutTests/compositing/content-changed-chicken-egg.html
+ DisableCompositingQueryAsserts disabler;
+
+ if (changeType == CanvasChanged)
+ compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
+
+ if (changeType == CanvasContextChanged) {
+ compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
+
+ // Although we're missing test coverage, we need to call
+ // GraphicsLayer::setContentsToPlatformLayer with the new platform
+ // layer for this canvas.
+ // See http://crbug.com/349195
+ if (hasCompositedLayerMapping())
+ compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
+ }
if (m_compositedLayerMapping)
m_compositedLayerMapping->contentChanged(changeType);
}
-bool RenderLayer::canRender3DTransforms() const
-{
- return compositor()->canRender3DTransforms();
-}
-
bool RenderLayer::paintsWithFilters() const
{
if (!renderer()->hasFilter())
return false;
- if (compositingState() != PaintsIntoOwnBacking)
- return true;
-
- if (!m_compositedLayerMapping || !m_compositedLayerMapping->canCompositeFilters())
- return true;
-
- return false;
+ // https://code.google.com/p/chromium/issues/detail?id=343759
+ DisableCompositingQueryAsserts disabler;
+ return !m_compositedLayerMapping || compositingState() != PaintsIntoOwnBacking;
}
-bool RenderLayer::requiresFullLayerImageForFilters() const
+LayoutSize RenderLayer::subpixelAccumulation() const
{
- if (!paintsWithFilters())
- return false;
- FilterEffectRenderer* filter = filterRenderer();
- return filter ? filter->hasFilterThatMovesPixels() : false;
+ return m_subpixelAccumulation;
}
-LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
+void RenderLayer::setSubpixelAccumulation(const LayoutSize& size)
{
- hasLayerOffset = true;
-
- if (!parent())
- return LayoutPoint();
-
- // This is similar to root() but we check if an ancestor layer would
- // prevent the optimization from working.
- 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;
+ m_subpixelAccumulation = size;
}
-void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
+void RenderLayer::updateLayerPositionsAfterLayout()
{
- RenderGeometryMap geometryMap(UseTransforms);
- if (this != rootLayer)
- geometryMap.pushMappingsToAncestor(parent(), 0);
- updateLayerPositions(&geometryMap, flags);
-}
+ TRACE_EVENT0("blink", "RenderLayer::updateLayerPositionsAfterLayout");
-void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLayerPositionsFlags flags)
-{
- updateLayerPosition(); // For relpositioned layers or non-positioned layers,
- // we need to keep in sync, since we may have shifted relative
- // to our parent layer.
- if (geometryMap)
- geometryMap->pushMappingsToAncestor(this, parent());
-
- // Clear our cached clip rect information.
- m_clipper.clearClipRects();
+ m_clipper.clearClipRectsIncludingDescendants();
+ updateLayerPositionRecursive();
- if (hasOverflowControls()) {
- LayoutPoint offsetFromRoot;
- if (geometryMap)
- offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint()));
- else {
- // FIXME: It looks suspicious to call convertToLayerCoords here
- // as canUseConvertToLayerCoords may be true for an ancestor layer.
- convertToLayerCoords(root(), offsetFromRoot);
- }
- scrollableArea()->positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
+ {
+ // FIXME: Remove incremental compositing updates after fixing the chicken/egg issues
+ // https://code.google.com/p/chromium/issues/detail?id=343756
+ DisableCompositingQueryAsserts disabler;
+ bool needsPaginationUpdate = isPaginated() || enclosingPaginationLayer();
+ updatePaginationRecursive(needsPaginationUpdate);
}
+}
- updateDescendantDependentFlags();
-
- if (flags & UpdatePagination)
- updatePagination();
- else {
- m_isPaginated = false;
- m_enclosingPaginationLayer = 0;
- }
-
- repainter().repaintAfterLayout(geometryMap, flags & CheckForRepaint);
-
- // Go ahead and update the reflection's position and size.
+void RenderLayer::updateLayerPositionRecursive()
+{
if (m_reflectionInfo)
m_reflectionInfo->reflection()->layout();
- // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
- bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
- if (compositedLayerMapping())
- flags &= ~IsCompositingUpdateRoot;
-
- if (useRegionBasedColumns() && renderer()->isInFlowRenderFlowThread()) {
- updatePagination();
- flags |= UpdatePagination;
- }
-
- if (renderer()->hasColumns())
- flags |= UpdatePagination;
+ // FIXME: We should be able to remove this call because we don't care about
+ // any descendant-dependent flags, but code somewhere else is reading these
+ // flags and depending on us to update them.
+ updateDescendantDependentFlags();
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateLayerPositions(geometryMap, flags);
-
- if ((flags & UpdateCompositingLayers) && compositedLayerMapping()) {
- CompositedLayerMapping::UpdateAfterLayoutFlags updateFlags = CompositedLayerMapping::CompositingChildrenOnly;
- if (flags & NeedsFullRepaintInBacking)
- updateFlags |= CompositedLayerMapping::NeedsFullRepaint;
- if (isUpdateRoot)
- updateFlags |= CompositedLayerMapping::IsUpdateRoot;
- compositedLayerMapping()->updateAfterLayout(updateFlags);
- }
-
- if (geometryMap)
- geometryMap->popMappingsToAncestor(parent());
+ child->updateLayerPositionRecursive();
}
-void RenderLayer::setAncestorChainHasSelfPaintingLayerDescendant()
+void RenderLayer::updateHasSelfPaintingLayerDescendant() const
{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (!layer->m_hasSelfPaintingLayerDescendantDirty && layer->hasSelfPaintingLayerDescendant())
- break;
+ ASSERT(m_hasSelfPaintingLayerDescendantDirty);
- layer->m_hasSelfPaintingLayerDescendantDirty = false;
- layer->m_hasSelfPaintingLayerDescendant = true;
+ m_hasSelfPaintingLayerDescendant = false;
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant()) {
+ m_hasSelfPaintingLayerDescendant = true;
+ break;
+ }
}
+
+ m_hasSelfPaintingLayerDescendantDirty = false;
}
void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
// If we have reached a self-painting layer, we know our parent should have a self-painting descendant
// in this case, there is no need to dirty our ancestors further.
if (layer->isSelfPaintingLayer()) {
- ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->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);
-
- // We may or may not have an unclipped descendant. If we do, we'll reset
- // this to true the next time composited scrolling state is updated.
- layer->setHasUnclippedDescendant(false);
-
- // If we have reached an out of flow positioned layer, we know our parent should have an out-of-flow positioned descendant.
- // In this case, there is no need to dirty our ancestors further.
- if (layer->renderer()->isOutOfFlowPositioned()) {
- ASSERT(!parent() || parent()->m_hasOutOfFlowPositionedDescendantDirty || parent()->hasOutOfFlowPositionedDescendant());
+ ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty || parent()->m_hasSelfPaintingLayerDescendant);
break;
}
}
}
-bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
-{
- const Settings* settings = renderer()->document().settings();
- return settings && settings->acceleratedCompositingForOverflowScrollEnabled();
-}
-
-// FIXME: This is a temporary flag and should be removed once accelerated
-// overflow scroll is ready (crbug.com/254111).
-bool RenderLayer::compositorDrivenAcceleratedScrollingEnabled() const
+bool RenderLayer::scrollsWithViewport() const
{
- if (!acceleratedCompositingForOverflowScrollEnabled())
- return false;
-
- const Settings* settings = renderer()->document().settings();
- return settings && settings->isCompositorDrivenAcceleratedScrollingEnabled();
+ return renderer()->style()->position() == FixedPosition && renderer()->containerForFixedPosition() == renderer()->view();
}
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();
-
- // Fixed-position elements are a special case. They are static with respect
- // to the viewport, which is not represented by any RenderObject, and their
- // containingBlock() method returns the root HTML element (while its true
- // containingBlock should really be the viewport). The real measure for a
- // non-transformed fixed-position element is as follows: any fixed position
- // element, A, scrolls with respect an element, B, if and only if B is not
- // fixed position.
- //
- // Unfortunately, it gets a bit more complicated - a fixed-position element
- // which has a transform acts exactly as an absolute-position element
- // (including having a real, non-viewport containing block).
- //
- // Below, a "root" fixed position element is defined to be one whose
- // containing block is the root. These root-fixed-position elements are
- // the only ones that need this special case code - other fixed position
- // elements, as well as all absolute, relative, and static elements use the
- // logic below.
- const bool isRootFixedPos = position == FixedPosition && containingBlock->enclosingLayer() == rootLayer;
- const bool otherIsRootFixedPos = otherPosition == FixedPosition && otherContainingBlock->enclosingLayer() == rootLayer;
-
- if (isRootFixedPos && otherIsRootFixedPos)
- return false;
- if (isRootFixedPos || otherIsRootFixedPos)
+ if (scrollsWithViewport() != other->scrollsWithViewport())
return true;
-
- if (containingBlock == otherContainingBlock)
- return false;
-
- // Maintain a set of containing blocks between the first layer and its
- // closest scrollable ancestor.
- HashSet<const RenderObject*> containingBlocks;
- while (containingBlock) {
- if (containingBlock->enclosingLayer()->scrollsOverflow())
- break;
- containingBlocks.add(containingBlock);
- containingBlock = containingBlock->containingBlock();
- }
-
- // Do the same for the 2nd layer, but if we find a common containing block,
- // it means both layers are contained within a single non-scrolling subtree.
- // Hence, they will not scroll with respect to each other.
- 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);
+ return ancestorScrollingLayer() != other->ancestorScrollingLayer();
}
-void RenderLayer::updateLayerPositionsAfterOverflowScroll()
+void RenderLayer::updateTransformationMatrix()
{
- RenderGeometryMap geometryMap(UseTransforms);
- RenderView* view = renderer()->view();
- if (this != view->layer())
- geometryMap.pushMappingsToAncestor(parent(), 0);
-
- // FIXME: why is it OK to not check the ancestors of this layer in order to
- // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
- updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
-}
-
-void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap, UpdateLayerPositionsAfterScrollFlags flags)
-{
- // FIXME: This shouldn't be needed, but there are some corner cases where
- // these flags are still dirty. Update so that the check below is valid.
- updateDescendantDependentFlags();
-
- // If we have no visible content and no visible descendants, there is no point recomputing
- // our rectangles as they will be empty. If our visibility changes, we are expected to
- // recompute all our positions anyway.
- 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 & HasSeenViewportConstrainedAncestor
- || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) {
- // FIXME: We could track the repaint container as we walk down the tree.
- repainter().computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
- } else {
- // Check that RenderLayerRepainter's cached rects are correct.
- // FIXME: re-enable these assertions when the issue with table cells is resolved: https://bugs.webkit.org/show_bug.cgi?id=103432
- // ASSERT(repainter().m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint()));
- // ASSERT(repainter().m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap));
+ if (m_transform) {
+ RenderBox* box = renderBox();
+ ASSERT(box);
+ m_transform->makeIdentity();
+ box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+ makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositing());
}
-
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateLayerPositionsAfterScroll(geometryMap, flags);
-
- // We don't update our reflection as scrolling is a translation which does not change the size()
- // of an object, thus RenderReplica will still repaint itself properly as the layer position was
- // updated above.
-
- if (geometryMap)
- geometryMap->popMappingsToAncestor(parent());
}
-bool RenderLayer::hasBlendMode() const
+void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle)
{
- return RuntimeEnabledFeatures::cssCompositingEnabled() && renderer()->hasBlendMode();
-}
-
-void RenderLayer::updateBlendMode()
-{
- if (!RuntimeEnabledFeatures::cssCompositingEnabled())
+ if (oldStyle && newStyle->transformDataEquivalent(*oldStyle))
return;
- bool hadBlendMode = m_blendMode != BlendModeNormal;
- BlendMode newBlendMode = renderer()->style()->blendMode();
- if (newBlendMode != m_blendMode) {
- m_blendMode = newBlendMode;
-
- // Only update the flag if a blend mode is set or unset.
- if (!hadBlendMode || !hasBlendMode())
- dirtyAncestorChainBlendedDescendantStatus();
-
- if (compositedLayerMapping())
- compositedLayerMapping()->setBlendMode(newBlendMode);
- }
-}
-
-void RenderLayer::updateTransform()
-{
// hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
// so check style too.
- bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
+ bool hasTransform = renderer()->hasTransform() && newStyle->hasTransform();
bool had3DTransform = has3DTransform();
bool hadTransform = m_transform;
// Layers with transforms act as clip rects roots, so clear the cached clip rects here.
m_clipper.clearClipRectsIncludingDescendants();
+ } else if (hasTransform) {
+ m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects);
}
- if (hasTransform) {
- RenderBox* box = renderBox();
- ASSERT(box);
- m_transform->makeIdentity();
- box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
- makeMatrixRenderable(*m_transform, canRender3DTransforms());
- }
+ updateTransformationMatrix();
if (had3DTransform != has3DTransform())
dirty3DTransformedDescendantStatus();
}
+static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer)
+{
+ if (RenderObject* containingBlock = layer->renderer()->containingBlock())
+ return containingBlock->enclosingLayer();
+ return 0;
+}
+
+RenderLayer* RenderLayer::renderingContextRoot()
+{
+ RenderLayer* renderingContext = 0;
+
+ if (shouldPreserve3D())
+ renderingContext = this;
+
+ for (RenderLayer* current = enclosingLayerForContainingBlock(this); current && current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(current))
+ renderingContext = current;
+
+ return renderingContext;
+}
+
TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
{
if (!m_transform)
return TransformationMatrix();
- if (renderer()->style()->isRunningAcceleratedAnimation()) {
- TransformationMatrix currTransform;
- RefPtr<RenderStyle> style = renderer()->animation().getAnimatedStyleForRenderer(renderer());
- style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin);
- makeMatrixRenderable(currTransform, canRender3DTransforms());
- return currTransform;
- }
-
// m_transform includes transform-origin, so we need to recompute the transform here.
if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
RenderBox* box = renderBox();
TransformationMatrix currTransform;
box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
- makeMatrixRenderable(currTransform, canRender3DTransforms());
+ makeMatrixRenderable(currTransform, compositor()->hasAcceleratedCompositing());
return currTransform;
}
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();
bool RenderLayer::useRegionBasedColumns() const
{
- const Settings* settings = renderer()->document().settings();
- return settings && settings->regionBasedColumnsEnabled();
+ return renderer()->document().regionBasedColumnsEnabled();
}
-void RenderLayer::updatePagination()
+void RenderLayer::updatePaginationRecursive(bool needsPaginationUpdate)
{
m_isPaginated = false;
m_enclosingPaginationLayer = 0;
- if (compositedLayerMapping() || !parent())
+ if (useRegionBasedColumns() && renderer()->isRenderFlowThread())
+ needsPaginationUpdate = true;
+
+ if (needsPaginationUpdate)
+ updatePagination();
+
+ if (renderer()->hasColumns())
+ needsPaginationUpdate = true;
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->updatePaginationRecursive(needsPaginationUpdate);
+}
+
+void RenderLayer::updatePagination()
+{
+ if (compositingState() != NotComposited || !parent())
return; // FIXME: We will have to deal with paginated compositing layers someday.
// FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
// layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
// to that layer easily.
bool regionBasedColumnsUsed = useRegionBasedColumns();
- if (regionBasedColumnsUsed && renderer()->isInFlowRenderFlowThread()) {
+ if (regionBasedColumnsUsed && renderer()->isRenderFlowThread()) {
m_enclosingPaginationLayer = this;
return;
}
m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
m_enclosingPaginationLayer = 0;
- } else
+ } else {
m_isPaginated = parent()->renderer()->hasColumns();
+ }
return;
}
}
// If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
- RenderLayerStackingNode* ancestorStackingContainerNode = m_stackingNode->ancestorStackingContainerNode();
+ RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ancestorStackingContextNode();
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns()) {
m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
return;
}
- if (curr->stackingNode() == ancestorStackingContainerNode)
+ if (curr->stackingNode() == ancestorStackingContextNode)
return;
}
}
-void RenderLayer::setHasVisibleContent()
+LayoutPoint RenderLayer::positionFromPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
{
- if (m_hasVisibleContent && !m_visibleContentStatusDirty) {
- ASSERT(!parent() || parent()->hasVisibleDescendant());
- return;
- }
+ FloatPoint point = renderObject->localToContainerPoint(FloatPoint(), paintInvalidationContainer, 0, 0, paintInvalidationState);
- m_visibleContentStatusDirty = false;
- m_hasVisibleContent = true;
- repainter().computeRepaintRects(renderer()->containerForRepaint());
- if (!m_stackingNode->isNormalFlowOnly()) {
- // We don't collect invisible layers in z-order lists if we are not in compositing mode.
- // As we became visible, we need to dirty our stacking containers ancestors to be properly
- // collected. FIXME: When compositing, we could skip this dirtying phase.
- for (RenderLayerStackingNode* sc = m_stackingNode->ancestorStackingContainerNode(); sc; sc = sc->ancestorStackingContainerNode()) {
- sc->dirtyZOrderLists();
- if (sc->layer()->hasVisibleContent())
- break;
- }
- }
+ // FIXME: Eventually we are going to unify coordinates in GraphicsLayer space.
+ if (paintInvalidationContainer && paintInvalidationContainer->layer()->groupedMapping())
+ mapPointToPaintBackingCoordinates(paintInvalidationContainer, point);
- if (parent())
- parent()->setAncestorChainHasVisibleDescendant();
+ return LayoutPoint(point);
}
-void RenderLayer::dirtyVisibleContentStatus()
+void RenderLayer::mapPointToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, FloatPoint& point)
{
- m_visibleContentStatusDirty = true;
- if (parent())
- parent()->dirtyAncestorChainVisibleDescendantStatus();
-}
+ RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
+ if (!paintInvalidationLayer->groupedMapping()) {
+ point.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
+ return;
+ }
-void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
-{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (layer->m_visibleDescendantStatusDirty)
- break;
+ RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
+ if (!transformedAncestor)
+ return;
- layer->m_visibleDescendantStatusDirty = true;
- }
+ // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
+ // transformed ancestor.
+ point = paintInvalidationContainer->localToContainerPoint(point, transformedAncestor);
+
+ point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
}
-void RenderLayer::setAncestorChainHasVisibleDescendant()
+void RenderLayer::mapRectToPaintBackingCoordinates(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect)
{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (!layer->m_visibleDescendantStatusDirty && layer->hasVisibleDescendant())
- break;
-
- layer->m_hasVisibleDescendant = true;
- layer->m_visibleDescendantStatusDirty = false;
+ RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer();
+ if (!paintInvalidationLayer->groupedMapping()) {
+ rect.move(paintInvalidationLayer->compositedLayerMapping()->contentOffsetInCompositingLayer());
+ return;
}
+
+ RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclosingTransformedAncestor()->renderer();
+ if (!transformedAncestor)
+ return;
+
+ // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the
+ // transformed ancestor.
+ rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect(rect), transformedAncestor).boundingBox());
+
+ rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor());
}
-void RenderLayer::dirtyAncestorChainBlendedDescendantStatus()
+void RenderLayer::mapRectToPaintInvalidationBacking(const RenderObject* renderObject, const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState)
{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (layer->m_childLayerHasBlendModeStatusDirty)
- break;
+ if (!paintInvalidationContainer->layer()->groupedMapping()) {
+ renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
+ return;
+ }
- layer->m_childLayerHasBlendModeStatusDirty = true;
+ // This code adjusts the paint invalidation rectangle to be in the space of the transformed ancestor of the grouped (i.e. squashed)
+ // layer. This is because all layers that squash together need to issue paint invalidations w.r.t. a single container that is
+ // an ancestor of all of them, in order to properly take into account any local transforms etc.
+ // FIXME: remove this special-case code that works around the paint invalidation code structure.
+ renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
- if (layer->stackingNode()->isStackingContext())
- break;
- }
+ mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
}
-void RenderLayer::setAncestorChainBlendedDescendant()
+LayoutRect RenderLayer::computePaintInvalidationRect(const RenderObject* renderObject, const RenderLayer* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState)
{
- for (RenderLayer* layer = this; layer; layer = layer->parent()) {
- if (!layer->m_childLayerHasBlendModeStatusDirty && layer->childLayerHasBlendMode())
- break;
+ if (!paintInvalidationContainer->groupedMapping())
+ return renderObject->computePaintInvalidationRect(paintInvalidationContainer->renderer(), paintInvalidationState);
- layer->m_childLayerHasBlendMode = true;
- layer->m_childLayerHasBlendModeStatusDirty = false;
+ LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer->renderer(), paintInvalidationState);
+ mapRectToPaintBackingCoordinates(paintInvalidationContainer->renderer(), rect);
+ return rect;
+}
- if (layer->stackingNode()->isStackingContext())
- break;
- }
+void RenderLayer::dirtyVisibleContentStatus()
+{
+ m_visibleContentStatusDirty = true;
+ if (parent())
+ parent()->dirtyAncestorChainVisibleDescendantStatus();
}
-void RenderLayer::updateHasUnclippedDescendant()
+void RenderLayer::potentiallyDirtyVisibleContentStatus(EVisibility visibility)
{
- TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasUnclippedDescendant");
- ASSERT(renderer()->isOutOfFlowPositioned());
- if (!m_hasVisibleContent && !m_hasVisibleDescendant)
+ if (m_visibleContentStatusDirty)
return;
-
- FrameView* frameView = renderer()->view()->frameView();
- if (!frameView)
+ if (hasVisibleContent() == (visibility == VISIBLE))
return;
+ dirtyVisibleContentStatus();
+}
- const RenderObject* containingBlock = renderer()->containingBlock();
- setIsUnclippedDescendant(false);
- for (RenderLayer* ancestor = parent(); ancestor && ancestor->renderer() != containingBlock; ancestor = ancestor->parent()) {
- // TODO(vollick): This isn't quite right. Whenever ancestor is composited and clips
- // overflow, we're technically unclipped. However, this will currently cause a huge
- // number of layers to report that they are unclipped. Eventually, when we've formally
- // separated the clipping, transform, opacity, and stacking trees here and in the
- // compositor, we will be able to relax this restriction without it being prohibitively
- // expensive (currently, we have to do a lot of work in the compositor to honor a
- // clip child/parent relationship).
- if (ancestor->scrollsOverflow())
- setIsUnclippedDescendant(true);
- ancestor->setHasUnclippedDescendant(true);
+void RenderLayer::dirtyAncestorChainVisibleDescendantStatus()
+{
+ for (RenderLayer* layer = this; layer; layer = layer->parent()) {
+ if (layer->m_visibleDescendantStatusDirty)
+ break;
+
+ layer->m_visibleDescendantStatusDirty = true;
}
}
// FIXME: this is quite brute-force. We could be more efficient if we were to
-// track state and update it as appropriate as changes are made in the RenderObject tree.
-void RenderLayer::updateHasVisibleNonLayerContent()
+// track state and update it as appropriate as changes are made in the Render tree.
+void RenderLayer::updateScrollingStateAfterCompositingChange()
{
- TRACE_EVENT0("blink_rendering", "RenderLayer::updateHasVisibleNonLayerContent");
+ TRACE_EVENT0("blink", "RenderLayer::updateScrollingStateAfterCompositingChange");
m_hasVisibleNonLayerContent = false;
- for (RenderObject* r = renderer()->firstChild(); r; r = r->nextSibling()) {
+ for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()) {
if (!r->hasLayer()) {
m_hasVisibleNonLayerContent = true;
break;
}
}
+
+ m_hasNonCompositedChild = false;
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ if (child->compositingState() == NotComposited || child->compositingState() == HasOwnBackingButPaintsIntoAncestor) {
+ m_hasNonCompositedChild = true;
+ return;
+ }
+ }
}
-static bool subtreeContainsOutOfFlowPositionedLayer(const RenderLayer* subtreeRoot)
+// The descendant-dependent flags system is badly broken because we clean dirty
+// bits in upward tree walks, which means we need to call updateDescendantDependentFlags
+// at every node in the tree to fully clean all the dirty bits. While we'll in
+// the process of fixing this issue, updateDescendantDependentFlagsForEntireSubtree
+// provides a big hammer for actually cleaning all the dirty bits in a subtree.
+//
+// FIXME: Remove this function once the descendant-dependent flags system keeps
+// its dirty bits scoped to subtrees.
+void RenderLayer::updateDescendantDependentFlagsForEntireSubtree()
{
- return (subtreeRoot->renderer() && subtreeRoot->renderer()->isOutOfFlowPositioned()) || subtreeRoot->hasOutOfFlowPositionedDescendant();
+ updateDescendantDependentFlags();
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->updateDescendantDependentFlagsForEntireSubtree();
}
void RenderLayer::updateDescendantDependentFlags()
{
- if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
+ if (m_visibleDescendantStatusDirty) {
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)
+ if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
+ m_hasVisibleDescendant = true;
break;
+ }
}
m_visibleDescendantStatusDirty = false;
- m_hasSelfPaintingLayerDescendantDirty = false;
- m_hasOutOfFlowPositionedDescendantDirty = false;
- }
-
- if (m_childLayerHasBlendModeStatusDirty) {
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->stackingNode()->isStackingContext())
- child->updateDescendantDependentFlags();
-
- bool childLayerHasBlendMode = child->paintsWithBlendMode() || (child->m_childLayerHasBlendMode && !child->stackingNode()->isStackingContext());
- m_childLayerHasBlendMode |= childLayerHasBlendMode;
-
- if (m_childLayerHasBlendMode)
- break;
- }
- m_childLayerHasBlendModeStatusDirty = false;
}
if (m_visibleContentStatusDirty) {
+ bool previouslyHasVisibleContent = m_hasVisibleContent;
if (renderer()->style()->visibility() == VISIBLE)
m_hasVisibleContent = true;
else {
// layer may be hidden but still have some visible content, check for this
m_hasVisibleContent = false;
- RenderObject* r = renderer()->firstChild();
+ RenderObject* r = renderer()->slowFirstChild();
while (r) {
if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
m_hasVisibleContent = true;
break;
}
- if (r->firstChild() && !r->hasLayer())
- r = r->firstChild();
+ RenderObject* rendererFirstChild = r->slowFirstChild();
+ if (rendererFirstChild && !r->hasLayer())
+ r = rendererFirstChild;
else if (r->nextSibling())
r = r->nextSibling();
else {
}
}
m_visibleContentStatusDirty = false;
+
+ if (hasVisibleContent() != previouslyHasVisibleContent) {
+ setNeedsCompositingInputsUpdate();
+ // We need to tell m_renderer to recheck its rect because we
+ // pretend that invisible RenderObjects have 0x0 rects. Changing
+ // visibility therefore changes our rect and we need to visit
+ // this RenderObject during the invalidateTreeIfNeeded walk.
+ m_renderer->setMayNeedPaintInvalidation(true);
+ }
}
}
void RenderLayer::dirty3DTransformedDescendantStatus()
{
- RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContainerNode();
+ RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingContextNode();
if (!stackingNode)
return;
// Note that preserves3D() creates stacking context, so we can just run up the stacking containers.
while (stackingNode && stackingNode->layer()->preserves3D()) {
stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true;
- stackingNode = stackingNode->ancestorStackingContainerNode();
+ stackingNode = stackingNode->ancestorStackingContextNode();
}
}
return has3DTransform();
}
-bool RenderLayer::updateLayerPosition()
+IntSize RenderLayer::size() const
+{
+ if (renderer()->isInline() && renderer()->isRenderInline())
+ return toRenderInline(renderer())->linesBoundingBox().size();
+
+ // FIXME: Is snapping the size really needed here?
+ if (RenderBox* box = renderBox())
+ return pixelSnappedIntSize(box->size(), box->location());
+
+ return IntSize();
+}
+
+LayoutPoint RenderLayer::location() const
{
LayoutPoint localPoint;
LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
+
if (renderer()->isInline() && renderer()->isRenderInline()) {
RenderInline* inlineFlow = toRenderInline(renderer());
IntRect lineBox = inlineFlow->linesBoundingBox();
- setSize(lineBox.size());
inlineBoundingBoxOffset = toSize(lineBox.location());
localPoint += inlineBoundingBoxOffset;
} else if (RenderBox* box = renderBox()) {
- // FIXME: Is snapping the size really needed here for the RenderBox case?
- setSize(pixelSnappedIntSize(box->size(), box->location()));
localPoint += box->topLeftLocationOffset();
}
localPoint -= offset;
}
- if (renderer()->isOutOfFlowPositioned() && positionedParent->renderer()->isInFlowPositioned() && positionedParent->renderer()->isRenderInline()) {
- LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(toRenderBox(renderer()));
+ if (positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
+ LayoutSize offset = toRenderInline(positionedParent->renderer())->offsetForInFlowPositionedInline(*toRenderBox(renderer()));
localPoint += offset;
}
} else if (parent()) {
- if (compositedLayerMapping()) {
+ // FIXME: This code is very wrong. The compositing system doesn't
+ // understand columns and we're hacking around that fact by faking
+ // the position of the RenderLayers when we think we'll end up being
+ // composited. Hopefully we'll be able to unwind this hack when we
+ // implement multi-column using regions.
+ if (hasStyleDeterminedDirectCompositingReasons()) {
// FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
// They won't split across columns properly.
- LayoutSize columnOffset;
- if (!parent()->renderer()->hasColumns() && parent()->renderer()->isRoot() && renderer()->view()->hasColumns())
- renderer()->view()->adjustForColumns(columnOffset, localPoint);
+ if (!parent()->renderer()->hasColumns() && parent()->renderer()->isDocumentElement() && renderer()->view()->hasColumns())
+ localPoint += renderer()->view()->columnOffset(localPoint);
else
- parent()->renderer()->adjustForColumns(columnOffset, localPoint);
-
- localPoint += columnOffset;
+ localPoint += parent()->renderer()->columnOffset(localPoint);
}
if (parent()->renderer()->hasOverflowClip()) {
}
}
- 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.move(offsetForInFlowPosition());
// FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
localPoint -= inlineBoundingBoxOffset;
- positionOrOffsetChanged |= location() != localPoint;
- setLocation(localPoint);
- return positionOrOffsetChanged;
+ return localPoint;
+}
+
+const LayoutSize RenderLayer::offsetForInFlowPosition() const
+{
+ return renderer()->isRelPositioned() ? toRenderBoxModelObject(renderer())->offsetForInFlowPosition() : LayoutSize();
}
TransformationMatrix RenderLayer::perspectiveTransform() const
const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect();
RenderStyle* style = renderer()->style();
- return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()),
- floatValueForLength(style->perspectiveOriginY(), borderBox.height()));
+ return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.height().toFloat()));
}
static inline bool isFixedPositionedContainer(RenderLayer* layer)
return curr;
}
-RenderLayer* RenderLayer::enclosingScrollableLayer() const
-{
- if (RenderBox* enclosingScrollableBox = renderer()->enclosingScrollableBox())
- return enclosingScrollableBox->layer();
-
- return 0;
-}
-
RenderLayer* RenderLayer::enclosingTransformedAncestor() const
{
RenderLayer* curr = parent();
- while (curr && !curr->isRootLayer() && !curr->transform())
+ while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransform())
curr = curr->parent();
return curr;
}
-static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
+LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const
{
- return layer->stackingNode()->isNormalFlowOnly() ? layer->parent() : (layer->stackingNode()->ancestorStackingContainerNode() ? layer->stackingNode()->ancestorStackingContainerNode()->layer() : 0);
+ const AncestorDependentCompositingInputs& properties = ancestorDependentCompositingInputs();
+
+ TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
+ // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip are correct.
+ renderer()->mapLocalToContainer(properties.transformAncestor ? properties.transformAncestor->renderer() : 0, transformState, ApplyContainerFlip);
+ transformState.flatten();
+ return LayoutPoint(transformState.lastPlanarPoint());
}
-// FIXME: having two different functions named enclosingCompositingLayer and enclosingCompositingLayerForRepaint
-// is error-prone and misleading for reading code that uses these functions - especially compounded with
-// the includeSelf option. It is very likely that some call sites of this function actually mean to use
-// enclosingCompositingLayerForRepaint().
-RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
+const RenderLayer* RenderLayer::compositingContainer() const
{
- if (includeSelf && compositedLayerMapping())
- return const_cast<RenderLayer*>(this);
-
- for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
- if (curr->compositedLayerMapping())
- return const_cast<RenderLayer*>(curr);
- }
-
+ if (stackingNode()->isNormalFlowOnly())
+ return parent();
+ if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestorStackingContextNode())
+ return ancestorStackingNode->layer();
return 0;
}
-RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const
+bool RenderLayer::isPaintInvalidationContainer() const
+{
+ return compositingState() == PaintsIntoOwnBacking || compositingState() == PaintsIntoGroupedBacking;
+}
+
+// Note: enclosingCompositingLayer does not include squashed layers. Compositing stacking children of squashed layers
+// receive graphics layers that are parented to the compositing ancestor of the squashed layer.
+RenderLayer* RenderLayer::enclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot includeSelf) const
{
- if (includeSelf && compositingState() == PaintsIntoOwnBacking)
+ ASSERT(isAllowedToQueryCompositingState());
+
+ if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && compositingState() != PaintsIntoGroupedBacking)
return const_cast<RenderLayer*>(this);
- for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
- if (curr->compositingState() == PaintsIntoOwnBacking)
+ 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::ancestorCompositedScrollingLayer() const
+// Return the enclosingCompositedLayerForPaintInvalidation for the given RenderLayer
+// including crossing frame boundaries.
+RenderLayer* RenderLayer::enclosingLayerForPaintInvalidationCrossingFrameBoundaries() const
{
- if (!acceleratedCompositingForOverflowScrollEnabled())
- return 0;
+ const RenderLayer* layer = this;
+ RenderLayer* compositedLayer = 0;
+ while (!compositedLayer) {
+ compositedLayer = layer->enclosingLayerForPaintInvalidation();
+ if (!compositedLayer) {
+ RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
+ if (!owner)
+ break;
+ layer = owner->enclosingLayer();
+ }
+ }
+ return compositedLayer;
+}
- RenderObject* containingBlock = renderer()->containingBlock();
- if (!containingBlock)
- return 0;
+RenderLayer* RenderLayer::enclosingLayerForPaintInvalidation() const
+{
+ ASSERT(isAllowedToQueryCompositingState());
- for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
- if (ancestorLayer->needsCompositedScrolling())
- return ancestorLayer;
+ if (isPaintInvalidationContainer())
+ return const_cast<RenderLayer*>(this);
+
+ for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->compositingContainer()) {
+ if (curr->isPaintInvalidationContainer())
+ return const_cast<RenderLayer*>(curr);
}
return 0;
}
-RenderLayer* RenderLayer::ancestorScrollingLayer() const
+void RenderLayer::setNeedsCompositingInputsUpdate()
{
- RenderObject* containingBlock = renderer()->containingBlock();
- if (!containingBlock)
- return 0;
+ m_needsAncestorDependentCompositingInputsUpdate = true;
+ m_needsDescendantDependentCompositingInputsUpdate = true;
- for (RenderLayer* ancestorLayer = containingBlock->enclosingLayer(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
- if (ancestorLayer->scrollsOverflow())
- return ancestorLayer;
- }
+ for (RenderLayer* current = this; current && !current->m_childNeedsCompositingInputsUpdate; current = current->parent())
+ current->m_childNeedsCompositingInputsUpdate = true;
- return 0;
+ compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
}
-RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const
+void RenderLayer::updateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs& compositingInputs)
{
- const RenderLayer* curr = includeSelf ? this : parent();
- for (; curr; curr = curr->parent()) {
- if (curr->requiresFullLayerImageForFilters())
- return const_cast<RenderLayer*>(curr);
- }
+ m_ancestorDependentCompositingInputs = compositingInputs;
+ m_needsAncestorDependentCompositingInputsUpdate = false;
+}
- return 0;
+void RenderLayer::updateDescendantDependentCompositingInputs(const DescendantDependentCompositingInputs& compositingInputs)
+{
+ m_descendantDependentCompositingInputs = compositingInputs;
+ m_needsDescendantDependentCompositingInputsUpdate = false;
}
-bool RenderLayer::hasAncestorWithFilterOutsets() const
+void RenderLayer::didUpdateCompositingInputs()
{
- for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
- RenderLayerModelObject* renderer = curr->renderer();
- if (renderer->style()->hasFilterOutsets())
- return true;
- }
- return false;
+ ASSERT(!needsCompositingInputsUpdate());
+ m_childNeedsCompositingInputsUpdate = false;
+ if (m_scrollableArea)
+ m_scrollableArea->updateNeedsCompositedScrolling();
}
-RenderLayer* RenderLayer::clippingRootForPainting() const
+void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingReasons mask)
{
- if (compositedLayerMapping())
- return const_cast<RenderLayer*>(this);
+ if ((compositingReasons() & mask) == (reasons & mask))
+ return;
+ m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask);
+}
- const RenderLayer* current = this;
- while (current) {
- if (current->isRootLayer())
- return const_cast<RenderLayer*>(current);
-
- current = compositingContainer(current);
- ASSERT(current);
- if (current->transform()
- || (current->compositingState() == PaintsIntoOwnBacking)
- )
- return const_cast<RenderLayer*>(current);
- }
+void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant)
+{
+ if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescendant))
+ return;
- ASSERT_NOT_REACHED();
- return 0;
+ m_hasCompositingDescendant = hasCompositingDescendant;
+
+ if (hasCompositedLayerMapping())
+ compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
}
-bool RenderLayer::cannotBlitToWindow() const
+void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompositedDescendants)
{
- if (isTransparent() || m_reflectionInfo || hasTransform())
- return true;
- if (!parent())
- return false;
- return parent()->cannotBlitToWindow();
+ if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsolateCompositedDescendants))
+ return;
+
+ m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants;
+
+ if (hasCompositedLayerMapping())
+ compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
}
-bool RenderLayer::isTransparent() const
+bool RenderLayer::hasAncestorWithFilterOutsets() const
{
- if (renderer()->node() && renderer()->node()->isSVGElement())
- return false;
-
- return renderer()->isTransparent() || renderer()->hasMask();
+ for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
+ RenderLayerModelObject* renderer = curr->renderer();
+ if (renderer->style()->hasFilterOutsets())
+ return true;
+ }
+ return false;
}
RenderLayer* RenderLayer::transparentPaintingAncestor()
{
- if (compositedLayerMapping())
+ if (hasCompositedLayerMapping())
return 0;
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
- if (curr->compositedLayerMapping())
+ if (curr->hasCompositedLayerMapping())
return 0;
if (curr->isTransparent())
return curr;
RootOfTransparencyClipBox
};
-static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
+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, PaintBehavior paintBehavior)
+ TransparencyClipBoxBehavior transparencyBehavior, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
// If we have a mask, then the clip is limited to the border box area (and there is
// no need to examine child layers).
// a stacking container. This means we can just walk the layer tree directly.
for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionLayer() != curr)
- clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
+ clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, subPixelAccumulation, paintBehavior));
}
}
}
static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
- TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
+ TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
// FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
// paintDirtyRect, and that should cut down on the amount we have to paint. Still it
LayoutPoint delta;
layer->convertToLayerCoords(rootLayerForTransform, delta);
+ delta.move(subPixelAccumulation);
+ IntPoint pixelSnappedDelta = roundedIntPoint(delta);
TransformationMatrix transform;
- transform.translate(delta.x(), delta.y());
+ transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y());
transform = transform * *layer->transform();
// We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
// paints unfragmented.
- LayoutRect clipRect = layer->boundingBox(layer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior);
+ 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;
}
- LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes);
- expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
+ 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, PaintBehavior paintBehavior)
+LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
- return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
+ return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paintDirtyRect);
}
-void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
+void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior paintBehavior)
{
- bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && m_childLayerHasBlendMode;
- if (context->paintingDisabled() || ((paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency))
+ bool createTransparencyLayerForBlendMode = m_stackingNode->isStackingContext() && hasDescendantWithBlendMode();
+ if ((paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) && m_usedTransparency)
return;
RenderLayer* ancestor = transparentPaintingAncestor();
if (ancestor)
- ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
+ ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
if (paintsWithTransparency(paintBehavior) || paintsWithBlendMode() || createTransparencyLayerForBlendMode) {
m_usedTransparency = true;
context->save();
- LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
+ LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, subPixelAccumulation, paintBehavior);
context->clip(clipRect);
+
if (paintsWithBlendMode())
- context->setCompositeOperation(context->compositeOperation(), m_blendMode);
+ context->setCompositeOperation(context->compositeOperation(), m_renderer->style()->blendMode());
context->beginTransparencyLayer(renderer()->opacity());
+
+ if (paintsWithBlendMode())
+ context->setCompositeOperation(context->compositeOperation(), WebBlendModeNormal);
#ifdef REVEAL_TRANSPARENCY_LAYERS
context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
context->fillRect(clipRect);
} else
setLastChild(child);
- child->setParent(this);
+ child->m_parent = this;
+
+ setNeedsCompositingInputsUpdate();
if (child->stackingNode()->isNormalFlowOnly())
m_stackingNode->dirtyNormalFlowList();
if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) {
- // Dirty the z-order list in which we are contained. The ancestorStackingContainerNode() can be null in the
+ // Dirty the z-order list in which we are contained. The ancestorStackingContextNode() can be null in the
// case where we're building up generated content layers. This is ok, since the lists will start
// off dirty in that case anyway.
- child->stackingNode()->dirtyStackingContainerZOrderLists();
+ child->stackingNode()->dirtyStackingContextZOrderLists();
}
- child->updateDescendantDependentFlags();
- if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
- setAncestorChainHasVisibleDescendant();
-
- if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant())
- setAncestorChainHasSelfPaintingLayerDescendant();
-
- if (child->paintsWithBlendMode() || child->childLayerHasBlendMode())
- setAncestorChainBlendedDescendant();
-
- if (subtreeContainsOutOfFlowPositionedLayer(child)) {
- // Now that the out of flow positioned descendant is in the tree, we
- // need to tell the compositor to reevaluate the compositing
- // requirements since we may be able to mark more layers as having
- // an 'unclipped' descendant.
- compositor()->setNeedsUpdateCompositingRequirementsState();
- setAncestorChainHasOutOfFlowPositionedDescendant();
- }
+ dirtyAncestorChainVisibleDescendantStatus();
+ dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
- // When we first dirty a layer, we will also dirty all the siblings in that
- // layer's stacking context. We need to manually do it here as well, in case
- // we're adding this layer after the stacking context has already been
- // updated.
- child->stackingNode()->setDescendantsAreContiguousInStackingOrderDirty(true);
- compositor()->layerWasAdded(this, child);
+ child->updateDescendantDependentFlags();
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
- if (!renderer()->documentBeingDestroyed())
- compositor()->layerWillBeRemoved(this, oldChild);
-
- // remove the child
if (oldChild->previousSibling())
oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
if (oldChild->nextSibling())
if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild()) {
// Dirty the z-order list in which we are contained. When called via the
// reattachment process in removeOnlyThisLayer, the layer may already be disconnected
- // from the main layer tree, so we need to null-check the |stackingContainer| value.
- oldChild->stackingNode()->dirtyStackingContainerZOrderLists();
+ // from the main layer tree, so we need to null-check the
+ // |stackingContext| value.
+ oldChild->stackingNode()->dirtyStackingContextZOrderLists();
}
+ if (renderer()->style()->visibility() != VISIBLE)
+ dirtyVisibleContentStatus();
+
oldChild->setPreviousSibling(0);
oldChild->setNextSibling(0);
- oldChild->setParent(0);
+ oldChild->m_parent = 0;
+
+ dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
oldChild->updateDescendantDependentFlags();
- if (subtreeContainsOutOfFlowPositionedLayer(oldChild)) {
- // It may now be the case that a layer no longer has an unclipped
- // descendant. Let the compositor know that it needs to reevaluate
- // its compositing requirements to check this.
- compositor()->setNeedsUpdateCompositingRequirementsState();
- dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
- }
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
dirtyAncestorChainVisibleDescendantStatus();
- if (oldChild->paintsWithBlendMode() || oldChild->childLayerHasBlendMode())
- dirtyAncestorChainBlendedDescendantStatus();
-
- if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
- dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
-
return oldChild;
}
if (!m_parent)
return;
- // Mark that we are about to lose our layer. This makes render tree
- // walks ignore this layer while we're removing it.
- m_renderer->setHasLayer(false);
-
- compositor()->layerWillBeRemoved(m_parent, this);
-
- // Dirty the clip rects.
m_clipper.clearClipRectsIncludingDescendants();
RenderLayer* nextSib = nextSibling();
RenderLayer* next = current->nextSibling();
removeChild(current);
m_parent->addChild(current, nextSib);
- current->repainter().setRepaintStatus(NeedsFullRepaint);
- // updateLayerPositions depends on hasLayer() already being false for proper layout.
- ASSERT(!renderer()->hasLayer());
- current->updateLayerPositions(0); // FIXME: use geometry map.
+
+ // FIXME: We should call a specialized version of this function.
+ current->updateLayerPositionsAfterLayout();
current = next;
}
}
// Remove all descendant layers from the hierarchy and add them to the new position.
- for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
+ for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
// Clear out all the clip rects.
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);
-}
-
// Returns the layer reached on the walk up towards the ancestor.
static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location)
{
// FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
// may need to be revisited in a future patch.
// If the fixed renderer is inside a RenderFlowThread, we should not compute location using localToAbsolute,
- // since localToAbsolute maps the coordinates from named flow to regions coordinates and regions can be
+ // since localToAbsolute maps the coordinates from flow thread to regions coordinates and regions can be
// positioned in a completely different place in the viewport (RenderView).
if (position == FixedPosition && !fixedFlowThreadContainer && (!ancestorLayer || ancestorLayer == renderer->view()->layer())) {
// If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
// We should not reach RenderView layer past the RenderFlowThread layer for any
// children of the RenderFlowThread.
- if (renderer->flowThreadContainingBlock() && !layer->isOutOfFlowRenderFlowThread())
- ASSERT(parentLayer != renderer->view()->layer());
+ ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer->view()->layer());
if (foundAncestorFirst) {
// Found ancestorLayer before the abs. positioned container, so compute offset of both relative
rect.move(-delta.x(), -delta.y());
}
-bool RenderLayer::adjustForForceCompositedScrollingMode(bool value) const
-{
- switch (m_forceNeedsCompositedScrolling) {
- case DoNotForceCompositedScrolling:
- return value;
- case CompositedScrollingAlwaysOn:
- return true;
- case CompositedScrollingAlwaysOff:
- return false;
- }
-
- ASSERT_NOT_REACHED();
- return value;
-}
-
-bool RenderLayer::needsCompositedScrolling() const
-{
- return adjustForForceCompositedScrollingMode(m_needsCompositedScrolling);
-}
-
-RenderLayer* RenderLayer::scrollParent() const
-{
- if (!compositorDrivenAcceleratedScrollingEnabled())
- return 0;
-
- // Normal flow elements will be parented under the main scrolling layer, so
- // we don't need a scroll parent/child relationship to get them to scroll.
- if (stackingNode()->isNormalFlowOnly())
- return 0;
-
- // A layer scrolls with its containing block. So to find the overflow scrolling layer
- // that we scroll with respect to, we must ascend the layer tree until we reach the
- // first overflow scrolling div at or above our containing block. I will refer to this
- // layer as our 'scrolling ancestor'.
- //
- // Now, if we reside in a normal flow list, then we will naturally scroll with our scrolling
- // ancestor, and we need not be composited. If, on the other hand, we reside in a z-order
- // list, and on our walk upwards to our scrolling ancestor we find no layer that is a stacking
- // context, then we know that in the stacking tree, we will not be in the subtree rooted at
- // our scrolling ancestor, and we will therefore not scroll with it. In this case, we must
- // be a composited layer since the compositor will need to take special measures to ensure
- // that we scroll with our scrolling ancestor and it cannot do this if we do not promote.
- RenderLayer* scrollParent = ancestorCompositedScrollingLayer();
-
- if (!scrollParent || scrollParent->stackingNode()->isStackingContainer())
- return 0;
-
- // If we hit a stacking context on our way up to the ancestor scrolling layer, it will already
- // be composited due to an overflow scrolling parent, so we don't need to.
- for (RenderLayer* ancestor = parent(); ancestor && ancestor != scrollParent; ancestor = ancestor->parent()) {
- if (ancestor->stackingNode()->isStackingContainer())
- return 0;
- }
-
- return scrollParent;
-}
-
-RenderLayer* RenderLayer::clipParent() const
-{
- const bool needsAncestorClip = compositor()->clippedByAncestor(this);
-
- RenderLayer* clipParent = 0;
- if ((compositingReasons() & CompositingReasonOutOfFlowClipping) && !needsAncestorClip) {
- if (RenderObject* containingBlock = renderer()->containingBlock())
- clipParent = containingBlock->enclosingLayer()->enclosingCompositingLayer(true);
- }
-
- return clipParent;
-}
-
-void RenderLayer::setForceNeedsCompositedScrolling(RenderLayer::ForceNeedsCompositedScrollingMode mode)
-{
- if (m_forceNeedsCompositedScrolling == mode)
- return;
-
- m_forceNeedsCompositedScrolling = mode;
- didUpdateNeedsCompositedScrolling();
-}
-
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 = adoptPtrWillBeNoop(new RenderLayerReflectionInfo(*renderBox()));
m_reflectionInfo->updateAfterStyleChange(oldStyle);
} else if (m_reflectionInfo) {
+ m_reflectionInfo->destroy();
m_reflectionInfo = nullptr;
}
}
void RenderLayer::updateScrollableArea()
{
if (requiresScrollableArea())
- m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(renderBox()));
+ m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this));
else
m_scrollableArea = nullptr;
}
-PassOwnPtr<Vector<FloatRect> > RenderLayer::collectTrackedRepaintRects() const
-{
- if (CompositedLayerMapping* mapping = compositedLayerMapping())
- return mapping->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, RenderRegion* region, PaintLayerFlags paintFlags)
+void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, PaintLayerFlags paintFlags)
{
- OverlapTestRequestMap overlapTestRequests;
-
- LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot, region, &overlapTestRequests);
- paintLayer(context, paintingInfo, paintFlags);
-
- OverlapTestRequestMap::iterator end = overlapTestRequests.end();
- for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
- it->key->setIsOverlapped(false);
+ LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), paintingRoot);
+ if (shouldPaintLayerInSoftwareMode(paintingInfo, paintFlags))
+ paintLayer(context, paintingInfo, paintFlags);
}
void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* paintingRoot)
return false;
}
-void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect,
- BorderRadiusClippingRule rule)
+void RenderLayer::clipToRect(const LayerPaintingInfo& localPaintingInfo, GraphicsContext* context, const ClipRect& clipRect,
+ PaintLayerFlags paintFlags, BorderRadiusClippingRule rule)
{
- if (clipRect.rect() == paintDirtyRect && !clipRect.hasRadius())
+ if (clipRect.rect() == localPaintingInfo.paintDirtyRect && !clipRect.hasRadius())
return;
context->save();
context->clip(pixelSnappedIntRect(clipRect.rect()));
// any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
// containing block chain so we check that also.
for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
+ // Composited scrolling layers handle border-radius clip in the compositor via a mask layer. We do not
+ // want to apply a border-radius clip to the layer contents itself, because that would require re-rastering
+ // every frame to update the clip. We only want to make sure that the mask layer is properly clipped so
+ // that it can in turn clip the scrolled contents in the compositor.
+ if (layer->needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase))
+ break;
+
if (layer->renderer()->hasOverflowClip() && layer->renderer()->style()->hasBorderRadius() && inContainingBlockChain(this, layer)) {
LayoutPoint delta;
- layer->convertToLayerCoords(rootLayer, delta);
+ layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta);
context->clipRoundedRect(layer->renderer()->style()->getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
}
- if (layer == rootLayer)
+ if (layer == localPaintingInfo.rootLayer)
break;
}
}
context->restore();
}
-static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
-{
- Vector<RenderWidget*> overlappedRequestClients;
- OverlapTestRequestMap::iterator end = overlapTestRequests.end();
- LayoutRect boundingBox = layer->boundingBox(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)
{
// Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
// It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
- // will do a full repaint().
- if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isRoot())
+ // will do a full paintInvalidationForWholeRenderer().
+ if (layer->renderer()->document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer()->isDocumentElement())
return true;
return false;
static bool paintForFixedRootBackground(const RenderLayer* layer, PaintLayerFlags paintFlags)
{
- return layer->renderer()->isRoot() && (paintFlags & PaintLayerPaintingRootBackgroundOnly);
+ return layer->renderer()->isDocumentElement() && (paintFlags & PaintLayerPaintingRootBackgroundOnly);
+}
+
+static ShouldRespectOverflowClip shouldRespectOverflowClip(PaintLayerFlags paintFlags, const RenderObject* renderer)
+{
+ return (paintFlags & PaintLayerPaintingOverflowContents || (paintFlags & PaintLayerPaintingChildClippingMaskPhase && renderer->hasClipPath())) ? IgnoreOverflowClip : RespectOverflowClip;
}
void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
+ // https://code.google.com/p/chromium/issues/detail?id=343772
+ DisableCompositingQueryAsserts disabler;
+
if (compositingState() != NotComposited) {
- // The updatingControlTints() painting pass goes through compositing layers,
- // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
- if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)) {
- paintFlags |= PaintLayerTemporaryClipRects;
- } else if (!compositedLayerMapping()->paintsIntoCompositedAncestor()
- && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)
- && !paintForFixedRootBackground(this, paintFlags)) {
- // If this RenderLayer should paint into its own backing, that will be done via CompositedLayerMapping::paintIntoLayer().
- return;
+ if (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers) {
+ // FIXME: ok, but what about PaintBehaviorFlattenCompositingLayers? That's for printing.
+ // FIXME: why isn't the code here global, as opposed to being set on each paintLayer() call?
+ paintFlags |= PaintLayerUncachedClipRects;
}
- } else if (viewportConstrainedNotCompositedReason() == NotCompositedForBoundsOutOfView) {
- // Don't paint out-of-view viewport constrained layers (when doing prepainting) because they will never be visible
- // unless their position or viewport size is changed.
- return;
}
// Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
// layer from the parent now, assuming there is a parent
if (paintFlags & PaintLayerHaveTransparency) {
if (parent())
- parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
+ parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
else
- beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
+ beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
}
if (enclosingPaginationLayer()) {
// Make sure the parent's clip rects have been calculated.
ClipRect clipRect = paintingInfo.paintDirtyRect;
if (parent()) {
- ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
- IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
- clipRect = backgroundClipRect(clipRectsContext);
+ ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize);
+ if (shouldRespectOverflowClip(paintFlags, renderer()) == IgnoreOverflowClip)
+ clipRectsContext.setIgnoreOverflowClip();
+ clipRect = clipper().backgroundClipRect(clipRectsContext);
clipRect.intersect(paintingInfo.paintDirtyRect);
// Push the parent coordinate space's clip.
- parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->clipToRect(paintingInfo, context, clipRect, paintFlags);
}
paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
// the outline is painted in the background phase during composited scrolling.
// If it were painted in the foreground phase, it would move with the scrolled
// content. When not composited scrolling, the outline is painted in the
- // foreground phase. Since scrolled contents are moved by repainting in this
+ // foreground phase. Since scrolled contents are moved by paint invalidation in this
// case, the outline won't get 'dragged along'.
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);
+ float deviceScaleFactor = blink::deviceScaleFactor(renderer()->frame());
+ context->setDeviceScaleFactor(deviceScaleFactor);
GraphicsContext* transparencyLayerContext = context;
- if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isRoot())
+ if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer()->isRenderView() && !renderer()->isDocumentElement())
return;
// Ensure our lists are up-to-date.
LayoutPoint offsetFromRoot;
convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
- IntRect rootRelativeBounds;
+ if (compositingState() == PaintsIntoOwnBacking)
+ offsetFromRoot.move(subpixelAccumulation());
+
+ LayoutRect rootRelativeBounds;
bool rootRelativeBoundsComputed = false;
// Apply clip-path to context.
- bool hasClipPath = false;
+ GraphicsContextStateSaver clipStateSaver(*context, false);
RenderStyle* style = renderer()->style();
RenderSVGResourceClipper* resourceClipper = 0;
- ClipperContext clipperContext;
- if (renderer()->hasClipPath() && !context->paintingDisabled() && style) {
+ RenderSVGResourceClipper::ClipperState clipperState = RenderSVGResourceClipper::ClipperNotApplied;
+
+ // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container.
+ // It must, however, still be applied to the mask layer, so that the compositor can properly mask the
+ // scrolling contents and scrollbars.
+ if (renderer()->hasClipPath() && style && (!needsCompositedScrolling() || paintFlags & PaintLayerPaintingChildClippingMaskPhase)) {
ASSERT(style->clipPath());
- if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) {
- hasClipPath = true;
- context->save();
- ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath());
-
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
+ if (style->clipPath()->type() == ClipPathOperation::SHAPE) {
+ ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style->clipPath());
+ if (clipPath->isValid()) {
+ clipStateSaver.save();
+
+ if (!rootRelativeBoundsComputed) {
+ rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
+ rootRelativeBoundsComputed = true;
+ }
- context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
- } else if (style->clipPath()->getOperationType() == ClipPathOperation::REFERENCE) {
- ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath());
+ context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
+ }
+ } else if (style->clipPath()->type() == ClipPathOperation::REFERENCE) {
+ ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style->clipPath());
Document& document = renderer()->document();
// FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
Element* element = document.getElementById(referenceClipPathOperation->fragment());
- if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
+ if (isSVGClipPathElement(element) && element->renderer()) {
+ // FIXME: Saving at this point is not required in the 'mask'-
+ // case, or if the clip ends up empty.
+ clipStateSaver.save();
if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
rootRelativeBoundsComputed = true;
}
resourceClipper = toRenderSVGResourceClipper(toRenderSVGResourceContainer(element->renderer()));
if (!resourceClipper->applyClippingToContext(renderer(), rootRelativeBounds,
- paintingInfo.paintDirtyRect, context, clipperContext)) {
+ paintingInfo.paintDirtyRect, context, clipperState)) {
// No need to post-apply the clipper if this failed.
resourceClipper = 0;
}
// Blending operations must be performed only with the nearest ancestor stacking context.
// Note that there is no need to create a transparency layer if we're painting the root.
- bool createTransparencyLayerForBlendMode = !renderer()->isRoot() && m_stackingNode->isStackingContext() && m_childLayerHasBlendMode;
+ bool createTransparencyLayerForBlendMode = !renderer()->isDocumentElement() && m_stackingNode->isStackingContext() && hasDescendantWithBlendMode();
if (createTransparencyLayerForBlendMode)
- beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
+ beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
LayerPaintingInfo localPaintingInfo(paintingInfo);
+ bool deferredFiltersEnabled = renderer()->document().settings()->deferredFiltersEnabled();
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);
- rootRelativeBoundsComputed = true;
- }
- if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
- // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
- filterInfo->resetDirtySourceRect();
+ LayerFragments layerFragments;
+ if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
+ // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
+ // fragment should paint.
+ collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect,
+ (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ shouldRespectOverflowClip(paintFlags, renderer()), &offsetFromRoot, localPaintingInfo.subPixelAccumulation);
+ updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot);
+ }
+
+ if (filterPainter.haveFilterEffect()) {
+ ASSERT(this->filterInfo());
+
+ if (!rootRelativeBoundsComputed)
+ rootRelativeBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
+
+ if (filterPainter.prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect)) {
// Rewire the old context to a memory buffer, so that we can capture the contents of the layer.
// NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer
// on the original context and avoid duplicating "beginFilterEffect" after each transparency layer call. Also, note that
// beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method.
+ // With deferred filters, we don't need a separate context, but we do need to do transparency and clipping before starting
+ // filter processing.
+ // FIXME: when the legacy path is removed, remove the transparencyLayerContext as well.
+ ClipRect backgroundRect;
+ if (deferredFiltersEnabled) {
+ if (haveTransparency) {
+ // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one after filter processing.
+ beginTransparencyLayers(context, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
+ }
+ // We'll handle clipping to the dirty rect before filter rasterization.
+ // Filter processing will automatically expand the clip rect and the offscreen to accommodate any filter outsets.
+ // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
+ backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
+ clipToRect(localPaintingInfo, context, backgroundRect, paintFlags);
+ // Subsequent code should not clip to the dirty rect, since we've already
+ // done it above, and doing it later will defeat the outsets.
+ localPaintingInfo.clipToDirtyRect = false;
+ }
context = filterPainter.beginFilterEffect(context);
+ if (!filterPainter.hasStartedFilterEffect() && deferredFiltersEnabled) {
+ // If the the filter failed to start, undo the clip immediately
+ restoreClip(context, localPaintingInfo.paintDirtyRect, backgroundRect);
+ }
+
// Check that we didn't fail to allocate the graphics context for the offscreen buffer.
- if (filterPainter.hasStartedFilterEffect()) {
- localPaintingInfo.paintDirtyRect = filterPainter.repaintRect();
+ if (filterPainter.hasStartedFilterEffect() && !deferredFiltersEnabled) {
+ localPaintingInfo.paintDirtyRect = filterPainter.paintInvalidationRect();
// If the filter needs the full source image, we need to avoid using the clip rectangles.
// Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
// Note that we will still apply the clipping on the final rendering of the filter.
}
}
- if (filterPainter.hasStartedFilterEffect() && haveTransparency) {
+ if (filterPainter.hasStartedFilterEffect() && haveTransparency && !deferredFiltersEnabled) {
// If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
}
// If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
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;
+ ASSERT(!(localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText));
bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly;
else if (paintFlags & PaintLayerPaintingRootBackgroundOnly)
paintBehavior |= PaintBehaviorRootBackgroundOnly;
- LayerFragments layerFragments;
- if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
- // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
- // fragment should paint.
- collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.region, localPaintingInfo.paintDirtyRect,
- (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
- (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot);
- updatePaintingInfoForFragments(layerFragments, localPaintingInfo, paintFlags, shouldPaintContent, &offsetFromRoot);
- }
-
- if (shouldPaintBackground)
+ if (shouldPaintBackground) {
paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
- localPaintingInfo, paintBehavior, paintingRootForRenderer);
+ localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
+ }
if (shouldPaintNegZOrderList)
- paintList(m_stackingNode->negZOrderList(), context, localPaintingInfo, paintFlags);
+ paintChildren(NegativeZOrderChildren, context, paintingInfo, paintFlags);
- if (shouldPaintOwnContents)
+ if (shouldPaintOwnContents) {
paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
- localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, forceBlackText);
+ localPaintingInfo, paintBehavior, paintingRootForRenderer, selectionOnly, paintFlags);
+ }
if (shouldPaintOutline)
- paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer);
+ paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
- if (shouldPaintNormalFlowAndPosZOrderLists) {
- paintList(m_stackingNode->normalFlowList(), context, localPaintingInfo, paintFlags);
- paintList(m_stackingNode->posZOrderList(), context, localPaintingInfo, paintFlags);
- }
+ if (shouldPaintNormalFlowAndPosZOrderLists)
+ paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, paintingInfo, paintFlags);
if (shouldPaintOverlayScrollbars)
- paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo);
+ paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo, paintFlags);
if (filterPainter.hasStartedFilterEffect()) {
// Apply the correct clipping (ie. overflow: hidden).
// FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
- clipToRect(localPaintingInfo.rootLayer, transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect);
+ if (!deferredFiltersEnabled)
+ clipToRect(localPaintingInfo, transparencyLayerContext, backgroundRect, paintFlags);
+
context = filterPainter.applyFilterEffect();
restoreClip(transparencyLayerContext, localPaintingInfo.paintDirtyRect, backgroundRect);
}
ASSERT(transparencyLayerContext == context);
if (shouldPaintMask)
- paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer);
+ paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags);
if (shouldPaintClippingMask) {
// Paint the border radius mask for the fragments.
- paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer);
+ paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForRenderer, paintFlags);
}
// End our transparency layer
}
if (resourceClipper)
- resourceClipper->postApplyStatefulResource(renderer(), context, clipperContext);
-
- if (hasClipPath)
- context->restore();
+ resourceClipper->postApplyStatefulResource(renderer(), context, clipperState);
}
void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
// Apply the transform.
- GraphicsContextStateSaver stateSaver(*context);
- context->concatCTM(transform.toAffineTransform());
+ GraphicsContextStateSaver stateSaver(*context, false);
+ if (!transform.isIdentity()) {
+ stateSaver.save();
+ context->concatCTM(transform.toAffineTransform());
+ }
// Now do a paint with the root layer shifted to be us.
LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior,
- adjustedSubPixelAccumulation, paintingInfo.paintingRoot, paintingInfo.region, paintingInfo.overlapTestRequests);
+ adjustedSubPixelAccumulation, paintingInfo.paintingRoot);
paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
}
-void RenderLayer::paintList(Vector<RenderLayerStackingNode*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+bool RenderLayer::shouldPaintLayerInSoftwareMode(const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
- if (!list)
- return;
+ DisableCompositingQueryAsserts disabler;
+ return compositingState() == NotComposited
+ || compositingState() == HasOwnBackingButPaintsIntoAncestor
+ || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)
+ || ((paintFlags & PaintLayerPaintingReflection) && !has3DTransform())
+ || paintForFixedRootBackground(this, paintFlags);
+}
+
+void RenderLayer::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+{
if (!hasSelfPaintingLayerDescendant())
return;
-#if !ASSERT_DISABLED
+#if ENABLE(ASSERT)
LayerListMutationDetector mutationChecker(m_stackingNode.get());
#endif
- for (size_t i = 0; i < list->size(); ++i) {
- RenderLayer* childLayer = list->at(i)->layer();
+ RenderLayerStackingNodeIterator iterator(*m_stackingNode, childrenToVisit);
+ while (RenderLayerStackingNode* child = iterator.next()) {
+ RenderLayer* childLayer = child->layer();
+ // If this RenderLayer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
+ // and CompositedLayerMapping::doPaintTask().
+ if (!childLayer->shouldPaintLayerInSoftwareMode(paintingInfo, paintFlags))
+ continue;
+
if (!childLayer->isPaginated())
childLayer->paintLayer(context, paintingInfo, paintFlags);
else
}
}
-void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect,
- ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
- const LayoutRect* layerBoundingBox)
+void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect,
+ ClipRectsCacheSlot clipRectsCacheSlot, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
+ const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox)
{
if (!enclosingPaginationLayer() || hasTransform()) {
// For unpaginated layers, there is only one fragment.
LayerFragment fragment;
- ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
- calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
+ ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy, subPixelAccumulation);
+ if (respectOverflowClip == IgnoreOverflowClip)
+ clipRectsContext.setIgnoreOverflowClip();
+ clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
fragments.append(fragment);
return;
}
// Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
// layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
- ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
+ if (respectOverflowClip == IgnoreOverflowClip)
+ paginationClipRectsContext.setIgnoreOverflowClip();
LayoutRect layerBoundsInFlowThread;
ClipRect backgroundRectInFlowThread;
ClipRect foregroundRectInFlowThread;
ClipRect outlineRectInFlowThread;
- calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
+ clipper().calculateRects(paginationClipRectsContext, PaintInfo::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
outlineRectInFlowThread, &offsetWithinPaginatedLayer);
// Take our bounding box within the flow thread and clip it.
- LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);
+ LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer);
layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
// Shift the dirty rect into flow thread coordinates.
// Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
ClipRect ancestorClipRect = dirtyRect;
if (enclosingPaginationLayer()->parent()) {
- ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
- ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext);
+ ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
+ if (respectOverflowClip == IgnoreOverflowClip)
+ clipRectsContext.setIgnoreOverflowClip();
+ ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext);
ancestorClipRect.intersect(dirtyRect);
}
{
LayerFragments enclosingPaginationFragments;
LayoutPoint offsetOfPaginationLayerFromRoot;
- LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
- enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect,
- (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
- (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+ LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior);
+ enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect,
+ (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ shouldRespectOverflowClip(paintFlags, renderer()), &offsetOfPaginationLayerFromRoot, paintingInfo.subPixelAccumulation, &transformedExtent);
for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
const LayerFragment& fragment = enclosingPaginationFragments.at(i);
if (parent() != enclosingPaginationLayer()) {
enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot);
- ClipRectsContext clipRectsContext(enclosingPaginationLayer(), paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
- IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
- LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
+ ClipRectsContext clipRectsContext(enclosingPaginationLayer(), (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize);
+ if (shouldRespectOverflowClip(paintFlags, renderer()) == IgnoreOverflowClip)
+ clipRectsContext.setIgnoreOverflowClip();
+ LayoutRect parentClipRect = clipper().backgroundClipRect(clipRectsContext).rect();
parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
clipRect.intersect(parentClipRect);
}
- parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->clipToRect(paintingInfo, context, clipRect, paintFlags);
paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
}
}
+static inline LayoutSize subPixelAccumulationIfNeeded(const LayoutSize& subPixelAccumulation, CompositingState compositingState)
+{
+ // Only apply the sub-pixel accumulation if we don't paint into our own backing layer, otherwise the position
+ // of the renderer already includes any sub-pixel offset.
+ 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)
+ RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency || paintsWithBlendMode())
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
if (localPaintingInfo.clipToDirtyRect) {
// Paint our background first, before painting any child layers.
// Establish the clip used to paint our background.
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
+ clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
}
// Paint the background.
// FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
- renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, paintingRootForRenderer, 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)
+ RenderObject* paintingRootForRenderer, bool selectionOnly, PaintLayerFlags paintFlags)
{
// Begin transparency if we have something to paint.
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.paintBehavior);
+ beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.subPixelAccumulation, localPaintingInfo.paintBehavior);
break;
}
}
}
- PaintBehavior localPaintBehavior = forceBlackText ? (PaintBehavior)PaintBehaviorForceBlackText : paintBehavior;
-
// Optimize clipping for the single fragment case.
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
if (shouldClip)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, layerFragments[0].foregroundRect);
+ clipToRect(localPaintingInfo, context, layerFragments[0].foregroundRect, paintFlags);
- // We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for
+ // We have to loop through every fragment multiple times, since we have to issue paint invalidations in each specific phase in order for
// interleaving of the fragments to work properly.
paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, layerFragments,
- context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
+ context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
if (!selectionOnly) {
- paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
- paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
- paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, paintingRootForRenderer);
+ paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
+ paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
+ paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, paintBehavior, paintingRootForRenderer, paintFlags);
}
if (shouldClip)
}
void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context,
- const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer)
+ const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
{
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
continue;
if (shouldClip)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
+ clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags);
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
- if (phase == PaintPhaseForeground)
- paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
- renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
+ 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)
+ PaintBehavior paintBehavior, RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
continue;
// Paint our own outline
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.outlineRect, DoNotIncludeSelfForBorderRadius);
- renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, paintingRootForRenderer, 0, localPaintingInfo.rootLayer->renderer());
+ clipToRect(localPaintingInfo, context, fragment.outlineRect, paintFlags, 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)
+ RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
continue;
if (localPaintingInfo.clipToDirtyRect)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
+ clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
// Paint the mask.
// FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
- renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, paintingRootForRenderer, 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)
+ RenderObject* paintingRootForRenderer, PaintLayerFlags paintFlags)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
continue;
if (localPaintingInfo.clipToDirtyRect)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self.
+ clipToRect(localPaintingInfo, context, fragment.foregroundRect, paintFlags, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self.
// Paint the the clipped mask.
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, localPaintingInfo.region, 0, 0, localPaintingInfo.rootLayer->renderer());
- renderer()->paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseClippingMask, PaintBehaviorNormal, paintingRootForRenderer, 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)
+void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags paintFlags)
{
for (size_t i = 0; i < layerFragments.size(); ++i) {
const LayerFragment& fragment = layerFragments.at(i);
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ clipToRect(localPaintingInfo, context, fragment.backgroundRect, paintFlags);
if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea())
- scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)), pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
+ scrollableArea->paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + subPixelAccumulationIfNeeded(localPaintingInfo.subPixelAccumulation, compositingState()))), pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
}
}
{
// We need to do multiple passes, breaking up our child layer into strips.
Vector<RenderLayer*> columnLayers;
- RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContainerNode();
+ RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode();
for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
columnLayers.append(curr);
}
// It is possible for paintLayer() to be called after the child layer ceases to be paginated but before
- // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
- // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer.
+ // updatePaginationRecusive() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
+ // If this is the case, just bail out, since the upcoming call to updatePaginationRecusive() will paint invalidate the layer.
+ // FIXME: Is this true anymore? This seems very suspicious.
if (!columnLayers.size())
return;
// Each strip pushes a clip, since column boxes are specified as being
// like overflow:hidden.
- context->clip(pixelSnappedIntRect(colRect));
+ context->clip(enclosingIntRect(colRect));
if (!colIndex) {
// Apply a translation transform to change where the layer paints.
// RenderView should make sure to update layout before entering hit testing
ASSERT(!renderer()->frame()->view()->layoutPending());
- ASSERT(!renderer()->document().renderer()->needsLayout());
+ ASSERT(!renderer()->document().renderView()->needsLayout());
- LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect();
+ LayoutRect hitTestArea = renderer()->view()->documentRect();
if (!request.ignoreClipping())
hitTestArea.intersect(frameVisibleRect(renderer()));
// We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
// return ourselves. We do this so mouse events continue getting delivered after a drag has
// exited the WebView, and so hit testing over a scrollbar hits the content document.
- if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) {
+ // In addtion, it is possible for the mouse to stay in the document but there is no element.
+ // At that time, the events of the mouse should be fired.
+ LayoutPoint hitPoint = hitTestLocation.point();
+ if (!request.isChildFrameHitTest() && ((request.active() || request.release()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y()))) && isRootLayer()) {
renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(hitTestLocation.point()));
insideLayer = this;
}
// Now determine if the result is inside an anchor - if the urlElement isn't already set.
Node* node = result.innerNode();
if (node && !result.URLElement())
- result.setURLElement(toElement(node->enclosingLinkEventParentOrSelf()));
+ result.setURLElement(node->enclosingLinkEventParentOrSelf());
// Now return whether we were inside this layer (this will always be true for the root
// layer).
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;
-}
-
// Compute the z-offset of the point in the transformState.
// This is effectively projecting a ray normal to the plane of ancestor, finding where that
// ray intersects target, and computing the z delta between those two points.
// Make sure the parent's clip rects have been calculated.
if (parent()) {
- ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
- ClipRect clipRect = backgroundClipRect(clipRectsContext);
+ ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize));
// Go ahead and test the enclosing clip now.
if (!clipRect.intersects(hitTestLocation))
return 0;
// The following are used for keeping track of the z-depth of the hit point of 3d-transformed
// descendants.
- double localZOffset = -numeric_limits<double>::infinity();
+ double localZOffset = -std::numeric_limits<double>::infinity();
double* zOffsetForDescendantsPtr = 0;
double* zOffsetForContentsPtr = 0;
// Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
- } else if (m_has3DTransformedDescendant) {
- // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground.
- depthSortDescendants = true;
- zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
- zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
} else if (zOffset) {
zOffsetForDescendantsPtr = 0;
// Container needs us to give back a z offset for the hit layer.
RenderLayer* candidateLayer = 0;
// Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
- RenderLayer* hitLayer = hitTestList(m_stackingNode->posZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation,
+ RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
}
// Now check our overflow objects.
- hitLayer = hitTestList(m_stackingNode->normalFlowList(), rootLayer, request, result, hitTestRect, hitTestLocation,
+ hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
// Collect the fragments. This will compute the clip rectangles for each layer fragment.
LayerFragments layerFragments;
- collectFragments(layerFragments, rootLayer, hitTestLocation.region(), hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
+ collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) {
renderer()->updateHitTestResult(result, hitTestLocation.point());
}
// Now check our negative z-index children.
- hitLayer = hitTestList(m_stackingNode->negZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation,
+ hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
if (hitLayer) {
if (!depthSortDescendants)
{
LayerFragments enclosingPaginationFragments;
LayoutPoint offsetOfPaginationLayerFromRoot;
- LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
- enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect,
- RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+ // FIXME: We're missing a sub-pixel offset here crbug.com/348728
+ 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);
// Now compute the clips within a given fragment
if (parent() != enclosingPaginationLayer()) {
enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
-
- ClipRectsContext clipRectsContext(enclosingPaginationLayer(), hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
- LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
+ LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsContext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbarSize)).rect();
parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
clipRect.intersect(parentClipRect);
}
return true;
}
-RenderLayer* RenderLayer::hitTestList(Vector<RenderLayerStackingNode*>* list, 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)
+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 (!list)
- return 0;
-
if (!hasSelfPaintingLayerDescendant())
return 0;
RenderLayer* resultLayer = 0;
- for (int i = list->size() - 1; i >= 0; --i) {
- RenderLayer* childLayer = list->at(i)->layer();
+ RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoVisit);
+ while (RenderLayerStackingNode* child = iterator.next()) {
+ RenderLayer* childLayer = child->layer();
RenderLayer* hitLayer = 0;
HitTestResult tempResult(result.hitTestLocation());
if (childLayer->isPaginated())
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
{
Vector<RenderLayer*> columnLayers;
- RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContainerNode();
+ RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ? parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode();
for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
columnLayers.append(curr);
return 0;
}
-void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
+void RenderLayer::blockSelectionGapsBoundsChanged()
{
- ASSERT(parent());
- if (clipRectsContext.clipRectsType == TemporaryClipRects) {
- parent()->clipper().calculateClipRects(clipRectsContext, clipRects);
- return;
- }
-
- parent()->m_clipper.updateClipRects(clipRectsContext);
- clipRects = *parent()->clipper().clipRects(clipRectsContext);
-}
-
-static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position)
-{
- if (position == FixedPosition)
- return parentRects.fixedClipRect();
-
- if (position == AbsolutePosition)
- return parentRects.posClipRect();
-
- return parentRects.overflowClipRect();
-}
-
-ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const
-{
- ASSERT(parent());
-
- ClipRects parentRects;
-
- // If we cross into a different pagination context, then we can't rely on the cache.
- // Just switch over to using TemporaryClipRects.
- if (clipRectsContext.clipRectsType != TemporaryClipRects && parent()->enclosingPaginationLayer() != enclosingPaginationLayer()) {
- ClipRectsContext tempContext(clipRectsContext);
- tempContext.clipRectsType = TemporaryClipRects;
- parentClipRects(tempContext, parentRects);
- } else
- parentClipRects(clipRectsContext, parentRects);
-
- ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position());
- RenderView* view = renderer()->view();
- ASSERT(view);
-
- // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
- if (parentRects.fixed() && clipRectsContext.rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect())
- backgroundClipRect.move(view->frameView()->scrollOffsetForFixedPosition());
-
- return backgroundClipRect;
-}
-
-void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
- ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const
-{
- if (clipRectsContext.rootLayer != this && parent()) {
- backgroundRect = backgroundClipRect(clipRectsContext);
- backgroundRect.intersect(paintDirtyRect);
- } else
- backgroundRect = paintDirtyRect;
-
- foregroundRect = backgroundRect;
- outlineRect = backgroundRect;
-
- LayoutPoint offset;
- if (offsetFromRoot)
- offset = *offsetFromRoot;
- else
- convertToLayerCoords(clipRectsContext.rootLayer, offset);
- layerBounds = LayoutRect(offset, size());
-
- // Update the clip rects that will be passed to child layers.
- if (renderer()->hasOverflowClip()) {
- // This layer establishes a clip of some kind.
- if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip) {
- foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy));
- if (renderer()->style()->hasBorderRadius())
- foregroundRect.setHasRadius(true);
- }
-
- // If we establish an overflow clip at all, then go ahead and make sure our background
- // rect is intersected with our layer's bounds including our visual overflow,
- // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden.
- if (renderBox()->hasVisualOverflow()) {
- // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though
- // we may need to inflate our clip specifically for shadows or outsets.
- // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the
- // individual region boxes as overflow.
- LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect();
- renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped.
- layerBoundsWithVisualOverflow.moveBy(offset);
- if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
- backgroundRect.intersect(layerBoundsWithVisualOverflow);
- } else {
- // Shift the bounds to be for our region only.
- LayoutRect bounds = renderBox()->borderBoxRectInRegion(clipRectsContext.region);
- bounds.moveBy(offset);
- if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
- backgroundRect.intersect(bounds);
- }
- }
-
- // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box.
- if (renderer()->hasClip()) {
- // Clip applies to *us* as well, so go ahead and update the damageRect.
- LayoutRect newPosClip = toRenderBox(renderer())->clipRect(offset, clipRectsContext.region);
- backgroundRect.intersect(newPosClip);
- foregroundRect.intersect(newPosClip);
- outlineRect.intersect(newPosClip);
- }
-}
-
-LayoutRect RenderLayer::childrenClipRect() const
-{
- // FIXME: border-radius not accounted for.
- // FIXME: Regions not accounted for.
- RenderView* renderView = renderer()->view();
- RenderLayer* clippingRootLayer = clippingRootForPainting();
- LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects);
- // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
- calculateRects(clipRectsContext, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
-}
-
-LayoutRect RenderLayer::selfClipRect() const
-{
- // FIXME: border-radius not accounted for.
- // FIXME: Regions not accounted for.
- RenderView* renderView = renderer()->view();
- RenderLayer* clippingRootLayer = clippingRootForPainting();
- LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
- calculateRects(clipRectsContext, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox();
-}
-
-LayoutRect RenderLayer::localClipRect() const
-{
- // FIXME: border-radius not accounted for.
- // FIXME: Regions not accounted for.
- RenderLayer* clippingRootLayer = clippingRootForPainting();
- LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
- calculateRects(clipRectsContext, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
-
- LayoutRect clipRect = backgroundRect.rect();
- if (clipRect == PaintInfo::infiniteRect())
- return clipRect;
-
- LayoutPoint clippingRootOffset;
- convertToLayerCoords(clippingRootLayer, clippingRootOffset);
- clipRect.moveBy(-clippingRootOffset);
-
- return clipRect;
+ setNeedsCompositingInputsUpdate();
}
void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds)
{
m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds));
+ blockSelectionGapsBoundsChanged();
}
void RenderLayer::clearBlockSelectionGapsBounds()
m_blockSelectionGapsBounds = IntRect();
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->clearBlockSelectionGapsBounds();
+ blockSelectionGapsBoundsChanged();
}
-void RenderLayer::repaintBlockSelectionGaps()
+void RenderLayer::invalidatePaintForBlockSelectionGaps()
{
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->repaintBlockSelectionGaps();
+ child->invalidatePaintForBlockSelectionGaps();
if (m_blockSelectionGapsBounds.isEmpty())
return;
RenderBox* box = renderBox();
rect.move(-box->scrolledContentOffset());
if (!scrollableArea()->usesCompositedScrolling())
- rect.intersect(box->overflowClipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for.
+ rect.intersect(box->overflowClipRect(LayoutPoint()));
}
if (renderer()->hasClip())
- rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for.
+ rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint()));
if (!rect.isEmpty())
- renderer()->repaintRectangle(rect);
+ renderer()->invalidatePaintRectangle(rect);
+}
+
+IntRect RenderLayer::blockSelectionGapsBounds() const
+{
+ if (!renderer()->isRenderBlock())
+ return IntRect();
+
+ RenderBlock* renderBlock = toRenderBlock(renderer());
+ LayoutRect gapRects = renderBlock->selectionGapRectsForPaintInvalidation(renderBlock);
+
+ return pixelSnappedIntRect(gapRects);
}
bool RenderLayer::hasBlockSelectionGapBounds() const
{
- return !m_blockSelectionGapsBounds.isEmpty();
+ // FIXME: it would be more accurate to return !blockSelectionGapsBounds().isEmpty(), but this is impossible
+ // at the moment because it causes invalid queries to layout-dependent code (crbug.com/372802).
+ // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::LayoutClean);
+
+ if (!renderer()->isRenderBlock())
+ return false;
+
+ return toRenderBlock(renderer())->shouldPaintSelectionGaps();
}
bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const
{
// Always examine the canvas and the root.
- // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
+ // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
// paints the root's background.
- if (isRootLayer() || renderer()->isRoot())
+ if (isRootLayer() || renderer()->isDocumentElement())
return true;
// If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
RenderView* view = renderer()->view();
ASSERT(view);
if (view && !renderer()->isRenderInline()) {
- LayoutRect b = layerBounds;
- b.inflate(view->maximalOutlineSize());
- if (b.intersects(damageRect))
+ if (layerBounds.intersects(damageRect))
return true;
}
// Otherwise we need to compute the bounding box of this single layer and see if it intersects
// the damage rect.
- return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect);
+ return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
}
-LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
+LayoutRect RenderLayer::logicalBoundingBox() const
{
// There are three special cases we need to consider.
// (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
// as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
// floats.
LayoutRect result;
- if (renderer()->isInline() && renderer()->isRenderInline())
+ if (renderer()->isInline() && renderer()->isRenderInline()) {
result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
- else if (renderer()->isTableRow()) {
+ } else if (renderer()->isTableRow()) {
// Our bounding box is just the union of all of our cells' border/overflow rects.
- for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
+ for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
if (child->isTableCell()) {
LayoutRect bbox = toRenderBox(child)->borderBoxRect();
result.unite(bbox);
} else {
RenderBox* box = renderBox();
ASSERT(box);
- if (!(flags & DontConstrainForMask) && box->hasMask()) {
- result = box->maskClipRect();
- box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not.
- } else {
- LayoutRect bbox = box->borderBoxRect();
- result = bbox;
- LayoutRect overflowRect = box->visualOverflowRect();
- if (bbox != overflowRect)
- result.unite(overflowRect);
- }
+ result = box->borderBoxRect();
+ result.unite(box->visualOverflowRect());
}
- RenderView* view = renderer()->view();
- ASSERT(view);
- if (view)
- result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
-
+ ASSERT(renderer()->view());
return result;
}
-LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags, const LayoutPoint* offsetFromRoot) const
+LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot) const
{
- LayoutRect result = localBoundingBox(flags);
- if (renderer()->isBox())
+ LayoutRect result = logicalBoundingBox();
+ if (m_renderer->isBox())
renderBox()->flipForWritingMode(result);
else
- renderer()->containingBlock()->flipForWritingMode(result);
-
- if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) {
- // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
- // get our true bounding box.
- LayoutPoint offsetWithinPaginationLayer;
- convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer);
- result.moveBy(offsetWithinPaginationLayer);
-
- RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
- result = enclosingFlowThread->fragmentsBoundingBox(result);
-
- LayoutPoint delta;
- if (offsetFromRoot)
- delta = *offsetFromRoot;
- else
- enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta);
- result.moveBy(delta);
- return result;
- }
+ m_renderer->containingBlock()->flipForWritingMode(result);
LayoutPoint delta;
if (offsetFromRoot)
return result;
}
-IntRect RenderLayer::absoluteBoundingBox() const
+static void expandRectForReflectionAndStackingChildren(const RenderLayer* ancestorLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result)
{
- return pixelSnappedIntRect(boundingBox(root()));
+ if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping())
+ result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundingBoxForCompositing(ancestorLayer));
+
+ ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer->stackingNode()->hasPositiveZOrderList());
+
+#if ENABLE(ASSERT)
+ LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(ancestorLayer)->stackingNode());
+#endif
+
+ RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), AllChildren);
+ while (RenderLayerStackingNode* node = iterator.next()) {
+ // Here we exclude both directly composited layers and squashing layers
+ // because those RenderLayers don't paint into the graphics layer
+ // for this RenderLayer. For example, the bounds of squashed RenderLayers
+ // will be included in the computation of the appropriate squashing
+ // GraphicsLayer.
+ if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()->compositingState() != NotComposited)
+ continue;
+ result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, options));
+ }
}
-IntRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
+LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const
{
- if (!isSelfPaintingLayer())
- return IntRect();
-
- // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
- if ((flags & ExcludeHiddenDescendants) && this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
- return IntRect();
+ LayoutPoint origin;
+ LayoutRect result = physicalBoundingBox(ancestorLayer, &origin);
- RenderLayerModelObject* renderer = this->renderer();
+ const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
- if (isRootLayer()) {
- // The root layer is always just the size of the document.
- return renderer->view()->unscaledDocumentRect();
- }
+ expandRectForReflectionAndStackingChildren(this, DoNotApplyBoundsChickenEggHacks, result);
- LayoutRect boundingBoxRect = localBoundingBox(flags);
+ result.moveBy(offsetFromRoot);
+ return result;
+}
- if (renderer->isBox())
- toRenderBox(renderer)->flipForWritingMode(boundingBoxRect);
- else
- renderer->containingBlock()->flipForWritingMode(boundingBoxRect);
-
- if (renderer->isRoot()) {
- // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited),
- // then it has to be big enough to cover the viewport in order to display the background. This is akin
- // to the code in RenderBox::paintRootBoxFillLayers().
- if (FrameView* frameView = renderer->view()->frameView()) {
- LayoutUnit contentsWidth = frameView->contentsWidth();
- LayoutUnit contentsHeight = frameView->contentsHeight();
-
- boundingBoxRect.setWidth(max(boundingBoxRect.width(), contentsWidth - boundingBoxRect.x()));
- boundingBoxRect.setHeight(max(boundingBoxRect.height(), contentsHeight - boundingBoxRect.y()));
- }
- }
+LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLayer, CalculateBoundsOptions options) const
+{
+ if (!isSelfPaintingLayer())
+ return LayoutRect();
- LayoutRect unionBounds = boundingBoxRect;
- bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (transform() && flags & PretendLayerHasOwnBacking);
+ if (!ancestorLayer)
+ ancestorLayer = this;
- if (flags & UseLocalClipRectIfPossible) {
- LayoutRect localClipRect = this->localClipRect();
- if (localClipRect != PaintInfo::infiniteRect()) {
- if ((flags & IncludeSelfTransform) && shouldIncludeTransform)
- localClipRect = transform()->mapRect(localClipRect);
+ // FIXME: This could be improved to do a check like hasVisibleNonCompositingDescendantLayers() (bug 92580).
+ if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant())
+ return LayoutRect();
- LayoutPoint ancestorRelOffset;
- convertToLayerCoords(ancestorLayer, ancestorRelOffset);
- localClipRect.moveBy(ancestorRelOffset);
- return pixelSnappedIntRect(localClipRect);
- }
- }
+ // The root layer is always just the size of the document.
+ if (isRootLayer())
+ return m_renderer->view()->unscaledDocumentRect();
- // FIXME: should probably just pass 'flags' down to descendants.
- CalculateLayerBoundsFlags descendantFlags = DefaultCalculateLayerBoundsFlags | (flags & ExcludeHiddenDescendants) | (flags & IncludeCompositedDescendants);
+ const bool shouldIncludeTransform = paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChickenEggHacks && transform());
- const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
+ LayoutRect localClipRect = clipper().localClipRect();
+ if (localClipRect != PaintInfo::infiniteRect()) {
+ if (shouldIncludeTransform)
+ localClipRect = transform()->mapRect(localClipRect);
- if (m_reflectionInfo) {
- RenderLayer* reflectionLayer = m_reflectionInfo->reflectionLayer();
- if (!reflectionLayer->compositedLayerMapping()) {
- IntRect childUnionBounds = reflectionLayer->calculateLayerBounds(this, 0, descendantFlags);
- unionBounds.unite(childUnionBounds);
- }
+ LayoutPoint delta;
+ convertToLayerCoords(ancestorLayer, delta);
+ localClipRect.moveBy(delta);
+ return localClipRect;
}
- ASSERT(m_stackingNode->isStackingContainer() || (!m_stackingNode->posZOrderList() || !m_stackingNode->posZOrderList()->size()));
+ LayoutPoint origin;
+ LayoutRect result = physicalBoundingBox(ancestorLayer, &origin);
-#if !ASSERT_DISABLED
- LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this)->stackingNode());
-#endif
+ const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded();
- // FIXME: Descendants that are composited should not necessarily be skipped, if they don't paint into their own
- // separate backing. Instead, they ought to contribute to the bounds of the layer we're trying to compute.
- // This applies to all z-order lists below.
- RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), AllChildren);
- while (RenderLayerStackingNode* node = iterator.next()) {
- if (flags & IncludeCompositedDescendants || !node->layer()->compositedLayerMapping()) {
- IntRect childUnionBounds = node->layer()->calculateLayerBounds(this, 0, descendantFlags);
- unionBounds.unite(childUnionBounds);
- }
- }
+ // Reflections are implemented with RenderLayers that hang off of the reflected layer. However,
+ // the reflection layer subtree does not include the subtree of the parent RenderLayer, so
+ // a recursive computation of stacking children yields no results. This breaks cases when there are stacking
+ // children of the parent, that need to be included in reflected composited bounds.
+ // Fix this by including composited bounds of stacking children of the reflected RenderLayer.
+ if (hasCompositedLayerMapping() && parent() && parent()->reflectionInfo() && parent()->reflectionInfo()->reflectionLayer() == this)
+ expandRectForReflectionAndStackingChildren(parent(), options, result);
+ else
+ expandRectForReflectionAndStackingChildren(this, options, result);
// FIXME: We can optimize the size of the composited layers, by not enlarging
// filtered areas with the outsets if we know that the filter is going to render in hardware.
// https://bugs.webkit.org/show_bug.cgi?id=81239
- if (flags & IncludeLayerFilterOutsets)
- renderer->style()->filterOutsets().expandRect(unionBounds);
+ m_renderer->style()->filterOutsets().expandRect(result);
- 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);
+ if (shouldIncludeTransform)
+ result = transform()->mapRect(result);
- return pixelSnappedIntRect(unionBounds);
+ LayoutPoint delta;
+ convertToLayerCoords(ancestorLayer, delta);
+ result.moveBy(delta);
+ return result;
}
CompositingState RenderLayer::compositingState() const
{
+ ASSERT(isAllowedToQueryCompositingState());
+
// This is computed procedurally so there is no redundant state variable that
// can get out of sync from the real actual compositing state.
+ if (m_groupedMapping) {
+ ASSERT(compositor()->layerSquashingEnabled());
+ ASSERT(!m_compositedLayerMapping);
+ return PaintsIntoGroupedBacking;
+ }
+
if (!m_compositedLayerMapping)
return NotComposited;
- if (m_compositedLayerMapping && compositedLayerMapping()->paintsIntoCompositedAncestor())
+ if (compositedLayerMapping()->paintsIntoCompositedAncestor())
return HasOwnBackingButPaintsIntoAncestor;
- ASSERT(m_compositedLayerMapping);
return PaintsIntoOwnBacking;
}
+bool RenderLayer::isAllowedToQueryCompositingState() const
+{
+ if (gCompositingQueryMode == CompositingQueriesAreAllowed)
+ return true;
+ return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCompositingUpdate;
+}
+
+CompositedLayerMapping* RenderLayer::compositedLayerMapping() const
+{
+ ASSERT(isAllowedToQueryCompositingState());
+ return m_compositedLayerMapping.get();
+}
+
+GraphicsLayer* RenderLayer::graphicsLayerBacking() const
+{
+ switch (compositingState()) {
+ case NotComposited:
+ return 0;
+ case PaintsIntoGroupedBacking:
+ return groupedMapping()->squashingLayer();
+ default:
+ return compositedLayerMapping()->mainGraphicsLayer();
+ }
+}
+
+GraphicsLayer* RenderLayer::graphicsLayerBackingForScrolling() const
+{
+ switch (compositingState()) {
+ case NotComposited:
+ return 0;
+ case PaintsIntoGroupedBacking:
+ return groupedMapping()->squashingLayer();
+ default:
+ return compositedLayerMapping()->scrollingContentsLayer() ? compositedLayerMapping()->scrollingContentsLayer() : compositedLayerMapping()->mainGraphicsLayer();
+ }
+}
+
CompositedLayerMapping* RenderLayer::ensureCompositedLayerMapping()
{
if (!m_compositedLayerMapping) {
- m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(this));
- compositor()->layerBecameComposited(this);
+ m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this));
+ m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
updateOrRemoveFilterEffectRenderer();
-
- if (RuntimeEnabledFeatures::cssCompositingEnabled())
- compositedLayerMapping()->setBlendMode(m_blendMode);
}
return m_compositedLayerMapping.get();
}
void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed)
{
- if (m_compositedLayerMapping && !renderer()->documentBeingDestroyed())
- compositor()->layerBecameNonComposited(this);
+ if (!layerBeingDestroyed) {
+ // We need to make sure our decendants get a geometry update. In principle,
+ // we could call setNeedsGraphicsLayerUpdate on our children, but that would
+ // require walking the z-order lists to find them. Instead, we over-invalidate
+ // by marking our parent as needing a geometry update.
+ if (RenderLayer* compositingParent = enclosingLayerWithCompositedLayerMapping(ExcludeSelf))
+ compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
+ }
+
m_compositedLayerMapping.clear();
if (!layerBeingDestroyed)
updateOrRemoveFilterEffectRenderer();
}
+void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool layerBeingDestroyed)
+{
+ if (groupedMapping == m_groupedMapping)
+ return;
+
+ if (!layerBeingDestroyed && m_groupedMapping) {
+ m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
+ m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this);
+ }
+ m_groupedMapping = groupedMapping;
+ if (!layerBeingDestroyed && m_groupedMapping)
+ m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
+}
+
bool RenderLayer::hasCompositedMask() const
{
return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer();
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_renderer->hasBlendMode() && compositingState() != PaintsIntoOwnBacking;
+}
+
bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
{
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
if (renderer()->hasOverflowClip())
return false;
- return listBackgroundIsKnownToBeOpaqueInRect(m_stackingNode->posZOrderList(), localRect)
- || listBackgroundIsKnownToBeOpaqueInRect(m_stackingNode->negZOrderList(), localRect)
- || listBackgroundIsKnownToBeOpaqueInRect(m_stackingNode->normalFlowList(), localRect);
+ return childBackgroundIsKnownToBeOpaqueInRect(localRect);
}
-bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayerStackingNode*>* list, const LayoutRect& localRect) const
+bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
{
- if (!list || list->isEmpty())
- return false;
-
- for (Vector<RenderLayerStackingNode*>::const_reverse_iterator iter = list->rbegin(); iter != list->rend(); ++iter) {
- const RenderLayer* childLayer = (*iter)->layer();
- if (childLayer->compositedLayerMapping())
+ RenderLayerStackingNodeReverseIterator revertseIterator(*m_stackingNode, PositiveZOrderChildren | NormalFlowChildren | NegativeZOrderChildren);
+ while (RenderLayerStackingNode* child = revertseIterator.next()) {
+ const RenderLayer* childLayer = child->layer();
+ // Stop at composited paint boundaries.
+ if (childLayer->isPaintInvalidationContainer())
continue;
if (!childLayer->canUseConvertToLayerCoords())
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_stackingNode->isNormalFlowOnly()
+ if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAcceleratedCompositing())
+ return true;
+ return m_layerType == NormalLayer
|| (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars())
- || needsCompositedScrolling()
- || renderer()->hasReflection()
- || renderer()->hasMask()
- || renderer()->isTableRow()
- || renderer()->isCanvas()
- || renderer()->isVideo()
- || renderer()->isEmbeddedObject()
- || renderer()->isRenderIFrame();
+ || needsCompositedScrolling();
}
void RenderLayer::updateSelfPaintingLayer()
{
bool isSelfPaintingLayer = shouldBeSelfPaintingLayer();
- if (m_isSelfPaintingLayer == isSelfPaintingLayer)
+ if (this->isSelfPaintingLayer() == isSelfPaintingLayer)
return;
m_isSelfPaintingLayer = isSelfPaintingLayer;
- if (!parent())
- return;
- if (isSelfPaintingLayer)
- parent()->setAncestorChainHasSelfPaintingLayerDescendant();
- else
+
+ if (parent())
parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
}
// <img src=...>
// </div>
// so test for 0x0 RenderTexts here
- for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
+ for (RenderObject* child = renderer()->slowFirstChild(); child; child = child->nextSibling()) {
if (!child->hasLayer()) {
if (child->isRenderInline() || !child->isBox())
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();
+ return renderer()->style()->hasBoxDecorations() || renderer()->style()->hasBackground();
}
bool RenderLayer::hasVisibleBoxDecorations() const
return false;
}
-void RenderLayer::updateVisibilityAfterStyleChange(const RenderStyle* oldStyle)
-{
- if (!oldStyle || (oldStyle->visibility() != renderer()->style()->visibility()))
- compositor()->setNeedsUpdateCompositingRequirementsState();
-}
-
-void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
+void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
{
- if (oldStyle && (renderer()->style()->position() == oldStyle->position()))
- return;
-
- bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
- bool isOutOfFlowPositioned = renderer()->isOutOfFlowPositioned();
- if (!wasOutOfFlowPositioned && !isOutOfFlowPositioned)
- return;
-
- // Even if the layer remains out-of-flow, a change to this property
- // will likely change its containing block. We must clear these bits
- // so that they can be set properly by the RenderLayerCompositor.
- for (RenderLayer* ancestor = parent(); ancestor; ancestor = ancestor->parent())
- ancestor->setHasUnclippedDescendant(false);
-
- // Ensures that we reset the above bits correctly.
- compositor()->setNeedsUpdateCompositingRequirementsState();
-
- if (wasOutOfFlowPositioned && isOutOfFlowPositioned)
+ if (!newStyle->hasFilter() && (!oldStyle || !oldStyle->hasFilter()))
return;
- if (isOutOfFlowPositioned) {
- setAncestorChainHasOutOfFlowPositionedDescendant();
- compositor()->addOutOfFlowPositionedLayer(this);
- } else {
- dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
- compositor()->removeOutOfFlowPositionedLayer(this);
-
- // We need to reset the isUnclippedDescendant bit here because normally
- // the "unclipped-ness" property is only updated in
- // RenderLayerCompositor::updateCompositingRequirementsState(). However,
- // it is only updated for layers which are known to be out of flow.
- // Since this is no longer out of flow, we have to explicitly ensure
- // that it doesn't think it is unclipped.
- setIsUnclippedDescendant(false);
- }
-}
-
-static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
-{
- ASSERT(newStyle);
- return (oldStyle && oldStyle->hasFilter()) || newStyle->hasFilter();
+ updateOrRemoveFilterClients();
+ updateOrRemoveFilterEffectRenderer();
}
-inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
+bool RenderLayer::attemptDirectCompositingUpdate(StyleDifference diff, const RenderStyle* oldStyle)
{
- ASSERT(newStyle);
- return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip());
-}
+ CompositingReasons oldPotentialCompositingReasonsFromStyle = m_potentialCompositingReasonsFromStyle;
+ compositor()->updatePotentialCompositingReasonsFromStyle(this);
-inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
-{
- ASSERT(newStyle);
- return !compositedLayerMapping() && oldStyle && (oldStyle->overflowX() != newStyle->overflowX()) && m_stackingNode->ancestorStackingContainerNode()->layer()->hasCompositingDescendant();
-}
+ // This function implements an optimization for transforms and opacity.
+ // A common pattern is for a touchmove handler to update the transform
+ // and/or an opacity of an element every frame while the user moves their
+ // finger across the screen. The conditions below recognize when the
+ // compositing state is set up to receive a direct transform or opacity
+ // update.
-inline bool RenderLayer::needsCompositingLayersRebuiltForFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle, bool didPaintWithFilters) const
-{
- if (!hasOrHadFilters(oldStyle, newStyle))
+ if (!diff.hasAtMostPropertySpecificDifferences(StyleDifference::TransformChanged | StyleDifference::OpacityChanged))
+ return false;
+ // The potentialCompositingReasonsFromStyle could have changed without
+ // a corresponding StyleDifference if an animation started or ended.
+ if (m_potentialCompositingReasonsFromStyle != oldPotentialCompositingReasonsFromStyle)
+ return false;
+ // We could add support for reflections if we updated the transform on
+ // the reflection layers.
+ if (renderer()->hasReflection())
+ return false;
+ // If we're unwinding a scheduleSVGFilterLayerUpdateHack(), then we can't
+ // perform a direct compositing update because the filters code is going
+ // to produce different output this time around. We can remove this code
+ // once we fix the chicken/egg bugs in the filters code and delete the
+ // scheduleSVGFilterLayerUpdateHack().
+ if (renderer()->node() && renderer()->node()->svgFilterNeedsLayerUpdate())
+ return false;
+ if (!m_compositedLayerMapping)
return false;
- if (renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter)) {
- // When the compositor is performing the filter animation, we shouldn't touch the compositing layers.
- // All of the layers above us should have been promoted to compositing layers already.
+ // To cut off almost all the work in the compositing update for
+ // this case, we treat inline transforms has having assumed overlap
+ // (similar to how we treat animated transforms). Notice that we read
+ // CompositingReasonInlineTransform from the m_compositingReasons, which
+ // means that the inline transform actually triggered assumed overlap in
+ // the overlap map.
+ if (diff.transformChanged() && !(m_compositingReasons & CompositingReasonInlineTransform))
return false;
- }
- FilterOutsets newOutsets = newStyle->filterOutsets();
- if (oldStyle && (oldStyle->filterOutsets() != newOutsets)) {
- // When filter outsets change, we need to:
- // (1) Recompute the overlap map to promote the correct layers to composited layers.
- // (2) Update the composited layer bounds (and child GraphicsLayer positions) on platforms
- // whose compositors can't compute their own filter outsets.
- return true;
- }
+ // We composite transparent RenderLayers differently from non-transparent
+ // RenderLayers even when the non-transparent RenderLayers are already a
+ // stacking context.
+ if (diff.opacityChanged() && m_renderer->style()->hasOpacity() != oldStyle->hasOpacity())
+ return false;
-#if HAVE(COMPOSITOR_FILTER_OUTSETS)
- if ((didPaintWithFilters != paintsWithFilters()) && !newOutsets.isZero()) {
- // When the layer used to paint filters in software and now paints filters in the
- // compositor, the compositing layer bounds need to change from including filter outsets to
- // excluding filter outsets, on platforms whose compositors compute their own outsets.
- // Similarly for the reverse change from compositor-painted to software-painted filters.
- return true;
- }
-#endif
+ updateTransform(oldStyle, renderer()->style());
- return false;
+ // FIXME: Consider introducing a smaller graphics layer update scope
+ // that just handles transforms and opacity. GraphicsLayerUpdateLocal
+ // will also program bounds, clips, and many other properties that could
+ // not possibly have changed.
+ m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLocal);
+ compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange);
+ return true;
}
-void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
+void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
{
- if (!hasOrHadFilters(oldStyle, newStyle))
+ if (attemptDirectCompositingUpdate(diff, oldStyle))
return;
- updateOrRemoveFilterClients();
- // During an accelerated animation, both WebKit and the compositor animate properties.
- // However, WebKit shouldn't ask the compositor to update its filters if the compositor is performing the animation.
- bool shouldUpdateFilters = compositedLayerMapping() && !renderer()->animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitFilter);
- if (shouldUpdateFilters)
- compositedLayerMapping()->updateFilters(renderer()->style());
- updateOrRemoveFilterEffectRenderer();
-}
-
-void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
-{
m_stackingNode->updateIsNormalFlowOnly();
+ m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
if (m_scrollableArea)
m_scrollableArea->updateAfterStyleChange(oldStyle);
- m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
- updateVisibilityAfterStyleChange(oldStyle);
+
// Overlay scrollbars can make this layer self-painting so we need
// to recompute the bit once scrollbars have been updated.
updateSelfPaintingLayer();
- updateOutOfFlowPositioned(oldStyle);
- updateReflectionInfo(oldStyle);
-
- if (RuntimeEnabledFeatures::cssCompositingEnabled())
- updateBlendMode();
+ if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) {
+ ASSERT(!oldStyle || diff.needsFullLayout());
+ updateReflectionInfo(oldStyle);
+ }
updateDescendantDependentFlags();
- updateTransform();
- bool didPaintWithFilters = false;
-
- if (paintsWithFilters())
- didPaintWithFilters = true;
+ updateTransform(oldStyle, renderer()->style());
updateFilters(oldStyle, renderer()->style());
- const RenderStyle* newStyle = renderer()->style();
- if (compositor()->updateLayerCompositingState(this)
- || needsCompositingLayersRebuiltForClip(oldStyle, newStyle)
- || needsCompositingLayersRebuiltForOverflow(oldStyle, newStyle)
- || needsCompositingLayersRebuiltForFilters(oldStyle, newStyle, didPaintWithFilters))
- compositor()->setCompositingLayersNeedRebuild();
- else if (compositedLayerMapping())
- compositedLayerMapping()->updateGraphicsLayerGeometry();
+ setNeedsCompositingInputsUpdate();
}
bool RenderLayer::scrollsOverflow() const
return false;
}
-bool RenderLayer::isCSSCustomFilterEnabled() const
-{
- // We only want to enable shaders if WebGL is also enabled on this platform.
- const Settings* settings = renderer()->document().settings();
- return settings && RuntimeEnabledFeatures::cssCustomFilterEnabled() && settings->webGLEnabled();
-}
-
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->getOperationType() != FilterOperation::REFERENCE)
+ if (filterOperation->type() != FilterOperation::REFERENCE)
continue;
- ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation);
+ ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
// FIXME: Cache the ReferenceFilter if it didn't change.
RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create();
- float zoom = style->effectiveZoom() * WebCore::deviceScaleFactor(renderer()->frame());
- referenceFilter->setFilterResolution(FloatSize(zoom, zoom));
+ float zoom = style->effectiveZoom();
+ referenceFilter->setAbsoluteTransform(AffineTransform().scale(zoom, zoom));
referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referenceFilter.get(), renderer(), referenceFilter->sourceGraphic(),
referenceOperation));
referenceOperation->setFilter(referenceFilter.release());
}
}
- if (!filters.hasCustomFilter())
- return filters;
-
- if (!isCSSCustomFilterEnabled()) {
- // CSS Custom filters should not parse at all in this case, but there might be
- // remaining styles that were parsed when the flag was enabled. Reproduces in DumpRenderTree
- // because it resets the flag while the previous test is still loaded.
- return FilterOperations();
- }
-
- FilterOperations outputFilters;
- for (size_t i = 0; i < filters.size(); ++i) {
- RefPtr<FilterOperation> filterOperation = filters.operations().at(i);
- if (filterOperation->getOperationType() == FilterOperation::CUSTOM) {
- // We have to wait until the program of CSS Shaders is loaded before setting it on the layer.
- // Note that we will handle the loading of the shaders and repainting of the layer in updateOrRemoveFilterClients.
- const CustomFilterOperation* customOperation = static_cast<const CustomFilterOperation*>(filterOperation.get());
- RefPtr<CustomFilterProgram> program = customOperation->program();
- if (!program->isLoaded())
- continue;
-
- CustomFilterGlobalContext* globalContext = renderer()->view()->customFilterGlobalContext();
- RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo());
- if (!validatedProgram->isInitialized())
- continue;
-
- RefPtr<ValidatedCustomFilterOperation> validatedOperation = ValidatedCustomFilterOperation::create(validatedProgram.release(),
- customOperation->parameters(), customOperation->meshRows(), customOperation->meshColumns(), customOperation->meshType());
- outputFilters.operations().append(validatedOperation.release());
- continue;
- }
- outputFilters.operations().append(filterOperation.release());
- }
- return outputFilters;
+ return filters;
}
void RenderLayer::updateOrRemoveFilterClients()
return;
}
- if (renderer()->style()->filter().hasCustomFilter())
- ensureFilterInfo()->updateCustomFilterClients(renderer()->style()->filter());
- else if (hasFilterInfo())
- filterInfo()->removeCustomFilterClients();
-
if (renderer()->style()->filter().hasReferenceFilter())
ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->filter());
else if (hasFilterInfo())
// Don't delete the whole filter info here, because we might use it
// for loading CSS shader files.
if (RenderLayerFilterInfo* filterInfo = this->filterInfo())
- filterInfo->setRenderer(0);
+ filterInfo->setRenderer(nullptr);
return;
}
RenderLayerFilterInfo* filterInfo = ensureFilterInfo();
if (!filterInfo->renderer()) {
RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create();
- RenderingMode renderingMode = renderer()->frame()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
- filterRenderer->setRenderingMode(renderingMode);
filterInfo->setRenderer(filterRenderer.release());
-
- // We can optimize away code paths in other places if we know that there are no software filters.
- renderer()->document().view()->setHasSoftwareFilters(true);
}
// If the filter fails to build, remove it from the layer. It will still attempt to
// go through regular processing (e.g. compositing), but never apply anything.
if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
- filterInfo->setRenderer(0);
+ filterInfo->setRenderer(nullptr);
}
-void RenderLayer::filterNeedsRepaint()
+void RenderLayer::filterNeedsPaintInvalidation()
{
- toElement(renderer()->node())->scheduleLayerUpdate();
- if (renderer()->view())
- renderer()->repaint();
+ {
+ DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().lifecycle());
+ // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a style recalc, which
+ // is a problem because this function can be called while performing layout.
+ // Presumably this represents an illegal data flow of layout or compositing
+ // information into the style system.
+ toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack();
+ }
+
+ renderer()->setShouldDoFullPaintInvalidation(true);
}
void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const
{
+ computeSelfHitTestRects(rects);
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+ child->addLayerHitTestRects(rects);
+}
+
+void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const
+{
if (!size().isEmpty()) {
Vector<LayoutRect> rect;
if (renderBox() && renderBox()->scrollsOverflow()) {
// For scrolling layers, rects are taken to be in the space of the contents.
- // We need to include both the entire contents, and also the bounding box
- // of the layer in the space of it's parent (eg. for border / scroll bars).
- rect.append(m_scrollableArea->overflowRect());
+ // We need to include the bounding box of the layer in the space of its parent
+ // (eg. for border / scroll bars) and if it's composited then the entire contents
+ // as well as they may be on another composited layer. Skip reporting contents
+ // for non-composited layers as they'll get projected to the same layer as the
+ // bounding box.
+ if (compositingState() != NotComposited)
+ rect.append(m_scrollableArea->overflowRect());
+
rects.set(this, rect);
if (const RenderLayer* parentLayer = parent()) {
LayerHitTestRects::iterator iter = rects.find(parentLayer);
- if (iter == rects.end())
- iter = rects.add(parentLayer, Vector<LayoutRect>()).iterator;
- iter->value.append(boundingBox(parentLayer));
+ if (iter == rects.end()) {
+ rects.add(parentLayer, Vector<LayoutRect>()).storedValue->value.append(physicalBoundingBox(parentLayer));
+ } else {
+ iter->value.append(physicalBoundingBox(parentLayer));
+ }
}
} else {
- rect.append(localBoundingBox());
+ rect.append(logicalBoundingBox());
rects.set(this, rect);
}
}
+}
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->addLayerHitTestRects(rects);
+void RenderLayer::setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()
+{
+ renderer()->setShouldDoFullPaintInvalidation(true);
+
+ // Disable for reading compositingState() in isPaintInvalidationContainer() below.
+ DisableCompositingQueryAsserts disabler;
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isPaintInvalidationContainer())
+ child->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
+ }
}
-} // namespace WebCore
+DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
+ : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { }
+
+} // namespace blink
#ifndef NDEBUG
-void showLayerTree(const WebCore::RenderLayer* layer)
+void showLayerTree(const blink::RenderLayer* layer)
{
if (!layer)
return;
- if (WebCore::Frame* frame = layer->renderer()->frame()) {
- WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState);
+ if (blink::LocalFrame* frame = layer->renderer()->frame()) {
+ WTF::String output = externalRepresentation(frame, blink::RenderAsTextShowAllLayers | blink::RenderAsTextShowLayerNesting | blink::RenderAsTextShowCompositedLayers | blink::RenderAsTextShowAddresses | blink::RenderAsTextShowIDAndClass | blink::RenderAsTextDontUpdateLayout | blink::RenderAsTextShowLayoutState);
fprintf(stderr, "%s\n", output.utf8().data());
}
}
-void showLayerTree(const WebCore::RenderObject* renderer)
+void showLayerTree(const blink::RenderObject* renderer)
{
if (!renderer)
return;