| Index: tests/PictureTest.cpp
|
| ===================================================================
|
| --- tests/PictureTest.cpp (revision 12922)
|
| +++ tests/PictureTest.cpp (working copy)
|
| @@ -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 @@
|
| }
|
| }
|
|
|
| -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())
|
| +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 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 },
|
| };
|
| +
|
| + 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;
|
| + init_paint(&paint, bm);
|
| +
|
| + SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
|
| r.offset(pos.fX, pos.fY);
|
| - canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
|
| +
|
| + canvas->drawRect(r, 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 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);
|
|
|
| - SkShader* s = SkShader::CreateBitmapShader(bm,
|
| - SkShader::kClamp_TileMode,
|
| - SkShader::kClamp_TileMode);
|
| + canvas->drawOval(r, paint);
|
| +}
|
| +
|
| +static void drawrrect_proc(SkCanvas* canvas, const SkBitmap& bm,
|
| + const SkBitmap& altBM, const SkPoint& pos) {
|
| SkPaint paint;
|
| - paint.setShader(s)->unref();
|
| - canvas->drawRect(r, paint);
|
| - canvas->drawOval(r, 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 @@
|
| 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 @@
|
| 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 @@
|
|
|
| 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 @@
|
| 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 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 @@
|
| 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 @@
|
| 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
|
|
|