| 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..dd2d018d29dab960cf2c69602d063772cb01894c 100644
|
| --- a/cc/playback/display_list_raster_source.cc
|
| +++ b/cc/playback/display_list_raster_source.cc
|
| @@ -4,17 +4,220 @@
|
|
|
| #include "cc/playback/display_list_raster_source.h"
|
|
|
| +#include "base/containers/adapters.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "cc/base/region.h"
|
| #include "cc/debug/debug_colors.h"
|
| +#include "cc/playback/discardable_image_map.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 {
|
| +
|
| +SkIRect RoundOutRect(const SkRect& rect) {
|
| + SkIRect result;
|
| + rect.roundOut(&result);
|
| + return result;
|
| +}
|
| +
|
| +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 = getTotalMatrix();
|
| + SkRect paint_bounds;
|
| + bool computed_paint_bounds = ComputePaintBounds(
|
| + SkRect::MakeXYWH(x, y, image->width(), image->height()), paint,
|
| + &paint_bounds);
|
| + if (computed_paint_bounds && !canvas_bounds_.intersects(paint_bounds))
|
| + return;
|
| +
|
| + SkSize scale;
|
| + bool is_decomposable = ExtractScale(ctm, &scale);
|
| + ScopedDecodedImageLock scoped_lock(
|
| + image_decode_controller_, image,
|
| + SkRect::MakeIWH(image->width(), image->height()), scale,
|
| + is_decomposable, ctm.hasPerspective(), paint);
|
| + const DecodedDrawImage& decoded_image = scoped_lock.decoded_image();
|
| + DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().width()));
|
| + DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().height()));
|
| + 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 = getTotalMatrix();
|
| + SkRect paint_bounds;
|
| + bool computed_paint_bounds =
|
| + ComputePaintBounds(MapRect(ctm, dst), paint, &paint_bounds);
|
| + if (computed_paint_bounds && !canvas_bounds_.intersects(paint_bounds))
|
| + 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, *src,
|
| + 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->makeOffset(decoded_image.src_rect_offset().width(),
|
| + decoded_image.src_rect_offset().height());
|
| + 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(
|
| + adjusted_src.x() * x_scale, adjusted_src.y() * y_scale,
|
| + adjusted_src.width() * x_scale, adjusted_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 {
|
| + // Blink doesn't issue image nine calls.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + SaveLayerStrategy willSaveLayer(const SkRect* rect,
|
| + const SkPaint* paint,
|
| + SaveFlags save_flags) override {
|
| + saved_paints_.push_back(paint);
|
| + return SkNWayCanvas::willSaveLayer(rect, paint, save_flags);
|
| + }
|
| +
|
| + void willSave() override {
|
| + saved_paints_.push_back(nullptr);
|
| + return SkNWayCanvas::willSave();
|
| + }
|
| +
|
| + void willRestore() override {
|
| + DCHECK_GT(saved_paints_.size(), 0u);
|
| + saved_paints_.pop_back();
|
| + SkNWayCanvas::willRestore();
|
| + }
|
| +
|
| + private:
|
| + class ScopedDecodedImageLock {
|
| + public:
|
| + ScopedDecodedImageLock(ImageDecodeController* image_decode_controller,
|
| + const SkImage* image,
|
| + const SkRect& src_rect,
|
| + const SkSize& scale,
|
| + bool is_decomposable,
|
| + bool has_perspective,
|
| + const SkPaint* paint)
|
| + : image_decode_controller_(image_decode_controller),
|
| + paint_(paint),
|
| + draw_image_(image,
|
| + RoundOutRect(src_rect),
|
| + 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_;
|
| + };
|
| +
|
| + bool ComputePaintBounds(const SkRect& rect,
|
| + const SkPaint* paint,
|
| + SkRect* paint_bounds) {
|
| + return ComputeRectBoundsFromPaint(rect, paint, saved_paints_, paint_bounds);
|
| + }
|
| +
|
| + ImageDecodeController* image_decode_controller_;
|
| + const SkRect canvas_bounds_;
|
| + std::vector<const SkPaint*> saved_paints_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| scoped_refptr<DisplayListRasterSource>
|
| DisplayListRasterSource::CreateFromDisplayListRecordingSource(
|
| const DisplayListRecordingSource* other,
|
| @@ -38,7 +241,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 +260,30 @@ 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);
|
| + // TODO(vmpstr): This can be improved by plumbing whether the tile itself has
|
| + // discardable images. This way we would only pay for the hijack canvas if the
|
| + // tile actually needed it.
|
| + if (display_list_->MayHaveDiscardableImages()) {
|
| + SkImageInfo info = raster_canvas->imageInfo();
|
| + ImageHijackCanvas canvas(info.width(), info.height(),
|
| + image_decode_controller_);
|
| + canvas.addCanvas(raster_canvas);
|
| +
|
| + RasterCommon(&canvas, nullptr, canvas_rect, canvas_rect, contents_scale);
|
| + } else {
|
| + RasterCommon(raster_canvas, nullptr, canvas_rect, canvas_rect,
|
| + contents_scale);
|
| + }
|
| }
|
|
|
| void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas,
|
| @@ -75,13 +293,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 +523,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_ ||
|
| + image_decode_controller_ == image_decode_controller);
|
| + image_decode_controller_ = image_decode_controller;
|
| +}
|
| +
|
| } // namespace cc
|
|
|