aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-29 21:00:39 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-29 21:00:39 +0000
commitfe7b1ed30a75cecfe80d1ba4d1f60295e99aeef0 (patch)
tree05dd1397127c756a562bd54cbfccbb1f35d99e67 /tests
parent417bc1382ee527077d96414552b52050335b3350 (diff)
add SkPictureUtils::GatherPixelRefs()
Review URL: https://codereview.appspot.com/6845106 git-svn-id: http://skia.googlecode.com/svn/trunk@6615 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'tests')
-rw-r--r--tests/PictureTest.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 44cf59a889..567a8d2006 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -6,11 +6,232 @@
*/
#include "Test.h"
#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkData.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkRandom.h"
+#include "SkShader.h"
#include "SkStream.h"
+#include "SkPictureUtils.h"
+
+static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
+ bm->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(color);
+ if (immutable) {
+ bm->setImmutable();
+ }
+}
+
+typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkPoint&);
+
+static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
+ const SkPoint& pos) {
+ canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
+}
+
+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);
+}
+
+static void drawshader_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);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ canvas->drawRect(r, 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]);
+ }
+ pic->endRecording();
+ return pic;
+}
+
+static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) {
+ rect->fLeft = rand.nextRangeScalar(-W, 2*W);
+ rect->fTop = rand.nextRangeScalar(-H, 2*H);
+ rect->fRight = rect->fLeft + rand.nextRangeScalar(0, W);
+ rect->fBottom = rect->fTop + rand.nextRangeScalar(0, H);
+
+ // we integralize rect to make our tests more predictable, since Gather is
+ // a little sloppy.
+ SkIRect ir;
+ rect->round(&ir);
+ 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);
+
+ SkCanvas canvas(*result);
+ canvas.translate(-SkIntToScalar(ir.left()), -SkIntToScalar(ir.top()));
+ canvas.drawPicture(*pic);
+}
+
+template <typename T> int find_index(const T* array, T elem, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (array[i] == elem) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Return true if 'ref' is found in array[]
+static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int count) {
+ 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) {
+ // 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
+ // assert that count <= number-of-bits-in-our-int.
+ SkASSERT((unsigned)count <= 32);
+ uint32_t bitarray = 0;
+
+ SkAutoLockPixels alp(bm);
+
+ for (int y = 0; y < bm.height(); ++y) {
+ for (int x = 0; x < bm.width(); ++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
+ // pixel.
+ if (pmc) {
+ int index = SkGetPackedR32(pmc);
+ SkASSERT(SkGetPackedG32(pmc) == index);
+ SkASSERT(SkGetPackedB32(pmc) == index);
+ SkASSERT(index < count);
+ bitarray |= 1 << index;
+ }
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ if (bitarray & (1 << i)) {
+ *array->append() = refs[i];
+ }
+ }
+}
+
+static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
+ const int IW = 8;
+ const int IH = IW;
+ const SkScalar W = SkIntToScalar(IW);
+ const SkScalar H = W;
+
+ static const int N = 4;
+ SkBitmap bm[N];
+ SkPMColor pmcolors[N];
+ SkPixelRef* refs[N];
+
+ const SkPoint pos[] = {
+ { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
+ };
+
+ // Our convention is that the color components contain the index of their
+ // corresponding bitmap/pixelref
+ for (int i = 0; i < N; ++i) {
+ make_bm(&bm[i], IW, IH, SkColorSetARGB(0xFF, i, i, i), true);
+ refs[i] = bm[i].pixelRef();
+ }
+
+ static const DrawBitmapProc procs[] = {
+ drawbitmap_proc, drawbitmaprect_proc, drawshader_proc
+ };
+
+ SkRandom rand;
+ for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) {
+ SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k]));
+
+ // quick check for a small piece of each quadrant, which should just
+ // contain 1 bitmap.
+ 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);
+ SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r));
+ REPORTER_ASSERT(reporter, data);
+ int count = data->size() / sizeof(SkPixelRef*);
+ REPORTER_ASSERT(reporter, 1 == count);
+ REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]);
+ }
+
+ // 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);
+ size_t dataSize = data ? data->size() : 0;
+ int gatherCount = dataSize / sizeof(SkPixelRef*);
+ SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize);
+ SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
+ SkAutoDataUnref adu(data);
+
+ gather_from_colors(result, refs, N, &array);
+
+ /*
+ * 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
+ * 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);
+ REPORTER_ASSERT(reporter, found);
+#if 0
+ // enable this block of code to debug failures, as it will rerun
+ // the case that failed.
+ if (!found) {
+ SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
+ size_t dataSize = data ? data->size() : 0;
+ }
+#endif
+ }
+ }
+ }
+}
+
#ifdef SK_DEBUG
// Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only
// run in debug mode.
@@ -91,6 +312,7 @@ static void TestPicture(skiatest::Reporter* reporter) {
test_serializing_empty_picture();
#endif
test_peephole(reporter);
+ test_gatherpixelrefs(reporter);
}
#include "TestClassDef.h"