OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/paint/PaintInvalidator.h" | 5 #include "core/paint/PaintInvalidator.h" |
6 | 6 |
| 7 #include "core/editing/FrameSelection.h" |
7 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
| 9 #include "core/frame/LocalFrame.h" |
| 10 #include "core/frame/Settings.h" |
8 #include "core/layout/LayoutObject.h" | 11 #include "core/layout/LayoutObject.h" |
| 12 #include "core/layout/LayoutTable.h" |
| 13 #include "core/layout/svg/SVGLayoutSupport.h" |
| 14 #include "core/paint/PaintLayer.h" |
| 15 #include "core/paint/PaintLayerScrollableArea.h" |
9 | 16 |
10 namespace blink { | 17 namespace blink { |
11 | 18 |
12 void PaintInvalidator::invalidatePaintIfNeeded(FrameView& frameView, const Paint
PropertyTreeBuilderContext& treeContext, Optional<PaintInvalidatorContext>& pain
tInvalidatorContext) | 19 void PaintInvalidatorContext::mapLocalRectToPaintInvalidationBacking(const Layou
tObject& object, LayoutRect& rect) const |
13 { | 20 { |
14 paintInvalidatorContext.emplace(*frameView.layoutView(), m_pendingDelayedPai
ntInvalidations); | 21 // TODO(wangxianzhu): For now this is the same as the slow path in PaintInva
lidationState.cpp |
15 frameView.invalidatePaintIfNeeded(*paintInvalidatorContext); | 22 // (slowMapToVisualRectInAncestorSpace()). Should implement this with Geomet
ryMapper. |
16 } | 23 if (object.isBox()) |
17 | 24 toLayoutBox(object).flipForWritingMode(rect); |
18 void PaintInvalidator::invalidatePaintIfNeeded(const LayoutObject& layoutObject,
const PaintPropertyTreeBuilderContext& treeContext, const PaintInvalidatorConte
xt& parentPaintInvalidatorContext, Optional<PaintInvalidatorContext>& paintInval
idatorContext) | 25 |
19 { | 26 if (object.isLayoutView()) |
20 if (!layoutObject.shouldCheckForPaintInvalidation(parentPaintInvalidatorCont
ext)) | 27 toLayoutView(object).mapToVisualRectInAncestorSpace(paintInvalidationCon
tainer, rect, InputIsInFrameCoordinates, DefaultVisualRectFlags); |
| 28 else |
| 29 object.mapToVisualRectInAncestorSpace(paintInvalidationContainer, rect); |
| 30 } |
| 31 |
| 32 static LayoutRect computePaintInvalidationRectInBacking(const LayoutObject& obje
ct, const PaintInvalidatorContext& context) |
| 33 { |
| 34 if (object.isSVG() && !object.isSVGRoot()) { |
| 35 // TODO(wangxianzhu): For now this is the same as the slow path in Paint
InvalidationState.cpp |
| 36 // (PaintInvalidationState::computePaintInvalidationRectInBackingForSVG(
)). Should implement this with GeometryMapper. |
| 37 LayoutRect rect = SVGLayoutSupport::clippedOverflowRectForPaintInvalidat
ion(object, *context.paintInvalidationContainer); |
| 38 if (context.paintInvalidationContainer->layer()->groupedMapping()) |
| 39 PaintLayer::mapRectInPaintInvalidationContainerToBacking(*context.pa
intInvalidationContainer, rect); |
| 40 return rect; |
| 41 } |
| 42 |
| 43 LayoutRect rect = object.localOverflowRectForPaintInvalidation(); |
| 44 context.mapLocalRectToPaintInvalidationBacking(object, rect); |
| 45 return rect; |
| 46 } |
| 47 |
| 48 static LayoutPoint computeLocationFromPaintInvalidationBacking(const LayoutObjec
t& object, const PaintInvalidatorContext& context) |
| 49 { |
| 50 // TODO(wangxianzhu): For now this is the same as the slow path in PaintInva
lidationState.cpp |
| 51 // (slowLocalToAncestorPoint()). Should implement this with GeometryMapper. |
| 52 FloatPoint point; |
| 53 if (object != context.paintInvalidationContainer) { |
| 54 if (object.isLayoutView()) { |
| 55 point = toLayoutView(object).localToAncestorPoint(point, context.pai
ntInvalidationContainer, TraverseDocumentBoundaries | InputIsInFrameCoordinates)
; |
| 56 } else { |
| 57 point = object.localToAncestorPoint(point, context.paintInvalidation
Container, TraverseDocumentBoundaries); |
| 58 // Paint invalidation does not include scroll of paintInvalidationCo
ntainer. |
| 59 if (context.paintInvalidationContainer->isBox()) { |
| 60 const LayoutBox* box = toLayoutBox(context.paintInvalidationCont
ainer); |
| 61 if (box->hasOverflowClip()) |
| 62 point.move(box->scrolledContentOffset()); |
| 63 } |
| 64 } |
| 65 } |
| 66 |
| 67 |
| 68 if (context.paintInvalidationContainer->layer()->groupedMapping()) |
| 69 PaintLayer::mapPointInPaintInvalidationContainerToBacking(*context.paint
InvalidationContainer, point); |
| 70 |
| 71 return LayoutPoint(point); |
| 72 } |
| 73 |
| 74 static void updatePaintingLayer(const LayoutObject& object, PaintInvalidatorCont
ext& context) |
| 75 { |
| 76 if (object.hasLayer() && toLayoutBoxModelObject(object).hasSelfPaintingLayer
()) |
| 77 context.paintingLayer = toLayoutBoxModelObject(object).layer(); |
| 78 |
| 79 if (object.isLayoutBlockFlow() && toLayoutBlockFlow(object).containsFloats()
) |
| 80 context.paintingLayer->setNeedsPaintPhaseFloat(); |
| 81 |
| 82 if (object == context.paintingLayer->layoutObject()) |
21 return; | 83 return; |
22 | 84 |
23 paintInvalidatorContext.emplace(parentPaintInvalidatorContext, layoutObject)
; | 85 if (object.styleRef().hasOutline()) |
24 | 86 context.paintingLayer->setNeedsPaintPhaseDescendantOutlines(); |
25 if (layoutObject.mayNeedPaintInvalidationSubtree()) | 87 |
26 paintInvalidatorContext->setForceSubtreeInvalidationCheckingWithinContai
ner(); | 88 if (object.hasBoxDecorationBackground() |
27 | 89 // We also paint overflow controls in background phase. |
28 PaintInvalidationReason reason = layoutObject.getMutableForPainting().invali
datePaintIfNeeded(*paintInvalidatorContext); | 90 || (object.hasOverflowClip() && toLayoutBox(object).getScrollableArea()-
>hasOverflowControls())) { |
29 layoutObject.getMutableForPainting().clearPaintInvalidationFlags(*paintInval
idatorContext); | 91 context.paintingLayer->setNeedsPaintPhaseDescendantBlockBackgrounds(); |
30 | 92 } |
31 paintInvalidatorContext->updateForChildren(reason); | 93 |
| 94 if (object.isTable()) { |
| 95 const LayoutTable& table = toLayoutTable(object); |
| 96 if (table.collapseBorders() && !table.collapsedBorders().isEmpty()) |
| 97 context.paintingLayer->setNeedsPaintPhaseDescendantBlockBackgrounds(
); |
| 98 } |
| 99 } |
| 100 |
| 101 static void updateContext(const LayoutObject& object, PaintInvalidatorContext& c
ontext) |
| 102 { |
| 103 if (object.isPaintInvalidationContainer()) { |
| 104 context.paintInvalidationContainer = toLayoutBoxModelObject(&object); |
| 105 if (object.styleRef().isStackingContext()) |
| 106 context.paintInvalidationContainerForStackedContents = toLayoutBoxMo
delObject(&object); |
| 107 } else if (object.isLayoutView()) { |
| 108 // paintInvalidationContainerForStackedContents is only for stacked desc
endants in its own frame, |
| 109 // because it doesn't establish stacking context for stacked contents in
sub-frames. |
| 110 // Contents stacked in the root stacking context in this frame should us
e this frame's paintInvalidationContainer. |
| 111 context.paintInvalidationContainerForStackedContents = context.paintInva
lidationContainer; |
| 112 } else if (object.styleRef().isStacked() |
| 113 // This is to exclude some objects (e.g. LayoutText) inheriting stacked
style from parent but aren't actually stacked. |
| 114 && object.hasLayer() |
| 115 && context.paintInvalidationContainer != context.paintInvalidationContai
nerForStackedContents) { |
| 116 // The current object is stacked, so we should use m_paintInvalidationCo
ntainerForStackedContents as its |
| 117 // paint invalidation container on which the current object is painted. |
| 118 context.paintInvalidationContainer = context.paintInvalidationContainerF
orStackedContents; |
| 119 if (context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::Fo
rcedSubtreeFullInvalidationForStackedContents) |
| 120 context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::F
orcedSubtreeFullInvalidation; |
| 121 } |
| 122 |
| 123 if (object == context.paintInvalidationContainer) { |
| 124 // When we hit a new paint invalidation container, we don't need to |
| 125 // continue forcing a check for paint invalidation, since we're |
| 126 // descending into a different invalidation container. (For instance if |
| 127 // our parents were moved, the entire container will just move.) |
| 128 if (object != context.paintInvalidationContainerForStackedContents) { |
| 129 // However, we need to keep the ForcedSubtreeFullInvalidationForStac
kedContents flag |
| 130 // if the current object isn't the paint invalidation container of s
tacked contents. |
| 131 context.forcedSubtreeInvalidationFlags &= PaintInvalidatorContext::F
orcedSubtreeFullInvalidationForStackedContents; |
| 132 } else { |
| 133 context.forcedSubtreeInvalidationFlags = 0; |
| 134 } |
| 135 } |
| 136 |
| 137 DCHECK(context.paintInvalidationContainer == object.containerForPaintInvalid
ation()); |
| 138 DCHECK(context.paintingLayer == object.paintingLayer()); |
| 139 |
| 140 if (object.mayNeedPaintInvalidationSubtree()) |
| 141 context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::Force
dSubtreeInvalidationChecking; |
| 142 |
| 143 context.oldBounds = object.previousPaintInvalidationRect(); |
| 144 context.oldLocation = object.previousPositionFromPaintInvalidationBacking(); |
| 145 context.newBounds = computePaintInvalidationRectInBacking(object, context); |
| 146 context.newLocation = computeLocationFromPaintInvalidationBacking(object, co
ntext); |
| 147 |
| 148 IntSize adjustment = object.scrollAdjustmentForPaintInvalidation(*context.pa
intInvalidationContainer); |
| 149 context.newLocation.move(adjustment); |
| 150 context.newBounds.move(adjustment); |
| 151 |
| 152 object.getMutableForPainting().setPreviousPaintInvalidationRect(context.newB
ounds); |
| 153 object.getMutableForPainting().setPreviousPositionFromPaintInvalidationBacki
ng(context.newLocation); |
| 154 } |
| 155 |
| 156 void PaintInvalidator::invalidatePaintIfNeeded(FrameView& frameView, PaintInvali
datorContext& context) |
| 157 { |
| 158 LayoutView* layoutView = frameView.layoutView(); |
| 159 CHECK(layoutView); |
| 160 |
| 161 context.paintInvalidationContainer = context.paintInvalidationContainerForSt
ackedContents = &layoutView->containerForPaintInvalidation(); |
| 162 context.paintingLayer = layoutView->layer(); |
| 163 |
| 164 if (!frameView.frame().settings() || !frameView.frame().settings()->rootLaye
rScrolls()) |
| 165 frameView.invalidatePaintOfScrollControlsIfNeeded(context); |
| 166 |
| 167 if (frameView.frame().selection().isCaretBoundsDirty()) |
| 168 frameView.frame().selection().invalidateCaretRect(); |
| 169 |
| 170 // Temporary callback for crbug.com/487345,402044 |
| 171 // TODO(ojan): Make this more general to be used by PositionObserver |
| 172 // and rAF throttling. |
| 173 IntRect visibleRect = frameView.rootFrameToContents(frameView.computeVisible
Area()); |
| 174 layoutView->sendMediaPositionChangeNotifications(visibleRect); |
| 175 } |
| 176 |
| 177 void PaintInvalidator::invalidatePaintIfNeeded(const LayoutObject& object, Paint
InvalidatorContext& context) |
| 178 { |
| 179 object.getMutableForPainting().ensureIsReadyForPaintInvalidation(); |
| 180 |
| 181 if (!context.forcedSubtreeInvalidationFlags && !object.shouldCheckForPaintIn
validationRegardlessOfPaintInvalidationState()) |
| 182 return; |
| 183 |
| 184 updatePaintingLayer(object, context); |
| 185 |
| 186 if (object.document().printing()) |
| 187 return; // Don't invalidate paints if we're printing. |
| 188 |
| 189 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "PaintInvalida
tor::invalidatePaintIfNeeded()", "object", object.debugName().ascii()); |
| 190 |
| 191 updateContext(object, context); |
| 192 |
| 193 if (!object.shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationStat
e() && context.forcedSubtreeInvalidationFlags == PaintInvalidatorContext::Forced
SubtreeInvalidationRectUpdate) { |
| 194 // We are done updating the paint invalidation rect. No other paint inva
lidation work to do for this object. |
| 195 return; |
| 196 } |
| 197 |
| 198 switch (object.invalidatePaintIfNeeded(context)) { |
| 199 case PaintInvalidationDelayedFull: |
| 200 m_pendingDelayedPaintInvalidations.append(&object); |
| 201 break; |
| 202 case PaintInvalidationSubtree: |
| 203 context.forcedSubtreeInvalidationFlags |= (PaintInvalidatorContext::Forc
edSubtreeFullInvalidation | PaintInvalidatorContext::ForcedSubtreeFullInvalidati
onForStackedContents); |
| 204 break; |
| 205 case PaintInvalidationSVGResourceChange: |
| 206 context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::Force
dSubtreeInvalidationChecking; |
| 207 break; |
| 208 default: |
| 209 break; |
| 210 } |
| 211 |
| 212 if (context.oldLocation != context.newLocation) |
| 213 context.forcedSubtreeInvalidationFlags |= PaintInvalidatorContext::Force
dSubtreeInvalidationChecking; |
| 214 |
| 215 object.getMutableForPainting().clearPaintInvalidationFlags(); |
32 } | 216 } |
33 | 217 |
34 void PaintInvalidator::processPendingDelayedPaintInvalidations() | 218 void PaintInvalidator::processPendingDelayedPaintInvalidations() |
35 { | 219 { |
36 for (auto target : m_pendingDelayedPaintInvalidations) | 220 for (auto target : m_pendingDelayedPaintInvalidations) |
37 target->getMutableForPainting().setShouldDoDelayedFullPaintInvalidation(
); | 221 target->getMutableForPainting().setShouldDoFullPaintInvalidation(PaintIn
validationDelayedFull); |
38 } | 222 } |
39 | 223 |
40 } // namespace blink | 224 } // namespace blink |
OLD | NEW |