aboutsummaryrefslogtreecommitdiffstats
path: root/gm
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2011-06-06 17:02:24 -0400
committerDerek Sollenberger <djsollen@google.com>2011-06-07 14:00:04 -0400
commit0b15698a8c76bb8abc1b555c1d91892669b4118f (patch)
tree08732d5fbb7484ce7e10c65c96fb56294053073a /gm
parent9770b0f3d2b5d512daac50c2c9561d2c073cd8d2 (diff)
downloadexternal_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.zip
external_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.tar.gz
external_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.tar.bz2
Skia Merge (revision 1510)
This CL includes bug fixes and closely mirrors the version of Skia used in Chrome M13, which is likely to be our baseline for ICS. The CL also adds source files for the SampleApp which will allow us to execute basic skia tests. The SampleApp requires the utils/views directory in order to run. Finally, we have included the PDF backend for Skia in order to experiment with using it to generate PDF files for certain applications. Note: The SampleApp and PDF code are not built as part of libskia. Change-Id: I1895ccfbd8074e25f19148cc7bd1b4af571fb307
Diffstat (limited to 'gm')
-rw-r--r--gm/Android.mk1
-rw-r--r--gm/bitmapfilters.cpp17
-rw-r--r--gm/blurs.cpp33
-rw-r--r--gm/gm_files.mk1
-rw-r--r--gm/gmmain.cpp6
-rwxr-xr-xgm/nocolorbleed.cpp75
-rw-r--r--gm/pathfill.cpp31
-rw-r--r--gm/shadertext.cpp6
-rw-r--r--gm/shadows.cpp75
-rw-r--r--gm/shapes.cpp8
-rw-r--r--gm/strokerects.cpp9
11 files changed, 182 insertions, 80 deletions
diff --git a/gm/Android.mk b/gm/Android.mk
index b3aeadf..acfb4a5 100644
--- a/gm/Android.mk
+++ b/gm/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \
complexclip.cpp \
filltypes.cpp \
gradients.cpp \
+ nocolorbleed.cpp \
pathfill.cpp \
points.cpp \
poly2poly.cpp \
diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp
index 0487fe6..3903913 100644
--- a/gm/bitmapfilters.cpp
+++ b/gm/bitmapfilters.cpp
@@ -3,15 +3,20 @@
namespace skiagm {
static void make_bm(SkBitmap* bm) {
- const SkColor colors[] = {
+ const SkColor colors[4] = {
SK_ColorRED, SK_ColorGREEN,
SK_ColorBLUE, SK_ColorWHITE
};
- SkColorTable* ctable = new SkColorTable(colors, 4);
+ SkPMColor colorsPM[4];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
+ colorsPM[i] = SkPreMultiplyColor(colors[i]);
+ }
+ SkColorTable* ctable = new SkColorTable(colorsPM, 4);
+
bm->setConfig(SkBitmap::kIndex8_Config, 2, 2);
bm->allocPixels(ctable);
ctable->unref();
-
+
*bm->getAddr8(0, 0) = 0;
*bm->getAddr8(1, 0) = 1;
*bm->getAddr8(0, 1) = 2;
@@ -57,7 +62,7 @@ static SkScalar draw_row(SkCanvas* canvas, const SkBitmap& bm) {
canvas->translate(SkIntToScalar(48), 0);
canvas->scale(SkIntToScalar(scale), SkIntToScalar(scale));
-
+
x += draw_set(canvas, bm, 0, &paint);
paint.reset();
paint.setAlpha(0x80);
@@ -90,7 +95,7 @@ protected:
SkScalar x = SkIntToScalar(10);
SkScalar y = SkIntToScalar(10);
-
+
canvas->translate(x, y);
y = draw_row(canvas, fBM8);
canvas->translate(0, y);
@@ -100,7 +105,7 @@ protected:
canvas->translate(0, y);
draw_row(canvas, fBM32);
}
-
+
private:
typedef GM INHERITED;
};
diff --git a/gm/blurs.cpp b/gm/blurs.cpp
index 26fdc79..c934178 100644
--- a/gm/blurs.cpp
+++ b/gm/blurs.cpp
@@ -5,14 +5,14 @@ namespace skiagm {
class BlursGM : public GM {
public:
- BlursGM() {}
+ BlursGM() {}
protected:
virtual SkString onShortName() {
return SkString("blurs");
}
- virtual SkISize onISize() {
+ virtual SkISize onISize() {
return make_isize(700, 500);
}
@@ -37,8 +37,8 @@ protected:
SkPaint paint;
paint.setAntiAlias(true);
- paint.setTextSize(25);
- canvas->translate(-40, 0);
+ paint.setTextSize(SkIntToScalar(25));
+ canvas->translate(SkIntToScalar(-40), SkIntToScalar(0));
SkBlurMaskFilter::BlurFlags flags = SkBlurMaskFilter::kNone_BlurFlag;
for (int j = 0; j < 2; j++) {
@@ -46,27 +46,32 @@ protected:
paint.setColor(SK_ColorBLUE);
for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
if (gRecs[i].fStyle != NONE) {
- SkMaskFilter* mf = SkBlurMaskFilter::Create(20,
- gRecs[i].fStyle,
- flags);
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(
+ SkIntToScalar(20), gRecs[i].fStyle, flags
+ );
paint.setMaskFilter(mf)->unref();
} else {
paint.setMaskFilter(NULL);
}
- canvas->drawCircle(200 + gRecs[i].fCx*100,
- 200 + gRecs[i].fCy*100, 50, paint);
+ canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100)
+ , SkIntToScalar(200 + gRecs[i].fCy*100)
+ , SkIntToScalar(50)
+ , paint);
}
// draw text
{
- SkMaskFilter* mf = SkBlurMaskFilter::Create(4,
- SkBlurMaskFilter::kNormal_BlurStyle,
- flags);
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(
+ SkIntToScalar(4)
+ , SkBlurMaskFilter::kNormal_BlurStyle
+ , flags
+ );
paint.setMaskFilter(mf)->unref();
SkScalar x = SkIntToScalar(70);
SkScalar y = SkIntToScalar(400);
paint.setColor(SK_ColorBLACK);
canvas->drawText("Hamburgefons Style", 18, x, y, paint);
- canvas->drawText("Hamburgefons Style", 18, x, y + SkIntToScalar(50), paint);
+ canvas->drawText("Hamburgefons Style", 18
+ , x, y + SkIntToScalar(50), paint);
paint.setMaskFilter(NULL);
paint.setColor(SK_ColorWHITE);
x -= SkIntToScalar(2);
@@ -75,7 +80,7 @@ protected:
}
canvas->restore();
flags = SkBlurMaskFilter::kHighQuality_BlurFlag;
- canvas->translate(350, 0);
+ canvas->translate(SkIntToScalar(350), SkIntToScalar(0));
}
}
diff --git a/gm/gm_files.mk b/gm/gm_files.mk
index e867820..fec20b6 100644
--- a/gm/gm_files.mk
+++ b/gm/gm_files.mk
@@ -3,6 +3,7 @@ SOURCE := \
blurs.cpp \
filltypes.cpp \
gradients.cpp \
+ nocolorbleed.cpp \
pathfill.cpp \
points.cpp \
poly2poly.cpp \
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 6267fd4..ea205e3 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -441,7 +441,7 @@ int main(int argc, char * const argv[]) {
const char* readPath = NULL; // if non-null, were we read from to compare
const char* diffPath = NULL; // if non-null, where we write our diffs (from compare)
- bool doReplay = false;
+ bool doReplay = true;
bool doSerialize = false;
const char* const commandName = argv[0];
char* const* stop = argv + argc;
@@ -461,8 +461,8 @@ int main(int argc, char * const argv[]) {
if (argv < stop && **argv) {
diffPath = *argv;
}
- } else if (strcmp(*argv, "--replay") == 0) {
- doReplay = true;
+ } else if (strcmp(*argv, "--noreplay") == 0) {
+ doReplay = false;
} else if (strcmp(*argv, "--serialize") == 0) {
doSerialize = true;
} else {
diff --git a/gm/nocolorbleed.cpp b/gm/nocolorbleed.cpp
new file mode 100755
index 0000000..3dec7cc
--- /dev/null
+++ b/gm/nocolorbleed.cpp
@@ -0,0 +1,75 @@
+#include "gm.h"
+
+namespace skiagm {
+
+class NoColorBleedGM : public GM {
+public:
+ NoColorBleedGM() {}
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("nocolorbleed");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(200, 200);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ drawBG(canvas);
+
+ SkBitmap sprite;
+ sprite.setConfig(SkBitmap::kARGB_8888_Config, 4, 4, 4*sizeof(SkColor));
+ const SkColor spriteData[16] = {
+ SK_ColorBLACK, SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW,
+ SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorRED,
+ SK_ColorGREEN, SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLUE,
+ SK_ColorYELLOW, SK_ColorMAGENTA, SK_ColorCYAN, SK_ColorBLACK
+ };
+ sprite.allocPixels();
+ sprite.lockPixels();
+ SkPMColor* addr = sprite.getAddr32(0, 0);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(spriteData); ++i) {
+ addr[i] = SkPreMultiplyColor(spriteData[i]);
+ }
+ sprite.unlockPixels();
+
+ // We draw a magnified subrect of the sprite
+ // sample interpolation may cause color bleeding around edges
+ // the subrect is a pure white area
+ SkIRect srcRect;
+ SkRect dstRect;
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ //First row : full texture with and without filtering
+ srcRect.setXYWH(0, 0, 4, 4);
+ dstRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0)
+ , SkIntToScalar(100), SkIntToScalar(100));
+ canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint);
+ dstRect.setXYWH(SkIntToScalar(100), SkIntToScalar(0)
+ , SkIntToScalar(100), SkIntToScalar(100));
+ canvas->drawBitmapRect(sprite, &srcRect, dstRect);
+ //Second row : sub rect of texture with and without filtering
+ srcRect.setXYWH(1, 1, 2, 2);
+ dstRect.setXYWH(SkIntToScalar(25), SkIntToScalar(125)
+ , SkIntToScalar(50), SkIntToScalar(50));
+ canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint);
+ dstRect.setXYWH(SkIntToScalar(125), SkIntToScalar(125)
+ , SkIntToScalar(50), SkIntToScalar(50));
+ canvas->drawBitmapRect(sprite, &srcRect, dstRect);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new NoColorBleedGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp
index ec56942..713847f 100644
--- a/gm/pathfill.cpp
+++ b/gm/pathfill.cpp
@@ -6,14 +6,15 @@
typedef SkScalar (*MakePathProc)(SkPath*);
static SkScalar make_frame(SkPath* path) {
- SkRect r = { 10, 10, 630, 470 };
- path->addRoundRect(r, 15, 15);
+ SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(630), SkIntToScalar(470) };
+ path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15));
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(5);
+ paint.setStrokeWidth(SkIntToScalar(5));
paint.getFillPath(*path, path);
- return 15;
+ return SkIntToScalar(15);
}
static SkScalar make_triangle(SkPath* path) {
@@ -24,21 +25,23 @@ static SkScalar make_triangle(SkPath* path) {
path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
path->close();
- path->offset(10, 0);
+ path->offset(SkIntToScalar(10), SkIntToScalar(0));
return SkIntToScalar(30);
}
static SkScalar make_rect(SkPath* path) {
- SkRect r = { 10, 10, 30, 30 };
+ SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(30), SkIntToScalar(30) };
path->addRect(r);
- path->offset(10, 0);
+ path->offset(SkIntToScalar(10), SkIntToScalar(0));
return SkIntToScalar(30);
}
static SkScalar make_oval(SkPath* path) {
- SkRect r = { 10, 10, 30, 30 };
+ SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(30), SkIntToScalar(30) };
path->addOval(r);
- path->offset(10, 0);
+ path->offset(SkIntToScalar(10), SkIntToScalar(0));
return SkIntToScalar(30);
}
@@ -56,8 +59,8 @@ static SkScalar make_sawtooth(SkPath* path) {
x += dx;
path->lineTo(x, y + dy);
}
- path->lineTo(x, y + 2 * dy);
- path->lineTo(x0, y + 2 * dy);
+ path->lineTo(x, y + (2 * dy));
+ path->lineTo(x0, y + (2 * dy));
path->close();
return SkIntToScalar(30);
}
@@ -100,7 +103,7 @@ class PathFillGM : public GM {
SkPath fPath[N];
SkScalar fDY[N];
public:
- PathFillGM() {
+ PathFillGM() {
for (size_t i = 0; i < N; i++) {
fDY[i] = gProcs[i](&fPath[i]);
}
@@ -111,7 +114,7 @@ protected:
return SkString("pathfill");
}
- virtual SkISize onISize() {
+ virtual SkISize onISize() {
return make_isize(640, 480);
}
@@ -127,7 +130,7 @@ protected:
for (size_t i = 0; i < N; i++) {
canvas->drawPath(fPath[i], paint);
- canvas->translate(0, fDY[i]);
+ canvas->translate(SkIntToScalar(0), fDY[i]);
}
}
diff --git a/gm/shadertext.cpp b/gm/shadertext.cpp
index 1cf562c..ea87823 100644
--- a/gm/shadertext.cpp
+++ b/gm/shadertext.cpp
@@ -11,7 +11,7 @@ static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
bm->eraseColor(0);
SkCanvas canvas(*bm);
- SkScalar s = w < h ? w : h;
+ SkScalar s = SkIntToScalar(SkMin32(w, h));
SkPoint pts[] = { { 0, 0 }, { s, s } };
SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
@@ -121,7 +121,7 @@ protected:
const char text[] = "Shaded Text";
const int textLen = SK_ARRAY_COUNT(text) - 1;
- static int pointSize = SkIntToScalar(48);
+ const int pointSize = 48;
int w = pointSize * textLen;
int h = pointSize;
@@ -194,5 +194,3 @@ static GM* MyFactory(void*) { return new ShaderTextGM; }
static GMRegistry reg(MyFactory);
}
-
-
diff --git a/gm/shadows.cpp b/gm/shadows.cpp
index 5afde49..bba997f 100644
--- a/gm/shadows.cpp
+++ b/gm/shadows.cpp
@@ -1,32 +1,29 @@
#include "gm.h"
-#include "SkPicture.h"
-#include "SkRectShape.h"
#include "SkBlurDrawLooper.h"
namespace skiagm {
///////////////////////////////////////////////////////////////////////////////
-class ShadowsGM : public GM {
+static void setup(SkPaint* paint, SkColor c, SkScalar strokeWidth) {
+ paint->setColor(c);
+ if (strokeWidth < 0) {
+ paint->setStyle(SkPaint::kFill_Style);
+ } else {
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(strokeWidth);
+ }
+}
+class ShadowsGM : public GM {
public:
SkPath fCirclePath;
- SkPaint fPaint;
- SkRectShape fRectShape;
+ SkRect fRect;
+
ShadowsGM() {
fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) );
- fPaint.setStrokeWidth(SkIntToScalar(4));
- fPaint.setAntiAlias(true);
- fPaint.setColor(0xFF00FF00);
- fPaint.setStyle(SkPaint::kStroke_Style);
- SkRect rect;
- rect.set(SkIntToScalar(10), SkIntToScalar(10),
- SkIntToScalar(30), SkIntToScalar(30));
- fRectShape.setRect(rect);
- fRectShape.paint().setColor(SK_ColorRED);
- }
-
- virtual ~ShadowsGM() {
+ fRect.set(SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(30), SkIntToScalar(30));
}
protected:
@@ -47,43 +44,61 @@ protected:
SkBlurDrawLooper* shadowLoopers[5];
shadowLoopers[0] =
- new SkBlurDrawLooper (10, 5, 10, 0xFF0000FF,
+ new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5),
+ SkIntToScalar(10), 0xFF0000FF,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkAutoUnref aurL0(shadowLoopers[0]);
shadowLoopers[1] =
- new SkBlurDrawLooper (10, 5, 10, 0xFF0000FF,
+ new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5),
+ SkIntToScalar(10), 0xFF0000FF,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag );
SkAutoUnref aurL1(shadowLoopers[1]);
shadowLoopers[2] =
- new SkBlurDrawLooper (5, 5, 10, 0xFF000000,
+ new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(5),
+ SkIntToScalar(10), 0xFF000000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkAutoUnref aurL2(shadowLoopers[2]);
shadowLoopers[3] =
- new SkBlurDrawLooper (5, -5 ,-10, 0x7FFF0000,
+ new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(-5),
+ SkIntToScalar(-10), 0x7FFF0000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkAutoUnref aurL3(shadowLoopers[3]);
shadowLoopers[4] =
- new SkBlurDrawLooper (0, 5, 5, 0xFF000000,
+ new SkBlurDrawLooper (SkIntToScalar(0), SkIntToScalar(5),
+ SkIntToScalar(5), 0xFF000000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkAutoUnref aurL4(shadowLoopers[4]);
- for (int looper = 0; looper < 5; looper ++)
- {
- fRectShape.paint().setLooper(shadowLoopers[looper]);
- canvas->resetMatrix();
- canvas->translate(SkIntToScalar(looper*40), SkIntToScalar(0));
- canvas->drawShape(&fRectShape);
- fPaint.setLooper(shadowLoopers[looper]);
+ static const struct {
+ SkColor fColor;
+ SkScalar fStrokeWidth;
+ } gRec[] = {
+ { SK_ColorRED, -SK_Scalar1 },
+ { SK_ColorGREEN, SkIntToScalar(4) },
+ };
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(shadowLoopers); ++i) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ paint.setLooper(shadowLoopers[i]);
+
+ canvas->translate(SkIntToScalar(i*40), SkIntToScalar(0));
+ setup(&paint, gRec[0].fColor, gRec[0].fStrokeWidth);
+ canvas->drawRect(fRect, paint);
+
canvas->translate(SkIntToScalar(0), SkIntToScalar(40));
- canvas->drawPath(fCirclePath, fPaint);
+ setup(&paint, gRec[1].fColor, gRec[1].fStrokeWidth);
+ canvas->drawPath(fCirclePath, paint);
}
}
diff --git a/gm/shapes.cpp b/gm/shapes.cpp
index 324ce7e..5daea0a 100644
--- a/gm/shapes.cpp
+++ b/gm/shapes.cpp
@@ -57,6 +57,8 @@ public:
for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
SkSafeRef(fMatrixRefs[i] = fGroup.getShapeMatrixRef(i));
}
+ SkScalar c = SkIntToScalar(50);
+ fMatrixRefs[3]->preRotate(SkIntToScalar(30), c, c);
}
virtual ~ShapesGM() {
@@ -81,10 +83,6 @@ protected:
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
- SkMatrix saveM = *fMatrixRefs[3];
- SkScalar c = SkIntToScalar(50);
- fMatrixRefs[3]->preRotate(SkIntToScalar(30), c, c);
-
SkMatrix matrix;
SkGroupShape* gs = new SkGroupShape;
@@ -111,8 +109,6 @@ protected:
canvas->drawPicture(*pict);
pict->unref();
#endif
-
- *fMatrixRefs[3] = saveM;
}
private:
diff --git a/gm/strokerects.cpp b/gm/strokerects.cpp
index b716407..891b95a 100644
--- a/gm/strokerects.cpp
+++ b/gm/strokerects.cpp
@@ -29,14 +29,14 @@ static const SkScalar SH = SkIntToScalar(H);
class StrokeRectGM : public GM {
public:
- StrokeRectGM() {}
+ StrokeRectGM() {}
protected:
virtual SkString onShortName() {
return SkString("strokerects");
}
- virtual SkISize onISize() {
+ virtual SkISize onISize() {
return make_isize(W*2, H*2);
}
@@ -63,7 +63,10 @@ protected:
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(SW * x, SH * y);
- canvas->clipRect(SkRect::MakeLTRB(2, 2, SW - 2, SH - 2));
+ canvas->clipRect(SkRect::MakeLTRB(
+ SkIntToScalar(2), SkIntToScalar(2)
+ , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
+ ));
SkRandom rand;
for (int i = 0; i < N; i++) {