diff options
author | vmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 23:57:47 +0000 |
---|---|---|
committer | vmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 23:57:47 +0000 |
commit | 66d5ac0c4ff1e95e240d076c798300435891b58b (patch) | |
tree | 37c4a5bff614acaadc927e79d84bb4b94fb63aa3 /skia/ext | |
parent | 6cdce5554de9e4b686afc4cd9a934491ebae7fcc (diff) | |
download | chromium_src-66d5ac0c4ff1e95e240d076c798300435891b58b.zip chromium_src-66d5ac0c4ff1e95e240d076c798300435891b58b.tar.gz chromium_src-66d5ac0c4ff1e95e240d076c798300435891b58b.tar.bz2 |
cc: Add a gathers pixel refs with positions util.
This is part 1 of reducing the number of picture walks
during GatherPixelRefs in picture.cc. This adds a utility
similar to SkPictureUtils except it gathers all lazy refs
in a picture along with their positions. Also adds tests.
BUG=242703
Review URL: https://chromiumcodereview.appspot.com/15732015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203515 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext')
-rw-r--r-- | skia/ext/lazy_pixel_ref_utils.cc | 417 | ||||
-rw-r--r-- | skia/ext/lazy_pixel_ref_utils.h | 33 | ||||
-rw-r--r-- | skia/ext/lazy_pixel_ref_utils_unittest.cc | 730 |
3 files changed, 1180 insertions, 0 deletions
diff --git a/skia/ext/lazy_pixel_ref_utils.cc b/skia/ext/lazy_pixel_ref_utils.cc new file mode 100644 index 0000000..87b487e --- /dev/null +++ b/skia/ext/lazy_pixel_ref_utils.cc @@ -0,0 +1,417 @@ +// Copyright 2013 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 "lazy_pixel_ref_utils.h" + +#include "SkCanvas.h" +#include "SkData.h" +#include "SkDevice.h" +#include "SkDraw.h" +#include "SkPixelRef.h" +#include "SkRRect.h" +#include "SkRasterClip.h" +#include "SkRect.h" +#include "SkShader.h" + +#include "lazy_pixel_ref.h" + +namespace skia { + +namespace { + +// URI label for a lazily decoded SkPixelRef. +const char kLabelLazyDecoded[] = "lazy"; + +class LazyPixelRefSet { + public: + LazyPixelRefSet( + std::vector<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs) + : pixel_refs_(pixel_refs) {} + + void add(SkPixelRef* pixel_ref, const SkRect& rect) { + // Only save lazy pixel refs. + if (pixel_ref->getURI() && + !strcmp(pixel_ref->getURI(), kLabelLazyDecoded)) { + LazyPixelRefUtils::PositionLazyPixelRef position_pixel_ref; + position_pixel_ref.lazy_pixel_ref = + static_cast<skia::LazyPixelRef*>(pixel_ref); + position_pixel_ref.pixel_ref_rect = rect; + pixel_refs_->push_back(position_pixel_ref); + } + } + + private: + std::vector<LazyPixelRefUtils::PositionLazyPixelRef>* pixel_refs_; +}; + +class GatherPixelRefDevice : public SkDevice { + public: + GatherPixelRefDevice(const SkBitmap& bm, LazyPixelRefSet* lazy_pixel_ref_set) + : SkDevice(bm), lazy_pixel_ref_set_(lazy_pixel_ref_set) {} + + virtual void clear(SkColor color) SK_OVERRIDE {} + virtual void writePixels(const SkBitmap& bitmap, + int x, + int y, + SkCanvas::Config8888 config8888) SK_OVERRIDE {} + + virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (getBitmapFromPaint(paint, &bitmap)) { + SkRect clip_rect = SkRect::Make(draw.fRC->getBounds()); + SkRect canvas_rect = SkRect::MakeWH(width(), height()); + SkRect paint_rect = SkRect::MakeEmpty(); + paint_rect.intersect(canvas_rect, clip_rect); + + addBitmap(bitmap, paint_rect); + } + } + + virtual void drawPoints(const SkDraw& draw, + SkCanvas::PointMode mode, + size_t count, + const SkPoint points[], + const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (!getBitmapFromPaint(paint, &bitmap)) + return; + + if (count == 0) + return; + + SkPoint min_point = points[0]; + SkPoint max_point = points[0]; + for (size_t i = 1; i < count; ++i) { + const SkPoint& point = points[i]; + min_point.set(std::min(min_point.x(), point.x()), + std::min(min_point.y(), point.y())); + max_point.set(std::max(max_point.x(), point.x()), + std::max(max_point.y(), point.y())); + } + + SkRect bounds = SkRect::MakeLTRB( + min_point.x(), min_point.y(), max_point.x(), max_point.y()); + + GatherPixelRefDevice::drawRect(draw, bounds, paint); + } + virtual void drawRect(const SkDraw& draw, + const SkRect& rect, + const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (getBitmapFromPaint(paint, &bitmap)) { + SkRect mapped_rect; + draw.fMatrix->mapRect(&mapped_rect, rect); + mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds())); + addBitmap(bitmap, mapped_rect); + } + } + virtual void drawOval(const SkDraw& draw, + const SkRect& rect, + const SkPaint& paint) SK_OVERRIDE { + GatherPixelRefDevice::drawRect(draw, rect, paint); + } + virtual void drawRRect(const SkDraw& draw, + const SkRRect& rect, + const SkPaint& paint) SK_OVERRIDE { + GatherPixelRefDevice::drawRect(draw, rect.rect(), paint); + } + virtual void drawPath(const SkDraw& draw, + const SkPath& path, + const SkPaint& paint, + const SkMatrix* prePathMatrix, + bool pathIsMutable) SK_OVERRIDE { + SkBitmap bitmap; + if (!getBitmapFromPaint(paint, &bitmap)) + return; + + SkRect path_bounds = path.getBounds(); + SkRect final_rect; + if (prePathMatrix != NULL) + prePathMatrix->mapRect(&final_rect, path_bounds); + else + final_rect = path_bounds; + + GatherPixelRefDevice::drawRect(draw, final_rect, paint); + } + virtual void drawBitmap(const SkDraw& draw, + const SkBitmap& bitmap, + const SkIRect* srcRectOrNull, + const SkMatrix& matrix, + const SkPaint& paint) SK_OVERRIDE { + SkMatrix total_matrix; + total_matrix.setConcat(*draw.fMatrix, matrix); + + SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); + SkRect mapped_rect; + total_matrix.mapRect(&mapped_rect, bitmap_rect); + addBitmap(bitmap, mapped_rect); + + SkBitmap paint_bitmap; + if (getBitmapFromPaint(paint, &paint_bitmap)) + addBitmap(paint_bitmap, mapped_rect); + } + virtual void drawBitmapRect(const SkDraw& draw, + const SkBitmap& bitmap, + const SkRect* srcOrNull, + const SkRect& dst, + const SkPaint& paint) SK_OVERRIDE { + SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); + SkMatrix matrix; + matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit); + GatherPixelRefDevice::drawBitmap(draw, bitmap, NULL, matrix, paint); + } + virtual void drawSprite(const SkDraw& draw, + const SkBitmap& bitmap, + int x, + int y, + const SkPaint& paint) SK_OVERRIDE { + // Sprites aren't affected by current matrix, so we can't reuse drawRect. + SkMatrix matrix; + matrix.setTranslate(x, y); + + SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height()); + SkRect mapped_rect; + matrix.mapRect(&mapped_rect, bitmap_rect); + + addBitmap(bitmap, mapped_rect); + SkBitmap paint_bitmap; + if (getBitmapFromPaint(paint, &paint_bitmap)) + addBitmap(paint_bitmap, mapped_rect); + } + virtual void drawText(const SkDraw& draw, + const void* text, + size_t len, + SkScalar x, + SkScalar y, + const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (!getBitmapFromPaint(paint, &bitmap)) + return; + + // Math is borrowed from SkBBoxRecord + SkRect bounds; + paint.measureText(text, len, &bounds); + SkPaint::FontMetrics metrics; + paint.getFontMetrics(&metrics); + + if (paint.isVerticalText()) { + SkScalar h = bounds.fBottom - bounds.fTop; + if (paint.getTextAlign() == SkPaint::kCenter_Align) { + bounds.fTop -= h / 2; + bounds.fBottom -= h / 2; + } + bounds.fBottom += metrics.fBottom; + bounds.fTop += metrics.fTop; + } + else { + SkScalar w = bounds.fRight - bounds.fLeft; + if (paint.getTextAlign() == SkPaint::kCenter_Align) { + bounds.fLeft -= w / 2; + bounds.fRight -= w / 2; + } else if (paint.getTextAlign() == SkPaint::kRight_Align) { + bounds.fLeft -= w; + bounds.fRight -= w; + } + bounds.fTop = metrics.fTop; + bounds.fBottom = metrics.fBottom; + } + + SkScalar pad = (metrics.fBottom - metrics.fTop) / 2; + bounds.fLeft -= pad; + bounds.fRight += pad; + bounds.fLeft += x; + bounds.fRight += x; + bounds.fTop += y; + bounds.fBottom += y; + + GatherPixelRefDevice::drawRect(draw, bounds, paint); + } + virtual void drawPosText(const SkDraw& draw, + const void* text, + size_t len, + const SkScalar pos[], + SkScalar constY, + int scalarsPerPos, + const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (!getBitmapFromPaint(paint, &bitmap)) + return; + + if (len == 0) + return; + + // Similar to SkDraw asserts. + SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2); + + SkPoint min_point; + SkPoint max_point; + if (scalarsPerPos == 1) { + min_point.set(pos[0], constY); + max_point.set(pos[0], constY); + } else if (scalarsPerPos == 2) { + min_point.set(pos[0], constY + pos[1]); + max_point.set(pos[0], constY + pos[1]); + } + + for (size_t i = 0; i < len; ++i) { + SkScalar x = pos[i * scalarsPerPos]; + SkScalar y = constY; + if (scalarsPerPos == 2) + y += pos[i * scalarsPerPos + 1]; + + min_point.set( + std::min(x, min_point.x()), + std::min(y, min_point.y())); + max_point.set( + std::max(x, max_point.x()), + std::max(y, max_point.y())); + } + + SkRect bounds = SkRect::MakeLTRB( + min_point.x(), min_point.y(), max_point.x(), max_point.y()); + + // Math is borrowed from SkBBoxRecord + SkPaint::FontMetrics metrics; + paint.getFontMetrics(&metrics); + + bounds.fTop += metrics.fTop; + bounds.fBottom += metrics.fBottom; + + SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; + bounds.fLeft += pad; + bounds.fRight -= pad; + + GatherPixelRefDevice::drawRect(draw, bounds, paint); + } + virtual void drawTextOnPath(const SkDraw& draw, + const void* text, + size_t len, + const SkPath& path, + const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE { + SkBitmap bitmap; + if (!getBitmapFromPaint(paint, &bitmap)) + return; + + // Math is borrowed from SkBBoxRecord + SkRect bounds = path.getBounds(); + SkPaint::FontMetrics metrics; + paint.getFontMetrics(&metrics); + + SkScalar pad = metrics.fTop; + bounds.fLeft += pad; + bounds.fRight -= pad; + bounds.fTop += pad; + bounds.fBottom -= pad; + + GatherPixelRefDevice::drawRect(draw, bounds, paint); + } + virtual void drawVertices(const SkDraw& draw, + SkCanvas::VertexMode, + int vertexCount, + const SkPoint verts[], + const SkPoint texs[], + const SkColor colors[], + SkXfermode* xmode, + const uint16_t indices[], + int indexCount, + const SkPaint& paint) SK_OVERRIDE { + GatherPixelRefDevice::drawPoints( + draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint); + } + virtual void drawDevice(const SkDraw&, + SkDevice*, + int x, + int y, + const SkPaint&) SK_OVERRIDE {} + + protected: + virtual bool onReadPixels(const SkBitmap& bitmap, + int x, + int y, + SkCanvas::Config8888 config8888) SK_OVERRIDE { + return false; + } + + private: + LazyPixelRefSet* lazy_pixel_ref_set_; + + void addBitmap(const SkBitmap& bm, const SkRect& rect) { + lazy_pixel_ref_set_->add(bm.pixelRef(), rect); + } + + bool getBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) { + SkShader* shader = paint.getShader(); + if (shader) { + // Check whether the shader is a gradient in order to prevent generation + // of bitmaps from gradient shaders, which implement asABitmap. + if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) + return shader->asABitmap(bm, NULL, NULL); + } + return false; + } + +}; + +class NoSaveLayerCanvas : public SkCanvas { + public: + NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {} + + // Turn saveLayer() into save() for speed, should not affect correctness. + virtual int saveLayer(const SkRect* bounds, + const SkPaint* paint, + SaveFlags flags) SK_OVERRIDE { + + // Like SkPictureRecord, we don't want to create layers, but we do need + // to respect the save and (possibly) its rect-clip. + int count = this->INHERITED::save(flags); + if (bounds) { + this->INHERITED::clipRectBounds(bounds, flags, NULL); + } + return count; + } + + // Disable aa for speed. + virtual bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) + SK_OVERRIDE { + return this->INHERITED::clipRect(rect, op, false); + } + + virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) + SK_OVERRIDE { + return this->updateClipConservativelyUsingBounds( + path.getBounds(), op, path.isInverseFillType()); + } + virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) + SK_OVERRIDE { + return this->updateClipConservativelyUsingBounds( + rrect.getBounds(), op, false); + } + + private: + typedef SkCanvas INHERITED; +}; + +} // namespace + +void LazyPixelRefUtils::GatherPixelRefs( + SkPicture* picture, + std::vector<PositionLazyPixelRef>* lazy_pixel_refs) { + lazy_pixel_refs->clear(); + LazyPixelRefSet pixel_ref_set(lazy_pixel_refs); + + SkBitmap emptyBitmap; + emptyBitmap.setConfig( + SkBitmap::kNo_Config, picture->width(), picture->height()); + + GatherPixelRefDevice device(emptyBitmap, &pixel_ref_set); + NoSaveLayerCanvas canvas(&device); + + canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()), + SkRegion::kIntersect_Op, + false); + canvas.drawPicture(*picture); +} + +} // namespace skia diff --git a/skia/ext/lazy_pixel_ref_utils.h b/skia/ext/lazy_pixel_ref_utils.h new file mode 100644 index 0000000..e6cfdd1 --- /dev/null +++ b/skia/ext/lazy_pixel_ref_utils.h @@ -0,0 +1,33 @@ +// Copyright 2013 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. + +#ifndef SKIA_EXT_LAZY_PIXEL_REF_UTILS_H_ +#define SKIA_EXT_LAZY_PIXEL_REF_UTILS_H_ + +#include <vector> + +#include "SkPicture.h" +#include "SkRect.h" + +namespace skia { + +class LazyPixelRef; +class SK_API LazyPixelRefUtils { + public: + + struct PositionLazyPixelRef { + skia::LazyPixelRef* lazy_pixel_ref; + SkRect pixel_ref_rect; + }; + + static void GatherPixelRefs( + SkPicture* picture, + std::vector<PositionLazyPixelRef>* lazy_pixel_refs); +}; + +typedef std::vector<LazyPixelRefUtils::PositionLazyPixelRef> LazyPixelRefList; + +} + +#endif diff --git a/skia/ext/lazy_pixel_ref_utils_unittest.cc b/skia/ext/lazy_pixel_ref_utils_unittest.cc new file mode 100644 index 0000000..2854ef0 --- /dev/null +++ b/skia/ext/lazy_pixel_ref_utils_unittest.cc @@ -0,0 +1,730 @@ +// Copyright 2013 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 "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "cc/test/geometry_test_utils.h" +#include "skia/ext/lazy_pixel_ref.h" +#include "skia/ext/lazy_pixel_ref_utils.h" +#include "skia/ext/refptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkFlattenableBuffers.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkShader.h" +#include "third_party/skia/src/core/SkOrderedReadBuffer.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/skia_util.h" + +namespace skia { + +namespace { + +void CreateBitmap(gfx::Size size, const char* uri, SkBitmap* bitmap); + +class TestPixelRef : public SkPixelRef { + public: + TestPixelRef(int width, int height); + virtual ~TestPixelRef(); + + virtual SkFlattenable::Factory getFactory() OVERRIDE; + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE; + virtual void onUnlockPixels() OVERRIDE {} + virtual SkPixelRef* deepCopy(SkBitmap::Config config, const SkIRect* subset) + OVERRIDE; + + private: + scoped_ptr<char[]> pixels_; +}; + +class TestLazyPixelRef : public skia::LazyPixelRef { + public: + TestLazyPixelRef(int width, int height); + virtual ~TestLazyPixelRef(); + + virtual SkFlattenable::Factory getFactory() OVERRIDE; + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE; + virtual void onUnlockPixels() OVERRIDE {} + virtual bool PrepareToDecode(const PrepareParams& params) OVERRIDE; + virtual SkPixelRef* deepCopy(SkBitmap::Config config, const SkIRect* subset) + OVERRIDE; + virtual void Decode() OVERRIDE {} + + private: + scoped_ptr<char[]> pixels_; +}; + +class TestLazyShader : public SkShader { + public: + TestLazyShader() { CreateBitmap(gfx::Size(50, 50), "lazy", &bitmap_); } + + TestLazyShader(SkFlattenableReadBuffer& flattenable_buffer) { + SkOrderedReadBuffer& buffer = + static_cast<SkOrderedReadBuffer&>(flattenable_buffer); + SkReader32* reader = buffer.getReader32(); + + reader->skip(-4); + uint32_t toSkip = reader->readU32(); + reader->skip(toSkip); + + CreateBitmap(gfx::Size(50, 50), "lazy", &bitmap_); + } + + virtual SkShader::BitmapType asABitmap(SkBitmap* bitmap, + SkMatrix* matrix, + TileMode xy[2]) const OVERRIDE { + if (bitmap) + *bitmap = bitmap_; + return SkShader::kDefault_BitmapType; + } + + // Pure virtual implementaiton. + virtual void shadeSpan(int x, int y, SkPMColor[], int count) OVERRIDE {} + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(TestLazyShader); + + private: + SkBitmap bitmap_; +}; + +TestPixelRef::TestPixelRef(int width, int height) + : pixels_(new char[4 * width * height]) {} + +TestPixelRef::~TestPixelRef() {} + +SkFlattenable::Factory TestPixelRef::getFactory() { return NULL; } + +void* TestPixelRef::onLockPixels(SkColorTable** color_table) { + return pixels_.get(); +} + +SkPixelRef* TestPixelRef::deepCopy(SkBitmap::Config config, + const SkIRect* subset) { + this->ref(); + return this; +} + +TestLazyPixelRef::TestLazyPixelRef(int width, int height) + : pixels_(new char[4 * width * height]) {} + +TestLazyPixelRef::~TestLazyPixelRef() {} + +SkFlattenable::Factory TestLazyPixelRef::getFactory() { return NULL; } + +void* TestLazyPixelRef::onLockPixels(SkColorTable** color_table) { + return pixels_.get(); +} + +bool TestLazyPixelRef::PrepareToDecode(const PrepareParams& params) { + return true; +} + +SkPixelRef* TestLazyPixelRef::deepCopy(SkBitmap::Config config, + const SkIRect* subset) { + this->ref(); + return this; +} + +void CreateBitmap(gfx::Size size, const char* uri, SkBitmap* bitmap) { + skia::RefPtr<TestLazyPixelRef> lazy_pixel_ref = + skia::AdoptRef(new TestLazyPixelRef(size.width(), size.height())); + lazy_pixel_ref->setURI(uri); + + bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); + bitmap->setPixelRef(lazy_pixel_ref.get()); +} + +SkCanvas* StartRecording(SkPicture* picture, gfx::Rect layer_rect) { + SkCanvas* canvas = picture->beginRecording( + layer_rect.width(), + layer_rect.height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag | + SkPicture::kOptimizeForClippedPlayback_RecordingFlag); + + canvas->save(); + canvas->translate(-layer_rect.x(), -layer_rect.y()); + canvas->clipRect(SkRect::MakeXYWH( + layer_rect.x(), layer_rect.y(), layer_rect.width(), layer_rect.height())); + + return canvas; +} + +void StopRecording(SkPicture* picture, SkCanvas* canvas) { + canvas->restore(); + picture->endRecording(); +} + +} // namespace + +TEST(LazyPixelRefUtilsTest, DrawPaint) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + canvas->drawPaint(first_paint); + canvas->clipRect(SkRect::MakeXYWH(34, 45, 56, 67)); + canvas->drawPaint(second_paint); + // Total clip is now (34, 45, 56, 55) + canvas->clipRect(SkRect::MakeWH(100, 100)); + canvas->drawPaint(third_paint); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 256, 256), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(34, 45, 56, 67), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(34, 45, 56, 55), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawPoints) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + SkPoint points[3]; + points[0].set(10, 10); + points[1].set(100, 20); + points[2].set(50, 100); + // (10, 10, 90, 90). + canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, first_paint); + + canvas->save(); + + canvas->clipRect(SkRect::MakeWH(50, 50)); + // (10, 10, 40, 40). + canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, second_paint); + + canvas->restore(); + + points[0].set(50, 55); + points[1].set(50, 55); + points[2].set(200, 200); + // (50, 55, 150, 145). + canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, third_paint); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 10, 90, 90), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 10, 40, 40), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 55, 150, 145), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawRect) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + // (10, 20, 30, 40). + canvas->drawRect(SkRect::MakeXYWH(10, 20, 30, 40), first_paint); + + canvas->save(); + + canvas->translate(5, 17); + // (5, 50, 25, 35) + canvas->drawRect(SkRect::MakeXYWH(0, 33, 25, 35), second_paint); + + canvas->restore(); + + canvas->clipRect(SkRect::MakeXYWH(50, 50, 50, 50)); + canvas->translate(20, 20); + // (50, 50, 50, 50) + canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), third_paint); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 20, 30, 40), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(5, 50, 25, 35), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 50, 50, 50), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawRRect) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + SkRRect rrect; + rrect.setRect(SkRect::MakeXYWH(10, 20, 30, 40)); + + // (10, 20, 30, 40). + canvas->drawRRect(rrect, first_paint); + + canvas->save(); + + canvas->translate(5, 17); + rrect.setRect(SkRect::MakeXYWH(0, 33, 25, 35)); + // (5, 50, 25, 35) + canvas->drawRRect(rrect, second_paint); + + canvas->restore(); + + canvas->clipRect(SkRect::MakeXYWH(50, 50, 50, 50)); + canvas->translate(20, 20); + rrect.setRect(SkRect::MakeXYWH(0, 0, 100, 100)); + // (50, 50, 50, 50) + canvas->drawRRect(rrect, third_paint); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 20, 30, 40), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(5, 50, 25, 35), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 50, 50, 50), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawOval) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + canvas->save(); + + canvas->scale(2, 0.5); + // (20, 10, 60, 20). + canvas->drawOval(SkRect::MakeXYWH(10, 20, 30, 40), first_paint); + + canvas->restore(); + canvas->save(); + + canvas->translate(1, 2); + // (1, 35, 25, 35) + canvas->drawRect(SkRect::MakeXYWH(0, 33, 25, 35), second_paint); + + canvas->restore(); + + canvas->clipRect(SkRect::MakeXYWH(50, 50, 50, 50)); + canvas->translate(20, 20); + // (50, 50, 50, 50) + canvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 100), third_paint); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(20, 10, 60, 20), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(1, 35, 25, 35), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 50, 50, 50), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawPath) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + SkPath path; + path.moveTo(12, 13); + path.lineTo(50, 50); + path.lineTo(22, 101); + + // (12, 13, 38, 88). + canvas->drawPath(path, first_paint); + + canvas->save(); + canvas->clipRect(SkRect::MakeWH(50, 50)); + + // (12, 13, 38, 37). + canvas->drawPath(path, second_paint); + + canvas->restore(); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(2u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(12, 13, 38, 88), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(12, 13, 38, 37), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawBitmap) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + SkBitmap first; + CreateBitmap(gfx::Size(50, 50), "lazy", &first); + SkBitmap second; + CreateBitmap(gfx::Size(50, 50), "lazy", &second); + SkBitmap third; + CreateBitmap(gfx::Size(50, 50), "lazy", &third); + SkBitmap fourth; + CreateBitmap(gfx::Size(50, 1), "lazy", &fourth); + SkBitmap fifth; + CreateBitmap(gfx::Size(10, 10), "lazy", &fifth); + + canvas->save(); + + // At (0, 0). + canvas->drawBitmap(first, 0, 0); + canvas->translate(25, 0); + // At (25, 0). + canvas->drawBitmap(second, 0, 0); + canvas->translate(0, 50); + // At (50, 50). + canvas->drawBitmap(third, 25, 0); + + canvas->restore(); + canvas->save(); + + canvas->rotate(90); + // At (0, 0), rotated 90 degrees + canvas->drawBitmap(fourth, 0, 0); + + canvas->restore(); + + canvas->scale(5, 6); + // At (0, 0), scaled by 5 and 6 + canvas->drawBitmap(fifth, 0, 0); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(5u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(25, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 50, 50, 50), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(-1, 0, 1, 50), + gfx::SkRectToRectF(pixel_refs[3].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 60), + gfx::SkRectToRectF(pixel_refs[4].pixel_ref_rect)); + +} + +TEST(LazyPixelRefUtilsTest, DrawBitmapRect) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + SkBitmap first; + CreateBitmap(gfx::Size(50, 50), "lazy", &first); + SkBitmap second; + CreateBitmap(gfx::Size(50, 50), "lazy", &second); + SkBitmap third; + CreateBitmap(gfx::Size(50, 50), "lazy", &third); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + SkPaint non_lazy_paint; + + canvas->save(); + + // (0, 0, 100, 100). + canvas->drawBitmapRect(first, SkRect::MakeWH(100, 100), &non_lazy_paint); + canvas->translate(25, 0); + // (75, 50, 10, 10). + canvas->drawBitmapRect( + second, SkRect::MakeXYWH(50, 50, 10, 10), &non_lazy_paint); + canvas->translate(5, 50); + // (0, 30, 100, 100). One from bitmap, one from paint. + canvas->drawBitmapRect( + third, SkRect::MakeXYWH(-30, -20, 100, 100), &first_paint); + + canvas->restore(); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(4u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 100, 100), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(75, 50, 10, 10), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 30, 100, 100), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 30, 100, 100), + gfx::SkRectToRectF(pixel_refs[3].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawSprite) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + SkBitmap first; + CreateBitmap(gfx::Size(50, 50), "lazy", &first); + SkBitmap second; + CreateBitmap(gfx::Size(50, 50), "lazy", &second); + SkBitmap third; + CreateBitmap(gfx::Size(50, 50), "lazy", &third); + SkBitmap fourth; + CreateBitmap(gfx::Size(50, 50), "lazy", &fourth); + SkBitmap fifth; + CreateBitmap(gfx::Size(50, 50), "lazy", &fifth); + + canvas->save(); + + // Sprites aren't affected by the current matrix. + + // (0, 0, 50, 50). + canvas->drawSprite(first, 0, 0); + canvas->translate(25, 0); + // (10, 0, 50, 50). + canvas->drawSprite(second, 10, 0); + canvas->translate(0, 50); + // (25, 0, 50, 50). + canvas->drawSprite(third, 25, 0); + + canvas->restore(); + canvas->save(); + + canvas->rotate(90); + // (0, 0, 50, 50). + canvas->drawSprite(fourth, 0, 0); + + canvas->restore(); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + canvas->scale(5, 6); + // (100, 100, 50, 50). + canvas->drawSprite(fifth, 100, 100, &first_paint); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(6u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(25, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 50), + gfx::SkRectToRectF(pixel_refs[3].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(100, 100, 50, 50), + gfx::SkRectToRectF(pixel_refs[4].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(100, 100, 50, 50), + gfx::SkRectToRectF(pixel_refs[5].pixel_ref_rect)); +} + +TEST(LazyPixelRefUtilsTest, DrawText) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + SkPoint points[4]; + points[0].set(10, 50); + points[1].set(20, 50); + points[2].set(30, 50); + points[3].set(40, 50); + + SkPath path; + path.moveTo(10, 50); + path.lineTo(20, 50); + path.lineTo(30, 50); + path.lineTo(40, 50); + path.lineTo(50, 50); + + canvas->drawText("text", 4, 50, 50, first_paint); + canvas->drawPosText("text", 4, points, first_paint); + canvas->drawTextOnPath("text", 4, path, NULL, first_paint); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); +} + +TEST(LazyPixelRefUtilsTest, DrawVertices) { + gfx::Rect layer_rect(0, 0, 256, 256); + + skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); + SkCanvas* canvas = StartRecording(picture.get(), layer_rect); + + TestLazyShader first_shader; + SkPaint first_paint; + first_paint.setShader(&first_shader); + + TestLazyShader second_shader; + SkPaint second_paint; + second_paint.setShader(&second_shader); + + TestLazyShader third_shader; + SkPaint third_paint; + third_paint.setShader(&third_shader); + + SkPoint points[3]; + SkColor colors[3]; + uint16_t indecies[3] = {0, 1, 2}; + points[0].set(10, 10); + points[1].set(100, 20); + points[2].set(50, 100); + // (10, 10, 90, 90). + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, + 3, + points, + points, + colors, + NULL, + indecies, + 3, + first_paint); + + canvas->save(); + + canvas->clipRect(SkRect::MakeWH(50, 50)); + // (10, 10, 40, 40). + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, + 3, + points, + points, + colors, + NULL, + indecies, + 3, + second_paint); + + canvas->restore(); + + points[0].set(50, 55); + points[1].set(50, 55); + points[2].set(200, 200); + // (50, 55, 150, 145). + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, + 3, + points, + points, + colors, + NULL, + indecies, + 3, + third_paint); + + StopRecording(picture.get(), canvas); + + std::vector<skia::LazyPixelRefUtils::PositionLazyPixelRef> pixel_refs; + skia::LazyPixelRefUtils::GatherPixelRefs(picture.get(), &pixel_refs); + + EXPECT_EQ(3u, pixel_refs.size()); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 10, 90, 90), + gfx::SkRectToRectF(pixel_refs[0].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(10, 10, 40, 40), + gfx::SkRectToRectF(pixel_refs[1].pixel_ref_rect)); + EXPECT_FLOAT_RECT_EQ(gfx::RectF(50, 55, 150, 145), + gfx::SkRectToRectF(pixel_refs[2].pixel_ref_rect)); +} + +} // namespace skia |