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

Unified Diff: cc/paint/discardable_image_store.cc

Issue 2842333003: cc: Update discardable image metadata generation to get PaintImages. (Closed)
Patch Set: win 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/paint/discardable_image_store.h ('k') | cc/paint/display_item_list.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/paint/discardable_image_store.cc
diff --git a/cc/paint/discardable_image_store.cc b/cc/paint/discardable_image_store.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0c77a0c248cedca1504b56b8a2939ce6402ec185
--- /dev/null
+++ b/cc/paint/discardable_image_store.cc
@@ -0,0 +1,254 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/discardable_image_store.h"
+
+#include "base/containers/adapters.h"
+#include "base/memory/ptr_util.h"
+#include "cc/paint/display_item_list.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
+ SkRect dst;
+ matrix.mapRect(&dst, src);
+ return dst;
+}
+
+} // namespace
+
+class DiscardableImageStore::PaintTrackingCanvas : public SkNoDrawCanvas {
+ public:
+ PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {}
+ ~PaintTrackingCanvas() override = default;
+
+ bool ComputePaintBounds(const SkRect& rect,
+ const SkPaint* current_paint,
+ SkRect* paint_bounds) {
+ *paint_bounds = rect;
+ if (current_paint) {
+ if (!current_paint->canComputeFastBounds())
+ return false;
+ *paint_bounds =
+ current_paint->computeFastBounds(*paint_bounds, paint_bounds);
+ }
+
+ for (const auto& paint : base::Reversed(saved_paints_)) {
+ if (!paint.canComputeFastBounds())
+ return false;
+ *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
+ }
+
+ return true;
+ }
+
+ protected:
+ SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
+ saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
+ return SkNoDrawCanvas::getSaveLayerStrategy(rec);
+ }
+
+ void willSave() override {
+ saved_paints_.push_back(SkPaint());
+ return SkNoDrawCanvas::willSave();
+ }
+
+ void willRestore() override {
+ DCHECK_GT(saved_paints_.size(), 0u);
+ saved_paints_.pop_back();
+ SkNoDrawCanvas::willRestore();
+ }
+
+ private:
+ std::vector<SkPaint> saved_paints_;
+};
+
+DiscardableImageStore::DiscardableImageStore(
+ int width,
+ int height,
+ std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
+ base::flat_map<ImageId, gfx::Rect>* image_id_to_rect)
+ : canvas_(base::MakeUnique<PaintTrackingCanvas>(width, height)),
+ image_set_(image_set),
+ image_id_to_rect_(image_id_to_rect) {}
+
+DiscardableImageStore::~DiscardableImageStore() = default;
+
+SkNoDrawCanvas* DiscardableImageStore::GetNoDrawCanvas() {
+ return canvas_.get();
+}
+
+void DiscardableImageStore::GatherDiscardableImages(
+ const PaintOpBuffer* buffer) {
+ if (!buffer->HasDiscardableImages())
+ return;
+
+ SkMatrix original = canvas_->getTotalMatrix();
+ canvas_->save();
+ // TODO(khushalsagar): Optimize out save/restore blocks if there are no images
+ // in the draw ops between them.
+ for (auto* op : PaintOpBuffer::Iterator(buffer)) {
+ if (op->IsDrawOp()) {
+ switch (op->GetType()) {
+ case PaintOpType::DrawArc: {
+ auto* arc_op = static_cast<DrawArcOp*>(op);
+ AddImageFromFlags(arc_op->oval, arc_op->flags);
+ } break;
+ case PaintOpType::DrawCircle: {
+ auto* circle_op = static_cast<DrawCircleOp*>(op);
+ SkRect rect =
+ SkRect::MakeXYWH(circle_op->cx - circle_op->radius,
+ circle_op->cy - circle_op->radius,
+ 2 * circle_op->radius, 2 * circle_op->radius);
+ AddImageFromFlags(rect, circle_op->flags);
+ } break;
+ case PaintOpType::DrawDisplayItemList: {
+ auto* list_op = static_cast<DrawDisplayItemListOp*>(op);
+ list_op->list->GatherDiscardableImages(this);
+ } break;
+ case PaintOpType::DrawImage: {
+ auto* image_op = static_cast<DrawImageOp*>(op);
+ const SkImage* sk_image = image_op->image.sk_image().get();
+ AddImage(image_op->image,
+ SkRect::MakeIWH(sk_image->width(), sk_image->height()),
+ SkRect::MakeXYWH(image_op->left, image_op->top,
+ sk_image->width(), sk_image->height()),
+ nullptr, image_op->flags);
+ } break;
+ case PaintOpType::DrawImageRect: {
+ auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
+ SkMatrix matrix;
+ matrix.setRectToRect(image_rect_op->src, image_rect_op->dst,
+ SkMatrix::kFill_ScaleToFit);
+ AddImage(image_rect_op->image, image_rect_op->src, image_rect_op->dst,
+ &matrix, image_rect_op->flags);
+ } break;
+ case PaintOpType::DrawIRect: {
+ auto* rect_op = static_cast<DrawIRectOp*>(op);
+ AddImageFromFlags(SkRect::Make(rect_op->rect), rect_op->flags);
+ } break;
+ case PaintOpType::DrawOval: {
+ auto* oval_op = static_cast<DrawOvalOp*>(op);
+ AddImageFromFlags(oval_op->oval, oval_op->flags);
+ } break;
+ case PaintOpType::DrawPath: {
+ auto* path_op = static_cast<DrawPathOp*>(op);
+ AddImageFromFlags(path_op->path.getBounds(), path_op->flags);
+ } break;
+ case PaintOpType::DrawRecord: {
+ auto* record_op = static_cast<DrawRecordOp*>(op);
+ GatherDiscardableImages(record_op->record.get());
+ } break;
+ case PaintOpType::DrawRect: {
+ auto* rect_op = static_cast<DrawRectOp*>(op);
+ AddImageFromFlags(rect_op->rect, rect_op->flags);
+ } break;
+ case PaintOpType::DrawRRect: {
+ auto* rect_op = static_cast<DrawRRectOp*>(op);
+ AddImageFromFlags(rect_op->rrect.rect(), rect_op->flags);
+ } break;
+ // TODO(khushalsagar): Check if we should be querying images from any of
+ // the following ops.
+ case PaintOpType::DrawPosText:
+ case PaintOpType::DrawLine:
+ case PaintOpType::DrawDRRect:
+ case PaintOpType::DrawText:
+ case PaintOpType::DrawTextBlob:
+ case PaintOpType::DrawColor:
+ break;
+ default:
+ NOTREACHED();
+ }
+ } else {
+ op->Raster(canvas_.get(), original);
+ }
+ }
+ canvas_->restore();
+}
+
+// Currently this function only handles extracting images from SkImageShaders
+// embedded in SkPaints. Other embedded image cases, such as SkPictures,
+// are not yet handled.
+void DiscardableImageStore::AddImageFromFlags(const SkRect& rect,
+ const PaintFlags& flags) {
+ SkShader* shader = flags.getShader();
+ if (shader) {
+ SkMatrix matrix;
+ SkShader::TileMode xy[2];
+ SkImage* image = shader->isAImage(&matrix, xy);
+ if (image) {
+ PaintImage paint_image(sk_ref_sp(image),
+ PaintImage::AnimationType::UNKNOWN,
+ PaintImage::CompletionState::UNKNOWN);
+ // TODO(ericrk): Handle cases where we only need a sub-rect from the
+ // image. crbug.com/671821
+ AddImage(paint_image, SkRect::MakeFromIRect(image->bounds()), rect,
+ &matrix, flags);
+ }
+ }
+}
+
+void DiscardableImageStore::AddImage(const PaintImage& paint_image,
+ const SkRect& src_rect,
+ const SkRect& rect,
+ const SkMatrix* local_matrix,
+ const PaintFlags& flags) {
+ sk_sp<const SkImage> sk_image = paint_image.sk_image();
+ if (!sk_image->isLazyGenerated())
+ return;
+
+ const SkRect& clip_rect = SkRect::Make(canvas_->getDeviceClipBounds());
+ const SkMatrix& ctm = canvas_->getTotalMatrix();
+
+ SkRect paint_rect = MapRect(ctm, rect);
+ bool computed_paint_bounds =
+ canvas_->ComputePaintBounds(paint_rect, ToSkPaint(&flags), &paint_rect);
+ if (!computed_paint_bounds) {
+ // TODO(vmpstr): UMA this case.
+ paint_rect = clip_rect;
+ }
+
+ // Clamp the image rect by the current clip rect.
+ if (!paint_rect.intersect(clip_rect))
+ return;
+
+ SkFilterQuality filter_quality = flags.getFilterQuality();
+
+ SkIRect src_irect;
+ src_rect.roundOut(&src_irect);
+ gfx::Rect image_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
+
+ // During raster, we use the device clip bounds on the canvas, which outsets
+ // the actual clip by 1 due to the possibility of antialiasing. Account for
+ // this here by outsetting the image rect by 1. Note that this only affects
+ // queries into the rtree, which will now return images that only touch the
+ // bounds of the query rect.
+ //
+ // Note that it's not sufficient for us to inset the device clip bounds at
+ // raster time, since we might be sending a larger-than-one-item display
+ // item to skia, which means that skia will internally determine whether to
+ // raster the picture (using device clip bounds that are outset).
+ image_rect.Inset(-1, -1);
+
+ // The true target color space will be assigned when it is known, in
+ // GetDiscardableImagesInRect.
+ gfx::ColorSpace target_color_space;
+
+ SkMatrix matrix = ctm;
+ if (local_matrix)
+ matrix.postConcat(*local_matrix);
+
+ // TODO(khushalsagar): Keep PaintImage in DrawImage.
+ (*image_id_to_rect_)[sk_image->uniqueID()].Union(image_rect);
+ image_set_->push_back(
+ std::make_pair(DrawImage(std::move(sk_image), src_irect, filter_quality,
+ matrix, target_color_space),
+ image_rect));
+}
+
+} // namespace cc
« no previous file with comments | « cc/paint/discardable_image_store.h ('k') | cc/paint/display_item_list.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698