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/layout/LayoutBlockFlow.h" | 7 #include "core/layout/LayoutBlockFlow.h" |
8 #include "core/paint/PaintInvalidator.h" | 8 #include "core/paint/PaintInvalidator.h" |
9 #include "core/paint/PaintLayer.h" | 9 #include "core/paint/PaintLayer.h" |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... |
23 selectionPaintInvalidationMap().remove(&object); | 23 selectionPaintInvalidationMap().remove(&object); |
24 else | 24 else |
25 selectionPaintInvalidationMap().set(&object, rect); | 25 selectionPaintInvalidationMap().set(&object, rect); |
26 } | 26 } |
27 | 27 |
28 void ObjectPaintInvalidator::objectWillBeDestroyed(const LayoutObject& object) | 28 void ObjectPaintInvalidator::objectWillBeDestroyed(const LayoutObject& object) |
29 { | 29 { |
30 selectionPaintInvalidationMap().remove(&object); | 30 selectionPaintInvalidationMap().remove(&object); |
31 } | 31 } |
32 | 32 |
33 void ObjectPaintInvalidator::incrementallyInvalidatePaint() | 33 bool ObjectPaintInvalidator::incrementallyInvalidatePaint() |
34 { | 34 { |
35 const LayoutRect& oldBounds = m_context.oldBounds; | 35 const LayoutRect& oldBounds = m_context.oldBounds; |
36 const LayoutRect& newBounds = m_context.newBounds; | 36 const LayoutRect& newBounds = m_context.newBounds; |
37 | 37 |
38 DCHECK(oldBounds.location() == newBounds.location()); | 38 DCHECK(oldBounds.location() == newBounds.location()); |
39 | 39 |
40 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); | 40 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); |
| 41 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); |
| 42 if (!deltaRight && !deltaBottom) |
| 43 return false; |
| 44 |
41 if (deltaRight > 0) { | 45 if (deltaRight > 0) { |
42 LayoutRect invalidationRect(oldBounds.maxX(), newBounds.y(), deltaRight,
newBounds.height()); | 46 LayoutRect invalidationRect(oldBounds.maxX(), newBounds.y(), deltaRight,
newBounds.height()); |
43 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); | 47 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); |
44 } else if (deltaRight < 0) { | 48 } else if (deltaRight < 0) { |
45 LayoutRect invalidationRect(newBounds.maxX(), oldBounds.y(), -deltaRight
, oldBounds.height()); | 49 LayoutRect invalidationRect(newBounds.maxX(), oldBounds.y(), -deltaRight
, oldBounds.height()); |
46 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); | 50 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); |
47 } | 51 } |
48 | 52 |
49 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); | |
50 if (deltaBottom > 0) { | 53 if (deltaBottom > 0) { |
51 LayoutRect invalidationRect(newBounds.x(), oldBounds.maxY(), newBounds.w
idth(), deltaBottom); | 54 LayoutRect invalidationRect(newBounds.x(), oldBounds.maxY(), newBounds.w
idth(), deltaBottom); |
52 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); | 55 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); |
53 } else if (deltaBottom < 0) { | 56 } else if (deltaBottom < 0) { |
54 LayoutRect invalidationRect(oldBounds.x(), newBounds.maxY(), oldBounds.w
idth(), -deltaBottom); | 57 LayoutRect invalidationRect(oldBounds.x(), newBounds.maxY(), oldBounds.w
idth(), -deltaBottom); |
55 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); | 58 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, PaintInvalidationIncremental); |
56 } | 59 } |
| 60 |
| 61 return true; |
57 } | 62 } |
58 | 63 |
59 void ObjectPaintInvalidator::fullyInvalidatePaint(PaintInvalidationReason reason
, const LayoutRect& oldBounds, const LayoutRect& newBounds) | 64 void ObjectPaintInvalidator::fullyInvalidatePaint(PaintInvalidationReason reason
, const LayoutRect& oldBounds, const LayoutRect& newBounds) |
60 { | 65 { |
61 // The following logic avoids invalidating twice if one set of bounds contai
ns the other. | 66 // The following logic avoids invalidating twice if one set of bounds contai
ns the other. |
62 if (!newBounds.contains(oldBounds)) { | 67 if (!newBounds.contains(oldBounds)) { |
63 LayoutRect invalidationRect = oldBounds; | 68 LayoutRect invalidationRect = oldBounds; |
64 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, reason); | 69 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta
iner, invalidationRect, reason); |
65 | 70 |
66 if (invalidationRect.contains(newBounds)) | 71 if (invalidationRect.contains(newBounds)) |
(...skipping 12 matching lines...) Expand all Loading... |
79 m_object.getMutableForPainting().setPreviousBackgroundObscured(backgroun
dObscured); | 84 m_object.getMutableForPainting().setPreviousBackgroundObscured(backgroun
dObscured); |
80 backgroundObscurationChanged = true; | 85 backgroundObscurationChanged = true; |
81 } | 86 } |
82 | 87 |
83 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::Forc
edSubtreeFullInvalidation) | 88 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::Forc
edSubtreeFullInvalidation) |
84 return PaintInvalidationSubtree; | 89 return PaintInvalidationSubtree; |
85 | 90 |
86 if (m_object.shouldDoFullPaintInvalidation()) | 91 if (m_object.shouldDoFullPaintInvalidation()) |
87 return m_object.fullPaintInvalidationReason(); | 92 return m_object.fullPaintInvalidationReason(); |
88 | 93 |
| 94 if (m_context.oldBounds.isEmpty() && m_context.newBounds.isEmpty()) |
| 95 return PaintInvalidationNone; |
| 96 |
89 if (backgroundObscurationChanged) | 97 if (backgroundObscurationChanged) |
90 return PaintInvalidationBackgroundObscurationChange; | 98 return PaintInvalidationBackgroundObscurationChange; |
91 | 99 |
92 if (m_object.paintedOutputOfObjectHasNoEffect()) | 100 if (m_object.paintedOutputOfObjectHasNoEffectRegardlessOfSize()) |
93 return PaintInvalidationNone; | 101 return PaintInvalidationNone; |
94 | 102 |
95 const ComputedStyle& style = m_object.styleRef(); | 103 const ComputedStyle& style = m_object.styleRef(); |
96 | 104 |
97 // The outline may change shape because of position change of descendants. F
or simplicity, | 105 // The outline may change shape because of position change of descendants. F
or simplicity, |
98 // just force full paint invalidation if this object is marked for checking
paint invalidation | 106 // just force full paint invalidation if this object is marked for checking
paint invalidation |
99 // for any reason. | 107 // for any reason. |
100 // TODO(wangxianzhu): Optimize this. | 108 // TODO(wangxianzhu): Optimize this. |
101 if (style.hasOutline()) | 109 if (style.hasOutline()) |
102 return PaintInvalidationOutline; | 110 return PaintInvalidationOutline; |
103 | 111 |
104 bool locationChanged = m_context.newLocation != m_context.oldLocation; | 112 bool locationChanged = m_context.newLocation != m_context.oldLocation; |
105 | 113 |
106 // If the bounds are the same then we know that none of the statements below | 114 // If the bounds are the same then we know that none of the statements below |
107 // can match, so we can early out. | 115 // can match, so we can early out. However, we can't return PaintInvalidatio
nNone even if |
| 116 // !locationChagned, but conservatively return PaintInvalidationIncremental
because we are |
| 117 // not sure whether paint invalidation is actually needed just based on info
rmation known |
| 118 // to LayoutObject. For example, a LayoutBox may need paint invalidation if
border box changes. |
108 if (m_context.oldBounds == m_context.newBounds) | 119 if (m_context.oldBounds == m_context.newBounds) |
109 return locationChanged && !m_context.oldBounds.isEmpty() ? PaintInvalida
tionLocationChange : PaintInvalidationNone; | 120 return locationChanged ? PaintInvalidationLocationChange : PaintInvalida
tionIncremental; |
110 | |
111 // If we shifted, we don't know the exact reason so we are conservative and
trigger a full invalidation. Shifting could | |
112 // be caused by some layout property (left / top) or some in-flow layoutObje
ct inserted / removed before us in the tree. | |
113 if (m_context.newBounds.location() != m_context.oldBounds.location()) | |
114 return PaintInvalidationBoundsChange; | |
115 | 121 |
116 // If the size is zero on one of our bounds then we know we're going to have | 122 // If the size is zero on one of our bounds then we know we're going to have |
117 // to do a full invalidation of either old bounds or new bounds. | 123 // to do a full invalidation of either old bounds or new bounds. |
118 if (m_context.oldBounds.isEmpty()) | 124 if (m_context.oldBounds.isEmpty()) |
119 return PaintInvalidationBecameVisible; | 125 return PaintInvalidationBecameVisible; |
120 if (m_context.newBounds.isEmpty()) | 126 if (m_context.newBounds.isEmpty()) |
121 return PaintInvalidationBecameInvisible; | 127 return PaintInvalidationBecameInvisible; |
122 | 128 |
| 129 // If we shifted, we don't know the exact reason so we are conservative and
trigger a full invalidation. Shifting could |
| 130 // be caused by some layout property (left / top) or some in-flow layoutObje
ct inserted / removed before us in the tree. |
| 131 if (m_context.newBounds.location() != m_context.oldBounds.location()) |
| 132 return PaintInvalidationBoundsChange; |
| 133 |
123 if (locationChanged) | 134 if (locationChanged) |
124 return PaintInvalidationLocationChange; | 135 return PaintInvalidationLocationChange; |
125 | 136 |
126 return PaintInvalidationIncremental; | 137 return PaintInvalidationIncremental; |
127 } | 138 } |
128 | 139 |
129 void ObjectPaintInvalidator::invalidateSelectionIfNeeded(PaintInvalidationReason
reason) | 140 void ObjectPaintInvalidator::invalidateSelectionIfNeeded(PaintInvalidationReason
reason) |
130 { | 141 { |
131 // Update selection rect when we are doing full invalidation (in case that t
he object is moved, | 142 // Update selection rect when we are doing full invalidation (in case that t
he object is moved, |
132 // composite status changed, etc.) or shouldInvalidationSelection is set (in
case that the | 143 // composite status changed, etc.) or shouldInvalidationSelection is set (in
case that the |
133 // selection itself changed). | 144 // selection itself changed). |
134 bool fullInvalidation = isFullPaintInvalidationReason(reason); | 145 bool fullInvalidation = isImmediateFullPaintInvalidationReason(reason); |
135 if (!fullInvalidation && !m_object.shouldInvalidateSelection()) | 146 if (!fullInvalidation && !m_object.shouldInvalidateSelection()) |
136 return; | 147 return; |
137 | 148 |
138 LayoutRect oldSelectionRect = selectionPaintInvalidationMap().get(&m_object)
; | 149 LayoutRect oldSelectionRect = selectionPaintInvalidationMap().get(&m_object)
; |
139 LayoutRect newSelectionRect = m_object.localSelectionRect(); | 150 LayoutRect newSelectionRect = m_object.localSelectionRect(); |
140 if (!newSelectionRect.isEmpty()) | 151 if (!newSelectionRect.isEmpty()) |
141 m_context.mapLocalRectToPaintInvalidationBacking(m_object, newSelectionR
ect); | 152 m_context.mapLocalRectToPaintInvalidationBacking(m_object, newSelectionR
ect); |
142 | 153 |
143 newSelectionRect.move(m_object.scrollAdjustmentForPaintInvalidation(*m_conte
xt.paintInvalidationContainer)); | 154 newSelectionRect.move(m_object.scrollAdjustmentForPaintInvalidation(*m_conte
xt.paintInvalidationContainer)); |
144 | 155 |
145 setPreviousSelectionPaintInvalidationRect(m_object, newSelectionRect); | 156 setPreviousSelectionPaintInvalidationRect(m_object, newSelectionRect); |
146 | 157 |
147 if (!fullInvalidation) { | 158 if (!fullInvalidation) { |
148 fullyInvalidatePaint(PaintInvalidationSelection, oldSelectionRect, newSe
lectionRect); | 159 fullyInvalidatePaint(PaintInvalidationSelection, oldSelectionRect, newSe
lectionRect); |
149 m_context.paintingLayer->setNeedsRepaint(); | 160 m_context.paintingLayer->setNeedsRepaint(); |
150 m_object.invalidateDisplayItemClients(PaintInvalidationSelection); | 161 m_object.invalidateDisplayItemClients(PaintInvalidationSelection); |
151 } | 162 } |
152 } | 163 } |
153 | 164 |
154 PaintInvalidationReason ObjectPaintInvalidator::invalidatePaintIfNeededWithCompu
tedReason(PaintInvalidationReason reason) | 165 PaintInvalidationReason ObjectPaintInvalidator::invalidatePaintIfNeededWithCompu
tedReason(PaintInvalidationReason reason) |
155 { | 166 { |
156 // We need to invalidate the selection before checking for whether we are do
ing a full invalidation. | 167 // We need to invalidate the selection before checking for whether we are do
ing a full invalidation. |
157 // This is because we need to update the previous selection rect regardless. | 168 // This is because we need to update the previous selection rect regardless. |
158 invalidateSelectionIfNeeded(reason); | 169 invalidateSelectionIfNeeded(reason); |
159 | 170 |
| 171 if (reason == PaintInvalidationIncremental && !incrementallyInvalidatePaint(
)) |
| 172 reason = PaintInvalidationNone; |
| 173 |
160 switch (reason) { | 174 switch (reason) { |
161 case PaintInvalidationNone: | 175 case PaintInvalidationNone: |
162 // TODO(trchen): Currently we don't keep track of paint offset of layout
objects. | 176 // TODO(trchen): Currently we don't keep track of paint offset of layout
objects. |
163 // There are corner cases that the display items need to be invalidated
for paint offset | 177 // There are corner cases that the display items need to be invalidated
for paint offset |
164 // mutation, but incurs no pixel difference (i.e. bounds stay the same)
so no rect-based | 178 // mutation, but incurs no pixel difference (i.e. bounds stay the same)
so no rect-based |
165 // invalidation is issued. See crbug.com/508383 and crbug.com/515977. | 179 // invalidation is issued. See crbug.com/508383 and crbug.com/515977. |
166 // This is a workaround to force display items to update paint offset. | 180 // This is a workaround to force display items to update paint offset. |
167 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::
ForcedSubtreeInvalidationChecking) { | 181 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::
ForcedSubtreeInvalidationChecking) { |
168 reason = PaintInvalidationLocationChange; | 182 reason = PaintInvalidationLocationChange; |
169 break; | 183 break; |
170 } | 184 } |
171 return PaintInvalidationNone; | 185 return PaintInvalidationNone; |
172 case PaintInvalidationIncremental: | 186 case PaintInvalidationIncremental: |
173 incrementallyInvalidatePaint(); | |
174 break; | 187 break; |
175 case PaintInvalidationDelayedFull: | 188 case PaintInvalidationDelayedFull: |
176 return PaintInvalidationDelayedFull; | 189 return PaintInvalidationDelayedFull; |
177 default: | 190 default: |
178 DCHECK(isFullPaintInvalidationReason(reason)); | 191 DCHECK(isImmediateFullPaintInvalidationReason(reason)); |
179 fullyInvalidatePaint(reason, m_context.oldBounds, m_context.newBounds); | 192 fullyInvalidatePaint(reason, m_context.oldBounds, m_context.newBounds); |
180 } | 193 } |
181 | 194 |
182 m_context.paintingLayer->setNeedsRepaint(); | 195 m_context.paintingLayer->setNeedsRepaint(); |
183 m_object.invalidateDisplayItemClients(reason); | 196 m_object.invalidateDisplayItemClients(reason); |
184 return reason; | 197 return reason; |
185 } | 198 } |
186 | 199 |
187 } // namespace blink | 200 } // namespace blink |
OLD | NEW |