aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Reed <reed@google.com>2009-09-14 11:53:40 -0400
committerMike Reed <reed@google.com>2009-09-14 15:01:10 -0400
commite32706edd70b0f847fe4d124a195cd2927dc8021 (patch)
treec5fb8da02dc56601068c0e3695cc7298cf1bd8e9
parent7ca7644aeec45833638d2ce965f4c6ec62e71ade (diff)
downloadskia-e32706edd70b0f847fe4d124a195cd2927dc8021.tar.gz
add SkSize.h
add golden-master (gm) test app
-rw-r--r--Android.mk10
-rw-r--r--gm/Android.mk31
-rw-r--r--gm/bitmapfilters.cpp116
-rw-r--r--gm/filltypes.cpp83
-rw-r--r--gm/gm.h45
-rw-r--r--gm/gm_files.mk8
-rw-r--r--gm/gmmain.cpp197
-rw-r--r--gm/gradients.cpp113
-rw-r--r--gm/shapes.cpp126
-rw-r--r--gm/tilemodes.cpp155
-rw-r--r--gm/xfermodes.cpp188
-rw-r--r--include/core/SkSize.h90
12 files changed, 1160 insertions, 2 deletions
diff --git a/Android.mk b/Android.mk
index 70fd81b348..de09fd4901 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,3 +1,4 @@
+BASE_PATH := $(call my-dir)
LOCAL_PATH:= $(call my-dir)
#############################################################
@@ -253,7 +254,12 @@ LOCAL_MODULE:= libskiagl
include $(BUILD_SHARED_LIBRARY)
#############################################################
-# Build the skia benchmark too
+# Build the skia tools
#
-include $(LOCAL_PATH)/bench/Android.mk
+# benchmark (timings)
+include $(BASE_PATH)/bench/Android.mk
+
+# golden-master (fidelity / regression test)
+include $(BASE_PATH)/gm/Android.mk
+
diff --git a/gm/Android.mk b/gm/Android.mk
new file mode 100644
index 0000000000..6ce1dae3ec
--- /dev/null
+++ b/gm/Android.mk
@@ -0,0 +1,31 @@
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ filltypes.cpp \
+ gradients.cpp \
+ tilemodes.cpp \
+ bitmapfilters.cpp \
+ xfermodes.cpp \
+ gmmain.cpp
+
+# additional optional class for this tool
+LOCAL_SRC_FILES += \
+ ../src/utils/SkUnitMappers.cpp
+
+LOCAL_SHARED_LIBRARIES := libcutils libskia
+LOCAL_C_INCLUDES := \
+ external/skia/include/config \
+ external/skia/include/core \
+ external/skia/include/images \
+ external/skia/include/utils \
+ external/skia/include/effects
+
+#LOCAL_CFLAGS :=
+
+LOCAL_MODULE := skia_gm
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp
new file mode 100644
index 0000000000..0487fe6958
--- /dev/null
+++ b/gm/bitmapfilters.cpp
@@ -0,0 +1,116 @@
+#include "gm.h"
+
+namespace skiagm {
+
+static void make_bm(SkBitmap* bm) {
+ const SkColor colors[] = {
+ SK_ColorRED, SK_ColorGREEN,
+ SK_ColorBLUE, SK_ColorWHITE
+ };
+ SkColorTable* ctable = new SkColorTable(colors, 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;
+ *bm->getAddr8(1, 1) = 3;
+}
+
+static SkScalar draw_bm(SkCanvas* canvas, const SkBitmap& bm,
+ SkScalar x, SkScalar y, SkPaint* paint) {
+ canvas->drawBitmap(bm, x, y, paint);
+ return SkIntToScalar(bm.width()) * 5/4;
+}
+
+static SkScalar draw_set(SkCanvas* c, const SkBitmap& bm, SkScalar x,
+ SkPaint* p) {
+ x += draw_bm(c, bm, x, 0, p);
+ p->setFilterBitmap(true);
+ x += draw_bm(c, bm, x, 0, p);
+ p->setDither(true);
+ return x + draw_bm(c, bm, x, 0, p);
+}
+
+static const char* gConfigNames[] = {
+ "unknown config",
+ "A1",
+ "A8",
+ "Index8",
+ "565",
+ "4444",
+ "8888"
+};
+
+static SkScalar draw_row(SkCanvas* canvas, const SkBitmap& bm) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkPaint paint;
+ SkScalar x = 0;
+ const int scale = 32;
+
+ paint.setAntiAlias(true);
+ const char* name = gConfigNames[bm.config()];
+ canvas->drawText(name, strlen(name), x, SkIntToScalar(bm.height())*scale*5/8,
+ paint);
+ canvas->translate(SkIntToScalar(48), 0);
+
+ canvas->scale(SkIntToScalar(scale), SkIntToScalar(scale));
+
+ x += draw_set(canvas, bm, 0, &paint);
+ paint.reset();
+ paint.setAlpha(0x80);
+ draw_set(canvas, bm, x, &paint);
+ return x * scale / 3;
+}
+
+class FilterGM : public GM {
+public:
+ SkBitmap fBM8, fBM4444, fBM16, fBM32;
+
+ FilterGM() {
+ make_bm(&fBM8);
+ fBM8.copyTo(&fBM4444, SkBitmap::kARGB_4444_Config);
+ fBM8.copyTo(&fBM16, SkBitmap::kRGB_565_Config);
+ fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("bitmapfilters");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(540, 330);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+
+ canvas->translate(x, y);
+ y = draw_row(canvas, fBM8);
+ canvas->translate(0, y);
+ y = draw_row(canvas, fBM4444);
+ canvas->translate(0, y);
+ y = draw_row(canvas, fBM16);
+ canvas->translate(0, y);
+ draw_row(canvas, fBM32);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new FilterGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
+
+
diff --git a/gm/filltypes.cpp b/gm/filltypes.cpp
new file mode 100644
index 0000000000..e723f1610e
--- /dev/null
+++ b/gm/filltypes.cpp
@@ -0,0 +1,83 @@
+#include "gm.h"
+
+namespace skiagm {
+
+class FillTypeGM : public GM {
+ SkPath fPath;
+public:
+ FillTypeGM() {
+ const SkScalar radius = SkIntToScalar(45);
+ fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
+ fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("filltypes");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(835, 840);
+ }
+
+ void showPath(SkCanvas* canvas, int x, int y, SkPath::FillType ft,
+ SkScalar scale, const SkPaint& paint) {
+
+ const SkRect r = { 0, 0, SkIntToScalar(150), SkIntToScalar(150) };
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->clipRect(r);
+ canvas->drawColor(SK_ColorWHITE);
+ fPath.setFillType(ft);
+ canvas->translate(r.centerX(), r.centerY());
+ canvas->scale(scale, scale);
+ canvas->translate(-r.centerX(), -r.centerY());
+ canvas->drawPath(fPath, paint);
+ canvas->restore();
+ }
+
+ void showFour(SkCanvas* canvas, SkScalar scale, const SkPaint& paint) {
+ showPath(canvas, 0, 0, SkPath::kWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 0, SkPath::kEvenOdd_FillType,
+ scale, paint);
+ showPath(canvas, 00, 200, SkPath::kInverseWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 200, SkPath::kInverseEvenOdd_FillType,
+ scale, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ SkPaint paint;
+ const SkScalar scale = SkIntToScalar(5)/4;
+
+ paint.setAntiAlias(false);
+
+ showFour(canvas, SK_Scalar1, paint);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+
+ paint.setAntiAlias(true);
+
+ canvas->translate(SkIntToScalar(-450), SkIntToScalar(450));
+ showFour(canvas, SK_Scalar1, paint);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new FillTypeGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/gm.h b/gm/gm.h
new file mode 100644
index 0000000000..ab92ff6b3e
--- /dev/null
+++ b/gm/gm.h
@@ -0,0 +1,45 @@
+#ifndef skiagm_DEFINED
+#define skiagm_DEFINED
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+#include "SkSize.h"
+#include "SkString.h"
+#include "SkTRegistry.h"
+
+namespace skiagm {
+
+ static inline SkISize make_isize(int w, int h) {
+ SkISize sz;
+ sz.set(w, h);
+ return sz;
+ }
+
+ class GM {
+ public:
+ GM();
+ virtual ~GM();
+
+ void draw(SkCanvas*);
+ SkISize getISize() { return this->onISize(); }
+ const char* shortName() {
+ if (fShortName.size() == 0) {
+ fShortName = this->onShortName();
+ }
+ return fShortName.c_str();
+ }
+
+ protected:
+ virtual void onDraw(SkCanvas*) = 0;
+ virtual SkISize onISize() = 0;
+ virtual SkString onShortName() = 0;
+
+ private:
+ SkString fShortName;
+ };
+
+ typedef SkTRegistry<GM*, void*> GMRegistry;
+}
+
+#endif
diff --git a/gm/gm_files.mk b/gm/gm_files.mk
new file mode 100644
index 0000000000..50eb311d16
--- /dev/null
+++ b/gm/gm_files.mk
@@ -0,0 +1,8 @@
+SOURCE := \
+ bitmapfilters.cpp \
+ filltypes.cpp \
+ gradients.cpp \
+ shapes.cpp \
+ tilemodes.cpp \
+ xfermodes.cpp \
+ gmmain.cpp
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
new file mode 100644
index 0000000000..59f6c6443e
--- /dev/null
+++ b/gm/gmmain.cpp
@@ -0,0 +1,197 @@
+#include "gm.h"
+#include "SkColorPriv.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+
+using namespace skiagm;
+
+// need to explicitly declare this, or we get some weird infinite loop llist
+template GMRegistry* GMRegistry::gHead;
+
+class Iter {
+public:
+ Iter() {
+ fReg = GMRegistry::Head();
+ }
+
+ GM* next() {
+ if (fReg) {
+ GMRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ return fact(0);
+ }
+ return NULL;
+ }
+
+ static int Count() {
+ const GMRegistry* reg = GMRegistry::Head();
+ int count = 0;
+ while (reg) {
+ count += 1;
+ reg = reg->next();
+ }
+ return count;
+ }
+
+private:
+ const GMRegistry* fReg;
+};
+
+static SkString make_name(const char shortName[], const char configName[]) {
+ SkString name(shortName);
+ name.appendf("_%s", configName);
+ return name;
+}
+
+static SkString make_filename(const char path[], const SkString& name) {
+ SkString filename(path);
+ if (filename.size() && filename[filename.size() - 1] != '/') {
+ filename.append("/");
+ }
+ filename.appendf("%s.png", name.c_str());
+ return filename;
+}
+
+/* since PNG insists on unpremultiplying our alpha, we take no precision chances
+ and force all pixels to be 100% opaque, otherwise on compare we may not get
+ a perfect match.
+ */
+static void force_all_opaque(const SkBitmap& bitmap) {
+ SkAutoLockPixels lock(bitmap);
+ for (int y = 0; y < bitmap.height(); y++) {
+ for (int x = 0; x < bitmap.width(); x++) {
+ *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
+ }
+ }
+}
+
+static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) {
+ SkBitmap copy;
+ bitmap.copyTo(&copy, SkBitmap::kARGB_8888_Config);
+ force_all_opaque(copy);
+ return SkImageEncoder::EncodeFile(path.c_str(), copy,
+ SkImageEncoder::kPNG_Type, 100);
+}
+
+static void compare(const SkBitmap& target, const SkBitmap& base,
+ const SkString& name) {
+ SkBitmap copy;
+ const SkBitmap* bm = &target;
+ if (target.config() != SkBitmap::kARGB_8888_Config) {
+ target.copyTo(&copy, SkBitmap::kARGB_8888_Config);
+ bm = &copy;
+ }
+
+ force_all_opaque(*bm);
+
+ const int w = bm->width();
+ const int h = bm->height();
+ if (w != base.width() || h != base.height()) {
+ SkDebugf("---- dimensions mismatch for %s base [%d %d] current [%d %d]\n",
+ name.c_str(), base.width(), base.height(), w, h);
+ return;
+ }
+
+ SkAutoLockPixels bmLock(*bm);
+ SkAutoLockPixels baseLock(base);
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ SkPMColor c0 = *base.getAddr32(x, y);
+ SkPMColor c1 = *bm->getAddr32(x, y);
+ if (c0 != c1) {
+ SkDebugf("----- pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n",
+ name.c_str(), x, y, c0, c1);
+ return;
+ }
+ }
+ }
+}
+
+static const struct {
+ SkBitmap::Config fConfig;
+ bool fUsePicture;
+ const char* fName;
+} gRec[] = {
+ { SkBitmap::kARGB_8888_Config, false, "8888" },
+ { SkBitmap::kARGB_4444_Config, false, "4444" },
+ { SkBitmap::kRGB_565_Config, false, "565" },
+};
+
+int main (int argc, char * const argv[]) {
+ SkAutoGraphics ag;
+
+ const char* writePath = NULL; // if non-null, where we write the originals
+ const char* readPath = NULL; // if non-null, were we read from to compare
+
+ char* const* stop = argv + argc;
+ for (++argv; argv < stop; ++argv) {
+ if (strcmp(*argv, "-w") == 0) {
+ argv++;
+ if (argv < stop && **argv) {
+ writePath = *argv;
+ }
+ } else if (strcmp(*argv, "-r") == 0) {
+ argv++;
+ if (argv < stop && **argv) {
+ readPath = *argv;
+ }
+ }
+ }
+
+ Iter iter;
+ GM* gm;
+
+ while ((gm = iter.next()) != NULL) {
+ SkISize size = gm->getISize();
+ SkDebugf("creating... %s [%d %d]\n", gm->shortName(),
+ size.width(), size.height());
+
+ SkBitmap bitmap;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ bitmap.setConfig(gRec[i].fConfig, size.width(), size.height());
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ SkCanvas canvas(bitmap);
+
+ gm->draw(&canvas);
+
+ SkString name = make_name(gm->shortName(), gRec[i].fName);
+
+ if (writePath) {
+ SkString path = make_filename(writePath, name);
+ bool success = write_bitmap(path, bitmap);
+ if (!success) {
+ fprintf(stderr, "FAILED to write %s\n", path.c_str());
+ }
+ } else if (readPath) {
+ SkString path = make_filename(readPath, name);
+ SkBitmap orig;
+ bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig,
+ SkBitmap::kARGB_8888_Config,
+ SkImageDecoder::kDecodePixels_Mode, NULL);
+ if (success) {
+ compare(bitmap, orig, name);
+ } else {
+ fprintf(stderr, "FAILED to read %s\n", path.c_str());
+ }
+ }
+ }
+ SkDELETE(gm);
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+using namespace skiagm;
+
+GM::GM() {}
+GM::~GM() {}
+
+void GM::draw(SkCanvas* canvas) {
+ this->onDraw(canvas);
+}
+
+
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
new file mode 100644
index 0000000000..aed4e0b145
--- /dev/null
+++ b/gm/gradients.cpp
@@ -0,0 +1,113 @@
+#include "gm.h"
+#include "SkGradientShader.h"
+
+namespace skiagm {
+
+struct GradData {
+ int fCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+};
+
+static const SkColor gColors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
+};
+static const SkScalar gPos0[] = { 0, SK_Scalar1 };
+static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
+static const SkScalar gPos2[] = {
+ 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
+};
+
+static const GradData gGradData[] = {
+ { 2, gColors, NULL },
+ { 2, gColors, gPos0 },
+ { 2, gColors, gPos1 },
+ { 5, gColors, NULL },
+ { 5, gColors, gPos2 }
+};
+
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+ data.fCount, tm, mapper);
+}
+
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ data.fPos, data.fCount, tm, mapper);
+}
+
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+ data.fPos, data.fCount, mapper);
+}
+
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper);
+static const GradMaker gGradMakers[] = {
+ MakeLinear, MakeRadial, MakeSweep
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GradientsGM : public GM {
+public:
+ GradientsGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("gradients");
+ }
+
+ SkISize onISize() { return make_isize(640, 380); }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkPoint pts[2] = {
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) }
+ };
+ SkShader::TileMode tm = SkShader::kClamp_TileMode;
+ SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
+ SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
+ paint.setShader(shader);
+ canvas->drawRect(r, paint);
+ shader->unref();
+ canvas->translate(0, SkIntToScalar(120));
+ }
+ canvas->restore();
+ canvas->translate(SkIntToScalar(120), 0);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new GradientsGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/shapes.cpp b/gm/shapes.cpp
new file mode 100644
index 0000000000..b3d48638a4
--- /dev/null
+++ b/gm/shapes.cpp
@@ -0,0 +1,126 @@
+#include "gm.h"
+#include "SkPicture.h"
+#include "SkRectShape.h"
+#include "SkGroupShape.h"
+
+namespace skiagm {
+
+static SkRect make_rect(int l, int t, int r, int b) {
+ SkRect rect;
+ rect.set(SkIntToScalar(l), SkIntToScalar(t),
+ SkIntToScalar(r), SkIntToScalar(b));
+ return rect;
+}
+
+static SkShape* make_shape0(bool red) {
+ SkRectShape* s = new SkRectShape;
+ s->setRect(make_rect(10, 10, 90, 90));
+ if (red) {
+ s->paint().setColor(SK_ColorRED);
+ }
+ return s;
+}
+
+static SkShape* make_shape1() {
+ SkRectShape* s = new SkRectShape;
+ s->setOval(make_rect(10, 10, 90, 90));
+ s->paint().setColor(SK_ColorBLUE);
+ return s;
+}
+
+static SkShape* make_shape2() {
+ SkRectShape* s = new SkRectShape;
+ s->setRRect(make_rect(10, 10, 90, 90),
+ SkIntToScalar(20), SkIntToScalar(20));
+ s->paint().setColor(SK_ColorGREEN);
+ return s;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ShapesGM : public GM {
+ SkGroupShape fGroup;
+ SkMatrixRef* fMatrixRefs[4];
+public:
+ ShapesGM() {
+ SkMatrix m;
+ fGroup.appendShape(make_shape0(false))->unref();
+ m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50));
+ m.postTranslate(0, SkIntToScalar(120));
+ fGroup.appendShape(make_shape0(true), m)->unref();
+
+ m.setTranslate(SkIntToScalar(120), 0);
+ fGroup.appendShape(make_shape1(), m)->unref();
+ m.postTranslate(0, SkIntToScalar(120));
+ fGroup.appendShape(make_shape2(), m)->unref();
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
+ SkSafeRef(fMatrixRefs[i] = fGroup.getShapeMatrixRef(i));
+ }
+ }
+
+ virtual ~ShapesGM() {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
+ SkSafeUnref(fMatrixRefs[i]);
+ }
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("shapes");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(380, 480);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ 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;
+ SkAutoUnref aur(gs);
+ gs->appendShape(&fGroup);
+ matrix.setScale(-SK_Scalar1, SK_Scalar1);
+ matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240));
+ gs->appendShape(&fGroup, matrix);
+ matrix.setTranslate(SkIntToScalar(240), 0);
+ matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
+ gs->appendShape(&fGroup, matrix);
+
+#if 0
+ canvas->drawShape(gs);
+#else
+ SkPicture pict;
+ SkCanvas* cv = pict.beginRecording(1000, 1000);
+ cv->scale(SK_ScalarHalf, SK_ScalarHalf);
+ cv->drawShape(gs);
+ cv->translate(SkIntToScalar(680), SkIntToScalar(480));
+ cv->scale(-SK_Scalar1, SK_Scalar1);
+ cv->drawShape(gs);
+ pict.endRecording();
+ canvas->drawPicture(pict);
+#endif
+
+ *fMatrixRefs[3] = saveM;
+}
+
+private:
+ typedef GM INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ShapesGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp
new file mode 100644
index 0000000000..d836ea58bd
--- /dev/null
+++ b/gm/tilemodes.cpp
@@ -0,0 +1,155 @@
+#include "gm.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+
+// effects
+#include "SkGradientShader.h"
+#include "SkUnitMappers.h"
+#include "SkBlurDrawLooper.h"
+
+namespace skiagm {
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+ bm->setConfig(config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+ SkPoint pts[] = { { 0, 0 }, { SkIntToScalar(w), SkIntToScalar(h)} };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+ SkPaint paint;
+
+ SkUnitMapper* um = NULL;
+
+ um = new SkCosineMapper;
+// um = new SkDiscreteMapper(12);
+
+ SkAutoUnref au(um);
+
+ paint.setDither(true);
+ paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+ SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+ canvas.drawPaint(paint);
+}
+
+static void setup(SkPaint* paint, const SkBitmap& bm, bool filter,
+ SkShader::TileMode tmx, SkShader::TileMode tmy) {
+ SkShader* shader = SkShader::CreateBitmapShader(bm, tmx, tmy);
+ paint->setShader(shader)->unref();
+ paint->setFilterBitmap(filter);
+}
+
+static const SkBitmap::Config gConfigs[] = {
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kARGB_4444_Config
+};
+static const int gWidth = 32;
+static const int gHeight = 32;
+
+class TilingGM : public GM {
+ SkBlurDrawLooper fLooper;
+public:
+ TilingGM()
+ : fLooper(SkIntToScalar(1), SkIntToScalar(2), SkIntToScalar(2),
+ 0x88000000) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ makebm(&fTexture[i], gConfigs[i], gWidth, gHeight);
+ }
+ }
+
+ SkBitmap fTexture[SK_ARRAY_COUNT(gConfigs)];
+
+protected:
+ SkString onShortName() {
+ return SkString("tilemodes");
+ }
+
+ SkISize onISize() { return make_isize(880, 560); }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkRect r = { 0, 0, SkIntToScalar(gWidth*2), SkIntToScalar(gHeight*2) };
+
+ static const char* gConfigNames[] = { "8888", "565", "4444" };
+
+ static const bool gFilters[] = { false, true };
+ static const char* gFilterNames[] = { "point", "bilinear" };
+
+ static const SkShader::TileMode gModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode };
+ static const char* gModeNames[] = { "C", "R", "M" };
+
+ SkScalar y = SkIntToScalar(24);
+ SkScalar x = SkIntToScalar(10);
+
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setDither(true);
+ p.setLooper(&fLooper);
+ str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]);
+
+ p.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawText(str.c_str(), str.size(), x + r.width()/2, y, p);
+
+ x += r.width() * 4 / 3;
+ }
+ }
+
+ y += SkIntToScalar(16);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gFilters); j++) {
+ x = SkIntToScalar(10);
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint paint;
+ setup(&paint, fTexture[i], gFilters[j], gModes[kx], gModes[ky]);
+ paint.setDither(true);
+
+ canvas->save();
+ canvas->translate(x, y);
+ canvas->drawRect(r, paint);
+ canvas->restore();
+
+ x += r.width() * 4 / 3;
+ }
+ }
+ {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setLooper(&fLooper);
+ str.printf("%s, %s", gConfigNames[i], gFilterNames[j]);
+ canvas->drawText(str.c_str(), str.size(), x, y + r.height() * 2 / 3, p);
+ }
+
+ y += r.height() * 4 / 3;
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new TilingGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp
new file mode 100644
index 0000000000..5a43f4abb9
--- /dev/null
+++ b/gm/xfermodes.cpp
@@ -0,0 +1,188 @@
+#include "gm.h"
+#include "SkBitmap.h"
+#include "SkShader.h"
+#include "SkXfermode.h"
+
+namespace skiagm {
+
+static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) {
+ src->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ src->allocPixels();
+ src->eraseColor(0);
+
+ SkCanvas c(*src);
+ SkPaint p;
+ SkRect r;
+ SkScalar ww = SkIntToScalar(w);
+ SkScalar hh = SkIntToScalar(h);
+
+ p.setAntiAlias(true);
+ p.setColor(0xFFFFCC44);
+ r.set(0, 0, ww*3/4, hh*3/4);
+ c.drawOval(r, p);
+
+ dst->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ dst->allocPixels();
+ dst->eraseColor(0);
+ c.setBitmapDevice(*dst);
+
+ p.setColor(0xFF66AAFF);
+ r.set(ww/3, hh/3, ww*19/20, hh*19/20);
+ c.drawRect(r, p);
+}
+
+static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
+
+class XfermodesGM : public GM {
+ SkBitmap fBitmap;
+ SkBitmap fBG;
+ SkBitmap fSrcB, fDstB;
+
+ void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha) {
+ SkPaint p;
+
+ canvas->drawBitmap(fSrcB, 0, 0, &p);
+ p.setAlpha(alpha);
+ p.setXfermode(mode);
+ canvas->drawBitmap(fDstB, 0, 0, &p);
+ }
+
+public:
+ XfermodesGM() {
+ const int W = 64;
+ const int H = 64;
+
+ fBitmap.setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ fBitmap.allocPixels();
+
+ fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
+ fBG.setPixels(gBG);
+ fBG.setIsOpaque(true);
+
+ make_bitmaps(W, H, &fSrcB, &fDstB);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("xfermodes");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(790, 480);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ return;
+ SkShader* s = SkShader::CreateBitmapShader(fBG,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkPaint p;
+ SkMatrix m;
+
+ p.setShader(s)->unref();
+ m.setScale(SkIntToScalar(8), SkIntToScalar(8));
+ s->setLocalMatrix(m);
+ canvas->drawPaint(p);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+ } gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+
+ { SkXfermode::kPlus_Mode, "Plus" },
+ { SkXfermode::kMultiply_Mode, "Multiply" },
+ { SkXfermode::kScreen_Mode, "Screen" },
+ { SkXfermode::kOverlay_Mode, "Overlay" },
+ { SkXfermode::kDarken_Mode, "Darken" },
+ { SkXfermode::kLighten_Mode, "Lighten" },
+ { SkXfermode::kColorDodge_Mode, "ColorDodge" },
+ { SkXfermode::kColorBurn_Mode, "ColorBurn" },
+ { SkXfermode::kHardLight_Mode, "HardLight" },
+ { SkXfermode::kSoftLight_Mode, "SoftLight" },
+ { SkXfermode::kDifference_Mode, "Difference" },
+ { SkXfermode::kExclusion_Mode, "Exclusion" },
+ };
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ SkCanvas c(fBitmap);
+ const SkScalar w = SkIntToScalar(fBitmap.width());
+ const SkScalar h = SkIntToScalar(fBitmap.height());
+ SkShader* s = SkShader::CreateBitmapShader(fBG,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+
+ SkPaint labelP;
+ labelP.setAntiAlias(true);
+ labelP.setTextAlign(SkPaint::kCenter_Align);
+
+ const int W = 5;
+
+ SkScalar x0 = 0;
+ for (int twice = 0; twice < 2; twice++) {
+ SkScalar x = x0, y = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ fBitmap.eraseColor(0);
+ draw_mode(&c, mode, twice ? 0x88 : 0xFF);
+ SkSafeUnref(mode);
+
+ SkPaint p;
+ SkRect r;
+ r.set(x, y, x+w, y+h);
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ p.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(r, p);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setShader(s);
+ r.inset(SK_ScalarHalf, SK_ScalarHalf);
+ canvas->drawRect(r, p);
+
+ canvas->drawBitmap(fBitmap, x, y, NULL);
+
+ canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
+ x + w/2, y - labelP.getTextSize()/2, labelP);
+
+ x += w + SkIntToScalar(10);
+ if ((i % W) == W - 1) {
+ x = x0;
+ y += h + SkIntToScalar(30);
+ }
+ }
+ x0 += SkIntToScalar(400);
+ }
+ s->unref();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new XfermodesGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/include/core/SkSize.h b/include/core/SkSize.h
new file mode 100644
index 0000000000..d432102c3b
--- /dev/null
+++ b/include/core/SkSize.h
@@ -0,0 +1,90 @@
+
+
+#ifndef SkSize_DEFINED
+#define SkSize_DEFINED
+
+template <typename T> struct SkTSize {
+ T fWidth;
+ T fHeight;
+
+ void set(T w, T h) {
+ fWidth = w;
+ fHeight = h;
+ }
+
+ /** Returns true iff fWidth == 0 && fHeight == 0
+ */
+ bool isZero() const {
+ return 0 == fWidth && 0 == fHeight;
+ }
+
+ /** Returns true if either widht or height are <= 0 */
+ bool isEmpty() const {
+ return fWidth <= 0 || fHeight <= 0;
+ }
+
+ /** Set the width and height to 0 */
+ void setEmpty() {
+ fWidth = fHeight = 0;
+ }
+
+ T width() const { return fWidth; }
+ T height() const { return fHeight; }
+
+ /** If width or height is < 0, it is set to 0 */
+ void clampNegToZero() {
+ if (fWidth < 0) {
+ fWidth = 0;
+ }
+ if (fHeight < 0) {
+ fHeight = 0;
+ }
+ }
+
+ bool equals(T w, T h) const {
+ return fWidth == w && fHeight == h;
+ }
+};
+
+template <typename T>
+static inline bool operator==(const SkTSize<T>& a, const SkTSize<T>& b) {
+ return a.fWidth == b.fWidth && a.fHeight == b.fHeight;
+}
+
+template <typename T>
+static inline bool operator!=(const SkTSize<T>& a, const SkTSize<T>& b) {
+ return !(a == b);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkISize : public SkTSize<int32_t> {};
+
+#include "SkScalar.h"
+
+struct SkSize : public SkTSize<SkScalar> {
+ SkSize& operator=(const SkISize& src) {
+ this->set(SkIntToScalar(src.fWidth), SkIntToScalar(src.fHeight));
+ return *this;
+ }
+
+ SkISize round() const {
+ SkISize s;
+ s.set(SkScalarRound(fWidth), SkScalarRound(fHeight));
+ return s;
+ }
+
+ SkISize ceil() const {
+ SkISize s;
+ s.set(SkScalarCeil(fWidth), SkScalarCeil(fHeight));
+ return s;
+ }
+
+ SkISize floor() const {
+ SkISize s;
+ s.set(SkScalarFloor(fWidth), SkScalarFloor(fHeight));
+ return s;
+ }
+};
+
+#endif