| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "content/renderer/paint_aggregator.h" | 5 #include "content/renderer/paint_aggregator.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 | 9 |
| 10 // ---------------------------------------------------------------------------- | 10 // ---------------------------------------------------------------------------- |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 if (dy > 0) { | 68 if (dy > 0) { |
| 69 damaged_rect.set_y(scroll_rect.y()); | 69 damaged_rect.set_y(scroll_rect.y()); |
| 70 damaged_rect.set_height(dy); | 70 damaged_rect.set_height(dy); |
| 71 } else { | 71 } else { |
| 72 damaged_rect.set_y(scroll_rect.bottom() + dy); | 72 damaged_rect.set_y(scroll_rect.bottom() + dy); |
| 73 damaged_rect.set_height(-dy); | 73 damaged_rect.set_height(-dy); |
| 74 } | 74 } |
| 75 } | 75 } |
| 76 | 76 |
| 77 // In case the scroll offset exceeds the width/height of the scroll rect | 77 // In case the scroll offset exceeds the width/height of the scroll rect |
| 78 return scroll_rect.Intersect(damaged_rect); | 78 damaged_rect.Intersect(scroll_rect); |
| 79 return damaged_rect; |
| 79 } | 80 } |
| 80 | 81 |
| 81 gfx::Rect PaintAggregator::PendingUpdate::GetPaintBounds() const { | 82 gfx::Rect PaintAggregator::PendingUpdate::GetPaintBounds() const { |
| 82 gfx::Rect bounds; | 83 gfx::Rect bounds; |
| 83 for (size_t i = 0; i < paint_rects.size(); ++i) | 84 for (size_t i = 0; i < paint_rects.size(); ++i) |
| 84 bounds = bounds.Union(paint_rects[i]); | 85 bounds.Union(paint_rects[i]); |
| 85 return bounds; | 86 return bounds; |
| 86 } | 87 } |
| 87 | 88 |
| 88 bool PaintAggregator::HasPendingUpdate() const { | 89 bool PaintAggregator::HasPendingUpdate() const { |
| 89 return !update_.scroll_rect.IsEmpty() || !update_.paint_rects.empty(); | 90 return !update_.scroll_rect.IsEmpty() || !update_.paint_rects.empty(); |
| 90 } | 91 } |
| 91 | 92 |
| 92 void PaintAggregator::ClearPendingUpdate() { | 93 void PaintAggregator::ClearPendingUpdate() { |
| 93 update_ = PendingUpdate(); | 94 update_ = PendingUpdate(); |
| 94 } | 95 } |
| 95 | 96 |
| 96 void PaintAggregator::PopPendingUpdate(PendingUpdate* update) { | 97 void PaintAggregator::PopPendingUpdate(PendingUpdate* update) { |
| 97 // Combine paint rects if their combined area is not sufficiently less than | 98 // Combine paint rects if their combined area is not sufficiently less than |
| 98 // the area of the union of all paint rects. We skip this if there is a | 99 // the area of the union of all paint rects. We skip this if there is a |
| 99 // scroll rect since scrolling benefits from smaller paint rects. | 100 // scroll rect since scrolling benefits from smaller paint rects. |
| 100 if (update_.scroll_rect.IsEmpty() && update_.paint_rects.size() > 1) { | 101 if (update_.scroll_rect.IsEmpty() && update_.paint_rects.size() > 1) { |
| 101 int paint_area = 0; | 102 int paint_area = 0; |
| 102 gfx::Rect union_rect; | 103 gfx::Rect union_rect; |
| 103 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { | 104 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { |
| 104 paint_area += update_.paint_rects[i].size().GetArea(); | 105 paint_area += update_.paint_rects[i].size().GetArea(); |
| 105 union_rect = union_rect.Union(update_.paint_rects[i]); | 106 union_rect.Union(update_.paint_rects[i]); |
| 106 } | 107 } |
| 107 int union_area = union_rect.size().GetArea(); | 108 int union_area = union_rect.size().GetArea(); |
| 108 if (float(paint_area) / float(union_area) > kMaxPaintRectsAreaRatio) | 109 if (float(paint_area) / float(union_area) > kMaxPaintRectsAreaRatio) |
| 109 CombinePaintRects(); | 110 CombinePaintRects(); |
| 110 } | 111 } |
| 111 *update = update_; | 112 *update = update_; |
| 112 ClearPendingUpdate(); | 113 ClearPendingUpdate(); |
| 113 } | 114 } |
| 114 | 115 |
| 115 void PaintAggregator::InvalidateRect(const gfx::Rect& rect) { | 116 void PaintAggregator::InvalidateRect(const gfx::Rect& rect) { |
| 116 // Combine overlapping paints using smallest bounding box. | 117 // Combine overlapping paints using smallest bounding box. |
| 117 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { | 118 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { |
| 118 const gfx::Rect& existing_rect = update_.paint_rects[i]; | 119 const gfx::Rect& existing_rect = update_.paint_rects[i]; |
| 119 if (existing_rect.Contains(rect)) // Optimize out redundancy. | 120 if (existing_rect.Contains(rect)) // Optimize out redundancy. |
| 120 return; | 121 return; |
| 121 if (rect.Intersects(existing_rect) || rect.SharesEdgeWith(existing_rect)) { | 122 if (rect.Intersects(existing_rect) || rect.SharesEdgeWith(existing_rect)) { |
| 122 // Re-invalidate in case the union intersects other paint rects. | 123 // Re-invalidate in case the union intersects other paint rects. |
| 123 gfx::Rect combined_rect = existing_rect.Union(rect); | 124 gfx::Rect combined_rect = existing_rect; |
| 125 combined_rect.Union(rect); |
| 124 update_.paint_rects.erase(update_.paint_rects.begin() + i); | 126 update_.paint_rects.erase(update_.paint_rects.begin() + i); |
| 125 InvalidateRect(combined_rect); | 127 InvalidateRect(combined_rect); |
| 126 return; | 128 return; |
| 127 } | 129 } |
| 128 } | 130 } |
| 129 | 131 |
| 130 // Add a non-overlapping paint. | 132 // Add a non-overlapping paint. |
| 131 update_.paint_rects.push_back(rect); | 133 update_.paint_rects.push_back(rect); |
| 132 | 134 |
| 133 // If the new paint overlaps with a scroll, then it forces an invalidation of | 135 // If the new paint overlaps with a scroll, then it forces an invalidation of |
| 134 // the scroll. If the new paint is contained by a scroll, then trim off the | 136 // the scroll. If the new paint is contained by a scroll, then trim off the |
| 135 // scroll damage to avoid redundant painting. | 137 // scroll damage to avoid redundant painting. |
| 136 if (!update_.scroll_rect.IsEmpty()) { | 138 if (!update_.scroll_rect.IsEmpty()) { |
| 137 if (ShouldInvalidateScrollRect(rect)) { | 139 if (ShouldInvalidateScrollRect(rect)) { |
| 138 InvalidateScrollRect(); | 140 InvalidateScrollRect(); |
| 139 } else if (update_.scroll_rect.Contains(rect)) { | 141 } else if (update_.scroll_rect.Contains(rect)) { |
| 140 update_.paint_rects[update_.paint_rects.size() - 1] = | 142 gfx::Rect paint_rect = rect; |
| 141 rect.Subtract(update_.GetScrollDamage()); | 143 paint_rect.Subtract(update_.GetScrollDamage()); |
| 144 update_.paint_rects[update_.paint_rects.size() - 1] = paint_rect; |
| 142 if (update_.paint_rects[update_.paint_rects.size() - 1].IsEmpty()) | 145 if (update_.paint_rects[update_.paint_rects.size() - 1].IsEmpty()) |
| 143 update_.paint_rects.erase(update_.paint_rects.end() - 1); | 146 update_.paint_rects.erase(update_.paint_rects.end() - 1); |
| 144 } | 147 } |
| 145 } | 148 } |
| 146 | 149 |
| 147 if (update_.paint_rects.size() > kMaxPaintRects) | 150 if (update_.paint_rects.size() > kMaxPaintRects) |
| 148 CombinePaintRects(); | 151 CombinePaintRects(); |
| 149 | 152 |
| 150 // Track how large the paint_rects vector grows during an invalidation | 153 // Track how large the paint_rects vector grows during an invalidation |
| 151 // sequence. Note: A subsequent invalidation may end up being combined | 154 // sequence. Note: A subsequent invalidation may end up being combined |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 // an invalidation of the scroll. | 209 // an invalidation of the scroll. |
| 207 if (ShouldInvalidateScrollRect(gfx::Rect())) | 210 if (ShouldInvalidateScrollRect(gfx::Rect())) |
| 208 InvalidateScrollRect(); | 211 InvalidateScrollRect(); |
| 209 } | 212 } |
| 210 | 213 |
| 211 gfx::Rect PaintAggregator::ScrollPaintRect(const gfx::Rect& paint_rect, | 214 gfx::Rect PaintAggregator::ScrollPaintRect(const gfx::Rect& paint_rect, |
| 212 int dx, int dy) const { | 215 int dx, int dy) const { |
| 213 gfx::Rect result = paint_rect; | 216 gfx::Rect result = paint_rect; |
| 214 | 217 |
| 215 result.Offset(dx, dy); | 218 result.Offset(dx, dy); |
| 216 result = update_.scroll_rect.Intersect(result); | 219 result.Intersect(update_.scroll_rect); |
| 217 | 220 |
| 218 // Subtract out the scroll damage rect to avoid redundant painting. | 221 // Subtract out the scroll damage rect to avoid redundant painting. |
| 219 return result.Subtract(update_.GetScrollDamage()); | 222 result.Subtract(update_.GetScrollDamage()); |
| 223 return result; |
| 220 } | 224 } |
| 221 | 225 |
| 222 bool PaintAggregator::ShouldInvalidateScrollRect(const gfx::Rect& rect) const { | 226 bool PaintAggregator::ShouldInvalidateScrollRect(const gfx::Rect& rect) const { |
| 223 if (!rect.IsEmpty()) { | 227 if (!rect.IsEmpty()) { |
| 224 if (!update_.scroll_rect.Intersects(rect)) | 228 if (!update_.scroll_rect.Intersects(rect)) |
| 225 return false; | 229 return false; |
| 226 | 230 |
| 227 if (!update_.scroll_rect.Contains(rect)) | 231 if (!update_.scroll_rect.Contains(rect)) |
| 228 return true; | 232 return true; |
| 229 } | 233 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 // | 268 // |
| 265 if (update_.scroll_rect.IsEmpty()) { | 269 if (update_.scroll_rect.IsEmpty()) { |
| 266 gfx::Rect bounds = update_.GetPaintBounds(); | 270 gfx::Rect bounds = update_.GetPaintBounds(); |
| 267 update_.paint_rects.clear(); | 271 update_.paint_rects.clear(); |
| 268 update_.paint_rects.push_back(bounds); | 272 update_.paint_rects.push_back(bounds); |
| 269 } else { | 273 } else { |
| 270 gfx::Rect inner, outer; | 274 gfx::Rect inner, outer; |
| 271 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { | 275 for (size_t i = 0; i < update_.paint_rects.size(); ++i) { |
| 272 const gfx::Rect& existing_rect = update_.paint_rects[i]; | 276 const gfx::Rect& existing_rect = update_.paint_rects[i]; |
| 273 if (update_.scroll_rect.Contains(existing_rect)) { | 277 if (update_.scroll_rect.Contains(existing_rect)) { |
| 274 inner = inner.Union(existing_rect); | 278 inner.Union(existing_rect); |
| 275 } else { | 279 } else { |
| 276 outer = outer.Union(existing_rect); | 280 outer.Union(existing_rect); |
| 277 } | 281 } |
| 278 } | 282 } |
| 279 update_.paint_rects.clear(); | 283 update_.paint_rects.clear(); |
| 280 update_.paint_rects.push_back(inner); | 284 update_.paint_rects.push_back(inner); |
| 281 update_.paint_rects.push_back(outer); | 285 update_.paint_rects.push_back(outer); |
| 282 } | 286 } |
| 283 } | 287 } |
| OLD | NEW |