Index: cc/playback/display_list_raster_source.cc |
diff --git a/cc/playback/display_list_raster_source.cc b/cc/playback/display_list_raster_source.cc |
index cc4f7a7807d4b95b21a292c48d7440b560fbc222..ddea055e339b4741f59422204ba1430b73232a68 100644 |
--- a/cc/playback/display_list_raster_source.cc |
+++ b/cc/playback/display_list_raster_source.cc |
@@ -8,13 +8,215 @@ |
#include "cc/base/region.h" |
#include "cc/debug/debug_colors.h" |
#include "cc/playback/display_item_list.h" |
+#include "cc/tiles/image_decode_controller.h" |
#include "skia/ext/analysis_canvas.h" |
#include "third_party/skia/include/core/SkCanvas.h" |
#include "third_party/skia/include/core/SkPictureRecorder.h" |
+#include "third_party/skia/include/utils/SkNWayCanvas.h" |
#include "ui/gfx/geometry/rect_conversions.h" |
namespace cc { |
+namespace { |
+ |
+SkRect MapRect(const SkMatrix& matrix, const SkRect& src) { |
+ SkRect dst; |
+ matrix.mapRect(&dst, src); |
+ return dst; |
+} |
+ |
+bool ExtractScale(const SkMatrix& matrix, SkSize* scale) { |
enne (OOO)
2015/12/02 23:33:25
Put this somewhere common and don't copy and paste
vmpstr
2015/12/03 21:20:23
Put up https://codereview.chromium.org/1497543004/
|
+ *scale = SkSize::Make(matrix.getScaleX(), matrix.getScaleY()); |
+ if (matrix.getType() & SkMatrix::kAffine_Mask) { |
+ if (!matrix.decomposeScale(scale)) { |
+ scale->set(1, 1); |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+class ImageHijackCanvas : public SkNWayCanvas { |
+ public: |
+ ImageHijackCanvas(int width, |
+ int height, |
+ ImageDecodeController* image_decode_controller) |
+ : SkNWayCanvas(width, height), |
+ image_decode_controller_(image_decode_controller), |
+ canvas_bounds_(SkRect::MakeIWH(width, height)) {} |
+ |
+ protected: |
+ // Ensure that pictures are unpacked by this canvas, instead of being |
+ // forwarded to the raster canvas. |
+ void onDrawPicture(const SkPicture* picture, |
+ const SkMatrix* matrix, |
+ const SkPaint* paint) override { |
+ SkCanvas::onDrawPicture(picture, matrix, paint); |
+ } |
+ |
+ void onDrawImage(const SkImage* image, |
+ SkScalar x, |
+ SkScalar y, |
+ const SkPaint* paint) override { |
+ if (!image->isLazyGenerated()) { |
+ SkNWayCanvas::onDrawImage(image, x, y, paint); |
+ return; |
+ } |
+ |
+ SkMatrix ctm = this->getTotalMatrix(); |
+ if (!canvas_bounds_.intersects(MapRect( |
+ ctm, SkRect::MakeXYWH(x, y, image->width(), image->height())))) { |
+ return; |
+ } |
+ |
+ SkSize scale; |
+ bool is_decomposable = ExtractScale(ctm, &scale); |
+ ScopedDecodedImageLock scoped_lock(image_decode_controller_, image, scale, |
+ is_decomposable, ctm.hasPerspective(), |
+ paint); |
+ const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); |
+ const SkPaint* decoded_paint = scoped_lock.decoded_paint(); |
+ |
+ bool need_scale = !decoded_image.is_scale_adjustment_identity(); |
+ if (need_scale) { |
+ SkNWayCanvas::save(); |
+ SkNWayCanvas::scale(1.f / (decoded_image.scale_adjustment().width()), |
+ 1.f / (decoded_image.scale_adjustment().height())); |
+ } |
+ SkNWayCanvas::onDrawImage(decoded_image.image(), x, y, decoded_paint); |
+ if (need_scale) |
+ SkNWayCanvas::restore(); |
+ } |
+ |
+ void onDrawImageRect(const SkImage* image, |
+ const SkRect* src, |
+ const SkRect& dst, |
+ const SkPaint* paint, |
+ SrcRectConstraint constraint) override { |
+ if (!image->isLazyGenerated()) { |
+ SkNWayCanvas::onDrawImageRect(image, src, dst, paint, constraint); |
+ return; |
+ } |
+ |
+ SkMatrix ctm = this->getTotalMatrix(); |
+ if (!canvas_bounds_.intersects(MapRect(ctm, dst))) |
+ return; |
+ |
+ SkRect src_storage; |
+ if (!src) { |
+ src_storage = SkRect::MakeIWH(image->width(), image->height()); |
+ src = &src_storage; |
+ } |
+ SkMatrix matrix; |
+ matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit); |
+ matrix.postConcat(ctm); |
+ |
+ SkSize scale; |
+ bool is_decomposable = ExtractScale(matrix, &scale); |
+ ScopedDecodedImageLock scoped_lock(image_decode_controller_, image, scale, |
+ is_decomposable, matrix.hasPerspective(), |
+ paint); |
+ const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); |
+ const SkPaint* decoded_paint = scoped_lock.decoded_paint(); |
+ |
+ SkRect adjusted_src = *src; |
+ if (!decoded_image.is_scale_adjustment_identity()) { |
+ float x_scale = decoded_image.scale_adjustment().width(); |
+ float y_scale = decoded_image.scale_adjustment().height(); |
+ adjusted_src = |
+ SkRect::MakeXYWH(src->x() * x_scale, src->y() * y_scale, |
+ src->width() * x_scale, src->height() * y_scale); |
+ } |
+ SkNWayCanvas::onDrawImageRect(decoded_image.image(), &adjusted_src, dst, |
+ decoded_paint, constraint); |
+ } |
+ |
+ void onDrawImageNine(const SkImage* image, |
+ const SkIRect& center, |
+ const SkRect& dst, |
+ const SkPaint* paint) override { |
+ if (!image->isLazyGenerated()) { |
+ SkNWayCanvas::onDrawImageNine(image, center, dst, paint); |
+ return; |
+ } |
+ |
+ if (!canvas_bounds_.intersects(dst)) |
+ return; |
+ |
+ SkMatrix ctm = this->getTotalMatrix(); |
+ SkSize scale; |
+ bool is_decomposable = ExtractScale(ctm, &scale); |
+ ScopedDecodedImageLock scoped_lock(image_decode_controller_, image, scale, |
+ is_decomposable, ctm.hasPerspective(), |
+ paint); |
+ const DecodedDrawImage& decoded_image = scoped_lock.decoded_image(); |
+ const SkPaint* decoded_paint = scoped_lock.decoded_paint(); |
+ |
+ SkIRect adjusted_center = center; |
+ if (!decoded_image.is_scale_adjustment_identity()) { |
+ float x_scale = decoded_image.scale_adjustment().width(); |
+ float y_scale = decoded_image.scale_adjustment().height(); |
+ adjusted_center = SkIRect::MakeXYWH( |
+ static_cast<int>(std::floor(center.x() * x_scale)), |
+ static_cast<int>(std::floor(center.y() * y_scale)), |
+ static_cast<int>(std::ceil(center.width() * x_scale)), |
+ static_cast<int>(std::ceil(center.height() * y_scale))); |
+ } |
+ SkNWayCanvas::onDrawImageNine(decoded_image.image(), adjusted_center, dst, |
+ decoded_paint); |
+ } |
+ |
+ private: |
+ class ScopedDecodedImageLock { |
+ public: |
+ ScopedDecodedImageLock(ImageDecodeController* image_decode_controller, |
+ const SkImage* image, |
+ const SkSize& scale, |
+ bool is_decomposable, |
+ bool has_perspective, |
+ const SkPaint* paint) |
+ : image_decode_controller_(image_decode_controller), |
+ paint_(paint), |
+ draw_image_(image, |
+ scale, |
+ paint ? paint->getFilterQuality() : kNone_SkFilterQuality, |
+ has_perspective, |
+ is_decomposable), |
+ decoded_draw_image_( |
+ image_decode_controller_->GetDecodedImageForDraw(draw_image_)) { |
+ DCHECK(image->isLazyGenerated()); |
+ if (paint) { |
+ decoded_paint_ = *paint; |
+ decoded_paint_.setFilterQuality(decoded_draw_image_.filter_quality()); |
+ } |
+ } |
+ |
+ ~ScopedDecodedImageLock() { |
+ image_decode_controller_->DrawWithImageFinished(draw_image_, |
+ decoded_draw_image_); |
+ } |
+ |
+ const DecodedDrawImage& decoded_image() const { |
+ return decoded_draw_image_; |
+ } |
+ const SkPaint* decoded_paint() const { |
+ return paint_ ? &decoded_paint_ : nullptr; |
+ } |
+ |
+ private: |
+ ImageDecodeController* image_decode_controller_; |
+ const SkPaint* paint_; |
+ DrawImage draw_image_; |
+ DecodedDrawImage decoded_draw_image_; |
+ SkPaint decoded_paint_; |
+ }; |
+ |
+ ImageDecodeController* image_decode_controller_; |
+ const SkRect canvas_bounds_; |
+}; |
+ |
+} // namespace |
+ |
scoped_refptr<DisplayListRasterSource> |
DisplayListRasterSource::CreateFromDisplayListRecordingSource( |
const DisplayListRecordingSource* other, |
@@ -38,7 +240,8 @@ DisplayListRasterSource::DisplayListRasterSource( |
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), |
slow_down_raster_scale_factor_for_debug_( |
other->slow_down_raster_scale_factor_for_debug_), |
- should_attempt_to_use_distance_field_text_(false) {} |
+ should_attempt_to_use_distance_field_text_(false), |
+ image_decode_controller_(nullptr) {} |
DisplayListRasterSource::DisplayListRasterSource( |
const DisplayListRasterSource* other, |
@@ -56,16 +259,22 @@ DisplayListRasterSource::DisplayListRasterSource( |
slow_down_raster_scale_factor_for_debug_( |
other->slow_down_raster_scale_factor_for_debug_), |
should_attempt_to_use_distance_field_text_( |
- other->should_attempt_to_use_distance_field_text_) {} |
+ other->should_attempt_to_use_distance_field_text_), |
+ image_decode_controller_(other->image_decode_controller_) {} |
DisplayListRasterSource::~DisplayListRasterSource() { |
} |
void DisplayListRasterSource::PlaybackToSharedCanvas( |
- SkCanvas* canvas, |
+ SkCanvas* raster_canvas, |
const gfx::Rect& canvas_rect, |
float contents_scale) const { |
- RasterCommon(canvas, NULL, canvas_rect, canvas_rect, contents_scale); |
+ SkImageInfo info = raster_canvas->imageInfo(); |
+ ImageHijackCanvas canvas(info.width(), info.height(), |
+ image_decode_controller_); |
+ canvas.addCanvas(raster_canvas); |
+ |
+ RasterCommon(&canvas, NULL, canvas_rect, canvas_rect, contents_scale); |
} |
void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas, |
@@ -75,13 +284,18 @@ void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas, |
} |
void DisplayListRasterSource::PlaybackToCanvas( |
- SkCanvas* canvas, |
+ SkCanvas* raster_canvas, |
const gfx::Rect& canvas_bitmap_rect, |
const gfx::Rect& canvas_playback_rect, |
float contents_scale) const { |
- PrepareForPlaybackToCanvas(canvas, canvas_bitmap_rect, canvas_playback_rect, |
- contents_scale); |
- RasterCommon(canvas, NULL, canvas_bitmap_rect, canvas_playback_rect, |
+ PrepareForPlaybackToCanvas(raster_canvas, canvas_bitmap_rect, |
+ canvas_playback_rect, contents_scale); |
+ |
+ SkImageInfo info = raster_canvas->imageInfo(); |
+ ImageHijackCanvas canvas(info.width(), info.height(), |
+ image_decode_controller_); |
+ canvas.addCanvas(raster_canvas); |
+ RasterCommon(&canvas, NULL, canvas_bitmap_rect, canvas_playback_rect, |
contents_scale); |
} |
@@ -300,4 +514,14 @@ DisplayListRasterSource::CreateCloneWithoutLCDText() const { |
new DisplayListRasterSource(this, can_use_lcd_text)); |
} |
+void DisplayListRasterSource::SetImageDecodeController( |
+ ImageDecodeController* image_decode_controller) { |
+ DCHECK(image_decode_controller); |
+ // Note that although this function should only be called once, tests tend to |
+ // call it several times using the same controller. |
+ DCHECK(!image_decode_controller_ || |
enne (OOO)
2015/12/02 23:33:25
rip DCHECK_IMPLIES
vmpstr
2015/12/03 21:20:23
heh yup!
|
+ image_decode_controller_ == image_decode_controller); |
+ image_decode_controller_ = image_decode_controller; |
+} |
+ |
} // namespace cc |