Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp |
| diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp |
| index 5c88fec583bfd63efc364c7c337d02d3fa493737..dcc7db4777143df4f5b90a8c3f1e73680ef1168e 100644 |
| --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp |
| +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp |
| @@ -21,36 +21,28 @@ |
| namespace blink { |
| -static bool isAbsolutePositionUnderRelativePositionInline(const LayoutObject& object) |
| -{ |
| - if (object.styleRef().position() != AbsolutePosition) |
| - return false; |
| - if (LayoutObject* container = object.container()) |
| - return container->isAnonymousBlock() && container->styleRef().position() == RelativePosition; |
| - return false; |
| -} |
| - |
| static bool supportsCachedOffsets(const LayoutObject& object) |
| { |
| - // TODO(wangxianzhu): Move some conditions to fast path if possible. |
| return !object.hasTransformRelatedProperty() |
| && !object.hasReflection() |
| && !object.hasFilter() |
| && !object.isLayoutFlowThread() |
| && !object.isLayoutMultiColumnSpannerPlaceholder() |
| - && object.styleRef().position() != FixedPosition |
| && !object.styleRef().isFlippedBlocksWritingMode() |
| - // TODO(crbug.com/598094): Handle this in fast path. |
| - && !isAbsolutePositionUnderRelativePositionInline(object); |
| + && !(object.isLayoutBlock() && object.isSVG()); |
| } |
| PaintInvalidationState::PaintInvalidationState(const LayoutView& layoutView, Vector<LayoutObject*>& pendingDelayedPaintInvalidations) |
| : m_currentObject(layoutView) |
| - , m_clipped(false) |
| - , m_cachedOffsetsEnabled(true) |
| , m_forcedSubtreeInvalidationWithinContainer(false) |
| , m_forcedSubtreeInvalidationRectUpdateWithinContainer(false) |
| - , m_paintInvalidationContainer(layoutView.containerForPaintInvalidation()) |
| + , m_clipped(false) |
| + , m_clippedForAbsolutePosition(false) |
| + , m_cachedOffsetsEnabled(true) |
| + , m_cachedOffsetsForAbsolutePositionEnabled(true) |
| + , m_paintInvalidationContainer(&layoutView.containerForPaintInvalidation()) |
| + , m_paintInvalidationContainerForStackedContents(m_paintInvalidationContainer) |
| + , m_containerForAbsolutePosition(layoutView) |
| , m_pendingDelayedPaintInvalidations(pendingDelayedPaintInvalidations) |
| , m_enclosingSelfPaintingLayer(*layoutView.layer()) |
| #if ENABLE(ASSERT) |
| @@ -62,41 +54,26 @@ PaintInvalidationState::PaintInvalidationState(const LayoutView& layoutView, Vec |
| return; |
| } |
| - FloatPoint point = layoutView.localToAncestorPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries | InputIsInFrameCoordinates); |
| + FloatPoint point = layoutView.localToAncestorPoint(FloatPoint(), m_paintInvalidationContainer, TraverseDocumentBoundaries | InputIsInFrameCoordinates); |
| m_paintOffset = LayoutSize(point.x(), point.y()); |
| -} |
| - |
| -// TODO(wangxianzhu): This is temporary for positioned object whose paintInvalidationContainer is different from |
| -// the one we find during tree walk. Remove this after we fix the issue with tree walk in DOM-order. |
| -PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& parentState, const LayoutBoxModelObject& currentObject, const LayoutBoxModelObject& paintInvalidationContainer) |
| - : m_currentObject(currentObject) |
| - , m_clipped(parentState.m_clipped) |
| - , m_cachedOffsetsEnabled(parentState.m_cachedOffsetsEnabled) |
| - , m_forcedSubtreeInvalidationWithinContainer(parentState.m_forcedSubtreeInvalidationWithinContainer) |
| - , m_forcedSubtreeInvalidationRectUpdateWithinContainer(parentState.m_forcedSubtreeInvalidationRectUpdateWithinContainer) |
| - , m_clipRect(parentState.m_clipRect) |
| - , m_paintOffset(parentState.m_paintOffset) |
| - , m_paintInvalidationContainer(paintInvalidationContainer) |
| - , m_svgTransform(parentState.m_svgTransform) |
| - , m_pendingDelayedPaintInvalidations(parentState.pendingDelayedPaintInvalidationTargets()) |
| - , m_enclosingSelfPaintingLayer(parentState.enclosingSelfPaintingLayer(currentObject)) |
| -#if ENABLE(ASSERT) |
| - , m_didUpdateForChildren(true) |
| -#endif |
| -{ |
| - ASSERT(parentState.m_didUpdateForChildren); |
| - ASSERT(!m_cachedOffsetsEnabled); |
| + m_paintOffsetForAbsolutePosition = m_paintOffset; |
| } |
| PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& parentState, const LayoutObject& currentObject) |
| : m_currentObject(currentObject) |
| - , m_clipped(parentState.m_clipped) |
| - , m_cachedOffsetsEnabled(parentState.m_cachedOffsetsEnabled) |
| , m_forcedSubtreeInvalidationWithinContainer(parentState.m_forcedSubtreeInvalidationWithinContainer) |
| , m_forcedSubtreeInvalidationRectUpdateWithinContainer(parentState.m_forcedSubtreeInvalidationRectUpdateWithinContainer) |
| + , m_clipped(parentState.m_clipped) |
| + , m_clippedForAbsolutePosition(parentState.m_clippedForAbsolutePosition) |
| , m_clipRect(parentState.m_clipRect) |
| + , m_clipRectForAbsolutePosition(parentState.m_clipRectForAbsolutePosition) |
| , m_paintOffset(parentState.m_paintOffset) |
| - , m_paintInvalidationContainer(currentObject.isPaintInvalidationContainer() ? toLayoutBoxModelObject(currentObject) : parentState.m_paintInvalidationContainer) |
| + , m_paintOffsetForAbsolutePosition(parentState.m_paintOffsetForAbsolutePosition) |
| + , m_cachedOffsetsEnabled(parentState.m_cachedOffsetsEnabled) |
| + , m_cachedOffsetsForAbsolutePositionEnabled(parentState.m_cachedOffsetsForAbsolutePositionEnabled) |
| + , m_paintInvalidationContainer(parentState.m_paintInvalidationContainer) |
| + , m_paintInvalidationContainerForStackedContents(parentState.m_paintInvalidationContainerForStackedContents) |
| + , m_containerForAbsolutePosition(currentObject.canContainAbsolutePositionObjects() ? currentObject : parentState.m_containerForAbsolutePosition) |
| , m_svgTransform(parentState.m_svgTransform) |
| , m_pendingDelayedPaintInvalidations(parentState.pendingDelayedPaintInvalidationTargets()) |
| , m_enclosingSelfPaintingLayer(parentState.enclosingSelfPaintingLayer(currentObject)) |
| @@ -116,11 +93,37 @@ PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& par |
| ASSERT(parentState.m_didUpdateForChildren); |
| + EPosition position = currentObject.styleRef().position(); |
| + |
| + if (currentObject.isPaintInvalidationContainer()) { |
| + m_paintInvalidationContainer = toLayoutBoxModelObject(¤tObject); |
| + if (currentObject.styleRef().isStackingContext()) { |
| + m_paintInvalidationContainerForStackedContents = toLayoutBoxModelObject(¤tObject); |
| + |
| + // Disable cached offsets for absolute-position objects if this object is not a container for |
| + // absolute-position because absolute-position objects' locations are determined by something |
| + // above their paint invalidation container. |
| + if (m_currentObject != m_containerForAbsolutePosition) |
| + m_cachedOffsetsForAbsolutePositionEnabled = false; |
| + } |
| + } else if (currentObject.isLayoutView()) { |
| + // m_paintInvalidationContainerForStackedContents doesn't cross frame boundary. |
|
chrishtr
2016/03/31 00:15:02
Why?
Xianzhu
2016/03/31 01:41:28
Added explanation as comment:
// m_paintInvalidat
|
| + m_paintInvalidationContainerForStackedContents = m_paintInvalidationContainer; |
| + } else if (currentObject.styleRef().isStacked() |
| + // This is to exclude some objects (e.g. LayoutText) inheriting stacked style from parent but aren't actually stacked. |
| + && currentObject.hasLayer() |
| + && m_paintInvalidationContainer != m_paintInvalidationContainerForStackedContents) { |
|
chrishtr
2016/03/31 00:15:02
Can you explain in detail what this logic is doing
Xianzhu
2016/03/31 01:41:28
Added explanation as comment:
// The current objec
|
| + m_paintInvalidationContainer = m_paintInvalidationContainerForStackedContents; |
| + // We are changing paint invalidation container, but didn't track paint offset from |
| + // m_paintInvalidationContainerForStackedContents, so disable cached offsets. |
| + m_cachedOffsetsEnabled = false; |
| + } |
| + |
| if (!currentObject.isBoxModelObject() && !currentObject.isSVG()) |
| return; |
| - if (m_cachedOffsetsEnabled && !supportsCachedOffsets(currentObject)) |
| - m_cachedOffsetsEnabled = false; |
| + if (m_cachedOffsetsEnabled || currentObject == m_paintInvalidationContainer) |
| + m_cachedOffsetsEnabled = supportsCachedOffsets(currentObject); |
| if (currentObject.isSVG()) { |
| if (currentObject.isSVGRoot()) { |
| @@ -158,6 +161,34 @@ PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& par |
| return; |
| } |
| + if (position == FixedPosition) { |
| + if (m_paintInvalidationContainer != currentObject.view() && m_paintInvalidationContainer->view() == currentObject.view()) { |
| + // TODO(crbug.com/598762): localToAncestorPoint() is incorrect for fixed-position when paintInvalidationContainer |
| + // is under the containing LayoutView. |
| + m_cachedOffsetsEnabled = false; |
| + return; |
| + } |
| + FloatPoint fixedOffset = currentObject.localToAncestorPoint(FloatPoint(), m_paintInvalidationContainer, TraverseDocumentBoundaries); |
| + m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()); |
| + // Ancestor clippings are ignored for simplicity. |
| + m_clipped = false; |
| + return; |
| + } |
| + |
| + if (position == AbsolutePosition) { |
| + m_cachedOffsetsEnabled = m_cachedOffsetsForAbsolutePositionEnabled; |
| + if (!m_cachedOffsetsEnabled) |
| + return; |
| + |
| + m_paintOffset = m_paintOffsetForAbsolutePosition; |
| + m_clipped = m_clippedForAbsolutePosition; |
| + m_clipRect = m_clipRectForAbsolutePosition; |
| + |
| + const LayoutObject& container = parentState.m_containerForAbsolutePosition; |
| + if (container.isInFlowPositioned() && container.isLayoutInline()) |
| + m_paintOffset += toLayoutInline(container).offsetForInFlowPositionedInline(toLayoutBox(m_currentObject)); |
| + } |
| + |
| if (currentObject.isBox()) |
| m_paintOffset += toLayoutBox(currentObject).locationOffset(); |
| @@ -172,6 +203,24 @@ void PaintInvalidationState::updateForChildren() |
| m_didUpdateForChildren = true; |
| #endif |
| + updateForNormalChildren(); |
| + |
| + if (m_currentObject == m_containerForAbsolutePosition) { |
| + if (m_paintInvalidationContainer == m_paintInvalidationContainerForStackedContents) { |
| + m_cachedOffsetsForAbsolutePositionEnabled = m_cachedOffsetsEnabled; |
| + if (m_cachedOffsetsEnabled) { |
| + m_paintOffsetForAbsolutePosition = m_paintOffset; |
| + m_clippedForAbsolutePosition = m_clipped; |
| + m_clipRectForAbsolutePosition = m_clipRect; |
| + } |
| + } else { |
| + m_cachedOffsetsForAbsolutePositionEnabled = false; |
| + } |
| + } |
| +} |
| + |
| +void PaintInvalidationState::updateForNormalChildren() |
| +{ |
| if (!m_cachedOffsetsEnabled) |
| return; |
| @@ -224,7 +273,7 @@ LayoutPoint PaintInvalidationState::computePositionFromPaintInvalidationBacking( |
| ASSERT(!m_didUpdateForChildren); |
| FloatPoint point; |
| - if (m_paintInvalidationContainer != m_currentObject) { |
| + if (m_paintInvalidationContainer != &m_currentObject) { |
| if (m_cachedOffsetsEnabled) { |
| if (m_currentObject.isSVG() && !m_currentObject.isSVGRoot()) |
| point = m_svgTransform.mapPoint(point); |
| @@ -234,12 +283,12 @@ LayoutPoint PaintInvalidationState::computePositionFromPaintInvalidationBacking( |
| // ASSERT(point == slowLocalOriginToAncestorPoint(m_currentObject, m_paintInvalidationContainer, FloatPoint()); |
| #endif |
| } else { |
| - point = slowLocalToAncestorPoint(m_currentObject, m_paintInvalidationContainer, FloatPoint()); |
| + point = slowLocalToAncestorPoint(m_currentObject, *m_paintInvalidationContainer, FloatPoint()); |
| } |
| } |
| - if (m_paintInvalidationContainer.layer()->groupedMapping()) |
| - PaintLayer::mapPointInPaintInvalidationContainerToBacking(m_paintInvalidationContainer, point); |
| + if (m_paintInvalidationContainer->layer()->groupedMapping()) |
| + PaintLayer::mapPointInPaintInvalidationContainerToBacking(*m_paintInvalidationContainer, point); |
| return LayoutPoint(point); |
| } |
| @@ -266,7 +315,7 @@ LayoutRect PaintInvalidationState::computePaintInvalidationRectInBackingForSVG() |
| if (m_clipped) |
| rect.intersect(m_clipRect); |
| #if ASSERT_SAME_RESULT_SLOW_AND_FAST_PATH |
| - LayoutRect slowPathRect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(m_currentObject, m_paintInvalidationContainer); |
| + LayoutRect slowPathRect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(m_currentObject, *m_paintInvalidationContainer); |
| // TODO(crbug.com/597902): Slow path misses clipping of paintInvalidationContainer. |
| if (m_clipped) |
| slowPathRect.intersect(m_clipRect); |
| @@ -276,11 +325,11 @@ LayoutRect PaintInvalidationState::computePaintInvalidationRectInBackingForSVG() |
| } else { |
| // TODO(wangxianzhu): Sometimes m_cachedOffsetsEnabled==false doesn't mean we can't use cached |
| // m_svgTransform. We can use hybrid fast-path (for SVG) and slow-path (for things above the SVGRoot). |
| - rect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(m_currentObject, m_paintInvalidationContainer); |
| + rect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(m_currentObject, *m_paintInvalidationContainer); |
| } |
| - if (m_paintInvalidationContainer.layer()->groupedMapping()) |
| - PaintLayer::mapRectInPaintInvalidationContainerToBacking(m_paintInvalidationContainer, rect); |
| + if (m_paintInvalidationContainer->layer()->groupedMapping()) |
| + PaintLayer::mapRectInPaintInvalidationContainerToBacking(*m_paintInvalidationContainer, rect); |
| return rect; |
| } |
| @@ -308,7 +357,7 @@ void PaintInvalidationState::mapLocalRectToPaintInvalidationBacking(LayoutRect& |
| if (m_cachedOffsetsEnabled) { |
| #if ASSERT_SAME_RESULT_SLOW_AND_FAST_PATH |
| LayoutRect slowPathRect(rect); |
| - slowMapToVisibleRectInAncestorSpace(m_currentObject, m_paintInvalidationContainer, slowPathRect); |
| + slowMapToVisibleRectInAncestorSpace(m_currentObject, *m_paintInvalidationContainer, slowPathRect); |
| #endif |
| rect.move(m_paintOffset); |
| if (m_clipped) |
| @@ -321,15 +370,16 @@ void PaintInvalidationState::mapLocalRectToPaintInvalidationBacking(LayoutRect& |
| // TODO(wangxianzhu): The isLayoutView() condition is for cases that a sub-frame creates a |
| // root PaintInvalidationState which doesn't inherit clip from ancestor frames. |
| // Remove the condition when we eliminate the latter case of PaintInvalidationState(const LayoutView&, ...). |
| + // We ignore ancestor clipping for FixedPosition in fast path. |
| // TODO(crbug.com/597903): Fast path and slow path should generate equal empty rects. |
| - ASSERT(m_currentObject.isLayoutView() || (rect.isEmpty() && slowPathRect.isEmpty()) || rect == slowPathRect); |
| + ASSERT(m_currentObject.isLayoutView() || m_currentObject.styleRef().position() == FixedPosition || (rect.isEmpty() && slowPathRect.isEmpty()) || rect == slowPathRect); |
| #endif |
| } else { |
| - slowMapToVisibleRectInAncestorSpace(m_currentObject, m_paintInvalidationContainer, rect); |
| + slowMapToVisibleRectInAncestorSpace(m_currentObject, *m_paintInvalidationContainer, rect); |
| } |
| - if (m_paintInvalidationContainer.layer()->groupedMapping()) |
| - PaintLayer::mapRectInPaintInvalidationContainerToBacking(m_paintInvalidationContainer, rect); |
| + if (m_paintInvalidationContainer->layer()->groupedMapping()) |
| + PaintLayer::mapRectInPaintInvalidationContainerToBacking(*m_paintInvalidationContainer, rect); |
| } |
| void PaintInvalidationState::addClipRectRelativeToPaintOffset(const LayoutRect& localClipRect) |