Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: cc/playback/discardable_image_map.cc

Issue 2748263002: Move cc::DisplayItemList and related classes into cc/paint/ (Closed)
Patch Set: Merge branch 'master' into ccpaint Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/playback/discardable_image_map.h ('k') | cc/playback/discardable_image_map_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/playback/discardable_image_map.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <limits>
11
12 #include "base/containers/adapters.h"
13 #include "base/memory/ptr_util.h"
14 #include "cc/base/math_util.h"
15 #include "cc/playback/display_item_list.h"
16 #include "third_party/skia/include/core/SkPath.h"
17 #include "third_party/skia/include/utils/SkNWayCanvas.h"
18 #include "ui/gfx/geometry/rect_conversions.h"
19 #include "ui/gfx/skia_util.h"
20
21 namespace cc {
22
23 SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
24 SkRect dst;
25 matrix.mapRect(&dst, src);
26 return dst;
27 }
28
29 // Returns a rect clamped to |max_size|. Note that |paint_rect| should intersect
30 // or be contained by a rect defined by (0, 0) and |max_size|.
31 gfx::Rect SafeClampPaintRectToSize(const SkRect& paint_rect,
32 const gfx::Size& max_size) {
33 // bounds_rect.x() + bounds_rect.width() (aka bounds_rect.right()) might
34 // overflow integer bounds, so do custom intersect, since gfx::Rect::Intersect
35 // uses bounds_rect.right().
36 gfx::RectF bounds_rect = gfx::SkRectToRectF(paint_rect);
37 float x_offset_if_negative = bounds_rect.x() < 0.f ? bounds_rect.x() : 0.f;
38 float y_offset_if_negative = bounds_rect.y() < 0.f ? bounds_rect.y() : 0.f;
39 bounds_rect.set_x(std::max(0.f, bounds_rect.x()));
40 bounds_rect.set_y(std::max(0.f, bounds_rect.y()));
41
42 // Verify that the rects intersect or that bound_rect is contained by
43 // max_size.
44 DCHECK_GE(bounds_rect.width(), -x_offset_if_negative);
45 DCHECK_GE(bounds_rect.height(), -y_offset_if_negative);
46 DCHECK_GE(max_size.width(), bounds_rect.x());
47 DCHECK_GE(max_size.height(), bounds_rect.y());
48
49 bounds_rect.set_width(std::min(bounds_rect.width() + x_offset_if_negative,
50 max_size.width() - bounds_rect.x()));
51 bounds_rect.set_height(std::min(bounds_rect.height() + y_offset_if_negative,
52 max_size.height() - bounds_rect.y()));
53 return gfx::ToEnclosingRect(bounds_rect);
54 }
55
56 namespace {
57
58 // We're using an NWay canvas with no added canvases, so in effect
59 // non-overridden functions are no-ops.
60 class DiscardableImagesMetadataCanvas : public SkNWayCanvas {
61 public:
62 DiscardableImagesMetadataCanvas(
63 int width,
64 int height,
65 std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
66 std::unordered_map<ImageId, gfx::Rect>* image_id_to_rect)
67 : SkNWayCanvas(width, height),
68 image_set_(image_set),
69 image_id_to_rect_(image_id_to_rect),
70 canvas_bounds_(SkRect::MakeIWH(width, height)),
71 canvas_size_(width, height) {}
72
73 protected:
74 // we need to "undo" the behavior of SkNWayCanvas, which will try to forward
75 // it.
76 void onDrawPicture(const SkPicture* picture,
77 const SkMatrix* matrix,
78 const SkPaint* paint) override {
79 SkCanvas::onDrawPicture(picture, matrix, paint);
80 }
81
82 void onDrawImage(const SkImage* image,
83 SkScalar x,
84 SkScalar y,
85 const SkPaint* paint) override {
86 const SkMatrix& ctm = getTotalMatrix();
87 AddImage(
88 sk_ref_sp(image), SkRect::MakeIWH(image->width(), image->height()),
89 MapRect(ctm, SkRect::MakeXYWH(x, y, image->width(), image->height())),
90 ctm, paint);
91 }
92
93 void onDrawImageRect(const SkImage* image,
94 const SkRect* src,
95 const SkRect& dst,
96 const SkPaint* paint,
97 SrcRectConstraint) override {
98 const SkMatrix& ctm = getTotalMatrix();
99 SkRect src_storage;
100 if (!src) {
101 src_storage = SkRect::MakeIWH(image->width(), image->height());
102 src = &src_storage;
103 }
104 SkMatrix matrix;
105 matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit);
106 matrix.preConcat(ctm);
107 AddImage(sk_ref_sp(image), *src, MapRect(ctm, dst), matrix, paint);
108 }
109
110 void onDrawImageNine(const SkImage* image,
111 const SkIRect& center,
112 const SkRect& dst,
113 const SkPaint* paint) override {
114 // No cc embedder issues image nine calls.
115 NOTREACHED();
116 }
117
118 void onDrawRect(const SkRect& r, const SkPaint& paint) override {
119 AddPaintImage(r, paint);
120 }
121
122 void onDrawPath(const SkPath& path, const SkPaint& paint) override {
123 AddPaintImage(path.getBounds(), paint);
124 }
125
126 void onDrawOval(const SkRect& r, const SkPaint& paint) override {
127 AddPaintImage(r, paint);
128 }
129
130 void onDrawArc(const SkRect& r,
131 SkScalar start_angle,
132 SkScalar sweep_angle,
133 bool use_center,
134 const SkPaint& paint) override {
135 AddPaintImage(r, paint);
136 }
137
138 void onDrawRRect(const SkRRect& rr, const SkPaint& paint) override {
139 AddPaintImage(rr.rect(), paint);
140 }
141
142 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
143 saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
144 return SkNWayCanvas::getSaveLayerStrategy(rec);
145 }
146
147 void willSave() override {
148 saved_paints_.push_back(SkPaint());
149 return SkNWayCanvas::willSave();
150 }
151
152 void willRestore() override {
153 DCHECK_GT(saved_paints_.size(), 0u);
154 saved_paints_.pop_back();
155 SkNWayCanvas::willRestore();
156 }
157
158 private:
159 bool ComputePaintBounds(const SkRect& rect,
160 const SkPaint* current_paint,
161 SkRect* paint_bounds) {
162 *paint_bounds = rect;
163 if (current_paint) {
164 if (!current_paint->canComputeFastBounds())
165 return false;
166 *paint_bounds =
167 current_paint->computeFastBounds(*paint_bounds, paint_bounds);
168 }
169
170 for (const auto& paint : base::Reversed(saved_paints_)) {
171 if (!paint.canComputeFastBounds())
172 return false;
173 *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
174 }
175
176 return true;
177 }
178
179 void AddImage(sk_sp<const SkImage> image,
180 const SkRect& src_rect,
181 const SkRect& rect,
182 const SkMatrix& matrix,
183 const SkPaint* paint) {
184 if (!image->isLazyGenerated())
185 return;
186
187 SkRect paint_rect;
188 bool computed_paint_bounds = ComputePaintBounds(rect, paint, &paint_rect);
189 if (!computed_paint_bounds) {
190 // TODO(vmpstr): UMA this case.
191 paint_rect = canvas_bounds_;
192 }
193
194 if (!paint_rect.intersects(canvas_bounds_))
195 return;
196
197 SkFilterQuality filter_quality = kNone_SkFilterQuality;
198 if (paint) {
199 filter_quality = paint->getFilterQuality();
200 }
201
202 SkIRect src_irect;
203 src_rect.roundOut(&src_irect);
204 gfx::Rect image_rect = SafeClampPaintRectToSize(paint_rect, canvas_size_);
205
206 // During raster, we use the device clip bounds on the canvas, which outsets
207 // the actual clip by 1 due to the possibility of antialiasing. Account for
208 // this here by outsetting the image rect by 1. Note that this only affects
209 // queries into the rtree, which will now return images that only touch the
210 // bounds of the query rect.
211 //
212 // Note that it's not sufficient for us to inset the device clip bounds at
213 // raster time, since we might be sending a larger-than-one-item display
214 // item to skia, which means that skia will internally determine whether to
215 // raster the picture (using device clip bounds that are outset).
216 image_rect.Inset(-1, -1);
217
218 (*image_id_to_rect_)[image->uniqueID()].Union(image_rect);
219 image_set_->push_back(std::make_pair(
220 DrawImage(std::move(image), src_irect, filter_quality, matrix),
221 image_rect));
222 }
223
224 // Currently this function only handles extracting images from SkImageShaders
225 // embedded in SkPaints. Other embedded image cases, such as SkPictures,
226 // are not yet handled.
227 void AddPaintImage(const SkRect& rect, const SkPaint& paint) {
228 SkShader* shader = paint.getShader();
229 if (shader) {
230 SkMatrix matrix;
231 SkShader::TileMode xy[2];
232 SkImage* image = shader->isAImage(&matrix, xy);
233 if (image) {
234 const SkMatrix& ctm = getTotalMatrix();
235 matrix.postConcat(ctm);
236 // TODO(ericrk): Handle cases where we only need a sub-rect from the
237 // image. crbug.com/671821
238 AddImage(sk_ref_sp(image), SkRect::MakeFromIRect(image->bounds()),
239 MapRect(ctm, rect), matrix, &paint);
240 }
241 }
242 }
243
244 std::vector<std::pair<DrawImage, gfx::Rect>>* image_set_;
245 std::unordered_map<ImageId, gfx::Rect>* image_id_to_rect_;
246 const SkRect canvas_bounds_;
247 const gfx::Size canvas_size_;
248 std::vector<SkPaint> saved_paints_;
249 };
250
251 } // namespace
252
253 DiscardableImageMap::DiscardableImageMap() {}
254
255 DiscardableImageMap::~DiscardableImageMap() {}
256
257 std::unique_ptr<SkCanvas> DiscardableImageMap::BeginGeneratingMetadata(
258 const gfx::Size& bounds) {
259 DCHECK(all_images_.empty());
260 return base::MakeUnique<DiscardableImagesMetadataCanvas>(
261 bounds.width(), bounds.height(), &all_images_, &image_id_to_rect_);
262 }
263
264 void DiscardableImageMap::EndGeneratingMetadata() {
265 images_rtree_.Build(all_images_,
266 [](const std::pair<DrawImage, gfx::Rect>& image) {
267 return image.second;
268 });
269 }
270
271 void DiscardableImageMap::GetDiscardableImagesInRect(
272 const gfx::Rect& rect,
273 float contents_scale,
274 std::vector<DrawImage>* images) const {
275 std::vector<size_t> indices;
276 images_rtree_.Search(rect, &indices);
277 for (size_t index : indices)
278 images->push_back(all_images_[index].first.ApplyScale(contents_scale));
279 }
280
281 gfx::Rect DiscardableImageMap::GetRectForImage(ImageId image_id) const {
282 const auto& it = image_id_to_rect_.find(image_id);
283 return it == image_id_to_rect_.end() ? gfx::Rect() : it->second;
284 }
285
286 DiscardableImageMap::ScopedMetadataGenerator::ScopedMetadataGenerator(
287 DiscardableImageMap* image_map,
288 const gfx::Size& bounds)
289 : image_map_(image_map),
290 metadata_canvas_(image_map->BeginGeneratingMetadata(bounds)) {}
291
292 DiscardableImageMap::ScopedMetadataGenerator::~ScopedMetadataGenerator() {
293 image_map_->EndGeneratingMetadata();
294 }
295
296 } // namespace cc
OLDNEW
« no previous file with comments | « cc/playback/discardable_image_map.h ('k') | cc/playback/discardable_image_map_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698