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

Side by Side Diff: cc/paint/discardable_image_store.cc

Issue 2842333003: cc: Update discardable image metadata generation to get PaintImages. (Closed)
Patch Set: addressed comments Created 3 years, 7 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
OLDNEW
(Empty)
1 // Copyright 2017 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/paint/discardable_image_store.h"
6
7 #include "base/containers/adapters.h"
8 #include "base/memory/ptr_util.h"
9 #include "cc/paint/display_item_list.h"
10 #include "third_party/skia/include/utils/SkNoDrawCanvas.h"
11 #include "ui/gfx/geometry/rect_conversions.h"
12 #include "ui/gfx/skia_util.h"
13
14 namespace cc {
15 namespace {
16
17 SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
18 SkRect dst;
19 matrix.mapRect(&dst, src);
20 return dst;
21 }
22
23 } // namespace
24
25 class DiscardableImageStore::PaintTrackingCanvas : public SkNoDrawCanvas {
26 public:
27 PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {}
28 ~PaintTrackingCanvas() override = default;
29
30 bool ComputePaintBounds(const SkRect& rect,
31 const SkPaint* current_paint,
32 SkRect* paint_bounds) {
33 *paint_bounds = rect;
34 if (current_paint) {
35 if (!current_paint->canComputeFastBounds())
36 return false;
37 *paint_bounds =
38 current_paint->computeFastBounds(*paint_bounds, paint_bounds);
39 }
40
41 for (const auto& paint : base::Reversed(saved_paints_)) {
42 if (!paint.canComputeFastBounds())
43 return false;
44 *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
45 }
46
47 return true;
48 }
49
50 protected:
51 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
52 saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
53 return SkNoDrawCanvas::getSaveLayerStrategy(rec);
54 }
55
56 void willSave() override {
57 saved_paints_.push_back(SkPaint());
58 return SkNoDrawCanvas::willSave();
59 }
60
61 void willRestore() override {
62 DCHECK_GT(saved_paints_.size(), 0u);
63 saved_paints_.pop_back();
64 SkNoDrawCanvas::willRestore();
65 }
66
67 private:
68 std::vector<SkPaint> saved_paints_;
69 };
70
71 DiscardableImageStore::DiscardableImageStore(
72 int width,
73 int height,
74 std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
75 std::unordered_map<ImageId, gfx::Rect>* image_id_to_rect)
76 : canvas_(base::MakeUnique<PaintTrackingCanvas>(width, height)),
77 image_set_(image_set),
78 image_id_to_rect_(image_id_to_rect) {}
79
80 DiscardableImageStore::~DiscardableImageStore() = default;
81
82 SkCanvas* DiscardableImageStore::NoDrawCanvas() {
83 return canvas_.get();
84 }
85
86 void DiscardableImageStore::GatherDiscardableImages(
87 const PaintOpBuffer* buffer) {
88 if (!buffer->HasDiscardableImages())
89 return;
90
91 SkMatrix original = canvas_->getTotalMatrix();
92 canvas_->save();
93 // TODO(khushalsagar): Optimize out save/restore blocks if the next op is a
vmpstr 2017/04/28 16:40:11 ... if draws between them don't have images.
Khushal 2017/05/03 21:07:07 Done.
94 // draw op with no images.
95 for (auto* op : PaintOpBuffer::Iterator(buffer)) {
96 if (op->IsDrawOp()) {
97 switch (op->GetType()) {
98 case PaintOpType::DrawArc: {
99 auto* arc_op = static_cast<DrawArcOp*>(op);
100 AddImageFromFlags(arc_op->oval, arc_op->flags);
101 } break;
102 case PaintOpType::DrawCircle: {
103 auto* circle_op = static_cast<DrawCircleOp*>(op);
104 SkRect rect =
105 SkRect::MakeXYWH(circle_op->cx - circle_op->radius,
106 circle_op->cy - circle_op->radius,
107 2 * circle_op->radius, 2 * circle_op->radius);
108 AddImageFromFlags(rect, circle_op->flags);
109 } break;
110 case PaintOpType::DrawDisplayItemList: {
111 auto* list_op = static_cast<DrawDisplayItemListOp*>(op);
112 list_op->list->GatherDiscardableImages(this);
113 } break;
114 case PaintOpType::DrawImage: {
115 auto* image_op = static_cast<DrawImageOp*>(op);
116 const SkImage* sk_image = image_op->image.sk_image().get();
117 AddImage(image_op->image,
118 SkRect::MakeIWH(sk_image->width(), sk_image->height()),
119 SkRect::MakeXYWH(image_op->left, image_op->top,
120 sk_image->width(), sk_image->height()),
121 nullptr, image_op->flags);
122 } break;
123 case PaintOpType::DrawImageRect: {
124 auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
125 SkMatrix matrix;
126 matrix.setRectToRect(image_rect_op->src, image_rect_op->dst,
127 SkMatrix::kFill_ScaleToFit);
128 AddImage(image_rect_op->image, image_rect_op->src, image_rect_op->dst,
129 &matrix, image_rect_op->flags);
130 } break;
131 case PaintOpType::DrawIRect: {
132 auto* rect_op = static_cast<DrawIRectOp*>(op);
133 AddImageFromFlags(SkRect::Make(rect_op->rect), rect_op->flags);
134 } break;
135 case PaintOpType::DrawOval: {
136 auto* oval_op = static_cast<DrawOvalOp*>(op);
137 AddImageFromFlags(oval_op->oval, oval_op->flags);
138 } break;
139 case PaintOpType::DrawPath: {
140 auto* path_op = static_cast<DrawPathOp*>(op);
141 AddImageFromFlags(path_op->path.getBounds(), path_op->flags);
142 } break;
143 case PaintOpType::DrawRecord: {
144 auto* record_op = static_cast<DrawRecordOp*>(op);
145 GatherDiscardableImages(record_op->record.get());
146 } break;
147 case PaintOpType::DrawRect: {
148 auto* rect_op = static_cast<DrawRectOp*>(op);
149 AddImageFromFlags(rect_op->rect, rect_op->flags);
150 } break;
151 case PaintOpType::DrawRRect: {
152 auto* rect_op = static_cast<DrawRRectOp*>(op);
153 AddImageFromFlags(rect_op->rrect.rect(), rect_op->flags);
154 } break;
155 // TODO(khushalsagar): Check if we should be querying images from any of
156 // the following ops.
157 case PaintOpType::DrawPosText:
158 case PaintOpType::DrawLine:
159 case PaintOpType::DrawDRRect:
160 case PaintOpType::DrawText:
161 case PaintOpType::DrawTextBlob:
162 case PaintOpType::DrawColor:
163 break;
164 default:
165 NOTREACHED();
166 }
167 } else {
168 op->Raster(canvas_.get(), original);
169 }
170 }
171 canvas_->restore();
172 }
173
174 // Currently this function only handles extracting images from SkImageShaders
175 // embedded in SkPaints. Other embedded image cases, such as SkPictures,
176 // are not yet handled.
177 void DiscardableImageStore::AddImageFromFlags(const SkRect& rect,
178 const PaintFlags& flags) {
179 SkShader* shader = flags.getShader();
180 if (shader) {
181 SkMatrix matrix;
182 SkShader::TileMode xy[2];
183 SkImage* image = shader->isAImage(&matrix, xy);
184 if (image) {
185 PaintImage paint_image(sk_ref_sp(image),
186 PaintImage::AnimationType::UNKNOWN,
187 PaintImage::CompletionState::UNKNOWN);
188 // TODO(ericrk): Handle cases where we only need a sub-rect from the
189 // image. crbug.com/671821
190 AddImage(paint_image, SkRect::MakeFromIRect(image->bounds()), rect,
191 &matrix, flags);
192 }
193 }
194 }
195
196 void DiscardableImageStore::AddImage(const PaintImage& paint_image,
197 const SkRect& src_rect,
198 const SkRect& rect,
199 const SkMatrix* local_matrix,
200 const PaintFlags& flags) {
201 sk_sp<const SkImage> sk_image = paint_image.sk_image();
202 if (!sk_image->isLazyGenerated())
203 return;
204
205 const SkRect clip_rect = SkRect::Make(canvas_->getDeviceClipBounds());
206 const SkMatrix& ctm = canvas_->getTotalMatrix();
207
208 SkRect paint_rect = MapRect(ctm, rect);
209 bool computed_paint_bounds =
210 canvas_->ComputePaintBounds(paint_rect, ToSkPaint(&flags), &paint_rect);
211 if (!computed_paint_bounds) {
212 // TODO(vmpstr): UMA this case.
213 paint_rect = clip_rect;
214 }
215
216 // Clamp the image rect by the current clip rect.
217 if (!paint_rect.intersect(clip_rect))
vmpstr 2017/04/28 16:40:11 I think you might want to add a similar check to i
Khushal 2017/05/03 21:07:07 I added a check to the hijack canvas to make sure
vmpstr 2017/05/05 18:56:20 Acknowledged.
218 return;
219
220 SkFilterQuality filter_quality = flags.getFilterQuality();
221
222 SkIRect src_irect;
223 src_rect.roundOut(&src_irect);
224 gfx::Rect image_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
225
226 // During raster, we use the device clip bounds on the canvas, which outsets
227 // the actual clip by 1 due to the possibility of antialiasing. Account for
228 // this here by outsetting the image rect by 1. Note that this only affects
229 // queries into the rtree, which will now return images that only touch the
230 // bounds of the query rect.
231 //
232 // Note that it's not sufficient for us to inset the device clip bounds at
233 // raster time, since we might be sending a larger-than-one-item display
234 // item to skia, which means that skia will internally determine whether to
235 // raster the picture (using device clip bounds that are outset).
236 image_rect.Inset(-1, -1);
237
238 // The true target color space will be assigned when it is known, in
239 // GetDiscardableImagesInRect.
240 gfx::ColorSpace target_color_space;
241
242 SkMatrix matrix = ctm;
243 if (local_matrix)
244 matrix.postConcat(*local_matrix);
245
246 // TODO(khushalsagar): Keep PaintImage in DrawImage.
247 (*image_id_to_rect_)[sk_image->uniqueID()].Union(image_rect);
248 image_set_->push_back(
249 std::make_pair(DrawImage(std::move(sk_image), src_irect, filter_quality,
250 matrix, target_color_space),
251 image_rect));
252 }
253
254 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698