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/BoxPaintInvalidator.h" | 5 #include "core/paint/BoxPaintInvalidator.h" |
6 | 6 |
7 #include "core/frame/Settings.h" | 7 #include "core/frame/Settings.h" |
8 #include "core/layout/LayoutView.h" | 8 #include "core/layout/LayoutView.h" |
9 #include "core/paint/ObjectPaintInvalidator.h" | 9 #include "core/paint/ObjectPaintInvalidator.h" |
10 #include "core/paint/PaintInvalidator.h" | 10 #include "core/paint/PaintInvalidator.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 typedef HashMap<const LayoutBox*, PreviousBoxSizes> PreviousBoxSizesMap; | 23 typedef HashMap<const LayoutBox*, PreviousBoxSizes> PreviousBoxSizesMap; |
24 static PreviousBoxSizesMap& previousBoxSizesMap() { | 24 static PreviousBoxSizesMap& previousBoxSizesMap() { |
25 DEFINE_STATIC_LOCAL(PreviousBoxSizesMap, map, ()); | 25 DEFINE_STATIC_LOCAL(PreviousBoxSizesMap, map, ()); |
26 return map; | 26 return map; |
27 } | 27 } |
28 | 28 |
29 void BoxPaintInvalidator::boxWillBeDestroyed(const LayoutBox& box) { | 29 void BoxPaintInvalidator::boxWillBeDestroyed(const LayoutBox& box) { |
30 previousBoxSizesMap().remove(&box); | 30 previousBoxSizesMap().remove(&box); |
31 } | 31 } |
32 | 32 |
33 static LayoutRect computeRightDelta(const LayoutPoint& location, | |
34 const LayoutSize& oldSize, | |
35 const LayoutSize& newSize, | |
36 int extraWidth) { | |
37 LayoutUnit delta = newSize.width() - oldSize.width(); | |
38 if (delta > 0) { | |
39 return LayoutRect(location.x() + oldSize.width() - extraWidth, location.y(), | |
40 delta + extraWidth, newSize.height()); | |
41 } | |
42 if (delta < 0) { | |
43 return LayoutRect(location.x() + newSize.width() - extraWidth, location.y(), | |
44 -delta + extraWidth, oldSize.height()); | |
45 } | |
46 return LayoutRect(); | |
47 } | |
48 | |
49 static LayoutRect computeBottomDelta(const LayoutPoint& location, | |
50 const LayoutSize& oldSize, | |
51 const LayoutSize& newSize, | |
52 int extraHeight) { | |
53 LayoutUnit delta = newSize.height() - oldSize.height(); | |
54 if (delta > 0) { | |
55 return LayoutRect(location.x(), | |
56 location.y() + oldSize.height() - extraHeight, | |
57 newSize.width(), delta + extraHeight); | |
58 } | |
59 if (delta < 0) { | |
60 return LayoutRect(location.x(), | |
61 location.y() + newSize.height() - extraHeight, | |
62 oldSize.width(), -delta + extraHeight); | |
63 } | |
64 return LayoutRect(); | |
65 } | |
66 | |
33 bool BoxPaintInvalidator::incrementallyInvalidatePaint() { | 67 bool BoxPaintInvalidator::incrementallyInvalidatePaint() { |
34 bool result = ObjectPaintInvalidatorWithContext(m_box, m_context) | 68 DCHECK(m_context.oldBounds.location() == m_context.newBounds.location()); |
chrishtr
2016/10/20 18:15:44
Could you add unittests to the geometric logic her
Xianzhu
2016/10/21 00:19:49
Done.
| |
35 .incrementallyInvalidatePaint(); | 69 LayoutRect rightDelta = computeRightDelta(m_context.newBounds.location(), |
70 m_context.oldBounds.size(), | |
71 m_context.newBounds.size(), 0); | |
72 LayoutRect bottomDelta = computeBottomDelta(m_context.newBounds.location(), | |
73 m_context.oldBounds.size(), | |
74 m_context.newBounds.size(), 0); | |
36 | 75 |
37 bool hasBoxDecorations = m_box.styleRef().hasBoxDecorations(); | 76 if (m_box.styleRef().hasBorder() || m_box.styleRef().hasBackground()) { |
38 if (!m_box.styleRef().hasBackground() && !hasBoxDecorations) | 77 LayoutSize oldBorderBoxSize = |
39 return result; | 78 computePreviousBorderBoxSize(m_context.oldBounds.size()); |
40 | 79 LayoutSize newBorderBoxSize = m_box.size(); |
41 const LayoutRect& oldBounds = m_context.oldBounds; | 80 DCHECK(m_context.oldLocation == m_context.newLocation); |
42 const LayoutRect& newBounds = m_context.newBounds; | 81 rightDelta.unite(computeRightDelta(m_context.newLocation, oldBorderBoxSize, |
43 | 82 newBorderBoxSize, m_box.borderRight())); |
44 LayoutSize oldBorderBoxSize = computePreviousBorderBoxSize(oldBounds.size()); | 83 bottomDelta.unite(computeBottomDelta(m_context.newLocation, |
45 LayoutSize newBorderBoxSize = m_box.size(); | 84 oldBorderBoxSize, newBorderBoxSize, |
46 | 85 m_box.borderBottom())); |
47 // If border m_box size didn't change, | |
48 // ObjectPaintInvalidatorWithContext::incrementallyInvalidatePaint() is good. | |
49 if (oldBorderBoxSize == newBorderBoxSize) | |
50 return result; | |
51 | |
52 // If size of the paint invalidation rect equals to size of border box, | |
53 // ObjectPaintInvalidatorWithContext::incrementallyInvalidatePaint() | |
54 // is good for boxes having background without box decorations. | |
55 DCHECK( | |
56 oldBounds.location() == | |
57 newBounds.location()); // Otherwise we won't do incremental invalidation. | |
58 if (!hasBoxDecorations && m_context.newLocation == newBounds.location() && | |
59 oldBorderBoxSize == oldBounds.size() && | |
60 newBorderBoxSize == newBounds.size()) | |
61 return result; | |
62 | |
63 // Invalidate the right delta part and the right border of the old or new | |
64 // m_box which has smaller width. | |
65 if (LayoutUnit deltaWidth = | |
66 (oldBorderBoxSize.width() - newBorderBoxSize.width()).abs()) { | |
67 LayoutUnit smallerWidth = | |
68 std::min(oldBorderBoxSize.width(), newBorderBoxSize.width()); | |
69 LayoutUnit borderTopRightRadiusWidth = valueForLength( | |
70 m_box.styleRef().borderTopRightRadius().width(), smallerWidth); | |
71 LayoutUnit borderBottomRightRadiusWidth = valueForLength( | |
72 m_box.styleRef().borderBottomRightRadius().width(), smallerWidth); | |
73 LayoutUnit borderWidth = std::max( | |
74 LayoutUnit(m_box.borderRight()), | |
75 std::max(borderTopRightRadiusWidth, borderBottomRightRadiusWidth)); | |
76 LayoutRect rightDeltaRect( | |
77 m_context.newLocation.x() + smallerWidth - borderWidth, | |
78 m_context.newLocation.y(), deltaWidth + borderWidth, | |
79 std::max(oldBorderBoxSize.height(), newBorderBoxSize.height())); | |
80 invalidatePaintRectClippedByOldAndNewBounds(rightDeltaRect); | |
81 } | 86 } |
82 | 87 |
83 // Invalidate the bottom delta part and the bottom border of the old or new | 88 if (rightDelta.isEmpty() && bottomDelta.isEmpty()) |
84 // m_box which has smaller height. | 89 return false; |
85 if (LayoutUnit deltaHeight = | |
86 (oldBorderBoxSize.height() - newBorderBoxSize.height()).abs()) { | |
87 LayoutUnit smallerHeight = | |
88 std::min(oldBorderBoxSize.height(), newBorderBoxSize.height()); | |
89 LayoutUnit borderBottomLeftRadiusHeight = valueForLength( | |
90 m_box.styleRef().borderBottomLeftRadius().height(), smallerHeight); | |
91 LayoutUnit borderBottomRightRadiusHeight = valueForLength( | |
92 m_box.styleRef().borderBottomRightRadius().height(), smallerHeight); | |
93 LayoutUnit borderHeight = std::max( | |
94 LayoutUnit(m_box.borderBottom()), | |
95 std::max(borderBottomLeftRadiusHeight, borderBottomRightRadiusHeight)); | |
96 LayoutRect bottomDeltaRect( | |
97 m_context.newLocation.x(), | |
98 m_context.newLocation.y() + smallerHeight - borderHeight, | |
99 std::max(oldBorderBoxSize.width(), newBorderBoxSize.width()), | |
100 deltaHeight + borderHeight); | |
101 invalidatePaintRectClippedByOldAndNewBounds(bottomDeltaRect); | |
102 } | |
103 | 90 |
91 invalidatePaintRectClippedByOldAndNewBounds(rightDelta); | |
92 invalidatePaintRectClippedByOldAndNewBounds(bottomDelta); | |
104 return true; | 93 return true; |
105 } | 94 } |
106 | 95 |
107 void BoxPaintInvalidator::invalidatePaintRectClippedByOldAndNewBounds( | 96 void BoxPaintInvalidator::invalidatePaintRectClippedByOldAndNewBounds( |
108 const LayoutRect& rect) { | 97 const LayoutRect& rect) { |
109 if (rect.isEmpty()) | 98 if (rect.isEmpty()) |
110 return; | 99 return; |
111 | 100 |
112 ObjectPaintInvalidator objectPaintInvalidator(m_box); | 101 ObjectPaintInvalidator objectPaintInvalidator(m_box); |
113 LayoutRect rectClippedByOldBounds = intersection(rect, m_context.oldBounds); | 102 LayoutRect rectClippedByOldBounds = intersection(rect, m_context.oldBounds); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 const ComputedStyle& style = m_box.styleRef(); | 172 const ComputedStyle& style = m_box.styleRef(); |
184 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || | 173 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || |
185 style.maskLayers().thisOrNextLayersUseContentBox() || | 174 style.maskLayers().thisOrNextLayersUseContentBox() || |
186 style.boxSizing() == BoxSizingBorderBox) { | 175 style.boxSizing() == BoxSizingBorderBox) { |
187 if (previousBoxSizesMap().get(&m_box).contentBoxRect != | 176 if (previousBoxSizesMap().get(&m_box).contentBoxRect != |
188 m_box.contentBoxRect()) | 177 m_box.contentBoxRect()) |
189 return PaintInvalidationContentBoxChange; | 178 return PaintInvalidationContentBoxChange; |
190 } | 179 } |
191 | 180 |
192 if (!style.hasBackground() && !style.hasBoxDecorations()) { | 181 if (!style.hasBackground() && !style.hasBoxDecorations()) { |
193 // We could let incremental invalidation cover non-composited scrollbars, | |
194 // but just do a full invalidation because incremental invalidation will go | |
195 // away with slimming paint. | |
196 if (reason == PaintInvalidationIncremental && | 182 if (reason == PaintInvalidationIncremental && |
197 m_context.oldBounds != m_context.newBounds && | 183 m_context.oldBounds != m_context.newBounds && |
198 m_box.hasNonCompositedScrollbars()) | 184 m_box.hasNonCompositedScrollbars()) |
199 return PaintInvalidationBorderBoxChange; | 185 return PaintInvalidationBorderBoxChange; |
200 return reason; | 186 return reason; |
201 } | 187 } |
202 | 188 |
203 if (style.backgroundLayers().thisOrNextLayersHaveLocalAttachment()) { | 189 if (style.backgroundLayers().thisOrNextLayersHaveLocalAttachment()) { |
204 if (previousBoxSizesMap().get(&m_box).layoutOverflowRect != | 190 if (previousBoxSizesMap().get(&m_box).layoutOverflowRect != |
205 m_box.layoutOverflowRect()) | 191 m_box.layoutOverflowRect()) |
206 return PaintInvalidationLayoutOverflowBoxChange; | 192 return PaintInvalidationLayoutOverflowBoxChange; |
207 } | 193 } |
208 | 194 |
209 LayoutSize oldBorderBoxSize = | 195 LayoutSize oldBorderBoxSize = |
210 computePreviousBorderBoxSize(m_context.oldBounds.size()); | 196 computePreviousBorderBoxSize(m_context.oldBounds.size()); |
211 LayoutSize newBorderBoxSize = m_box.size(); | 197 LayoutSize newBorderBoxSize = m_box.size(); |
212 | 198 |
213 if (oldBorderBoxSize == newBorderBoxSize) | 199 if (oldBorderBoxSize == newBorderBoxSize) |
214 return reason; | 200 return reason; |
215 | 201 |
216 // See another hasNonCompositedScrollbars() callsite above. | 202 // See another hasNonCompositedScrollbars() callsite above. |
217 if (m_box.hasNonCompositedScrollbars()) | 203 if (m_box.hasNonCompositedScrollbars()) |
218 return PaintInvalidationBorderBoxChange; | 204 return PaintInvalidationBorderBoxChange; |
219 | 205 |
220 if (style.hasVisualOverflowingEffect() || style.hasAppearance() || | 206 if (style.hasVisualOverflowingEffect() || style.hasAppearance() || |
221 style.hasFilterInducingProperty() || style.resize() != RESIZE_NONE) | 207 style.hasFilterInducingProperty() || style.resize() != RESIZE_NONE) |
222 return PaintInvalidationBorderBoxChange; | 208 return PaintInvalidationBorderBoxChange; |
223 | 209 |
224 if (style.hasBorderRadius()) { | 210 if (style.hasBorderRadius()) |
225 // If a border-radius exists and width/height is smaller than radius | 211 return PaintInvalidationBorderBoxChange; |
226 // width/height, we need to fully invalidate to cover the changed radius. | |
227 FloatRoundedRect oldRoundedRect = style.getRoundedBorderFor( | |
228 LayoutRect(LayoutPoint(0, 0), oldBorderBoxSize)); | |
229 FloatRoundedRect newRoundedRect = style.getRoundedBorderFor( | |
230 LayoutRect(LayoutPoint(0, 0), newBorderBoxSize)); | |
231 if (oldRoundedRect.getRadii() != newRoundedRect.getRadii()) | |
232 return PaintInvalidationBorderBoxChange; | |
233 } | |
234 | 212 |
235 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && | 213 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && |
236 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) | 214 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) |
237 return PaintInvalidationBorderBoxChange; | 215 return PaintInvalidationBorderBoxChange; |
238 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && | 216 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && |
239 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) | 217 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) |
240 return PaintInvalidationBorderBoxChange; | 218 return PaintInvalidationBorderBoxChange; |
241 | 219 |
242 return reason; | 220 return reason; |
243 } | 221 } |
244 | 222 |
245 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { | 223 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { |
246 PaintInvalidationReason reason = computePaintInvalidationReason(); | 224 PaintInvalidationReason reason = computePaintInvalidationReason(); |
247 if (reason == PaintInvalidationIncremental) { | 225 if (reason == PaintInvalidationIncremental) { |
248 if (incrementallyInvalidatePaint()) { | 226 if (incrementallyInvalidatePaint()) { |
249 m_context.paintingLayer->setNeedsRepaint(); | 227 m_context.paintingLayer->setNeedsRepaint(); |
250 m_box.invalidateDisplayItemClients(reason); | 228 m_box.invalidateDisplayItemClients(reason); |
251 } else { | 229 } else { |
252 reason = PaintInvalidationNone; | 230 reason = PaintInvalidationNone; |
253 } | 231 } |
254 // Though we have done our own version of incremental invalidation, we still | 232 // Though we have done incremental invalidation, we still need to call |
255 // need to call ObjectPaintInvalidator with PaintInvalidationNone to do any | 233 // ObjectPaintInvalidator with PaintInvalidationNone to do any other |
256 // other required operations. | 234 // required operations. |
257 reason = std::max( | 235 reason = std::max( |
258 reason, | 236 reason, |
259 ObjectPaintInvalidatorWithContext(m_box, m_context) | 237 ObjectPaintInvalidatorWithContext(m_box, m_context) |
260 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); | 238 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); |
261 } else { | 239 } else { |
262 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) | 240 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) |
263 .invalidatePaintIfNeededWithComputedReason(reason); | 241 .invalidatePaintIfNeededWithComputedReason(reason); |
264 } | 242 } |
265 | 243 |
266 if (PaintLayerScrollableArea* area = m_box.getScrollableArea()) | 244 if (PaintLayerScrollableArea* area = m_box.getScrollableArea()) |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 auto it = previousBoxSizesMap().find(&m_box); | 307 auto it = previousBoxSizesMap().find(&m_box); |
330 if (it != previousBoxSizesMap().end()) | 308 if (it != previousBoxSizesMap().end()) |
331 return it->value.borderBoxSize; | 309 return it->value.borderBoxSize; |
332 | 310 |
333 // We didn't save the old border box size because it was the same as the size | 311 // We didn't save the old border box size because it was the same as the size |
334 // of oldBounds. | 312 // of oldBounds. |
335 return previousBoundsSize; | 313 return previousBoundsSize; |
336 } | 314 } |
337 | 315 |
338 } // namespace blink | 316 } // namespace blink |
OLD | NEW |