Pull in Chromium's version of GatherPixelRefs
https://codereview.chromium.org/134473002/
git-svn-id: http://skia.googlecode.com/svn/trunk@13038 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index 608262e..ebac571 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -42,6 +42,7 @@
'../include/utils/SkDebugUtils.h',
'../include/utils/SkDeferredCanvas.h',
'../include/utils/SkDumpCanvas.h',
+ '../include/utils/SkGatherPixelRefsAndRects.h',
'../include/utils/SkInterpolator.h',
'../include/utils/SkLayer.h',
'../include/utils/SkMatrix44.h',
@@ -76,6 +77,7 @@
'../src/utils/SkDeferredCanvas.cpp',
'../src/utils/SkDumpCanvas.cpp',
'../src/utils/SkFloatUtils.h',
+ '../src/utils/SkGatherPixelRefsAndRects.cpp',
'../src/utils/SkInterpolator.cpp',
'../src/utils/SkLayer.cpp',
'../src/utils/SkMatrix44.cpp',
diff --git a/include/utils/SkPictureUtils.h b/include/utils/SkPictureUtils.h
index 5e6b051..c35aca8 100644
--- a/include/utils/SkPictureUtils.h
+++ b/include/utils/SkPictureUtils.h
@@ -9,6 +9,7 @@
#define SkPictureUtils_DEFINED
#include "SkPicture.h"
+#include "SkTDArray.h"
class SkData;
struct SkRect;
@@ -26,6 +27,57 @@
* and remains unchanged.
*/
static SkData* GatherPixelRefs(SkPicture* pict, const SkRect& area);
+
+ /**
+ * SkPixelRefContainer provides a base class for more elaborate pixel ref
+ * query structures (e.g., rtrees, quad-trees, etc.)
+ */
+ class SkPixelRefContainer : public SkRefCnt {
+ public:
+ virtual void add(SkPixelRef* pr, const SkRect& rect) = 0;
+
+ // The returned array may contain duplicates
+ virtual void query(const SkRect& queryRect, SkTDArray<SkPixelRef*> *result) = 0;
+
+ private:
+ typedef SkRefCnt INHERITED;
+ };
+
+ // Simple query structure that just stores a linked list of pixel refs
+ // and rects.
+ class SkPixelRefsAndRectsList : public SkPixelRefContainer {
+ public:
+ virtual void add(SkPixelRef* pr, const SkRect& rect) SK_OVERRIDE {
+ PixelRefAndRect *dst = fArray.append();
+
+ dst->fPixelRef = pr;
+ dst->fRect = rect;
+ }
+
+ virtual void query(const SkRect& queryRect, SkTDArray<SkPixelRef*> *result) SK_OVERRIDE {
+ for (int i = 0; i < fArray.count(); ++i) {
+ if (SkRect::Intersects(fArray[i].fRect, queryRect)) {
+ *result->append() = fArray[i].fPixelRef;
+ }
+ }
+ }
+
+ private:
+ struct PixelRefAndRect {
+ SkPixelRef* fPixelRef;
+ SkRect fRect;
+ };
+
+ SkTDArray<PixelRefAndRect> fArray;
+
+ typedef SkPixelRefContainer INHERITED;
+ };
+
+ /**
+ * Fill the provided pixel ref container with the picture's pixel ref
+ * and rect information.
+ */
+ static void GatherPixelRefsAndRects(SkPicture* pict, SkPixelRefContainer* prCont);
};
#endif
diff --git a/src/utils/SkGatherPixelRefsAndRects.cpp b/src/utils/SkGatherPixelRefsAndRects.cpp
new file mode 100644
index 0000000..7b3be55
--- /dev/null
+++ b/src/utils/SkGatherPixelRefsAndRects.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGatherPixelRefsAndRects.h"
+#include "SkNoSaveLayerCanvas.h"
+#include "SkPictureUtils.h"
+
+void SkPictureUtils::GatherPixelRefsAndRects(SkPicture* pict,
+ SkPictureUtils::SkPixelRefContainer* prCont) {
+ if (0 == pict->width() || 0 == pict->height()) {
+ return ;
+ }
+
+ SkGatherPixelRefsAndRectsDevice device(pict->width(), pict->height(), prCont);
+ SkNoSaveLayerCanvas canvas(&device);
+
+ canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
+ SkIntToScalar(pict->height())),
+ SkRegion::kIntersect_Op, false);
+ canvas.drawPicture(*pict);
+}
diff --git a/src/utils/SkGatherPixelRefsAndRects.h b/src/utils/SkGatherPixelRefsAndRects.h
new file mode 100644
index 0000000..5548472
--- /dev/null
+++ b/src/utils/SkGatherPixelRefsAndRects.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkGatherPixelRefsAndRects_DEFINED
+#define SkGatherPixelRefsAndRects_DEFINED
+
+#include "SkBitmap.h"
+#include "SkDevice.h"
+#include "SkDraw.h"
+#include "SkPictureUtils.h"
+#include "SkRasterClip.h"
+#include "SkRefCnt.h"
+#include "SkRRect.h"
+#include "SkTypes.h"
+
+// This GatherPixelRefs device passes all discovered pixel refs and their
+// device bounds to the user provided SkPixelRefContainer-derived object
+class SkGatherPixelRefsAndRectsDevice : public SkBaseDevice {
+public:
+ SK_DECLARE_INST_COUNT(SkGatherPixelRefsAndRectsDevice)
+
+ SkGatherPixelRefsAndRectsDevice(int width, int height,
+ SkPictureUtils::SkPixelRefContainer* prCont) {
+ fSize.set(width, height);
+ fPRCont = prCont;
+ SkSafeRef(fPRCont);
+ fEmptyBitmap.setConfig(SkBitmap::kNo_Config, width, height);
+ }
+
+ virtual ~SkGatherPixelRefsAndRectsDevice() {
+ SkSafeUnref(fPRCont);
+ }
+
+ virtual uint32_t getDeviceCapabilities() SK_OVERRIDE { return 0; }
+
+ virtual int width() const SK_OVERRIDE { return fSize.width(); }
+ virtual int height() const SK_OVERRIDE { return fSize.height(); }
+ virtual bool isOpaque() const SK_OVERRIDE { return false; }
+ virtual SkBitmap::Config config() const SK_OVERRIDE {
+ return SkBitmap::kNo_Config;
+ }
+ virtual void writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE {
+ NotSupported();
+ }
+ virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
+
+protected:
+ virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
+ return false;
+ }
+ virtual void clear(SkColor color) SK_OVERRIDE {
+ NothingToDo();
+ }
+ virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bm;
+
+ if (GetBitmapFromPaint(paint, &bm)) {
+ SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
+ fPRCont->add(bm.pixelRef(), clipRect);
+ }
+ }
+ virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
+ const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bm;
+ if (!GetBitmapFromPaint(paint, &bm)) {
+ return;
+ }
+
+ if (0 == count) {
+ return;
+ }
+
+ SkPoint min = points[0];
+ SkPoint max = points[0];
+ for (size_t i = 1; i < count; ++i) {
+ const SkPoint& point = points[i];
+
+ min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
+ max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
+ }
+
+ SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
+
+ this->drawRect(draw, bounds, paint);
+ }
+ virtual void drawRect(const SkDraw& draw, const SkRect& rect,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bm;
+ if (GetBitmapFromPaint(paint, &bm)) {
+ SkRect mappedRect;
+ draw.fMatrix->mapRect(&mappedRect, rect);
+ SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
+ mappedRect.intersect(clipRect);
+ fPRCont->add(bm.pixelRef(), mappedRect);
+ }
+ }
+ virtual void drawOval(const SkDraw& draw, const SkRect& rect,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->drawRect(draw, rect, paint);
+ }
+ virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->drawRect(draw, rrect.rect(), paint);
+ }
+ virtual void drawPath(const SkDraw& draw, const SkPath& path,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
+ bool pathIsMutable) SK_OVERRIDE {
+ SkBitmap bm;
+ if (!GetBitmapFromPaint(paint, &bm)) {
+ return;
+ }
+
+ SkRect pathBounds = path.getBounds();
+ if (NULL != prePathMatrix) {
+ prePathMatrix->mapRect(&pathBounds);
+ }
+
+ this->drawRect(draw, pathBounds, paint);
+ }
+ virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
+ const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
+ SkMatrix totMatrix;
+ totMatrix.setConcat(*draw.fMatrix, matrix);
+
+ SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()));
+ SkRect mappedRect;
+ totMatrix.mapRect(&mappedRect, bitmapRect);
+ fPRCont->add(bitmap.pixelRef(), mappedRect);
+
+ SkBitmap paintBitmap;
+ if (GetBitmapFromPaint(paint, &paintBitmap)) {
+ fPRCont->add(paintBitmap.pixelRef(), mappedRect);
+ }
+ }
+ virtual void drawSprite(const SkDraw&, 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(SkIntToScalar(x), SkIntToScalar(y));
+
+ SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()));
+ SkRect mappedRect;
+ matrix.mapRect(&mappedRect, bitmapRect);
+ fPRCont->add(bitmap.pixelRef(), mappedRect);
+
+ SkBitmap paintBitmap;
+ if (GetBitmapFromPaint(paint, &paintBitmap)) {
+ fPRCont->add(paintBitmap.pixelRef(), mappedRect);
+ }
+ }
+ virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
+ const SkRect* srcOrNull, const SkRect& dst,
+ const SkPaint& paint,
+ SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
+ SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()));
+ SkMatrix matrix;
+ matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
+ this->drawBitmap(draw, bitmap, matrix, paint);
+ }
+ 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.offset(x, y);
+
+ this->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 (0 == len) {
+ return;
+ }
+
+ // Similar to SkDraw asserts.
+ SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
+
+ SkPoint min, max;
+ if (1 == scalarsPerPos) {
+ min.set(pos[0], constY);
+ max.set(pos[0], constY);
+ } else if (2 == scalarsPerPos) {
+ min.set(pos[0], constY + pos[1]);
+ max.set(pos[0], constY + pos[1]);
+ }
+
+ for (size_t i = 1; i < len; ++i) {
+ SkScalar x = pos[i * scalarsPerPos];
+ SkScalar y = constY;
+ if (2 == scalarsPerPos) {
+ y += pos[i * scalarsPerPos + 1];
+ }
+
+ min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
+ max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
+ }
+
+ SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.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;
+
+ this->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;
+ // TODO: inset?!
+ bounds.fLeft += pad;
+ bounds.fRight -= pad;
+ bounds.fTop += pad;
+ bounds.fBottom -= pad;
+
+ this->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 {
+ this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
+ }
+ virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
+ const SkPaint&) SK_OVERRIDE {
+ NothingToDo();
+ }
+ // TODO: allow this call to return failure, or move to SkBitmapDevice only.
+ virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
+ return fEmptyBitmap;
+ }
+ virtual bool onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE {
+ NotSupported();
+ return false;
+ }
+ virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
+ virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
+ virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE { return false; }
+ virtual bool canHandleImageFilter(SkImageFilter*) SK_OVERRIDE { return false; }
+ virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
+ return false;
+ }
+
+private:
+ SkPictureUtils::SkPixelRefContainer* fPRCont;
+ SkISize fSize;
+
+ SkBitmap fEmptyBitmap; // legacy -- need to remove
+
+ static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
+ SkShader* shader = paint.getShader();
+ if (NULL != shader) {
+ if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
+ return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
+ }
+ }
+ return false;
+ }
+
+ virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
+ NotSupported();
+ }
+
+ virtual SkBaseDevice* onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage) SK_OVERRIDE {
+ // we expect to only get called via savelayer, in which case it is fine.
+ SkASSERT(kSaveLayer_Usage == usage);
+ return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice, (width, height, fPRCont));
+ }
+
+ virtual void flush() SK_OVERRIDE {}
+
+ static void NotSupported() {
+ SkDEBUGFAIL("this method should never be called");
+ }
+
+ static void NothingToDo() {}
+
+ typedef SkBaseDevice INHERITED;
+};
+
+#endif // SkGatherPixelRefsAndRects_DEFINED
+
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
index 8795a04..4af8da8 100644
--- a/src/utils/SkPictureUtils.cpp
+++ b/src/utils/SkPictureUtils.cpp
@@ -50,6 +50,8 @@
*/
class GatherPixelRefDevice : public SkBaseDevice {
public:
+ SK_DECLARE_INST_COUNT(GatherPixelRefDevice)
+
GatherPixelRefDevice(int width, int height, PixelRefSet* prset) {
fSize.set(width, height);
fEmptyBitmap.setConfig(SkBitmap::kNo_Config, width, height);
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 4e0ad1d..7810ce1 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -65,35 +65,42 @@
paint->setShader(shader)->unref();
}
-typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkBitmap&, const SkPoint&);
+typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&,
+ const SkBitmap&, const SkPoint&,
+ SkTDArray<SkPixelRef*>* usedPixRefs);
static void drawpaint_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
canvas->drawPaint(paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawpoints_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
- // draw a slightly inset rect
+ // draw a rect
SkPoint points[5] = {
- { pos.fX + 1, pos.fY + 1 },
- { pos.fX + bm.width() - 2, pos.fY + 1 },
- { pos.fX + bm.width() - 2, pos.fY + bm.height() - 2 },
- { pos.fX + 1, pos.fY + bm.height() - 2 },
- { pos.fX + 1, pos.fY + 1 },
+ { pos.fX, pos.fY },
+ { pos.fX + bm.width() - 1, pos.fY },
+ { pos.fX + bm.width() - 1, pos.fY + bm.height() - 1 },
+ { pos.fX, pos.fY + bm.height() - 1 },
+ { pos.fX, pos.fY },
};
canvas->drawPoints(SkCanvas::kPolygon_PointMode, 5, points, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawrect_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -101,10 +108,12 @@
r.offset(pos.fX, pos.fY);
canvas->drawRect(r, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawoval_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -112,10 +121,12 @@
r.offset(pos.fX, pos.fY);
canvas->drawOval(r, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawrrect_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -125,10 +136,12 @@
SkRRect rr;
rr.setRectXY(r, SkIntToScalar(bm.width())/4, SkIntToScalar(bm.height())/4);
canvas->drawRRect(rr, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawpath_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -139,37 +152,46 @@
path.offset(pos.fX, pos.fY);
canvas->drawPath(path, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawbitmap_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
// The bitmap in the paint is ignored unless we're drawing an A8 bitmap
canvas->drawBitmap(altBM, pos.fX, pos.fY, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
}
static void drawsprite_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
const SkMatrix& ctm = canvas->getTotalMatrix();
SkPoint p(pos);
ctm.mapPoints(&p, 1);
canvas->drawSprite(bm, (int)p.fX, (int)p.fY, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
}
#if 0
// Although specifiable, this case doesn't seem to make sense (i.e., the
// bitmap in the shader is never used).
static void drawsprite_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -179,21 +201,26 @@
ctm.mapPoints(&p, 1);
canvas->drawSprite(altBM, (int)p.fX, (int)p.fY, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
}
#endif
static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
r.offset(pos.fX, pos.fY);
canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawbitmaprect_withshader_proc(SkCanvas* canvas,
const SkBitmap& bm,
const SkBitmap& altBM,
- const SkPoint& pos) {
+ const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -202,29 +229,36 @@
// The bitmap in the paint is ignored unless we're drawing an A8 bitmap
canvas->drawBitmapRectToRect(altBM, NULL, r, &paint);
+ *usedPixRefs->append() = bm.pixelRef();
+ *usedPixRefs->append() = altBM.pixelRef();
}
static void drawtext_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
paint.setTextSize(SkIntToScalar(1.5*bm.width()));
canvas->drawText("0", 1, pos.fX, pos.fY+bm.width(), paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawpostext_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
paint.setTextSize(SkIntToScalar(1.5*bm.width()));
SkPoint point = { pos.fX, pos.fY + bm.height() };
canvas->drawPosText("O", 1, &point, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawtextonpath_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
@@ -235,18 +269,20 @@
path.offset(pos.fX, pos.fY+bm.height());
canvas->drawTextOnPath("O", 1, path, NULL, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
static void drawverts_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkBitmap& altBM, const SkPoint& pos) {
+ const SkBitmap& altBM, const SkPoint& pos,
+ SkTDArray<SkPixelRef*>* usedPixRefs) {
SkPaint paint;
init_paint(&paint, bm);
- SkPoint verts[4] = {
- { pos.fX+1, pos.fY+1 },
- { pos.fX + bm.width()-1, pos.fY+1 },
- { pos.fX + bm.width()-1, pos.fY + bm.height()-1 },
- { pos.fX+1, pos.fY + bm.height()-1 }
+ SkPoint verts[4] = {
+ { pos.fX, pos.fY },
+ { pos.fX + bm.width(), pos.fY },
+ { pos.fX + bm.width(), pos.fY + bm.height() },
+ { pos.fX, pos.fY + bm.height() }
};
SkPoint texs[4] = { { 0, 0 },
{ SkIntToScalar(bm.width()), 0 },
@@ -256,20 +292,25 @@
canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 4, verts, texs, NULL, NULL,
indices, 6, paint);
+ *usedPixRefs->append() = bm.pixelRef();
}
// Return a picture with the bitmaps drawn at the specified positions.
-static SkPicture* record_bitmaps(const SkBitmap bm[], const SkPoint pos[],
- int count, DrawBitmapProc proc) {
+static SkPicture* record_bitmaps(const SkBitmap bm[],
+ const SkPoint pos[],
+ SkTDArray<SkPixelRef*> analytic[],
+ int count,
+ DrawBitmapProc proc) {
SkPicture* pic = new SkPicture;
SkCanvas* canvas = pic->beginRecording(1000, 1000);
for (int i = 0; i < count; ++i) {
+ analytic[i].rewind();
canvas->save();
SkRect clipRect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY,
SkIntToScalar(bm[i].width()),
SkIntToScalar(bm[i].height()));
canvas->clipRect(clipRect, SkRegion::kIntersect_Op);
- proc(canvas, bm[i], bm[count+i], pos[i]);
+ proc(canvas, bm[i], bm[count+i], pos[i], &analytic[i]);
canvas->restore();
}
pic->endRecording();
@@ -363,6 +404,62 @@
}
}
+void gather_from_analytic(const SkPoint pos[], SkScalar w, SkScalar h,
+ const SkTDArray<SkPixelRef*> analytic[],
+ int count,
+ SkTDArray<SkPixelRef*>* result,
+ const SkRect& subset) {
+ for (int i = 0; i < count; ++i) {
+ SkRect rect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY, w, h);
+
+ if (SkRect::Intersects(subset, rect)) {
+ result->append(analytic[i].count(), analytic[i].begin());
+ }
+ }
+}
+
+static const DrawBitmapProc gProcs[] = {
+ drawpaint_proc,
+ drawpoints_proc,
+ drawrect_proc,
+ drawoval_proc,
+ drawrrect_proc,
+ drawpath_proc,
+ drawbitmap_proc,
+ drawbitmap_withshader_proc,
+ drawsprite_proc,
+#if 0
+ drawsprite_withshader_proc,
+#endif
+ drawbitmaprect_proc,
+ drawbitmaprect_withshader_proc,
+ drawtext_proc,
+ drawpostext_proc,
+ drawtextonpath_proc,
+ drawverts_proc,
+};
+
+static void create_textures(SkBitmap* bm, SkPixelRef** refs, int num, int w, int h) {
+ // Our convention is that the color components contain an encoding of
+ // the index of their corresponding bitmap/pixelref. (0,0,0,0) is
+ // reserved for the background
+ for (int i = 0; i < num; ++i) {
+ make_bm(&bm[i], w, h,
+ SkColorSetARGB(0xFF,
+ gColorScale*i+gColorOffset,
+ gColorScale*i+gColorOffset,
+ gColorScale*i+gColorOffset),
+ true);
+ refs[i] = bm[i].pixelRef();
+ }
+
+ // The A8 alternate bitmaps are all BW checkerboards
+ for (int i = 0; i < num; ++i) {
+ make_checkerboard(&bm[num+i], w, h, true);
+ refs[num+i] = bm[num+i].pixelRef();
+ }
+}
+
static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
const int IW = 32;
const int IH = IW;
@@ -372,58 +469,21 @@
static const int N = 4;
SkBitmap bm[2*N];
SkPixelRef* refs[2*N];
+ SkTDArray<SkPixelRef*> analytic[N];
const SkPoint pos[N] = {
{ 0, 0 }, { W, 0 }, { 0, H }, { W, H }
};
- // Our convention is that the color components contain an encoding of
- // the index of their corresponding bitmap/pixelref. (0,0,0,0) is
- // reserved for the background
- for (int i = 0; i < N; ++i) {
- make_bm(&bm[i], IW, IH,
- SkColorSetARGB(0xFF,
- gColorScale*i+gColorOffset,
- gColorScale*i+gColorOffset,
- gColorScale*i+gColorOffset),
- true);
- refs[i] = bm[i].pixelRef();
- }
-
- // The A8 alternate bitmaps are all BW checkerboards
- for (int i = 0; i < N; ++i) {
- make_checkerboard(&bm[N+i], IW, IH, true);
- refs[N+i] = bm[N+i].pixelRef();
- }
-
- static const DrawBitmapProc procs[] = {
- drawpaint_proc,
- drawpoints_proc,
- drawrect_proc,
- drawoval_proc,
- drawrrect_proc,
- drawpath_proc,
- drawbitmap_proc,
- drawbitmap_withshader_proc,
- drawsprite_proc,
-#if 0
- drawsprite_withshader_proc,
-#endif
- drawbitmaprect_proc,
- drawbitmaprect_withshader_proc,
- drawtext_proc,
- drawpostext_proc,
- drawtextonpath_proc,
- drawverts_proc,
- };
+ create_textures(bm, refs, N, IW, IH);
SkRandom rand;
- for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) {
- SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k]));
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
+ SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, analytic, N, gProcs[k]));
REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
// quick check for a small piece of each quadrant, which should just
- // contain 1 bitmap.
+ // contain 1 or 2 bitmaps.
for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
SkRect r;
r.set(2, 2, W - 2, H - 2);
@@ -453,7 +513,11 @@
SkRect r;
rand_rect(&r, rand, 2*W, 2*H);
- SkTDArray<SkPixelRef*> array;
+ SkTDArray<SkPixelRef*> fromImage;
+ gather_from_image(image, refs, N, &fromImage, r);
+
+ SkTDArray<SkPixelRef*> fromAnalytic;
+ gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
size_t dataSize = data ? data->size() : 0;
@@ -462,18 +526,22 @@
SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
SkAutoDataUnref adu(data);
- gather_from_image(image, refs, N, &array, r);
+ // Everything that we saw drawn should appear in the analytic list
+ // but the analytic list may contain some pixelRefs that were not
+ // seen in the image (e.g., A8 textures used as masks)
+ for (int i = 0; i < fromImage.count(); ++i) {
+ REPORTER_ASSERT(reporter, -1 != fromAnalytic.find(fromImage[i]));
+ }
/*
* GatherPixelRefs is conservative, so it can return more bitmaps
- * that we actually can see (usually because of conservative bounds
- * inflation for antialiasing). Thus our check here is only that
- * Gather didn't miss any that we actually saw. Even that isn't
+ * than are strictly required. Thus our check here is only that
+ * Gather didn't miss any that we actually needed. Even that isn't
* a strict requirement on Gather, which is meant to be quick and
* only mostly-correct, but at the moment this test should work.
*/
- for (int i = 0; i < array.count(); ++i) {
- bool found = find(gatherRefs, array[i], gatherCount);
+ for (int i = 0; i < fromAnalytic.count(); ++i) {
+ bool found = find(gatherRefs, fromAnalytic[i], gatherCount);
REPORTER_ASSERT(reporter, found);
#if 0
// enable this block of code to debug failures, as it will rerun
@@ -488,6 +556,89 @@
}
}
+static void test_gatherpixelrefsandrects(skiatest::Reporter* reporter) {
+ const int IW = 32;
+ const int IH = IW;
+ const SkScalar W = SkIntToScalar(IW);
+ const SkScalar H = W;
+
+ static const int N = 4;
+ SkBitmap bm[2*N];
+ SkPixelRef* refs[2*N];
+ SkTDArray<SkPixelRef*> analytic[N];
+
+ const SkPoint pos[N] = {
+ { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
+ };
+
+ create_textures(bm, refs, N, IW, IH);
+
+ SkRandom rand;
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
+ SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, analytic, N, gProcs[k]));
+
+ REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
+
+ SkAutoTUnref<SkPictureUtils::SkPixelRefContainer> prCont(
+ new SkPictureUtils::SkPixelRefsAndRectsList);
+
+ SkPictureUtils::GatherPixelRefsAndRects(pic, prCont);
+
+ // quick check for a small piece of each quadrant, which should just
+ // contain 1 or 2 bitmaps.
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
+ SkRect r;
+ r.set(2, 2, W - 2, H - 2);
+ r.offset(pos[i].fX, pos[i].fY);
+
+ SkTDArray<SkPixelRef*> gatheredRefs;
+ prCont->query(r, &gatheredRefs);
+
+ int count = gatheredRefs.count();
+ REPORTER_ASSERT(reporter, 1 == count || 2 == count);
+ if (1 == count) {
+ REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
+ } else if (2 == count) {
+ REPORTER_ASSERT(reporter,
+ (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
+ (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
+ }
+ }
+
+ SkBitmap image;
+ draw(pic, 2*IW, 2*IH, &image);
+
+ // Test a bunch of random (mostly) rects, and compare the gather results
+ // with the analytic results and the pixel refs seen in a rendering.
+ for (int j = 0; j < 100; ++j) {
+ SkRect r;
+ rand_rect(&r, rand, 2*W, 2*H);
+
+ SkTDArray<SkPixelRef*> fromImage;
+ gather_from_image(image, refs, N, &fromImage, r);
+
+ SkTDArray<SkPixelRef*> fromAnalytic;
+ gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
+
+ SkTDArray<SkPixelRef*> gatheredRefs;
+ prCont->query(r, &gatheredRefs);
+
+ // Everything that we saw drawn should appear in the analytic list
+ // but the analytic list may contain some pixelRefs that were not
+ // seen in the image (e.g., A8 textures used as masks)
+ for (int i = 0; i < fromImage.count(); ++i) {
+ REPORTER_ASSERT(reporter, -1 != fromAnalytic.find(fromImage[i]));
+ }
+
+ // Everything in the analytic list should appear in the gathered
+ // list.
+ for (int i = 0; i < fromAnalytic.count(); ++i) {
+ REPORTER_ASSERT(reporter, -1 != gatheredRefs.find(fromAnalytic[i]));
+ }
+ }
+ }
+}
+
#ifdef SK_DEBUG
// Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only
// run in debug mode.
@@ -875,6 +1026,7 @@
#endif
test_peephole();
test_gatherpixelrefs(reporter);
+ test_gatherpixelrefsandrects(reporter);
test_bitmap_with_encoded_data(reporter);
test_clone_empty(reporter);
test_clip_bound_opt(reporter);