| 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 |