| 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/ObjectPaintInvalidator.h" | 5 #include "core/paint/ObjectPaintInvalidator.h" |
| 6 | 6 |
| 7 #include "core/frame/FrameView.h" | 7 #include "core/frame/FrameView.h" |
| 8 #include "core/frame/LocalFrame.h" | 8 #include "core/frame/LocalFrame.h" |
| 9 #include "core/layout/LayoutBlockFlow.h" | 9 #include "core/layout/LayoutBlockFlow.h" |
| 10 #include "core/layout/LayoutView.h" | 10 #include "core/layout/LayoutView.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 // TODO(trchen): Use std::function<void, LayoutObject&> when available. | 41 // TODO(trchen): Use std::function<void, LayoutObject&> when available. |
| 42 template <typename LayoutObjectTraversalFunctor> | 42 template <typename LayoutObjectTraversalFunctor> |
| 43 void traverseNonCompositingDescendantsInPaintOrder( | 43 void traverseNonCompositingDescendantsInPaintOrder( |
| 44 const LayoutObject&, | 44 const LayoutObject&, |
| 45 const LayoutObjectTraversalFunctor&); | 45 const LayoutObjectTraversalFunctor&); |
| 46 | 46 |
| 47 template <typename LayoutObjectTraversalFunctor> | 47 template <typename LayoutObjectTraversalFunctor> |
| 48 void traverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationContai
ner( | 48 void traverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationContai
ner( |
| 49 const LayoutObject& object, | 49 const LayoutObject& object, |
| 50 const LayoutObjectTraversalFunctor& functor) { | 50 const LayoutObjectTraversalFunctor& functor) { |
| 51 // |object| is a paint invalidation container but is not a stacking context, s
o the paint | 51 // |object| is a paint invalidation container but is not a stacking context, |
| 52 // invalidation container of stacked descendants don't belong to |object| but
belong to | 52 // so the paint invalidation container of stacked descendants don't belong to |
| 53 // an ancestor. This function traverses all such descendants. | 53 // |object| but belong to an ancestor. This function traverses all such |
| 54 // descendants. |
| 54 DCHECK(object.isPaintInvalidationContainer() && | 55 DCHECK(object.isPaintInvalidationContainer() && |
| 55 !object.styleRef().isStackingContext()); | 56 !object.styleRef().isStackingContext()); |
| 56 | 57 |
| 57 LayoutObject* descendant = object.nextInPreOrder(&object); | 58 LayoutObject* descendant = object.nextInPreOrder(&object); |
| 58 while (descendant) { | 59 while (descendant) { |
| 59 if (!descendant->hasLayer() || !descendant->styleRef().isStacked()) { | 60 if (!descendant->hasLayer() || !descendant->styleRef().isStacked()) { |
| 60 // Case 1: The descendant is not stacked (or is stacked but has not been | 61 // Case 1: The descendant is not stacked (or is stacked but has not been |
| 61 // allocated a layer yet during style change), so either it's a paint inva
lidation | 62 // allocated a layer yet during style change), so either it's a paint |
| 62 // container in the same situation as |object|, or its paint invalidation | 63 // invalidation container in the same situation as |object|, or its paint |
| 63 // container is in such situation. Keep searching until a stacked layer is
found. | 64 // invalidation container is in such situation. Keep searching until a |
| 65 // stacked layer is found. |
| 64 descendant = descendant->nextInPreOrder(&object); | 66 descendant = descendant->nextInPreOrder(&object); |
| 65 } else if (!descendant->isPaintInvalidationContainer()) { | 67 } else if (!descendant->isPaintInvalidationContainer()) { |
| 66 // Case 2: The descendant is stacked and is not composited. | 68 // Case 2: The descendant is stacked and is not composited. |
| 67 // The invalidation container of its subtree is our ancestor, | 69 // The invalidation container of its subtree is our ancestor, |
| 68 // thus recur into the subtree. | 70 // thus recur into the subtree. |
| 69 traverseNonCompositingDescendantsInPaintOrder(*descendant, functor); | 71 traverseNonCompositingDescendantsInPaintOrder(*descendant, functor); |
| 70 descendant = descendant->nextInPreOrderAfterChildren(&object); | 72 descendant = descendant->nextInPreOrderAfterChildren(&object); |
| 71 } else if (descendant->styleRef().isStackingContext()) { | 73 } else if (descendant->styleRef().isStackingContext()) { |
| 72 // Case 3: The descendant is an invalidation container and is a stacking c
ontext. | 74 // Case 3: The descendant is an invalidation container and is a stacking |
| 73 // No objects in the subtree can have invalidation container outside of it
, | 75 // context. No objects in the subtree can have invalidation container |
| 74 // thus skip the whole subtree. | 76 // outside of it, thus skip the whole subtree. |
| 75 descendant = descendant->nextInPreOrderAfterChildren(&object); | 77 descendant = descendant->nextInPreOrderAfterChildren(&object); |
| 76 } else { | 78 } else { |
| 77 // Case 4: The descendant is an invalidation container but not a stacking
context. | 79 // Case 4: The descendant is an invalidation container but not a stacking |
| 78 // This is the same situation as |object|, thus keep searching. | 80 // context. This is the same situation as |object|, thus keep searching. |
| 79 descendant = descendant->nextInPreOrder(&object); | 81 descendant = descendant->nextInPreOrder(&object); |
| 80 } | 82 } |
| 81 } | 83 } |
| 82 } | 84 } |
| 83 | 85 |
| 84 template <typename LayoutObjectTraversalFunctor> | 86 template <typename LayoutObjectTraversalFunctor> |
| 85 void traverseNonCompositingDescendantsInPaintOrder( | 87 void traverseNonCompositingDescendantsInPaintOrder( |
| 86 const LayoutObject& object, | 88 const LayoutObject& object, |
| 87 const LayoutObjectTraversalFunctor& functor) { | 89 const LayoutObjectTraversalFunctor& functor) { |
| 88 functor(object); | 90 functor(object); |
| 89 LayoutObject* descendant = object.nextInPreOrder(&object); | 91 LayoutObject* descendant = object.nextInPreOrder(&object); |
| 90 while (descendant) { | 92 while (descendant) { |
| 91 if (!descendant->isPaintInvalidationContainer()) { | 93 if (!descendant->isPaintInvalidationContainer()) { |
| 92 functor(*descendant); | 94 functor(*descendant); |
| 93 descendant = descendant->nextInPreOrder(&object); | 95 descendant = descendant->nextInPreOrder(&object); |
| 94 } else if (descendant->styleRef().isStackingContext()) { | 96 } else if (descendant->styleRef().isStackingContext()) { |
| 95 // The descendant is an invalidation container and is a stacking context. | 97 // The descendant is an invalidation container and is a stacking context. |
| 96 // No objects in the subtree can have invalidation container outside of it
, | 98 // No objects in the subtree can have invalidation container outside of |
| 97 // thus skip the whole subtree. | 99 // it, thus skip the whole subtree. |
| 98 descendant = descendant->nextInPreOrderAfterChildren(&object); | 100 descendant = descendant->nextInPreOrderAfterChildren(&object); |
| 99 } else { | 101 } else { |
| 100 // If a paint invalidation container is not a stacking context, | 102 // If a paint invalidation container is not a stacking context, |
| 101 // some of its descendants may belong to the parent container. | 103 // some of its descendants may belong to the parent container. |
| 102 traverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationConta
iner( | 104 traverseNonCompositingDescendantsBelongingToAncestorPaintInvalidationConta
iner( |
| 103 *descendant, functor); | 105 *descendant, functor); |
| 104 descendant = descendant->nextInPreOrderAfterChildren(&object); | 106 descendant = descendant->nextInPreOrderAfterChildren(&object); |
| 105 } | 107 } |
| 106 } | 108 } |
| 107 } | 109 } |
| 108 | 110 |
| 109 void ObjectPaintInvalidator:: | 111 void ObjectPaintInvalidator:: |
| 110 invalidateDisplayItemClientsIncludingNonCompositingDescendants( | 112 invalidateDisplayItemClientsIncludingNonCompositingDescendants( |
| 111 PaintInvalidationReason reason) { | 113 PaintInvalidationReason reason) { |
| 112 // This is valid because we want to invalidate the client in the display item
list of the current backing. | 114 // This is valid because we want to invalidate the client in the display item |
| 115 // list of the current backing. |
| 113 DisableCompositingQueryAsserts disabler; | 116 DisableCompositingQueryAsserts disabler; |
| 114 | 117 |
| 115 slowSetPaintingLayerNeedsRepaint(); | 118 slowSetPaintingLayerNeedsRepaint(); |
| 116 traverseNonCompositingDescendantsInPaintOrder( | 119 traverseNonCompositingDescendantsInPaintOrder( |
| 117 m_object, [reason](const LayoutObject& object) { | 120 m_object, [reason](const LayoutObject& object) { |
| 118 if (object.hasLayer() && | 121 if (object.hasLayer() && |
| 119 toLayoutBoxModelObject(object).hasSelfPaintingLayer()) | 122 toLayoutBoxModelObject(object).hasSelfPaintingLayer()) |
| 120 toLayoutBoxModelObject(object).layer()->setNeedsRepaint(); | 123 toLayoutBoxModelObject(object).layer()->setNeedsRepaint(); |
| 121 object.invalidateDisplayItemClients(reason); | 124 object.invalidateDisplayItemClients(reason); |
| 122 }); | 125 }); |
| 123 } | 126 } |
| 124 | 127 |
| 125 DISABLE_CFI_PERF | 128 DISABLE_CFI_PERF |
| 126 void ObjectPaintInvalidator::invalidatePaintOfPreviousPaintInvalidationRect( | 129 void ObjectPaintInvalidator::invalidatePaintOfPreviousPaintInvalidationRect( |
| 127 const LayoutBoxModelObject& paintInvalidationContainer, | 130 const LayoutBoxModelObject& paintInvalidationContainer, |
| 128 PaintInvalidationReason reason) { | 131 PaintInvalidationReason reason) { |
| 129 // It's caller's responsibility to ensure enclosingSelfPaintingLayer's needsRe
paint is set. | 132 // It's caller's responsibility to ensure enclosingSelfPaintingLayer's |
| 130 // Don't set the flag here because getting enclosingSelfPaintLayer has cost an
d the caller can use | 133 // needsRepaint is set. Don't set the flag here because getting |
| 131 // various ways (e.g. PaintInvalidatinState::enclosingSelfPaintingLayer()) to
reduce the cost. | 134 // enclosingSelfPaintLayer has cost and the caller can use various ways (e.g. |
| 135 // PaintInvalidatinState::enclosingSelfPaintingLayer()) to reduce the cost. |
| 132 DCHECK(!m_object.paintingLayer() || m_object.paintingLayer()->needsRepaint()); | 136 DCHECK(!m_object.paintingLayer() || m_object.paintingLayer()->needsRepaint()); |
| 133 | 137 |
| 134 // These disablers are valid because we want to use the current compositing/in
validation status. | 138 // These disablers are valid because we want to use the current |
| 139 // compositing/invalidation status. |
| 135 DisablePaintInvalidationStateAsserts invalidationDisabler; | 140 DisablePaintInvalidationStateAsserts invalidationDisabler; |
| 136 DisableCompositingQueryAsserts compositingDisabler; | 141 DisableCompositingQueryAsserts compositingDisabler; |
| 137 | 142 |
| 138 LayoutRect invalidationRect = m_object.previousPaintInvalidationRect(); | 143 LayoutRect invalidationRect = m_object.previousPaintInvalidationRect(); |
| 139 invalidatePaintUsingContainer(paintInvalidationContainer, invalidationRect, | 144 invalidatePaintUsingContainer(paintInvalidationContainer, invalidationRect, |
| 140 reason); | 145 reason); |
| 141 m_object.invalidateDisplayItemClients(reason); | 146 m_object.invalidateDisplayItemClients(reason); |
| 142 | 147 |
| 143 // This method may be used to invalidate paint of an object changing paint inv
alidation container. | 148 // This method may be used to invalidate paint of an object changing paint |
| 144 // Clear previous paint invalidation rect on the original paint invalidation c
ontainer to avoid | 149 // invalidation container. Clear previous paint invalidation rect on the |
| 145 // under-invalidation if the new paint invalidation rect on the new paint inva
lidation container | 150 // original paint invalidation container to avoid under-invalidation if the |
| 146 // happens to be the same as the old one. | 151 // new paint invalidation rect on the new paint invalidation container happens |
| 152 // to be the same as the old one. |
| 147 m_object.getMutableForPainting().clearPreviousPaintInvalidationRects(); | 153 m_object.getMutableForPainting().clearPreviousPaintInvalidationRects(); |
| 148 } | 154 } |
| 149 | 155 |
| 150 void ObjectPaintInvalidator:: | 156 void ObjectPaintInvalidator:: |
| 151 invalidatePaintIncludingNonCompositingDescendants() { | 157 invalidatePaintIncludingNonCompositingDescendants() { |
| 152 // Since we're only painting non-composited layers, we know that they all shar
e the same paintInvalidationContainer. | 158 // Since we're only painting non-composited layers, we know that they all |
| 159 // share the same paintInvalidationContainer. |
| 153 const LayoutBoxModelObject& paintInvalidationContainer = | 160 const LayoutBoxModelObject& paintInvalidationContainer = |
| 154 m_object.containerForPaintInvalidation(); | 161 m_object.containerForPaintInvalidation(); |
| 155 traverseNonCompositingDescendantsInPaintOrder( | 162 traverseNonCompositingDescendantsInPaintOrder( |
| 156 m_object, [&paintInvalidationContainer](const LayoutObject& object) { | 163 m_object, [&paintInvalidationContainer](const LayoutObject& object) { |
| 157 if (object.hasLayer()) | 164 if (object.hasLayer()) |
| 158 toLayoutBoxModelObject(object).layer()->setNeedsRepaint(); | 165 toLayoutBoxModelObject(object).layer()->setNeedsRepaint(); |
| 159 ObjectPaintInvalidator(object) | 166 ObjectPaintInvalidator(object) |
| 160 .invalidatePaintOfPreviousPaintInvalidationRect( | 167 .invalidatePaintOfPreviousPaintInvalidationRect( |
| 161 paintInvalidationContainer, PaintInvalidationSubtree); | 168 paintInvalidationContainer, PaintInvalidationSubtree); |
| 162 }); | 169 }); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 181 invalidatePaintIncludingNonSelfPaintingLayerDescendants( | 188 invalidatePaintIncludingNonSelfPaintingLayerDescendants( |
| 182 const LayoutBoxModelObject& paintInvalidationContainer) { | 189 const LayoutBoxModelObject& paintInvalidationContainer) { |
| 183 slowSetPaintingLayerNeedsRepaint(); | 190 slowSetPaintingLayerNeedsRepaint(); |
| 184 invalidatePaintIncludingNonSelfPaintingLayerDescendantsInternal( | 191 invalidatePaintIncludingNonSelfPaintingLayerDescendantsInternal( |
| 185 paintInvalidationContainer); | 192 paintInvalidationContainer); |
| 186 } | 193 } |
| 187 | 194 |
| 188 void ObjectPaintInvalidator::invalidateDisplayItemClient( | 195 void ObjectPaintInvalidator::invalidateDisplayItemClient( |
| 189 const DisplayItemClient& client, | 196 const DisplayItemClient& client, |
| 190 PaintInvalidationReason reason) { | 197 PaintInvalidationReason reason) { |
| 191 // It's caller's responsibility to ensure enclosingSelfPaintingLayer's needsRe
paint is set. | 198 // It's caller's responsibility to ensure enclosingSelfPaintingLayer's |
| 192 // Don't set the flag here because getting enclosingSelfPaintLayer has cost an
d the caller can use | 199 // needsRepaint is set. Don't set the flag here because getting |
| 193 // various ways (e.g. PaintInvalidatinState::enclosingSelfPaintingLayer()) to
reduce the cost. | 200 // enclosingSelfPaintLayer has cost and the caller can use various ways (e.g. |
| 201 // PaintInvalidatinState::enclosingSelfPaintingLayer()) to reduce the cost. |
| 194 DCHECK(!m_object.paintingLayer() || m_object.paintingLayer()->needsRepaint()); | 202 DCHECK(!m_object.paintingLayer() || m_object.paintingLayer()->needsRepaint()); |
| 195 | 203 |
| 196 client.setDisplayItemsUncached(reason); | 204 client.setDisplayItemsUncached(reason); |
| 197 | 205 |
| 198 if (FrameView* frameView = m_object.frameView()) | 206 if (FrameView* frameView = m_object.frameView()) |
| 199 frameView->trackObjectPaintInvalidation(client, reason); | 207 frameView->trackObjectPaintInvalidation(client, reason); |
| 200 } | 208 } |
| 201 | 209 |
| 202 template <typename T> | 210 template <typename T> |
| 203 void addJsonObjectForRect(TracedValue* value, const char* name, const T& rect) { | 211 void addJsonObjectForRect(TracedValue* value, const char* name, const T& rect) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 return; | 244 return; |
| 237 | 245 |
| 238 if (HostWindow* window = frameView->getHostWindow()) | 246 if (HostWindow* window = frameView->getHostWindow()) |
| 239 window->invalidateRect(frameView->contentsToRootFrame(paintRect)); | 247 window->invalidateRect(frameView->contentsToRootFrame(paintRect)); |
| 240 } | 248 } |
| 241 | 249 |
| 242 void ObjectPaintInvalidator::setBackingNeedsPaintInvalidationInRect( | 250 void ObjectPaintInvalidator::setBackingNeedsPaintInvalidationInRect( |
| 243 const LayoutBoxModelObject& paintInvalidationContainer, | 251 const LayoutBoxModelObject& paintInvalidationContainer, |
| 244 const LayoutRect& rect, | 252 const LayoutRect& rect, |
| 245 PaintInvalidationReason reason) { | 253 PaintInvalidationReason reason) { |
| 246 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible c
rash here, | 254 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible |
| 247 // so assert but check that the layer is composited. | 255 // crash here, so assert but check that the layer is composited. |
| 248 DCHECK(paintInvalidationContainer.compositingState() != NotComposited); | 256 DCHECK(paintInvalidationContainer.compositingState() != NotComposited); |
| 249 | 257 |
| 250 PaintLayer& layer = *paintInvalidationContainer.layer(); | 258 PaintLayer& layer = *paintInvalidationContainer.layer(); |
| 251 if (layer.groupedMapping()) { | 259 if (layer.groupedMapping()) { |
| 252 if (GraphicsLayer* squashingLayer = | 260 if (GraphicsLayer* squashingLayer = |
| 253 layer.groupedMapping()->squashingLayer()) { | 261 layer.groupedMapping()->squashingLayer()) { |
| 254 // Note: the subpixel accumulation of layer() does not need to be added he
re. It is already taken into account. | 262 // Note: the subpixel accumulation of layer() does not need to be added |
| 263 // here. It is already taken into account. |
| 255 squashingLayer->setNeedsDisplayInRect(enclosingIntRect(rect), reason, | 264 squashingLayer->setNeedsDisplayInRect(enclosingIntRect(rect), reason, |
| 256 m_object); | 265 m_object); |
| 257 } | 266 } |
| 258 } else if (m_object.compositedScrollsWithRespectTo( | 267 } else if (m_object.compositedScrollsWithRespectTo( |
| 259 paintInvalidationContainer)) { | 268 paintInvalidationContainer)) { |
| 260 layer.compositedLayerMapping()->setScrollingContentsNeedDisplayInRect( | 269 layer.compositedLayerMapping()->setScrollingContentsNeedDisplayInRect( |
| 261 rect, reason, m_object); | 270 rect, reason, m_object); |
| 262 } else if (paintInvalidationContainer.usesCompositedScrolling()) { | 271 } else if (paintInvalidationContainer.usesCompositedScrolling()) { |
| 263 if (layer.compositedLayerMapping() | 272 if (layer.compositedLayerMapping() |
| 264 ->backgroundPaintsOntoScrollingContentsLayer()) { | 273 ->backgroundPaintsOntoScrollingContentsLayer()) { |
| 265 // TODO(flackr): Get a correct rect in the context of the scrolling conten
ts layer to update | 274 // TODO(flackr): Get a correct rect in the context of the scrolling |
| 266 // rather than updating the entire rect. | 275 // contents layer to update rather than updating the entire rect. |
| 267 const LayoutRect& scrollingContentsRect = | 276 const LayoutRect& scrollingContentsRect = |
| 268 toLayoutBox(m_object).layoutOverflowRect(); | 277 toLayoutBox(m_object).layoutOverflowRect(); |
| 269 layer.compositedLayerMapping()->setScrollingContentsNeedDisplayInRect( | 278 layer.compositedLayerMapping()->setScrollingContentsNeedDisplayInRect( |
| 270 scrollingContentsRect, reason, m_object); | 279 scrollingContentsRect, reason, m_object); |
| 271 layer.setNeedsRepaint(); | 280 layer.setNeedsRepaint(); |
| 272 invalidateDisplayItemClient( | 281 invalidateDisplayItemClient( |
| 273 *layer.compositedLayerMapping()->scrollingContentsLayer(), reason); | 282 *layer.compositedLayerMapping()->scrollingContentsLayer(), reason); |
| 274 } | 283 } |
| 275 layer.compositedLayerMapping()->setNonScrollingContentsNeedDisplayInRect( | 284 layer.compositedLayerMapping()->setNonScrollingContentsNeedDisplayInRect( |
| 276 rect, reason, m_object); | 285 rect, reason, m_object); |
| 277 } else { | 286 } else { |
| 278 // Otherwise invalidate everything. | 287 // Otherwise invalidate everything. |
| 279 layer.compositedLayerMapping()->setContentsNeedDisplayInRect(rect, reason, | 288 layer.compositedLayerMapping()->setContentsNeedDisplayInRect(rect, reason, |
| 280 m_object); | 289 m_object); |
| 281 } | 290 } |
| 282 } | 291 } |
| 283 | 292 |
| 284 void ObjectPaintInvalidator::invalidatePaintUsingContainer( | 293 void ObjectPaintInvalidator::invalidatePaintUsingContainer( |
| 285 const LayoutBoxModelObject& paintInvalidationContainer, | 294 const LayoutBoxModelObject& paintInvalidationContainer, |
| 286 const LayoutRect& dirtyRect, | 295 const LayoutRect& dirtyRect, |
| 287 PaintInvalidationReason invalidationReason) { | 296 PaintInvalidationReason invalidationReason) { |
| 288 // TODO(wangxianzhu): Enable the following assert after paint invalidation for
spv2 is ready. | 297 // TODO(wangxianzhu): Enable the following assert after paint invalidation for |
| 298 // spv2 is ready. |
| 289 // ASSERT(!RuntimeEnabledFeatures::slimmingPaintV2Enabled()); | 299 // ASSERT(!RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| 290 | 300 |
| 291 if (paintInvalidationContainer.frameView()->shouldThrottleRendering()) | 301 if (paintInvalidationContainer.frameView()->shouldThrottleRendering()) |
| 292 return; | 302 return; |
| 293 | 303 |
| 294 DCHECK(gDisablePaintInvalidationStateAsserts || | 304 DCHECK(gDisablePaintInvalidationStateAsserts || |
| 295 m_object.document().lifecycle().state() == | 305 m_object.document().lifecycle().state() == |
| 296 (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() | 306 (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() |
| 297 ? DocumentLifecycle::InPrePaint | 307 ? DocumentLifecycle::InPrePaint |
| 298 : DocumentLifecycle::InPaintInvalidation)); | 308 : DocumentLifecycle::InPaintInvalidation)); |
| 299 | 309 |
| 300 if (dirtyRect.isEmpty()) | 310 if (dirtyRect.isEmpty()) |
| 301 return; | 311 return; |
| 302 | 312 |
| 303 RELEASE_ASSERT(m_object.isRooted()); | 313 RELEASE_ASSERT(m_object.isRooted()); |
| 304 | 314 |
| 305 // FIXME: Unify "devtools.timeline.invalidationTracking" and "blink.invalidati
on". crbug.com/413527. | 315 // FIXME: Unify "devtools.timeline.invalidationTracking" and |
| 316 // "blink.invalidation". crbug.com/413527. |
| 306 TRACE_EVENT_INSTANT1( | 317 TRACE_EVENT_INSTANT1( |
| 307 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"), | 318 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"), |
| 308 "PaintInvalidationTracking", TRACE_EVENT_SCOPE_THREAD, "data", | 319 "PaintInvalidationTracking", TRACE_EVENT_SCOPE_THREAD, "data", |
| 309 InspectorPaintInvalidationTrackingEvent::data( | 320 InspectorPaintInvalidationTrackingEvent::data( |
| 310 &m_object, paintInvalidationContainer)); | 321 &m_object, paintInvalidationContainer)); |
| 311 TRACE_EVENT2( | 322 TRACE_EVENT2( |
| 312 TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), | 323 TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), |
| 313 "LayoutObject::invalidatePaintUsingContainer()", "object", | 324 "LayoutObject::invalidatePaintUsingContainer()", "object", |
| 314 m_object.debugName().ascii(), "info", | 325 m_object.debugName().ascii(), "info", |
| 315 jsonObjectForPaintInvalidationInfo( | 326 jsonObjectForPaintInvalidationInfo( |
| 316 dirtyRect, paintInvalidationReasonToString(invalidationReason))); | 327 dirtyRect, paintInvalidationReasonToString(invalidationReason))); |
| 317 | 328 |
| 318 // This conditional handles situations where non-rooted (and hence non-composi
ted) frames are | 329 // This conditional handles situations where non-rooted (and hence |
| 319 // painted, such as SVG images. | 330 // non-composited) frames are painted, such as SVG images. |
| 320 if (!paintInvalidationContainer.isPaintInvalidationContainer()) | 331 if (!paintInvalidationContainer.isPaintInvalidationContainer()) |
| 321 invalidatePaintRectangleOnWindow(paintInvalidationContainer, | 332 invalidatePaintRectangleOnWindow(paintInvalidationContainer, |
| 322 enclosingIntRect(dirtyRect)); | 333 enclosingIntRect(dirtyRect)); |
| 323 | 334 |
| 324 if (paintInvalidationContainer.view()->usesCompositing() && | 335 if (paintInvalidationContainer.view()->usesCompositing() && |
| 325 paintInvalidationContainer.isPaintInvalidationContainer()) | 336 paintInvalidationContainer.isPaintInvalidationContainer()) |
| 326 setBackingNeedsPaintInvalidationInRect(paintInvalidationContainer, | 337 setBackingNeedsPaintInvalidationInRect(paintInvalidationContainer, |
| 327 dirtyRect, invalidationReason); | 338 dirtyRect, invalidationReason); |
| 328 } | 339 } |
| 329 | 340 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 PaintInvalidationIncremental); | 412 PaintInvalidationIncremental); |
| 402 } | 413 } |
| 403 | 414 |
| 404 return true; | 415 return true; |
| 405 } | 416 } |
| 406 | 417 |
| 407 void ObjectPaintInvalidatorWithContext::fullyInvalidatePaint( | 418 void ObjectPaintInvalidatorWithContext::fullyInvalidatePaint( |
| 408 PaintInvalidationReason reason, | 419 PaintInvalidationReason reason, |
| 409 const LayoutRect& oldBounds, | 420 const LayoutRect& oldBounds, |
| 410 const LayoutRect& newBounds) { | 421 const LayoutRect& newBounds) { |
| 411 // The following logic avoids invalidating twice if one set of bounds contains
the other. | 422 // The following logic avoids invalidating twice if one set of bounds contains |
| 423 // the other. |
| 412 if (!newBounds.contains(oldBounds)) { | 424 if (!newBounds.contains(oldBounds)) { |
| 413 LayoutRect invalidationRect = oldBounds; | 425 LayoutRect invalidationRect = oldBounds; |
| 414 invalidatePaintUsingContainer(*m_context.paintInvalidationContainer, | 426 invalidatePaintUsingContainer(*m_context.paintInvalidationContainer, |
| 415 invalidationRect, reason); | 427 invalidationRect, reason); |
| 416 | 428 |
| 417 if (invalidationRect.contains(newBounds)) | 429 if (invalidationRect.contains(newBounds)) |
| 418 return; | 430 return; |
| 419 } | 431 } |
| 420 | 432 |
| 421 invalidatePaintUsingContainer(*m_context.paintInvalidationContainer, | 433 invalidatePaintUsingContainer(*m_context.paintInvalidationContainer, |
| 422 newBounds, reason); | 434 newBounds, reason); |
| 423 } | 435 } |
| 424 | 436 |
| 425 PaintInvalidationReason | 437 PaintInvalidationReason |
| 426 ObjectPaintInvalidatorWithContext::computePaintInvalidationReason() { | 438 ObjectPaintInvalidatorWithContext::computePaintInvalidationReason() { |
| 427 // This is before any early return to ensure the background obscuration status
is saved. | 439 // This is before any early return to ensure the background obscuration status |
| 440 // is saved. |
| 428 bool backgroundObscurationChanged = false; | 441 bool backgroundObscurationChanged = false; |
| 429 bool backgroundObscured = m_object.backgroundIsKnownToBeObscured(); | 442 bool backgroundObscured = m_object.backgroundIsKnownToBeObscured(); |
| 430 if (backgroundObscured != m_object.previousBackgroundObscured()) { | 443 if (backgroundObscured != m_object.previousBackgroundObscured()) { |
| 431 m_object.getMutableForPainting().setPreviousBackgroundObscured( | 444 m_object.getMutableForPainting().setPreviousBackgroundObscured( |
| 432 backgroundObscured); | 445 backgroundObscured); |
| 433 backgroundObscurationChanged = true; | 446 backgroundObscurationChanged = true; |
| 434 } | 447 } |
| 435 | 448 |
| 436 if (m_context.forcedSubtreeInvalidationFlags & | 449 if (m_context.forcedSubtreeInvalidationFlags & |
| 437 PaintInvalidatorContext::ForcedSubtreeFullInvalidation) | 450 PaintInvalidatorContext::ForcedSubtreeFullInvalidation) |
| 438 return PaintInvalidationSubtree; | 451 return PaintInvalidationSubtree; |
| 439 | 452 |
| 440 if (m_object.shouldDoFullPaintInvalidation()) | 453 if (m_object.shouldDoFullPaintInvalidation()) |
| 441 return m_object.fullPaintInvalidationReason(); | 454 return m_object.fullPaintInvalidationReason(); |
| 442 | 455 |
| 443 if (m_context.oldBounds.isEmpty() && m_context.newBounds.isEmpty()) | 456 if (m_context.oldBounds.isEmpty() && m_context.newBounds.isEmpty()) |
| 444 return PaintInvalidationNone; | 457 return PaintInvalidationNone; |
| 445 | 458 |
| 446 if (backgroundObscurationChanged) | 459 if (backgroundObscurationChanged) |
| 447 return PaintInvalidationBackgroundObscurationChange; | 460 return PaintInvalidationBackgroundObscurationChange; |
| 448 | 461 |
| 449 if (m_object.paintedOutputOfObjectHasNoEffectRegardlessOfSize()) | 462 if (m_object.paintedOutputOfObjectHasNoEffectRegardlessOfSize()) |
| 450 return PaintInvalidationNone; | 463 return PaintInvalidationNone; |
| 451 | 464 |
| 452 const ComputedStyle& style = m_object.styleRef(); | 465 const ComputedStyle& style = m_object.styleRef(); |
| 453 | 466 |
| 454 // The outline may change shape because of position change of descendants. For
simplicity, | 467 // The outline may change shape because of position change of descendants. For |
| 455 // just force full paint invalidation if this object is marked for checking pa
int invalidation | 468 // simplicity, just force full paint invalidation if this object is marked for |
| 456 // for any reason. | 469 // checking paint invalidation for any reason. |
| 457 // TODO(wangxianzhu): Optimize this. | 470 // TODO(wangxianzhu): Optimize this. |
| 458 if (style.hasOutline()) | 471 if (style.hasOutline()) |
| 459 return PaintInvalidationOutline; | 472 return PaintInvalidationOutline; |
| 460 | 473 |
| 461 bool locationChanged = m_context.newLocation != m_context.oldLocation; | 474 bool locationChanged = m_context.newLocation != m_context.oldLocation; |
| 462 | 475 |
| 463 // If the bounds are the same then we know that none of the statements below | 476 // If the bounds are the same then we know that none of the statements below |
| 464 // can match, so we can early out. However, we can't return PaintInvalidationN
one even if | 477 // can match, so we can early out. However, we can't return |
| 465 // !locationChagned, but conservatively return PaintInvalidationIncremental be
cause we are | 478 // PaintInvalidationNone even if !locationChagned, but conservatively return |
| 466 // not sure whether paint invalidation is actually needed just based on inform
ation known | 479 // PaintInvalidationIncremental because we are not sure whether paint |
| 467 // to LayoutObject. For example, a LayoutBox may need paint invalidation if bo
rder box changes. | 480 // invalidation is actually needed just based on information known to |
| 481 // LayoutObject. For example, a LayoutBox may need paint invalidation if |
| 482 // border box changes. |
| 468 if (m_context.oldBounds == m_context.newBounds) | 483 if (m_context.oldBounds == m_context.newBounds) |
| 469 return locationChanged ? PaintInvalidationLocationChange | 484 return locationChanged ? PaintInvalidationLocationChange |
| 470 : PaintInvalidationIncremental; | 485 : PaintInvalidationIncremental; |
| 471 | 486 |
| 472 // If the size is zero on one of our bounds then we know we're going to have | 487 // If the size is zero on one of our bounds then we know we're going to have |
| 473 // to do a full invalidation of either old bounds or new bounds. | 488 // to do a full invalidation of either old bounds or new bounds. |
| 474 if (m_context.oldBounds.isEmpty()) | 489 if (m_context.oldBounds.isEmpty()) |
| 475 return PaintInvalidationBecameVisible; | 490 return PaintInvalidationBecameVisible; |
| 476 if (m_context.newBounds.isEmpty()) | 491 if (m_context.newBounds.isEmpty()) |
| 477 return PaintInvalidationBecameInvisible; | 492 return PaintInvalidationBecameInvisible; |
| 478 | 493 |
| 479 // If we shifted, we don't know the exact reason so we are conservative and tr
igger a full invalidation. Shifting could | 494 // If we shifted, we don't know the exact reason so we are conservative and |
| 480 // be caused by some layout property (left / top) or some in-flow layoutObject
inserted / removed before us in the tree. | 495 // trigger a full invalidation. Shifting could be caused by some layout |
| 496 // property (left / top) or some in-flow layoutObject inserted / removed |
| 497 // before us in the tree. |
| 481 if (m_context.newBounds.location() != m_context.oldBounds.location()) | 498 if (m_context.newBounds.location() != m_context.oldBounds.location()) |
| 482 return PaintInvalidationBoundsChange; | 499 return PaintInvalidationBoundsChange; |
| 483 | 500 |
| 484 if (locationChanged) | 501 if (locationChanged) |
| 485 return PaintInvalidationLocationChange; | 502 return PaintInvalidationLocationChange; |
| 486 | 503 |
| 487 return PaintInvalidationIncremental; | 504 return PaintInvalidationIncremental; |
| 488 } | 505 } |
| 489 | 506 |
| 490 void ObjectPaintInvalidatorWithContext::invalidateSelectionIfNeeded( | 507 void ObjectPaintInvalidatorWithContext::invalidateSelectionIfNeeded( |
| 491 PaintInvalidationReason reason) { | 508 PaintInvalidationReason reason) { |
| 492 // Update selection rect when we are doing full invalidation (in case that the
object is moved, | 509 // Update selection rect when we are doing full invalidation (in case that the |
| 493 // composite status changed, etc.) or shouldInvalidationSelection is set (in c
ase that the | 510 // object is moved, composite status changed, etc.) or |
| 494 // selection itself changed). | 511 // shouldInvalidationSelection is set (in case that the selection itself |
| 512 // changed). |
| 495 bool fullInvalidation = isImmediateFullPaintInvalidationReason(reason); | 513 bool fullInvalidation = isImmediateFullPaintInvalidationReason(reason); |
| 496 if (!fullInvalidation && !m_object.shouldInvalidateSelection()) | 514 if (!fullInvalidation && !m_object.shouldInvalidateSelection()) |
| 497 return; | 515 return; |
| 498 | 516 |
| 499 LayoutRect oldSelectionRect = selectionPaintInvalidationMap().get(&m_object); | 517 LayoutRect oldSelectionRect = selectionPaintInvalidationMap().get(&m_object); |
| 500 LayoutRect newSelectionRect = m_object.localSelectionRect(); | 518 LayoutRect newSelectionRect = m_object.localSelectionRect(); |
| 501 if (!newSelectionRect.isEmpty()) { | 519 if (!newSelectionRect.isEmpty()) { |
| 502 m_context.mapLocalRectToPaintInvalidationBacking(m_object, | 520 m_context.mapLocalRectToPaintInvalidationBacking(m_object, |
| 503 newSelectionRect); | 521 newSelectionRect); |
| 504 newSelectionRect.move(m_object.scrollAdjustmentForPaintInvalidation( | 522 newSelectionRect.move(m_object.scrollAdjustmentForPaintInvalidation( |
| 505 *m_context.paintInvalidationContainer)); | 523 *m_context.paintInvalidationContainer)); |
| 506 } | 524 } |
| 507 | 525 |
| 508 setPreviousSelectionPaintInvalidationRect(m_object, newSelectionRect); | 526 setPreviousSelectionPaintInvalidationRect(m_object, newSelectionRect); |
| 509 | 527 |
| 510 if (!fullInvalidation) { | 528 if (!fullInvalidation) { |
| 511 fullyInvalidatePaint(PaintInvalidationSelection, oldSelectionRect, | 529 fullyInvalidatePaint(PaintInvalidationSelection, oldSelectionRect, |
| 512 newSelectionRect); | 530 newSelectionRect); |
| 513 m_context.paintingLayer->setNeedsRepaint(); | 531 m_context.paintingLayer->setNeedsRepaint(); |
| 514 m_object.invalidateDisplayItemClients(PaintInvalidationSelection); | 532 m_object.invalidateDisplayItemClients(PaintInvalidationSelection); |
| 515 } | 533 } |
| 516 } | 534 } |
| 517 | 535 |
| 518 PaintInvalidationReason | 536 PaintInvalidationReason |
| 519 ObjectPaintInvalidatorWithContext::invalidatePaintIfNeededWithComputedReason( | 537 ObjectPaintInvalidatorWithContext::invalidatePaintIfNeededWithComputedReason( |
| 520 PaintInvalidationReason reason) { | 538 PaintInvalidationReason reason) { |
| 521 // We need to invalidate the selection before checking for whether we are doin
g a full invalidation. | 539 // We need to invalidate the selection before checking for whether we are |
| 522 // This is because we need to update the previous selection rect regardless. | 540 // doing a full invalidation. This is because we need to update the previous |
| 541 // selection rect regardless. |
| 523 invalidateSelectionIfNeeded(reason); | 542 invalidateSelectionIfNeeded(reason); |
| 524 | 543 |
| 525 if (reason == PaintInvalidationIncremental && !incrementallyInvalidatePaint()) | 544 if (reason == PaintInvalidationIncremental && !incrementallyInvalidatePaint()) |
| 526 reason = PaintInvalidationNone; | 545 reason = PaintInvalidationNone; |
| 527 | 546 |
| 528 switch (reason) { | 547 switch (reason) { |
| 529 case PaintInvalidationNone: | 548 case PaintInvalidationNone: |
| 530 // TODO(trchen): Currently we don't keep track of paint offset of layout o
bjects. | 549 // TODO(trchen): Currently we don't keep track of paint offset of layout |
| 531 // There are corner cases that the display items need to be invalidated fo
r paint offset | 550 // objects. There are corner cases that the display items need to be |
| 532 // mutation, but incurs no pixel difference (i.e. bounds stay the same) so
no rect-based | 551 // invalidated for paint offset mutation, but incurs no pixel difference |
| 533 // invalidation is issued. See crbug.com/508383 and crbug.com/515977. | 552 // (i.e. bounds stay the same) so no rect-based invalidation is issued. |
| 534 // This is a workaround to force display items to update paint offset. | 553 // See crbug.com/508383 and crbug.com/515977. This is a workaround to |
| 554 // force display items to update paint offset. |
| 535 if (m_context.forcedSubtreeInvalidationFlags & | 555 if (m_context.forcedSubtreeInvalidationFlags & |
| 536 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking) { | 556 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking) { |
| 537 reason = PaintInvalidationLocationChange; | 557 reason = PaintInvalidationLocationChange; |
| 538 break; | 558 break; |
| 539 } | 559 } |
| 540 return PaintInvalidationNone; | 560 return PaintInvalidationNone; |
| 541 case PaintInvalidationIncremental: | 561 case PaintInvalidationIncremental: |
| 542 break; | 562 break; |
| 543 case PaintInvalidationDelayedFull: | 563 case PaintInvalidationDelayedFull: |
| 544 return PaintInvalidationDelayedFull; | 564 return PaintInvalidationDelayedFull; |
| 545 default: | 565 default: |
| 546 DCHECK(isImmediateFullPaintInvalidationReason(reason)); | 566 DCHECK(isImmediateFullPaintInvalidationReason(reason)); |
| 547 fullyInvalidatePaint(reason, m_context.oldBounds, m_context.newBounds); | 567 fullyInvalidatePaint(reason, m_context.oldBounds, m_context.newBounds); |
| 548 } | 568 } |
| 549 | 569 |
| 550 m_context.paintingLayer->setNeedsRepaint(); | 570 m_context.paintingLayer->setNeedsRepaint(); |
| 551 m_object.invalidateDisplayItemClients(reason); | 571 m_object.invalidateDisplayItemClients(reason); |
| 552 return reason; | 572 return reason; |
| 553 } | 573 } |
| 554 | 574 |
| 555 DisablePaintInvalidationStateAsserts::DisablePaintInvalidationStateAsserts() | 575 DisablePaintInvalidationStateAsserts::DisablePaintInvalidationStateAsserts() |
| 556 : m_disabler(&gDisablePaintInvalidationStateAsserts, true) {} | 576 : m_disabler(&gDisablePaintInvalidationStateAsserts, true) {} |
| 557 | 577 |
| 558 } // namespace blink | 578 } // namespace blink |
| OLD | NEW |