aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-01-09 19:20:45 +0000
committerGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-01-09 19:20:45 +0000
commited9866cc8ad9d9687eb0571e45128f1c9422d3f4 (patch)
tree3d6357f47f13117dfa8c44c08e44a490c4708633
parent88e1ec84d08ee7639940514494e718b34b6f6301 (diff)
Expand GatherPixelRefs unit test
-rw-r--r--src/utils/SkPictureUtils.cpp10
-rw-r--r--tests/PictureTest.cpp344
2 files changed, 301 insertions, 53 deletions
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
index e9dedf4d03..8795a04ce2 100644
--- a/src/utils/SkPictureUtils.cpp
+++ b/src/utils/SkPictureUtils.cpp
@@ -113,14 +113,20 @@ public:
this->addBitmapFromPaint(paint);
}
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
- const SkMatrix&, const SkPaint&) SK_OVERRIDE {
+ const SkMatrix&, const SkPaint& paint) SK_OVERRIDE {
this->addBitmap(bitmap);
+ if (SkBitmap::kA8_Config == bitmap.config()) {
+ this->addBitmapFromPaint(paint);
+ }
}
virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
const SkRect* srcOrNull, const SkRect& dst,
- const SkPaint&,
+ const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
this->addBitmap(bitmap);
+ if (SkBitmap::kA8_Config == bitmap.config()) {
+ this->addBitmapFromPaint(paint);
+ }
}
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint) SK_OVERRIDE {
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index acde9b6d58..e50f74e79a 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -23,6 +23,8 @@
#include "SkShader.h"
#include "SkStream.h"
+static const int gColorScale = 30;
+static const int gColorOffset = 60;
static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
bm->setConfig(SkBitmap::kARGB_8888_Config, w, h);
@@ -33,48 +35,242 @@ static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
}
}
-typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkPoint&);
+void make_checkerboard(SkBitmap* bm, int w, int h, bool immutable) {
+ SkASSERT(w % 2 == 0);
+ SkASSERT(h % 2 == 0);
+ bm->setConfig(SkBitmap::kA8_Config, w, h);
+ bm->allocPixels();
+ SkAutoLockPixels lock(*bm);
+ for (int y = 0; y < h; y += 2) {
+ uint8_t* s = bm->getAddr8(0, y);
+ for (int x = 0; x < w; x += 2) {
+ *s++ = 0xFF;
+ *s++ = 0x00;
+ }
+ s = bm->getAddr8(0, y + 1);
+ for (int x = 0; x < w; x += 2) {
+ *s++ = 0x00;
+ *s++ = 0xFF;
+ }
+ }
+ if (immutable) {
+ bm->setImmutable();
+ }
+}
-static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkPoint& pos) {
- canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
+static void init_paint(SkPaint* paint, const SkBitmap &bm) {
+ SkShader* shader = SkShader::CreateBitmapShader(bm,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ paint->setShader(shader)->unref();
}
-static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkPoint& pos) {
- SkRect r = {
- 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())
- };
- r.offset(pos.fX, pos.fY);
- canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
+typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkBitmap&, const SkPoint&);
+
+static void drawpaint_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ canvas->drawPaint(paint);
}
-static void drawshader_proc(SkCanvas* canvas, const SkBitmap& bm,
- const SkPoint& pos) {
- SkRect r = {
- 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())
+static void drawpoints_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ // draw a slightly inset 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 },
};
- r.offset(pos.fX, pos.fY);
- SkShader* s = SkShader::CreateBitmapShader(bm,
- SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode);
+ canvas->drawPoints(SkCanvas::kPolygon_PointMode, 5, points, paint);
+}
+
+static void drawrect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
SkPaint paint;
- paint.setShader(s)->unref();
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
canvas->drawRect(r, paint);
+}
+
+static void drawoval_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
canvas->drawOval(r, paint);
+}
+
+static void drawrrect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
SkRRect rr;
- rr.setRectXY(r, 10, 10);
+ rr.setRectXY(r, SkIntToScalar(bm.width())/4, SkIntToScalar(bm.height())/4);
canvas->drawRRect(rr, paint);
}
+static void drawpath_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkPath path;
+ path.lineTo(bm.width()/2.0f, SkIntToScalar(bm.height()));
+ path.lineTo(SkIntToScalar(bm.width()), 0);
+ path.close();
+ path.offset(pos.fX, pos.fY);
+
+ canvas->drawPath(path, paint);
+}
+
+static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
+}
+
+static void drawbitmap_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ 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);
+}
+
+static void drawsprite_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+
+ SkPoint p(pos);
+ ctm.mapPoints(&p, 1);
+
+ canvas->drawSprite(bm, (int)p.fX, (int)p.fY, NULL);
+}
+
+#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) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+
+ SkPoint p(pos);
+ ctm.mapPoints(&p, 1);
+
+ canvas->drawSprite(altBM, (int)p.fX, (int)p.fY, &paint);
+}
+#endif
+
+static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+
+ r.offset(pos.fX, pos.fY);
+ canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
+}
+
+static void drawbitmaprect_withshader_proc(SkCanvas* canvas,
+ const SkBitmap& bm,
+ const SkBitmap& altBM,
+ const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+
+ SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ r.offset(pos.fX, pos.fY);
+
+ // The bitmap in the paint is ignored unless we're drawing an A8 bitmap
+ canvas->drawBitmapRectToRect(altBM, NULL, r, &paint);
+}
+
+static void drawtext_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+ init_paint(&paint, bm);
+ paint.setTextSize(SkIntToScalar(1.5*bm.width()));
+
+ canvas->drawText("0", 1, pos.fX, pos.fY+bm.width(), paint);
+}
+
+static void drawpostext_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ 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);
+}
+
+static void drawtextonpath_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ SkPaint paint;
+
+ init_paint(&paint, bm);
+ paint.setTextSize(SkIntToScalar(1.5*bm.width()));
+
+ SkPath path;
+ path.lineTo(SkIntToScalar(bm.width()), 0);
+ path.offset(pos.fX, pos.fY+bm.height());
+
+ canvas->drawTextOnPath("O", 1, path, NULL, paint);
+}
+
+static void drawverts_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkBitmap& altBM, const SkPoint& pos) {
+ 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 texs[4] = { { 0, 0 },
+ { SkIntToScalar(bm.width()), 0 },
+ { SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) },
+ { 0, SkIntToScalar(bm.height()) } };
+ uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };
+
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 4, verts, texs, NULL, NULL,
+ indices, 6, paint);
+}
+
// 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) {
SkPicture* pic = new SkPicture;
SkCanvas* canvas = pic->beginRecording(1000, 1000);
for (int i = 0; i < count; ++i) {
- proc(canvas, bm[i], pos[i]);
+ 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]);
+ canvas->restore();
}
pic->endRecording();
return pic;
@@ -93,17 +289,10 @@ static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) {
rect->set(ir);
}
-// Allocate result to be large enough to hold subset, and then draw the picture
-// into it, offsetting by subset's top/left corner.
-static void draw(SkPicture* pic, const SkRect& subset, SkBitmap* result) {
- SkIRect ir;
- subset.roundOut(&ir);
- int w = ir.width();
- int h = ir.height();
- make_bm(result, w, h, 0, false);
+static void draw(SkPicture* pic, int width, int height, SkBitmap* result) {
+ make_bm(result, width, height, SK_ColorBLACK, false);
SkCanvas canvas(*result);
- canvas.translate(-SkIntToScalar(ir.left()), -SkIntToScalar(ir.top()));
canvas.drawPicture(*pic);
}
@@ -121,11 +310,22 @@ static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int c
return find_index<const SkPixelRef*>(array, ref, count) >= 0;
}
-// Look at each pixel in bm, and if its color appears in colors[], find the
-// corresponding value in refs[] and append that ref into array, skipping
-// duplicates of the same value.
-static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[],
- int count, SkTDArray<SkPixelRef*>* array) {
+// Look at each pixel that is inside 'subset', and if its color appears in
+// colors[], find the corresponding value in refs[] and append that ref into
+// array, skipping duplicates of the same value.
+// Note that gathering pixelRefs from rendered colors suffers from the problem
+// that multiple simultaneous textures (e.g., A8 for alpha and 8888 for color)
+// isn't easy to reconstruct.
+static void gather_from_image(const SkBitmap& bm, SkPixelRef* const refs[],
+ int count, SkTDArray<SkPixelRef*>* array,
+ const SkRect& subset) {
+ SkIRect ir;
+ subset.roundOut(&ir);
+
+ if (!ir.intersect(0, 0, bm.width()-1, bm.height()-1)) {
+ return;
+ }
+
// Since we only want to return unique values in array, when we scan we just
// set a bit for each index'd color found. In practice we only have a few
// distinct colors, so we just use an int's bits as our array. Hence the
@@ -135,8 +335,8 @@ static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[],
SkAutoLockPixels alp(bm);
- for (int y = 0; y < bm.height(); ++y) {
- for (int x = 0; x < bm.width(); ++x) {
+ for (int y = ir.fTop; y < ir.fBottom; ++y) {
+ for (int x = ir.fLeft; x < ir.fRight; ++x) {
SkPMColor pmc = *bm.getAddr32(x, y);
// the only good case where the color is not found would be if
// the color is transparent, meaning no bitmap was drawn in that
@@ -145,6 +345,11 @@ static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[],
uint32_t index = SkGetPackedR32(pmc);
SkASSERT(SkGetPackedG32(pmc) == index);
SkASSERT(SkGetPackedB32(pmc) == index);
+ if (0 == index) {
+ continue; // background color
+ }
+ SkASSERT(0 == (index - gColorOffset) % gColorScale);
+ index = (index - gColorOffset) / gColorScale;
SkASSERT(static_cast<int>(index) < count);
bitarray |= 1 << index;
}
@@ -159,28 +364,57 @@ static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[],
}
static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
- const int IW = 8;
+ const int IW = 32;
const int IH = IW;
const SkScalar W = SkIntToScalar(IW);
const SkScalar H = W;
static const int N = 4;
- SkBitmap bm[N];
- SkPixelRef* refs[N];
+ SkBitmap bm[2*N];
+ SkPixelRef* refs[2*N];
- const SkPoint pos[] = {
+ const SkPoint pos[N] = {
{ 0, 0 }, { W, 0 }, { 0, H }, { W, H }
};
- // Our convention is that the color components contain the index of their
- // corresponding bitmap/pixelref
+ // 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, i, i, i), true);
+ 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[] = {
- drawbitmap_proc, drawbitmaprect_proc, drawshader_proc
+ 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,
};
SkRandom rand;
@@ -197,20 +431,28 @@ static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r));
REPORTER_ASSERT(reporter, data);
if (data) {
+ SkPixelRef** gatheredRefs = (SkPixelRef**)data->data();
int count = static_cast<int>(data->size() / sizeof(SkPixelRef*));
- REPORTER_ASSERT(reporter, 1 == count);
- REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]);
+ 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 a deduced list of refs by looking at the colors drawn.
for (int j = 0; j < 100; ++j) {
SkRect r;
rand_rect(&r, rand, 2*W, 2*H);
- SkBitmap result;
- draw(pic, r, &result);
SkTDArray<SkPixelRef*> array;
SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
@@ -220,7 +462,7 @@ static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
SkAutoDataUnref adu(data);
- gather_from_colors(result, refs, N, &array);
+ gather_from_image(image, refs, N, &array, r);
/*
* GatherPixelRefs is conservative, so it can return more bitmaps