OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/playback/image_hijack_canvas.h" | |
6 | |
7 #include "base/optional.h" | |
8 #include "base/trace_event/trace_event.h" | |
9 #include "cc/playback/discardable_image_map.h" | |
10 #include "cc/tiles/image_decode_cache.h" | |
11 #include "third_party/skia/include/core/SkPath.h" | |
12 | |
13 namespace cc { | |
14 namespace { | |
15 | |
16 SkIRect RoundOutRect(const SkRect& rect) { | |
17 SkIRect result; | |
18 rect.roundOut(&result); | |
19 return result; | |
20 } | |
21 | |
22 class ScopedDecodedImageLock { | |
23 public: | |
24 ScopedDecodedImageLock(ImageDecodeCache* image_decode_cache, | |
25 sk_sp<const SkImage> image, | |
26 const SkRect& src_rect, | |
27 const SkMatrix& matrix, | |
28 const SkPaint* paint) | |
29 : image_decode_cache_(image_decode_cache), | |
30 draw_image_(std::move(image), | |
31 RoundOutRect(src_rect), | |
32 paint ? paint->getFilterQuality() : kNone_SkFilterQuality, | |
33 matrix), | |
34 decoded_draw_image_( | |
35 image_decode_cache_->GetDecodedImageForDraw(draw_image_)) { | |
36 DCHECK(draw_image_.image()->isLazyGenerated()); | |
37 if (paint) { | |
38 decoded_paint_ = *paint; | |
39 decoded_paint_->setFilterQuality(decoded_draw_image_.filter_quality()); | |
40 } | |
41 } | |
42 | |
43 ScopedDecodedImageLock(ScopedDecodedImageLock&& from) | |
44 : image_decode_cache_(from.image_decode_cache_), | |
45 draw_image_(std::move(from.draw_image_)), | |
46 decoded_draw_image_(std::move(from.decoded_draw_image_)), | |
47 decoded_paint_(std::move(from.decoded_paint_)) { | |
48 from.image_decode_cache_ = nullptr; | |
49 } | |
50 | |
51 ~ScopedDecodedImageLock() { | |
52 if (image_decode_cache_) | |
53 image_decode_cache_->DrawWithImageFinished(draw_image_, | |
54 decoded_draw_image_); | |
55 } | |
56 | |
57 const DecodedDrawImage& decoded_image() const { return decoded_draw_image_; } | |
58 const SkPaint* decoded_paint() const { | |
59 return decoded_paint_ ? &decoded_paint_.value() : nullptr; | |
60 } | |
61 | |
62 private: | |
63 ImageDecodeCache* image_decode_cache_; | |
64 DrawImage draw_image_; | |
65 DecodedDrawImage decoded_draw_image_; | |
66 base::Optional<SkPaint> decoded_paint_; | |
67 }; | |
68 | |
69 // Encapsulates a ScopedDecodedImageLock and an SkPaint. Use of this class | |
70 // ensures that the ScopedDecodedImageLock outlives the dependent SkPaint. | |
71 class ScopedImagePaint { | |
72 public: | |
73 // Tries to create a ScopedImagePaint for the provided SkPaint. If a | |
74 // the SkPaint does not contain an image that we support replacing, | |
75 // an empty base::Optional will be returned. | |
76 static base::Optional<ScopedImagePaint> TryCreate( | |
77 ImageDecodeCache* image_decode_cache, | |
78 const SkMatrix& ctm, | |
79 const SkPaint& paint) { | |
80 SkShader* shader = paint.getShader(); | |
81 if (!shader) | |
82 return base::Optional<ScopedImagePaint>(); | |
83 | |
84 SkMatrix matrix; | |
85 SkShader::TileMode xy[2]; | |
86 SkImage* image = shader->isAImage(&matrix, xy); | |
87 if (!image || !image->isLazyGenerated()) | |
88 return base::Optional<ScopedImagePaint>(); | |
89 | |
90 SkMatrix total_image_matrix = matrix; | |
91 total_image_matrix.preConcat(ctm); | |
92 | |
93 ScopedDecodedImageLock scoped_lock( | |
94 image_decode_cache, sk_ref_sp(image), | |
95 SkRect::MakeIWH(image->width(), image->height()), total_image_matrix, | |
96 &paint); | |
97 const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); | |
98 if (!decoded_image.image()) | |
99 return base::Optional<ScopedImagePaint>(); | |
100 | |
101 bool need_scale = !decoded_image.is_scale_adjustment_identity(); | |
102 if (need_scale) { | |
103 matrix.preScale(1.f / decoded_image.scale_adjustment().width(), | |
104 1.f / decoded_image.scale_adjustment().height()); | |
105 } | |
106 SkPaint scratch_paint = paint; | |
107 scratch_paint.setShader( | |
108 decoded_image.image()->makeShader(xy[0], xy[1], &matrix)); | |
109 scratch_paint.setFilterQuality(decoded_image.filter_quality()); | |
110 return ScopedImagePaint(std::move(scoped_lock), std::move(scratch_paint)); | |
111 } | |
112 | |
113 const SkPaint& paint() { return paint_; } | |
114 | |
115 private: | |
116 ScopedImagePaint(ScopedDecodedImageLock lock, SkPaint paint) | |
117 : lock_(std::move(lock)), paint_(std::move(paint)) {} | |
118 | |
119 ScopedDecodedImageLock lock_; | |
120 SkPaint paint_; | |
121 }; | |
122 | |
123 const SkImage* GetImageInPaint(const SkPaint& paint) { | |
124 SkShader* shader = paint.getShader(); | |
125 return shader ? shader->isAImage(nullptr, nullptr) : nullptr; | |
126 } | |
127 | |
128 } // namespace | |
129 | |
130 ImageHijackCanvas::ImageHijackCanvas(int width, | |
131 int height, | |
132 ImageDecodeCache* image_decode_cache, | |
133 const ImageIdFlatSet* images_to_skip) | |
134 : SkNWayCanvas(width, height), | |
135 image_decode_cache_(image_decode_cache), | |
136 images_to_skip_(images_to_skip) {} | |
137 | |
138 void ImageHijackCanvas::onDrawPicture(const SkPicture* picture, | |
139 const SkMatrix* matrix, | |
140 const SkPaint* paint) { | |
141 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
142 "ImageHijackCanvas::onDrawPicture"); | |
143 // Ensure that pictures are unpacked by this canvas, instead of being | |
144 // forwarded to the raster canvas. | |
145 SkCanvas::onDrawPicture(picture, matrix, paint); | |
146 } | |
147 | |
148 void ImageHijackCanvas::onDrawImage(const SkImage* image, | |
149 SkScalar x, | |
150 SkScalar y, | |
151 const SkPaint* paint) { | |
152 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
153 "ImageHijackCanvas::onDrawImage"); | |
154 if (!image->isLazyGenerated()) { | |
155 DCHECK(!ShouldSkipImage(image)); | |
156 SkNWayCanvas::onDrawImage(image, x, y, paint); | |
157 return; | |
158 } | |
159 | |
160 if (ShouldSkipImage(image)) | |
161 return; | |
162 | |
163 SkMatrix ctm = getTotalMatrix(); | |
164 | |
165 ScopedDecodedImageLock scoped_lock( | |
166 image_decode_cache_, sk_ref_sp(image), | |
167 SkRect::MakeIWH(image->width(), image->height()), ctm, paint); | |
168 const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); | |
169 if (!decoded_image.image()) | |
170 return; | |
171 | |
172 DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().width())); | |
173 DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().height())); | |
174 const SkPaint* decoded_paint = scoped_lock.decoded_paint(); | |
175 | |
176 bool need_scale = !decoded_image.is_scale_adjustment_identity(); | |
177 if (need_scale) { | |
178 SkNWayCanvas::save(); | |
179 SkNWayCanvas::scale(1.f / (decoded_image.scale_adjustment().width()), | |
180 1.f / (decoded_image.scale_adjustment().height())); | |
181 } | |
182 SkNWayCanvas::onDrawImage(decoded_image.image().get(), x, y, decoded_paint); | |
183 if (need_scale) | |
184 SkNWayCanvas::restore(); | |
185 } | |
186 | |
187 void ImageHijackCanvas::onDrawImageRect(const SkImage* image, | |
188 const SkRect* src, | |
189 const SkRect& dst, | |
190 const SkPaint* paint, | |
191 SrcRectConstraint constraint) { | |
192 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
193 "ImageHijackCanvas::onDrawImageRect"); | |
194 if (!image->isLazyGenerated()) { | |
195 DCHECK(!ShouldSkipImage(image)); | |
196 SkNWayCanvas::onDrawImageRect(image, src, dst, paint, constraint); | |
197 return; | |
198 } | |
199 | |
200 if (ShouldSkipImage(image)) | |
201 return; | |
202 | |
203 SkRect src_storage; | |
204 if (!src) { | |
205 src_storage = SkRect::MakeIWH(image->width(), image->height()); | |
206 src = &src_storage; | |
207 } | |
208 SkMatrix matrix; | |
209 matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit); | |
210 matrix.postConcat(getTotalMatrix()); | |
211 | |
212 ScopedDecodedImageLock scoped_lock(image_decode_cache_, sk_ref_sp(image), | |
213 *src, matrix, paint); | |
214 const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); | |
215 if (!decoded_image.image()) | |
216 return; | |
217 | |
218 const SkPaint* decoded_paint = scoped_lock.decoded_paint(); | |
219 | |
220 SkRect adjusted_src = | |
221 src->makeOffset(decoded_image.src_rect_offset().width(), | |
222 decoded_image.src_rect_offset().height()); | |
223 if (!decoded_image.is_scale_adjustment_identity()) { | |
224 float x_scale = decoded_image.scale_adjustment().width(); | |
225 float y_scale = decoded_image.scale_adjustment().height(); | |
226 adjusted_src = SkRect::MakeXYWH( | |
227 adjusted_src.x() * x_scale, adjusted_src.y() * y_scale, | |
228 adjusted_src.width() * x_scale, adjusted_src.height() * y_scale); | |
229 } | |
230 SkNWayCanvas::onDrawImageRect(decoded_image.image().get(), &adjusted_src, dst, | |
231 decoded_paint, constraint); | |
232 } | |
233 | |
234 void ImageHijackCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { | |
235 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
236 "ImageHijackCanvas::onDrawRect"); | |
237 if (ShouldSkipImageInPaint(paint)) | |
238 return; | |
239 | |
240 base::Optional<ScopedImagePaint> image_paint = | |
241 ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint); | |
242 if (!image_paint.has_value()) { | |
243 SkNWayCanvas::onDrawRect(r, paint); | |
244 return; | |
245 } | |
246 SkNWayCanvas::onDrawRect(r, image_paint.value().paint()); | |
247 } | |
248 | |
249 void ImageHijackCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { | |
250 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
251 "ImageHijackCanvas::onDrawPath"); | |
252 if (ShouldSkipImageInPaint(paint)) | |
253 return; | |
254 | |
255 base::Optional<ScopedImagePaint> image_paint = | |
256 ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint); | |
257 if (!image_paint.has_value()) { | |
258 SkNWayCanvas::onDrawPath(path, paint); | |
259 return; | |
260 } | |
261 SkNWayCanvas::onDrawPath(path, image_paint.value().paint()); | |
262 } | |
263 | |
264 void ImageHijackCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) { | |
265 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
266 "ImageHijackCanvas::onDrawOval"); | |
267 if (ShouldSkipImageInPaint(paint)) | |
268 return; | |
269 | |
270 base::Optional<ScopedImagePaint> image_paint = | |
271 ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint); | |
272 if (!image_paint.has_value()) { | |
273 SkNWayCanvas::onDrawOval(r, paint); | |
274 return; | |
275 } | |
276 SkNWayCanvas::onDrawOval(r, image_paint.value().paint()); | |
277 } | |
278 | |
279 void ImageHijackCanvas::onDrawArc(const SkRect& r, | |
280 SkScalar start_angle, | |
281 SkScalar sweep_angle, | |
282 bool use_center, | |
283 const SkPaint& paint) { | |
284 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
285 "ImageHijackCanvas::onDrawArc"); | |
286 if (ShouldSkipImageInPaint(paint)) | |
287 return; | |
288 | |
289 base::Optional<ScopedImagePaint> image_paint = | |
290 ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint); | |
291 if (!image_paint.has_value()) { | |
292 SkNWayCanvas::onDrawArc(r, start_angle, sweep_angle, use_center, paint); | |
293 return; | |
294 } | |
295 SkNWayCanvas::onDrawArc(r, start_angle, sweep_angle, use_center, | |
296 image_paint.value().paint()); | |
297 } | |
298 | |
299 void ImageHijackCanvas::onDrawRRect(const SkRRect& rr, const SkPaint& paint) { | |
300 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
301 "ImageHijackCanvas::onDrawRRect"); | |
302 if (ShouldSkipImageInPaint(paint)) | |
303 return; | |
304 | |
305 base::Optional<ScopedImagePaint> image_paint = | |
306 ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint); | |
307 if (!image_paint.has_value()) { | |
308 SkNWayCanvas::onDrawRRect(rr, paint); | |
309 return; | |
310 } | |
311 SkNWayCanvas::onDrawRRect(rr, image_paint.value().paint()); | |
312 } | |
313 | |
314 void ImageHijackCanvas::onDrawImageNine(const SkImage* image, | |
315 const SkIRect& center, | |
316 const SkRect& dst, | |
317 const SkPaint* paint) { | |
318 // No cc embedder issues image nine calls. | |
319 NOTREACHED(); | |
320 } | |
321 | |
322 bool ImageHijackCanvas::ShouldSkipImage(const SkImage* image) const { | |
323 bool skip = | |
324 images_to_skip_->find(image->uniqueID()) != images_to_skip_->end(); | |
325 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
326 "ImageHijackCanvas::ShouldSkipImage", "imageId", | |
327 image->uniqueID(), "skip", skip); | |
328 return skip; | |
329 } | |
330 | |
331 bool ImageHijackCanvas::ShouldSkipImageInPaint(const SkPaint& paint) const { | |
332 const SkImage* image = GetImageInPaint(paint); | |
333 return image ? ShouldSkipImage(image) : false; | |
334 } | |
335 | |
336 } // namespace cc | |
OLD | NEW |