Chromium Code Reviews| Index: third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp |
| diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp |
| index 34c56d65e6562dc8b404d9aaa7d16690874965c0..498c72a5a4e85c2e8526b0de3e7355c28250796d 100644 |
| --- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp |
| +++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp |
| @@ -6,6 +6,7 @@ |
| #include "core/frame/Settings.h" |
| #include "core/layout/LayoutView.h" |
| +#include "core/layout/compositing/CompositedLayerMapping.h" |
| #include "core/paint/ObjectPaintInvalidator.h" |
| #include "core/paint/PaintInvalidator.h" |
| #include "core/paint/PaintLayer.h" |
| @@ -68,42 +69,28 @@ static LayoutRect computeBottomDelta(const LayoutPoint& location, |
| return LayoutRect(); |
| } |
| -bool BoxPaintInvalidator::incrementallyInvalidatePaint() { |
| - LayoutRect rightDelta; |
| - LayoutRect bottomDelta; |
| - if (m_box.isLayoutView() && |
| - !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { |
| - // This corresponds to the special case in computePaintInvalidationReason() |
| - // for LayoutView in non-rootLayerScrolling mode. |
| - DCHECK(m_context.oldVisualRect.location() == |
| - m_context.newVisualRect.location()); |
| - rightDelta = computeRightDelta(m_context.newVisualRect.location(), |
| - m_context.oldVisualRect.size(), |
| - m_context.newVisualRect.size(), 0); |
| - bottomDelta = computeBottomDelta(m_context.newVisualRect.location(), |
| - m_context.oldVisualRect.size(), |
| - m_context.newVisualRect.size(), 0); |
| - } else { |
| - LayoutSize oldBorderBoxSize = |
| - previousBorderBoxSize(m_context.oldVisualRect.size()); |
| - LayoutSize newBorderBoxSize = m_box.size(); |
| - DCHECK(m_context.oldLocation == m_context.newLocation); |
| - rightDelta = computeRightDelta(m_context.newLocation, oldBorderBoxSize, |
| - newBorderBoxSize, m_box.borderRight()); |
| - bottomDelta = computeBottomDelta(m_context.newLocation, oldBorderBoxSize, |
| - newBorderBoxSize, m_box.borderBottom()); |
| - } |
| +bool BoxPaintInvalidator::incrementallyInvalidatePaint( |
| + PaintInvalidationReason reason, |
| + const LayoutRect& oldRect, |
| + const LayoutRect& newRect) { |
| + DCHECK(oldRect.location() == newRect.location()); |
| + LayoutRect rightDelta = computeRightDelta( |
| + newRect.location(), oldRect.size(), newRect.size(), |
| + reason == PaintInvalidationIncremental ? m_box.borderRight() : 0); |
| + LayoutRect bottomDelta = computeBottomDelta( |
| + newRect.location(), oldRect.size(), newRect.size(), |
| + reason == PaintInvalidationIncremental ? m_box.borderBottom() : 0); |
| if (rightDelta.isEmpty() && bottomDelta.isEmpty()) |
| return false; |
| ObjectPaintInvalidator objectPaintInvalidator(m_box); |
| objectPaintInvalidator.invalidatePaintUsingContainer( |
| - *m_context.paintInvalidationContainer, rightDelta, |
| - PaintInvalidationIncremental); |
| - objectPaintInvalidator.invalidatePaintUsingContainer( |
| - *m_context.paintInvalidationContainer, bottomDelta, |
| - PaintInvalidationIncremental); |
| + *m_context.paintInvalidationContainer, rightDelta, reason); |
| + if (rightDelta != bottomDelta) { |
|
chrishtr
2016/11/17 00:12:54
Why this new conditional?
Xianzhu
2016/11/17 17:37:52
This is avoid duplicated invalidation if oldRect o
|
| + objectPaintInvalidator.invalidatePaintUsingContainer( |
| + *m_context.paintInvalidationContainer, bottomDelta, reason); |
| + } |
| return true; |
| } |
| @@ -136,15 +123,9 @@ PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { |
| previousContentBoxRect() != m_box.contentBoxRect()) |
| return PaintInvalidationContentBoxChange; |
| - if (style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() && |
| - previousLayoutOverflowRect() != m_box.layoutOverflowRect()) |
| - return PaintInvalidationLayoutOverflowBoxChange; |
| - |
| - LayoutSize oldBorderBoxSize = |
| - previousBorderBoxSize(m_context.oldVisualRect.size()); |
| + LayoutSize oldBorderBoxSize = previousBorderBoxSize(); |
| LayoutSize newBorderBoxSize = m_box.size(); |
| bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize; |
| - |
| if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect) |
| return PaintInvalidationNone; |
| @@ -182,15 +163,126 @@ PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { |
| return PaintInvalidationIncremental; |
| } |
| +// If true, the background geometry will depend on the layout overflow rect, |
| +// even if it doesn't paint on the scrolling contents layer. |
| +bool BoxPaintInvalidator::backgroundPositionsInLayoutOverflowRect() { |
|
chrishtr
2016/11/17 00:12:54
backgroundGeometryDependsOnLayoutOverflowRect() ?
Xianzhu
2016/11/17 17:37:52
This name is much better. Done.
|
| + return m_box.styleRef() |
| + .backgroundLayers() |
| + .thisOrNextLayersHaveLocalAttachment(); |
| +} |
| + |
| +// Background positioning in layout overflow rect doesn't mean it will |
| +// paint onto the scrolling contents layer because some conditions prevent |
| +// it from that. We may also treat non-local solid color backgrounds as local |
| +// and paint onto the scrolling contents layer. |
| +// See PaintLayer::canPaintBackgroundOntoScrollingContentsLayer(). |
| +bool BoxPaintInvalidator::backgroundPaintsOntoScrollingContentsLayer() { |
| + if (!m_box.hasLayer()) |
| + return false; |
| + if (auto* mapping = m_box.layer()->compositedLayerMapping()) |
| + return mapping->backgroundPaintsOntoScrollingContentsLayer(); |
| + return false; |
| +} |
| + |
| +bool BoxPaintInvalidator::shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| + const LayoutRect& oldLayoutOverflow, |
| + const LayoutRect& newLayoutOverflow) { |
| + DCHECK(oldLayoutOverflow != newLayoutOverflow); |
| + if (newLayoutOverflow.isEmpty() || oldLayoutOverflow.isEmpty()) |
| + return true; |
| + if (newLayoutOverflow.location() != oldLayoutOverflow.location()) |
| + return true; |
| + if (newLayoutOverflow.width() != oldLayoutOverflow.width() && |
| + m_box.mustInvalidateFillLayersPaintOnHeightChange( |
| + m_box.styleRef().backgroundLayers())) |
| + return true; |
| + if (newLayoutOverflow.height() != oldLayoutOverflow.height() && |
| + m_box.mustInvalidateFillLayersPaintOnHeightChange( |
| + m_box.styleRef().backgroundLayers())) |
| + return true; |
| + return false; |
| +} |
| + |
| +void BoxPaintInvalidator::invalidateScrollingContentsBackgroundIfNeeded() { |
| + bool paintsOntoScrollingContentsLayer = |
| + backgroundPaintsOntoScrollingContentsLayer(); |
| + if (!paintsOntoScrollingContentsLayer && |
| + !backgroundPositionsInLayoutOverflowRect()) |
| + return; |
| + |
| + const LayoutRect& oldLayoutOverflow = previousLayoutOverflowRect(); |
| + LayoutRect newLayoutOverflow = m_box.layoutOverflowRect(); |
| + |
| + bool shouldFullyInvalidateOnScrollingContentsLayer = false; |
| + if (m_box.backgroundChangedSinceLastPaintInvalidation()) { |
| + if (!paintsOntoScrollingContentsLayer) { |
| + // The box should have been set needing full invalidation on style change. |
| + DCHECK(m_box.shouldDoFullPaintInvalidation()); |
| + return; |
| + } |
| + shouldFullyInvalidateOnScrollingContentsLayer = true; |
| + } else { |
| + // Check change of layout overflow in which the background is positioned. |
| + if (!m_box.hasPreviousBoxGeometries() || |
| + newLayoutOverflow == oldLayoutOverflow) |
| + return; |
| + if (!paintsOntoScrollingContentsLayer) { |
| + if (m_box.isLayoutView() && |
| + !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) |
| + return; |
| + if (shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| + oldLayoutOverflow, newLayoutOverflow)) { |
| + m_box.getMutableForPainting().setShouldDoFullPaintInvalidation( |
| + PaintInvalidationLayoutOverflowBoxChange); |
| + } |
| + return; |
| + } |
| + shouldFullyInvalidateOnScrollingContentsLayer = |
| + shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| + oldLayoutOverflow, newLayoutOverflow); |
| + } |
| + |
| + if (shouldFullyInvalidateOnScrollingContentsLayer) { |
| + ObjectPaintInvalidatorWithContext(m_box, m_context) |
| + .fullyInvalidatePaint( |
| + PaintInvalidationBackgroundOnScrollingContentsLayer, |
| + oldLayoutOverflow, newLayoutOverflow); |
| + } else { |
| + incrementallyInvalidatePaint( |
| + PaintInvalidationBackgroundOnScrollingContentsLayer, oldLayoutOverflow, |
| + newLayoutOverflow); |
| + } |
| + |
| + m_context.paintingLayer->setNeedsRepaint(); |
| + // Currently we use CompositedLayerMapping as the DisplayItemClient to paint |
| + // background on the scrolling contents layer. |
| + ObjectPaintInvalidator(m_box).invalidateDisplayItemClient( |
| + *m_box.layer()->compositedLayerMapping()->scrollingContentsLayer(), |
| + PaintInvalidationBackgroundOnScrollingContentsLayer); |
| +} |
| + |
| PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { |
| + invalidateScrollingContentsBackgroundIfNeeded(); |
| + |
| PaintInvalidationReason reason = computePaintInvalidationReason(); |
| if (reason == PaintInvalidationIncremental) { |
| - if (incrementallyInvalidatePaint()) { |
| + bool invalidated; |
| + if (m_box.isLayoutView() && |
| + !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { |
| + invalidated = incrementallyInvalidatePaint( |
| + reason, m_context.oldVisualRect, m_context.newVisualRect); |
| + } else { |
| + invalidated = incrementallyInvalidatePaint( |
| + reason, LayoutRect(m_context.oldLocation, previousBorderBoxSize()), |
| + LayoutRect(m_context.newLocation, m_box.size())); |
| + } |
| + if (invalidated) { |
| m_context.paintingLayer->setNeedsRepaint(); |
| m_box.invalidateDisplayItemClients(reason); |
| } else { |
| reason = PaintInvalidationNone; |
| } |
| + |
| // Though we have done incremental invalidation, we still need to call |
| // ObjectPaintInvalidator with PaintInvalidationNone to do any other |
| // required operations. |
| @@ -237,8 +329,9 @@ bool BoxPaintInvalidator::needsToSavePreviousBoxGeometries() { |
| // Background and mask layers can depend on other boxes than border box. See |
| // crbug.com/490533 |
| if (style.backgroundLayers().thisOrNextLayersUseContentBox() || |
| - style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() || |
| - style.maskLayers().thisOrNextLayersUseContentBox()) |
| + style.maskLayers().thisOrNextLayersUseContentBox() || |
| + backgroundPositionsInLayoutOverflowRect() || |
| + backgroundPaintsOntoScrollingContentsLayer()) |
| return true; |
| return false; |
| @@ -255,14 +348,13 @@ void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() { |
| return; |
| } |
| - PreviousBoxGeometries Geometries = {m_box.size(), m_box.contentBoxRect(), |
| + PreviousBoxGeometries geometries = {m_box.size(), m_box.contentBoxRect(), |
| m_box.layoutOverflowRect()}; |
| - previousBoxGeometriesMap().set(&m_box, Geometries); |
| + previousBoxGeometriesMap().set(&m_box, geometries); |
| m_box.getMutableForPainting().setHasPreviousBoxGeometries(true); |
| } |
| -LayoutSize BoxPaintInvalidator::previousBorderBoxSize( |
| - const LayoutSize& previousVisualRectSize) { |
| +LayoutSize BoxPaintInvalidator::previousBorderBoxSize() { |
| DCHECK(m_box.hasPreviousBoxGeometries() == |
| previousBoxGeometriesMap().contains(&m_box)); |
| if (m_box.hasPreviousBoxGeometries()) |
| @@ -270,7 +362,7 @@ LayoutSize BoxPaintInvalidator::previousBorderBoxSize( |
| // We didn't save the old border box size because it was the same as the size |
| // of oldVisualRect. |
| - return previousVisualRectSize; |
| + return m_context.oldVisualRect.size(); |
| } |
| LayoutRect BoxPaintInvalidator::previousContentBoxRect() { |