Index: third_party/WebKit/Source/core/paint/PaintInvalidator.cpp |
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp |
index 2edd221a78cf73e4479d4c830b7fc0a2887f04d5..e77cb726519662fe3bd441862ed39be376651ac5 100644 |
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp |
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp |
@@ -4,37 +4,213 @@ |
#include "core/paint/PaintInvalidator.h" |
+#include "core/editing/FrameSelection.h" |
#include "core/frame/FrameView.h" |
+#include "core/frame/LocalFrame.h" |
+#include "core/frame/Settings.h" |
#include "core/layout/LayoutObject.h" |
+#include "core/layout/LayoutTable.h" |
+#include "core/layout/svg/SVGLayoutSupport.h" |
+#include "core/paint/PaintLayer.h" |
+#include "core/paint/PaintLayerScrollableArea.h" |
namespace blink { |
-void PaintInvalidator::invalidatePaintIfNeeded(FrameView& frameView, const PaintPropertyTreeBuilderContext& treeContext, Optional<PaintInvalidatorContext>& paintInvalidatorContext) |
+void PaintInvalidatorContext::mapLocalRectToPaintInvalidationBacking(const LayoutObject& object, LayoutRect& rect) const |
{ |
- paintInvalidatorContext.emplace(*frameView.layoutView(), m_pendingDelayedPaintInvalidations); |
- frameView.invalidatePaintIfNeeded(*paintInvalidatorContext); |
+ // TODO(wangxianzhu): For now this is the same as the slow path in PaintInvalidationState.cpp |
+ // (slowMapToVisualRectInAncestorSpace()). Should implement this with GeometryMapper. |
+ if (object.isBox()) |
+ toLayoutBox(object).flipForWritingMode(rect); |
+ |
+ if (object.isLayoutView()) |
+ toLayoutView(object).mapToVisualRectInAncestorSpace(paintInvalidationContainer, rect, InputIsInFrameCoordinates, DefaultVisualRectFlags); |
+ else |
+ object.mapToVisualRectInAncestorSpace(paintInvalidationContainer, rect); |
+} |
+ |
+static LayoutRect computePaintInvalidationRectInBacking(const LayoutObject& object, const PaintInvalidatorContext& context) |
+{ |
+ if (object.isSVG() && !object.isSVGRoot()) { |
+ // TODO(wangxianzhu): For now this is the same as the slow path in PaintInvalidationState.cpp |
+ // (PaintInvalidationState::computePaintInvalidationRectInBackingForSVG()). Should implement this with GeometryMapper. |
+ LayoutRect rect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(object, *context.paintInvalidationContainer); |
+ if (context.paintInvalidationContainer->layer()->groupedMapping()) |
+ PaintLayer::mapRectInPaintInvalidationContainerToBacking(*context.paintInvalidationContainer, rect); |
+ return rect; |
+ } |
+ |
+ LayoutRect rect = object.localOverflowRectForPaintInvalidation(); |
+ context.mapLocalRectToPaintInvalidationBacking(object, rect); |
+ return rect; |
} |
-void PaintInvalidator::invalidatePaintIfNeeded(const LayoutObject& layoutObject, const PaintPropertyTreeBuilderContext& treeContext, const PaintInvalidatorContext& parentPaintInvalidatorContext, Optional<PaintInvalidatorContext>& paintInvalidatorContext) |
+static LayoutPoint computeLocationFromPaintInvalidationBacking(const LayoutObject& object, const PaintInvalidatorContext& context) |
{ |
- if (!layoutObject.shouldCheckForPaintInvalidation(parentPaintInvalidatorContext)) |
+ // TODO(wangxianzhu): For now this is the same as the slow path in PaintInvalidationState.cpp |
+ // (slowLocalToAncestorPoint()). Should implement this with GeometryMapper. |
+ FloatPoint point; |
+ if (object != context.paintInvalidationContainer) { |
+ if (object.isLayoutView()) |
+ point = toLayoutView(object).localToAncestorPoint(point, context.paintInvalidationContainer, TraverseDocumentBoundaries | InputIsInFrameCoordinates); |
+ else |
+ point = object.localToAncestorPoint(point, context.paintInvalidationContainer, TraverseDocumentBoundaries); |
chrishtr
2016/08/11 00:14:50
I think you'll need this code:
if (ancestor.isBo
Xianzhu
2016/08/11 01:27:08
Done.
|
+ } |
+ |
+ if (context.paintInvalidationContainer->layer()->groupedMapping()) |
+ PaintLayer::mapPointInPaintInvalidationContainerToBacking(*context.paintInvalidationContainer, point); |
+ |
+ return LayoutPoint(point); |
+} |
+ |
+static void updatePaintingLayer(const LayoutObject& object, PaintInvalidatorContext& context) |
+{ |
+ if (object.hasLayer() && toLayoutBoxModelObject(object).hasSelfPaintingLayer()) |
+ context.paintingLayer = toLayoutBoxModelObject(object).layer(); |
+ |
+ if (object.isLayoutBlockFlow() && toLayoutBlockFlow(object).containsFloats()) |
+ context.paintingLayer->setNeedsPaintPhaseFloat(); |
+ |
+ if (object == context.paintingLayer->layoutObject()) |
return; |
- paintInvalidatorContext.emplace(parentPaintInvalidatorContext, layoutObject); |
+ if (object.styleRef().hasOutline()) |
+ context.paintingLayer->setNeedsPaintPhaseDescendantOutlines(); |
+ |
+ if (object.hasBoxDecorationBackground() |
+ // We also paint overflow controls in background phase. |
+ || (object.hasOverflowClip() && toLayoutBox(object).getScrollableArea()->hasOverflowControls())) { |
+ context.paintingLayer->setNeedsPaintPhaseDescendantBlockBackgrounds(); |
+ } |
+ |
+ if (object.isTable()) { |
+ const LayoutTable& table = toLayoutTable(object); |
+ if (table.collapseBorders() && !table.collapsedBorders().isEmpty()) |
+ context.paintingLayer->setNeedsPaintPhaseDescendantBlockBackgrounds(); |
+ } |
+} |
+ |
+static void updateContext(const LayoutObject& object, PaintInvalidatorContext& context) |
+{ |
+ if (object.isPaintInvalidationContainer()) { |
+ context.paintInvalidationContainer = toLayoutBoxModelObject(&object); |
+ if (object.styleRef().isStackingContext()) |
+ context.paintInvalidationContainerForStackedContents = toLayoutBoxModelObject(&object); |
+ } else if (object.isLayoutView()) { |
+ // paintInvalidationContainerForStackedContents is only for stacked descendants in its own frame, |
+ // because it doesn't establish stacking context for stacked contents in sub-frames. |
+ // Contents stacked in the root stacking context in this frame should use this frame's paintInvalidationContainer. |
+ context.paintInvalidationContainerForStackedContents = context.paintInvalidationContainer; |
+ } else if (object.styleRef().isStacked() |
+ // This is to exclude some objects (e.g. LayoutText) inheriting stacked style from parent but aren't actually stacked. |
+ && object.hasLayer() |
+ && context.paintInvalidationContainer != context.paintInvalidationContainerForStackedContents) { |
+ // The current object is stacked, so we should use m_paintInvalidationContainerForStackedContents as its |
+ // paint invalidation container on which the current object is painted. |
+ context.paintInvalidationContainer = context.paintInvalidationContainerForStackedContents; |
+ if (context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::ForcedSubtreeFullInvalidationForStackedContents) |
+ context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::ForcedSubtreeFullInvalidation; |
+ } |
+ |
+ if (object == context.paintInvalidationContainer) { |
+ // When we hit a new paint invalidation container, we don't need to |
+ // continue forcing a check for paint invalidation, since we're |
+ // descending into a different invalidation container. (For instance if |
+ // our parents were moved, the entire container will just move.) |
+ if (object != context.paintInvalidationContainerForStackedContents) { |
+ // However, we need to keep the ForcedSubtreeFullInvalidationForStackedContents flag |
+ // if the current object isn't the paint invalidation container of stacked contents. |
+ context.forcedSubtreeInvalidationFlags &= PaintInvalidatorContext::ForcedSubtreeFullInvalidationForStackedContents; |
+ } else { |
+ context.forcedSubtreeInvalidationFlags = 0; |
+ } |
+ } |
+ |
+ DCHECK(context.paintInvalidationContainer == object.containerForPaintInvalidation()); |
+ DCHECK(context.paintingLayer == object.paintingLayer()); |
+ |
+ if (object.mayNeedPaintInvalidationSubtree()) |
+ context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::ForcedSubtreeInvalidationChecking; |
+ |
+ context.oldBounds = object.previousPaintInvalidationRect(); |
+ context.oldLocation = object.previousPositionFromPaintInvalidationBacking(); |
+ context.newBounds = computePaintInvalidationRectInBacking(object, context); |
+ context.newLocation = computeLocationFromPaintInvalidationBacking(object, context); |
+ |
+ IntSize adjustment = object.scrollAdjustmentForPaintInvalidation(*context.paintInvalidationContainer); |
+ context.newLocation.move(adjustment); |
+ context.newBounds.move(adjustment); |
+ |
+ object.getMutableForPainting().setPreviousPaintInvalidationRect(context.newBounds); |
+ object.getMutableForPainting().setPreviousPositionFromPaintInvalidationBacking(context.newLocation); |
+} |
+ |
+void PaintInvalidator::invalidatePaintIfNeeded(FrameView& frameView, PaintInvalidatorContext& context) |
+{ |
+ LayoutView* layoutView = frameView.layoutView(); |
+ CHECK(layoutView); |
+ |
+ context.paintInvalidationContainer = context.paintInvalidationContainerForStackedContents = &layoutView->containerForPaintInvalidation(); |
+ context.paintingLayer = layoutView->layer(); |
+ |
+ if (!frameView.frame().settings() || !frameView.frame().settings()->rootLayerScrolls()) |
+ frameView.invalidatePaintOfScrollControlsIfNeeded(context); |
+ |
+ if (frameView.frame().selection().isCaretBoundsDirty()) |
+ frameView.frame().selection().invalidateCaretRect(); |
+ |
+ // Temporary callback for crbug.com/487345,402044 |
+ // TODO(ojan): Make this more general to be used by PositionObserver |
+ // and rAF throttling. |
+ IntRect visibleRect = frameView.rootFrameToContents(frameView.computeVisibleArea()); |
+ layoutView->sendMediaPositionChangeNotifications(visibleRect); |
+} |
+ |
+void PaintInvalidator::invalidatePaintIfNeeded(const LayoutObject& object, PaintInvalidatorContext& context) |
+{ |
+ object.getMutableForPainting().ensureIsReadyForPaintInvalidation(); |
+ |
+ if (!context.forcedSubtreeInvalidationFlags && !object.shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState()) |
+ return; |
+ |
+ updatePaintingLayer(object, context); |
+ |
+ if (object.document().printing()) |
+ return; // Don't invalidate paints if we're printing. |
+ |
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "PaintInvalidator::invalidatePaintIfNeeded()", "object", object.debugName().ascii()); |
+ |
+ updateContext(object, context); |
+ |
+ if (!object.shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState() && context.forcedSubtreeInvalidationFlags == PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate) { |
+ // We are done updating the paint invalidation rect. No other paint invalidation work to do for this object. |
+ return; |
+ } |
- if (layoutObject.mayNeedPaintInvalidationSubtree()) |
- paintInvalidatorContext->setForceSubtreeInvalidationCheckingWithinContainer(); |
+ switch (object.invalidatePaintIfNeeded(context)) { |
+ case PaintInvalidationDelayedFull: |
+ m_pendingDelayedPaintInvalidations.append(&object); |
+ break; |
+ case PaintInvalidationSubtree: |
+ context.forcedSubtreeInvalidationFlags |= (PaintInvalidatorContext::ForcedSubtreeFullInvalidation | PaintInvalidatorContext::ForcedSubtreeFullInvalidationForStackedContents); |
+ break; |
+ case PaintInvalidationSVGResourceChange: |
+ context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::ForcedSubtreeInvalidationChecking; |
+ break; |
+ default: |
+ break; |
+ } |
- PaintInvalidationReason reason = layoutObject.getMutableForPainting().invalidatePaintIfNeeded(*paintInvalidatorContext); |
- layoutObject.getMutableForPainting().clearPaintInvalidationFlags(*paintInvalidatorContext); |
+ if (context.oldLocation != context.newLocation) |
+ context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::ForcedSubtreeInvalidationChecking; |
- paintInvalidatorContext->updateForChildren(reason); |
+ object.getMutableForPainting().clearPaintInvalidationFlags(); |
} |
void PaintInvalidator::processPendingDelayedPaintInvalidations() |
{ |
for (auto target : m_pendingDelayedPaintInvalidations) |
- target->getMutableForPainting().setShouldDoDelayedFullPaintInvalidation(); |
+ target->getMutableForPainting().setShouldDoFullPaintInvalidation(PaintInvalidationDelayedFull); |
} |
} // namespace blink |