Chromium Code Reviews| 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 |