aboutsummaryrefslogtreecommitdiffstats
path: root/gm
diff options
context:
space:
mode:
Diffstat (limited to 'gm')
-rw-r--r--gm/Android.mk30
-rw-r--r--gm/convexpaths.cpp202
-rw-r--r--gm/gammatext.cpp192
-rw-r--r--gm/gmmain.cpp105
-rw-r--r--gm/gradients.cpp44
-rw-r--r--gm/morphology.cpp98
-rw-r--r--gm/patheffects.cpp160
-rw-r--r--gm/strokefill.cpp35
-rw-r--r--gm/system_preferences.h12
-rw-r--r--gm/system_preferences_default.cpp10
-rw-r--r--gm/system_preferences_mac.mm24
-rw-r--r--gm/texdata.cpp2
12 files changed, 883 insertions, 31 deletions
diff --git a/gm/Android.mk b/gm/Android.mk
index 14f4d62..8dcb0ef 100644
--- a/gm/Android.mk
+++ b/gm/Android.mk
@@ -3,33 +3,59 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
+ gm.cpp \
+ gmmain.cpp \
+ system_preferences_default.cpp
+
+# Slides
+LOCAL_SRC_FILES += \
+ aaclip.cpp \
aarectmodes.cpp \
+ arithmode.cpp \
+ bitmapcopy.cpp \
bitmapfilters.cpp \
bitmapscroll.cpp \
blurs.cpp \
+ colormatrix.cpp \
complexclip.cpp \
complexclip2.cpp \
+ convexpaths.cpp \
+ cubicpaths.cpp \
+ degeneratesegments.cpp \
+ drawbitmaprect.cpp \
emptypath.cpp \
filltypes.cpp \
filltypespersp.cpp \
- gm.cpp \
- gmmain.cpp \
+ fontscaler.cpp \
+ gammatext.cpp \
gradients.cpp \
+ gradtext.cpp \
hairmodes.cpp \
+ imageblur.cpp \
lcdtext.cpp \
+ linepaths.cpp \
+ morphology.cpp \
ninepatchstretch.cpp \
nocolorbleed.cpp \
+ patheffects.cpp \
pathfill.cpp \
+ pathreverse.cpp \
points.cpp \
poly2poly.cpp \
+ quadpaths.cpp \
shadertext.cpp \
shadows.cpp \
shapes.cpp \
+ strokefill.cpp \
strokerects.cpp \
strokes.cpp \
+ tablecolorfilter.cpp \
+ testimagefilters.cpp \
texdata.cpp \
tilemodes.cpp \
tinybitmap.cpp \
+ verttext.cpp \
+ verttext2.cpp \
xfermodes.cpp
LOCAL_STATIC_LIBRARIES := libskiagpu
diff --git a/gm/convexpaths.cpp b/gm/convexpaths.cpp
new file mode 100644
index 0000000..2c719e8
--- /dev/null
+++ b/gm/convexpaths.cpp
@@ -0,0 +1,202 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkRandom.h"
+#include "SkTArray.h"
+
+namespace skiagm {
+
+class ConvexPathsGM : public GM {
+public:
+ ConvexPathsGM() {
+ this->setBGColor(0xFF000000);
+ this->makePaths();
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("convexpaths");
+ }
+
+
+ virtual SkISize onISize() {
+ return make_isize(1200, 900);
+ }
+
+ void makePaths() {
+ // CW
+ fPaths.push_back().moveTo(0, 0);
+ fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
+ 0, 100 * SK_Scalar1);
+ fPaths.back().lineTo(0, 0);
+
+ // CCW
+ fPaths.push_back().moveTo(0, 0);
+ fPaths.back().lineTo(0, 100 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
+ 0, 0);
+
+ // CW
+ fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 0,
+ 100 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
+ 0, 50 * SK_Scalar1);
+
+ // CCW
+ fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
+ 100 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 0,
+ 0, 50 * SK_Scalar1);
+
+ fPaths.push_back().addRect(0, 0,
+ 100 * SK_Scalar1, 100 * SK_Scalar1,
+ SkPath::kCW_Direction);
+
+ fPaths.push_back().addRect(0, 0,
+ 100 * SK_Scalar1, 100 * SK_Scalar1,
+ SkPath::kCCW_Direction);
+
+ fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, SkPath::kCW_Direction);
+
+ fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 40 * SK_Scalar1, SkPath::kCCW_Direction);
+
+ fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
+ 50 * SK_Scalar1,
+ 100 * SK_Scalar1),
+ SkPath::kCW_Direction);
+
+ fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
+ 100 * SK_Scalar1,
+ 50 * SK_Scalar1),
+ SkPath::kCCW_Direction);
+
+ fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
+ 100 * SK_Scalar1,
+ 5 * SK_Scalar1),
+ SkPath::kCCW_Direction);
+
+ fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
+ SK_Scalar1,
+ 100 * SK_Scalar1),
+ SkPath::kCCW_Direction);
+
+ fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
+ SK_Scalar1 * 100,
+ SK_Scalar1 * 100),
+ 40 * SK_Scalar1, 20 * SK_Scalar1,
+ SkPath::kCW_Direction);
+
+ fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
+ SK_Scalar1 * 100,
+ SK_Scalar1 * 100),
+ 20 * SK_Scalar1, 40 * SK_Scalar1,
+ SkPath::kCCW_Direction);
+
+ // shallow diagonals
+ fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
+ fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
+ fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
+
+ /*
+ It turns out arcTos are not automatically marked as convex and they
+ may in fact be ever so slightly concave.
+ fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
+ 50 * SK_Scalar1,
+ 100 * SK_Scalar1),
+ 25 * SK_Scalar1, 130 * SK_Scalar1, false);
+ */
+
+ // cubics
+ fPaths.push_back().cubicTo( 1 * SK_Scalar1, 1 * SK_Scalar1,
+ 10 * SK_Scalar1, 90 * SK_Scalar1,
+ 0 * SK_Scalar1, 100 * SK_Scalar1);
+ fPaths.push_back().cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
+ 20 * SK_Scalar1, 100 * SK_Scalar1,
+ 0 * SK_Scalar1, 0 * SK_Scalar1);
+
+ // triangle where one edge is a degenerate quad
+ fPaths.push_back().moveTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
+ fPaths.back().quadTo(SkFloatToScalar(16.9921875f), 45 * SK_Scalar1,
+ SkFloatToScalar(31.25f), 45 * SK_Scalar1);
+ fPaths.back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
+ fPaths.back().lineTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
+
+ // point degenerate
+ fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+
+ // moveTo only paths
+ fPaths.push_back().moveTo(0, 0);
+ fPaths.back().moveTo(0, 0);
+ fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
+ fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
+ fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
+
+ fPaths.push_back().moveTo(0, 0);
+ fPaths.back().moveTo(0, 0);
+
+ // line degenerate
+ fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
+ fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
+ fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
+ 50 * SK_Scalar1, 50 * SK_Scalar1);
+ fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
+ 100 * SK_Scalar1, 100 * SK_Scalar1);
+ fPaths.push_back().cubicTo(0, 0,
+ 0, 0,
+ 100 * SK_Scalar1, 100 * SK_Scalar1);
+
+ // small circle. This is listed last so that it has device coords far
+ // from the origin (small area relative to x,y values).
+ fPaths.push_back().addCircle(0, 0, SkFloatToScalar(0.8f));
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkRandom rand;
+ canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
+ for (int i = 0; i < fPaths.count(); ++i) {
+ canvas->save();
+ // position the path, and make it at off-integer coords.
+ canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 4,
+ SK_Scalar1 * 200 * (i / 5) + 3 * SK_Scalar1 / 4);
+ SkColor color = rand.nextU();
+ color |= 0xff000000;
+ paint.setColor(color);
+ SkASSERT(fPaths[i].isConvex());
+ canvas->drawPath(fPaths[i], paint);
+ canvas->restore();
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+ SkTArray<SkPath> fPaths;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ConvexPathsGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/gammatext.cpp b/gm/gammatext.cpp
new file mode 100644
index 0000000..6f1c298
--- /dev/null
+++ b/gm/gammatext.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkGradientShader.h"
+#include "SkTypeface.h"
+
+static SkShader* make_heatGradient(const SkPoint pts[2]) {
+ const SkColor colors[] = {
+ SK_ColorBLACK, SK_ColorBLUE, SK_ColorCYAN, SK_ColorGREEN,
+ SK_ColorYELLOW, SK_ColorRED, SK_ColorWHITE
+ };
+ const SkColor bw[] = { SK_ColorBLACK, SK_ColorWHITE };
+
+ return SkGradientShader::CreateLinear(pts, bw, NULL,
+ SK_ARRAY_COUNT(bw),
+ SkShader::kClamp_TileMode);
+}
+
+static bool setFont(SkPaint* paint, const char name[]) {
+ SkTypeface* tf = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
+ if (tf) {
+ paint->setTypeface(tf)->unref();
+ return true;
+ }
+ return false;
+}
+
+#ifdef SK_BUILD_FOR_MAC
+#import <ApplicationServices/ApplicationServices.h>
+#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
+
+static CGContextRef makeCG(const SkBitmap& bm) {
+ if (SkBitmap::kARGB_8888_Config != bm.config() ||
+ NULL == bm.getPixels()) {
+ return NULL;
+ }
+ CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+ CGContextRef cg = CGBitmapContextCreate(bm.getPixels(), bm.width(), bm.height(),
+ 8, bm.rowBytes(), space, BITMAP_INFO_RGB);
+ CFRelease(space);
+
+ CGContextSetAllowsFontSubpixelQuantization(cg, false);
+ CGContextSetShouldSubpixelQuantizeFonts(cg, false);
+
+ return cg;
+}
+
+extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
+
+static CGFontRef typefaceToCGFont(const SkTypeface* face) {
+ if (NULL == face) {
+ return 0;
+ }
+
+ CTFontRef ct = SkTypeface_GetCTFontRef(face);
+ return CTFontCopyGraphicsFont(ct, NULL);
+}
+
+static void cgSetPaintForText(CGContextRef cg, const SkPaint& paint) {
+ SkColor c = paint.getColor();
+ CGFloat rgba[] = {
+ SkColorGetB(c) / 255.0,
+ SkColorGetG(c) / 255.0,
+ SkColorGetR(c) / 255.0,
+ SkColorGetA(c) / 255.0,
+ };
+ CGContextSetRGBFillColor(cg, rgba[0], rgba[1], rgba[2], rgba[3]);
+
+ CGContextSetTextDrawingMode(cg, kCGTextFill);
+ CGContextSetFont(cg, typefaceToCGFont(paint.getTypeface()));
+ CGContextSetFontSize(cg, SkScalarToFloat(paint.getTextSize()));
+
+ CGContextSetAllowsFontSubpixelPositioning(cg, paint.isSubpixelText());
+ CGContextSetShouldSubpixelPositionFonts(cg, paint.isSubpixelText());
+
+ CGContextSetShouldAntialias(cg, paint.isAntiAlias());
+ CGContextSetShouldSmoothFonts(cg, paint.isLCDRenderText());
+}
+
+static void cgDrawText(CGContextRef cg, const void* text, size_t len,
+ float x, float y, const SkPaint& paint) {
+ if (cg) {
+ cgSetPaintForText(cg, paint);
+
+ uint16_t glyphs[200];
+ int count = paint.textToGlyphs(text, len, glyphs);
+
+ CGContextShowGlyphsAtPoint(cg, x, y, glyphs, count);
+ }
+}
+#endif
+
+namespace skiagm {
+
+/**
+ Test a set of clipping problems discovered while writing blitAntiRect,
+ and test all the code paths through the clipping blitters.
+ Each region should show as a blue center surrounded by a 2px green
+ border, with no red.
+*/
+
+#define HEIGHT 480
+
+class GammaTextGM : public GM {
+public:
+ GammaTextGM() {
+
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("gammatext");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(1024, HEIGHT);
+ }
+
+ static void drawGrad(SkCanvas* canvas) {
+ SkPoint pts[] = { { 0, 0 }, { 0, HEIGHT } };
+#if 0
+ const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+#else
+ SkShader* s = make_heatGradient(pts);
+#endif
+
+ canvas->clear(SK_ColorRED);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ SkRect r = { 0, 0, 1024, HEIGHT };
+ canvas->drawRect(r, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+#ifdef SK_BUILD_FOR_MAC
+ CGContextRef cg = makeCG(canvas->getDevice()->accessBitmap(false));
+#endif
+
+ drawGrad(canvas);
+
+ const SkColor fg[] = {
+ 0xFFFFFFFF,
+ 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
+ 0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
+ 0xFF000000,
+ };
+
+ const char* text = "Hamburgefons";
+ size_t len = strlen(text);
+
+ SkPaint paint;
+ setFont(&paint, "Times");
+ paint.setTextSize(SkIntToScalar(16));
+ paint.setAntiAlias(true);
+ paint.setLCDRenderText(true);
+
+ SkScalar x = 10;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
+ paint.setColor(fg[i]);
+
+ SkScalar y = 40;
+ SkScalar stopy = HEIGHT;
+ while (y < stopy) {
+#if 1
+ canvas->drawText(text, len, x, y, paint);
+#else
+ cgDrawText(cg, text, len, x, HEIGHT - y, paint);
+#endif
+ y += paint.getTextSize() * 2;
+ }
+ x += SkIntToScalar(1024) / SK_ARRAY_COUNT(fg);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new GammaTextGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 0af2933..523faf8 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -6,19 +6,21 @@
*/
#include "gm.h"
+#include "system_preferences.h"
#include "GrContext.h"
#include "GrRenderTarget.h"
#include "SkColorPriv.h"
#include "SkData.h"
+#include "SkDeferredCanvas.h"
#include "SkDevice.h"
#include "SkGpuCanvas.h"
#include "SkGpuDevice.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
-#include "SkNativeGLContext.h"
-#include "SkMesaGLContext.h"
+#include "gl/SkNativeGLContext.h"
+#include "gl/SkMesaGLContext.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkRefCnt.h"
@@ -32,6 +34,9 @@ extern bool gSkSuppressFontCachePurgeSpew;
#include "SkPDFDocument.h"
#endif
+// Until we resolve http://code.google.com/p/skia/issues/detail?id=455 ,
+// stop writing out XPS-format image baselines in gm.
+#undef SK_SUPPORT_XPS
#ifdef SK_SUPPORT_XPS
#include "SkXPSDevice.h"
#endif
@@ -268,26 +273,41 @@ static void invokeGM(GM* gm, SkCanvas* canvas) {
static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec,
GrContext* context,
GrRenderTarget* rt,
- SkBitmap* bitmap) {
+ SkBitmap* bitmap,
+ bool deferred) {
SkISize size (gm->getISize());
setup_bitmap(gRec, size, bitmap);
- SkCanvas canvas(*bitmap);
if (gRec.fBackend == kRaster_Backend) {
- invokeGM(gm, &canvas);
+ SkCanvas* canvas;
+ if (deferred) {
+ canvas = new SkDeferredCanvas;
+ canvas->setDevice(new SkDevice(*bitmap))->unref();
+ } else {
+ canvas = new SkCanvas(*bitmap);
+ }
+ SkAutoUnref canvasUnref(canvas);
+ invokeGM(gm, canvas);
+ canvas->flush();
} else { // GPU
if (NULL == context) {
return ERROR_NO_GPU_CONTEXT;
}
- SkGpuCanvas gc(context, rt);
- gc.setDevice(new SkGpuDevice(context, rt))->unref();
- invokeGM(gm, &gc);
+ SkCanvas* gc;
+ if (deferred) {
+ gc = new SkDeferredCanvas;
+ } else {
+ gc = new SkGpuCanvas(context, rt);
+ }
+ SkAutoUnref gcUnref(gc);
+ gc->setDevice(new SkGpuDevice(context, rt))->unref();
+ invokeGM(gm, gc);
// the device is as large as the current rendertarget, so we explicitly
// only readback the amount we expect (in size)
// overwrite our previous allocation
bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
size.fHeight);
- gc.readPixels(bitmap, 0, 0);
+ gc->readPixels(bitmap, 0, 0);
}
return ERROR_NONE;
}
@@ -488,7 +508,8 @@ static ErrorBitfield test_drawing(GM* gm,
if (gRec.fBackend == kRaster_Backend ||
gRec.fBackend == kGPU_Backend) {
// Early exit if we can't generate the image.
- ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap);
+ ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap,
+ false);
if (ERROR_NONE != errors) {
return errors;
}
@@ -506,6 +527,28 @@ static ErrorBitfield test_drawing(GM* gm,
"", *bitmap, &document, NULL);
}
+static ErrorBitfield test_deferred_drawing(GM* gm,
+ const ConfigData& gRec,
+ const SkBitmap& comparisonBitmap,
+ const char diffPath [],
+ GrContext* context,
+ GrRenderTarget* rt) {
+ SkDynamicMemoryWStream document;
+
+ if (gRec.fBackend == kRaster_Backend ||
+ gRec.fBackend == kGPU_Backend) {
+ SkBitmap bitmap;
+ // Early exit if we can't generate the image, but this is
+ // expected in some cases, so don't report a test failure.
+ if (!generate_image(gm, gRec, context, rt, &bitmap, true)) {
+ return ERROR_NONE;
+ }
+ return handle_test_results(gm, gRec, NULL, NULL, diffPath,
+ "-deferred", bitmap, NULL, &comparisonBitmap);
+ }
+ return ERROR_NONE;
+}
+
static ErrorBitfield test_picture_playback(GM* gm,
const ConfigData& gRec,
const SkBitmap& comparisonBitmap,
@@ -545,20 +588,30 @@ static ErrorBitfield test_picture_serialization(GM* gm,
}
static void usage(const char * argv0) {
- SkDebugf("%s [-w writePath] [-r readPath] [-d diffPath]\n", argv0);
- SkDebugf(" [--replay] [--serialize]\n");
+ SkDebugf(
+ "%s [-w writePath] [-r readPath] [-d diffPath] [--noreplay]\n"
+ " [--serialize] [--forceBWtext] [--nopdf] [--nodeferred]\n"
+ " [--match substring] [--notexturecache]"
+#if SK_MESA
+ " [--mesagl]"
+#endif
+ "\n\n", argv0);
SkDebugf(" writePath: directory to write rendered images in.\n");
SkDebugf(
" readPath: directory to read reference images from;\n"
" reports if any pixels mismatch between reference and new images\n");
SkDebugf(" diffPath: directory to write difference images in.\n");
- SkDebugf(" --replay: exercise SkPicture replay.\n");
+ SkDebugf(" --noreplay: do not exercise SkPicture replay.\n");
SkDebugf(
" --serialize: exercise SkPicture serialization & deserialization.\n");
+ SkDebugf(" --forceBWtext: disable text anti-aliasing.\n");
+ SkDebugf(" --nopdf: skip the pdf rendering test pass.\n");
+ SkDebugf(" --nodeferred: skip the deferred rendering test pass.\n");
SkDebugf(" --match foo will only run tests that substring match foo.\n");
#if SK_MESA
SkDebugf(" --mesagl will run using the osmesa sw gl rasterizer.\n");
#endif
+ SkDebugf(" --notexturecache: disable the gpu texture cache.\n");
}
static const ConfigData gRec[] = {
@@ -602,17 +655,21 @@ int main(int argc, char * const argv[]) {
// we don't need to see this during a run
gSkSuppressFontCachePurgeSpew = true;
+ setSystemPreferences();
+
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
const char* diffPath = NULL; // if non-null, where we write our diffs (from compare)
SkTDArray<const char*> fMatches;
-
+
bool doPDF = true;
bool doReplay = true;
bool doSerialize = false;
bool useMesa = false;
-
+ bool doDeferred = true;
+ bool disableTextureCache = false;
+
const char* const commandName = argv[0];
char* const* stop = argv + argc;
for (++argv; argv < stop; ++argv) {
@@ -637,6 +694,8 @@ int main(int argc, char * const argv[]) {
doReplay = false;
} else if (strcmp(*argv, "--nopdf") == 0) {
doPDF = false;
+ } else if (strcmp(*argv, "--nodeferred") == 0) {
+ doDeferred = false;
} else if (strcmp(*argv, "--serialize") == 0) {
doSerialize = true;
} else if (strcmp(*argv, "--match") == 0) {
@@ -649,6 +708,8 @@ int main(int argc, char * const argv[]) {
} else if (strcmp(*argv, "--mesagl") == 0) {
useMesa = true;
#endif
+ } else if (strcmp(*argv, "--notexturecache") == 0) {
+ disableTextureCache = true;
} else {
usage(commandName);
return -1;
@@ -705,6 +766,10 @@ int main(int argc, char * const argv[]) {
int testsFailed = 0;
int testsMissingReferenceImages = 0;
+ if (disableTextureCache) {
+ skiagm::GetGr()->setTextureCacheLimits(0, 0);
+ }
+
iter.reset();
while ((gm = iter.next()) != NULL) {
const char* shortName = gm->shortName();
@@ -734,7 +799,7 @@ int main(int argc, char * const argv[]) {
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
// Skip any tests that we don't even need to try.
uint32_t gmFlags = gm->getFlags();
- if ((kPDF_Backend == gRec[i].fBackend) &&
+ if ((kPDF_Backend == gRec[i].fBackend) &&
(!doPDF || (gmFlags & GM::kSkipPDF_Flag)))
{
continue;
@@ -758,6 +823,14 @@ int main(int argc, char * const argv[]) {
rt.get(), &forwardRenderedBitmap);
}
+ if (doDeferred && !testErrors &&
+ (kGPU_Backend == gRec[i].fBackend ||
+ kRaster_Backend == gRec[i].fBackend)) {
+ testErrors |= test_deferred_drawing(gm, gRec[i],
+ forwardRenderedBitmap,
+ diffPath, gGrContext, rt.get());
+ }
+
if ((ERROR_NONE == testErrors) && doReplay &&
!(gmFlags & GM::kSkipPicture_Flag)) {
testErrors |= test_picture_playback(gm, gRec[i],
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index aac8a96..3eb5633 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -213,6 +213,48 @@ private:
typedef GM INHERITED;
};
+/// Checks quality of large radial gradients, which may display
+/// some banding.
+
+class RadialGradientGM : public GM {
+public:
+ RadialGradientGM() {}
+
+protected:
+ SkString onShortName() { return SkString("radial_gradient"); }
+ virtual SkISize onISize() { return make_isize(1280, 1280); }
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFF000000);
+ }
+ virtual void onDraw(SkCanvas* canvas) {
+ const SkISize dim = this->getISize();
+
+ this->drawBG(canvas);
+
+ SkPaint paint;
+ paint.setDither(true);
+ SkPoint center;
+ center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
+ SkScalar radius = SkIntToScalar(dim.width())/2;
+ const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
+ const SkScalar pos[] = { SkFloatToScalar(0.0),
+ SkFloatToScalar(0.35),
+ SkFloatToScalar(1.0) };
+ SkShader* shader =
+ SkGradientShader::CreateRadial(center, radius, colors,
+ pos, SK_ARRAY_COUNT(pos),
+ SkShader::kClamp_TileMode);
+ paint.setShader(shader)->unref();
+ SkRect r = {
+ 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
+ };
+ canvas->drawRect(r, paint);
+ }
+private:
+ typedef GM INHERITED;
+};
+
+
///////////////////////////////////////////////////////////////////////////////
@@ -225,5 +267,7 @@ static GMRegistry reg2(MyFactory2);
static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
static GMRegistry reg3(MyFactory3);
+static GM* MyFactory4(void*) { return new RadialGradientGM; }
+static GMRegistry reg4(MyFactory4);
}
diff --git a/gm/morphology.cpp b/gm/morphology.cpp
new file mode 100644
index 0000000..bfaa406
--- /dev/null
+++ b/gm/morphology.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkMorphologyImageFilter.h"
+
+#define WIDTH 640
+#define HEIGHT 480
+
+namespace skiagm {
+
+class MorphologyGM : public GM {
+public:
+ MorphologyGM() {
+ this->setBGColor(0xFF000000);
+ fOnce = false;
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("morphology");
+ }
+
+ void make_bitmap() {
+ fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 135, 135);
+ fBitmap.allocPixels();
+ SkDevice device(fBitmap);
+ SkCanvas canvas(&device);
+ canvas.clear(0x0);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ const char* str1 = "ABC";
+ const char* str2 = "XYZ";
+ paint.setColor(0xFFFFFFFF);
+ paint.setTextSize(64);
+ canvas.drawText(str1, strlen(str1), 10, 55, paint);
+ canvas.drawText(str2, strlen(str2), 10, 110, paint);
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(WIDTH, HEIGHT);
+ }
+ virtual void onDraw(SkCanvas* canvas) {
+ if (!fOnce) {
+ make_bitmap();
+ fOnce = true;
+ }
+ struct {
+ int fRadiusX, fRadiusY;
+ bool erode;
+ SkScalar fX, fY;
+ } samples[] = {
+ { 0, 0, false, 0, 0 },
+ { 0, 2, false, 140, 0 },
+ { 2, 0, false, 280, 0 },
+ { 2, 2, false, 420, 0 },
+ { 0, 0, true, 0, 140 },
+ { 0, 2, true, 140, 140 },
+ { 2, 0, true, 280, 140 },
+ { 2, 2, true, 420, 140 },
+ };
+ const char* str = "The quick brown fox jumped over the lazy dog.";
+ SkPaint paint;
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(samples); ++i) {
+ if (samples[i].erode) {
+ paint.setImageFilter(new SkErodeImageFilter(
+ samples[i].fRadiusX,
+ samples[i].fRadiusY))->unref();
+ } else {
+ paint.setImageFilter(new SkDilateImageFilter(
+ samples[i].fRadiusX,
+ samples[i].fRadiusY))->unref();
+ }
+ SkRect bounds = SkRect::MakeXYWH(samples[i].fX,
+ samples[i].fY,
+ 140, 140);
+ canvas->saveLayer(&bounds, &paint);
+ canvas->drawBitmap(fBitmap, samples[i].fX, samples[i].fY);
+ canvas->restore();
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+ SkBitmap fBitmap;
+ bool fOnce;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new MorphologyGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/patheffects.cpp b/gm/patheffects.cpp
new file mode 100644
index 0000000..c606116
--- /dev/null
+++ b/gm/patheffects.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+
+namespace skiagm {
+
+static void compose_pe(SkPaint* paint) {
+ SkPathEffect* pe = paint->getPathEffect();
+ SkPathEffect* corner = new SkCornerPathEffect(25);
+ SkPathEffect* compose;
+ if (pe) {
+ compose = new SkComposePathEffect(pe, corner);
+ corner->unref();
+ } else {
+ compose = corner;
+ }
+ paint->setPathEffect(compose)->unref();
+}
+
+static void hair_pe(SkPaint* paint) {
+ paint->setStrokeWidth(0);
+}
+
+static void hair2_pe(SkPaint* paint) {
+ paint->setStrokeWidth(0);
+ compose_pe(paint);
+}
+
+static void stroke_pe(SkPaint* paint) {
+ paint->setStrokeWidth(12);
+ compose_pe(paint);
+}
+
+static void dash_pe(SkPaint* paint) {
+ SkScalar inter[] = { 20, 10, 10, 10 };
+ paint->setStrokeWidth(12);
+ paint->setPathEffect(new SkDashPathEffect(inter, SK_ARRAY_COUNT(inter),
+ 0))->unref();
+ compose_pe(paint);
+}
+
+static const int gXY[] = {
+4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
+};
+
+static void scale(SkPath* path, SkScalar scale) {
+ SkMatrix m;
+ m.setScale(scale, scale);
+ path->transform(m);
+}
+
+static void one_d_pe(SkPaint* paint) {
+ SkPath path;
+ path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+ for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+ path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+ path.close();
+ path.offset(SkIntToScalar(-6), 0);
+ scale(&path, 1.5);
+
+ paint->setPathEffect(new SkPath1DPathEffect(path, SkIntToScalar(21), 0,
+ SkPath1DPathEffect::kRotate_Style))->unref();
+ compose_pe(paint);
+}
+
+typedef void (*PE_Proc)(SkPaint*);
+static const PE_Proc gPE[] = { hair_pe, hair2_pe, stroke_pe, dash_pe, one_d_pe };
+
+static void fill_pe(SkPaint* paint) {
+ paint->setStyle(SkPaint::kFill_Style);
+ paint->setPathEffect(NULL);
+}
+
+static void discrete_pe(SkPaint* paint) {
+ paint->setPathEffect(new SkDiscretePathEffect(10, 4))->unref();
+}
+
+static SkPathEffect* MakeTileEffect() {
+ SkMatrix m;
+ m.setScale(SkIntToScalar(12), SkIntToScalar(12));
+
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(5));
+
+ return new SkPath2DPathEffect(m, path);
+}
+
+static void tile_pe(SkPaint* paint) {
+ paint->setPathEffect(MakeTileEffect())->unref();
+}
+
+static const PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
+
+class PathEffectGM : public GM {
+public:
+ PathEffectGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("patheffect");
+ }
+
+ SkISize onISize() { return make_isize(800, 600); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ SkPath path;
+ path.moveTo(20, 20);
+ path.lineTo(70, 120);
+ path.lineTo(120, 30);
+ path.lineTo(170, 80);
+ path.lineTo(240, 50);
+
+ size_t i;
+ canvas->save();
+ for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
+ gPE[i](&paint);
+ canvas->drawPath(path, paint);
+ canvas->translate(0, 75);
+ }
+ canvas->restore();
+
+ path.reset();
+ SkRect r = { 0, 0, 250, 120 };
+ path.addOval(r, SkPath::kCW_Direction);
+ r.inset(50, 50);
+ path.addRect(r, SkPath::kCCW_Direction);
+
+ canvas->translate(320, 20);
+ for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
+ gPE2[i](&paint);
+ canvas->drawPath(path, paint);
+ canvas->translate(0, 160);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* PathEffectFactory(void*) { return new PathEffectGM; }
+static GMRegistry regPathEffect(PathEffectFactory);
+
+}
diff --git a/gm/strokefill.cpp b/gm/strokefill.cpp
index a37af80..75fa008 100644
--- a/gm/strokefill.cpp
+++ b/gm/strokefill.cpp
@@ -27,24 +27,35 @@ protected:
return make_isize(640, 480);
}
+ static void show_bold(SkCanvas* canvas, const char text[], SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ size_t len = strlen(text);
+ SkPaint p(paint);
+ canvas->drawText(text, len, x, y, p);
+ p.setFakeBoldText(true);
+ canvas->drawText(text, len, x, y + SkIntToScalar(120), p);
+ }
+
virtual void onDraw(SkCanvas* canvas) {
+ SkScalar x = SkIntToScalar(100);
+ SkScalar y = SkIntToScalar(88);
+
SkPaint paint;
- const char text[] = "Hello"; // "Hello";
- const size_t len = sizeof(text) - 1;
paint.setAntiAlias(true);
paint.setTextSize(SkIntToScalar(100));
-// SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
- SkTypeface* hira = SkTypeface::CreateFromName("Papyrus", SkTypeface::kNormal);
- paint.setTypeface(hira);
- SkScalar x = SkIntToScalar(180);
- SkScalar y = SkIntToScalar(88);
-
- canvas->drawText(text, len, x, y, paint);
- paint.setFakeBoldText(true);
- canvas->drawText(text, len, x, y + SkIntToScalar(100), paint);
- paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(SkIntToScalar(5));
+ SkTypeface* face = SkTypeface::CreateFromName("Papyrus", SkTypeface::kNormal);
+ SkSafeUnref(paint.setTypeface(face));
+ show_bold(canvas, "Hello", x, y, paint);
+
+ face = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
+ SkSafeUnref(paint.setTypeface(face));
+ const char hyphen[] = { 0xE3, 0x83, 0xBC, 0 };
+ show_bold(canvas, hyphen, x + SkIntToScalar(300), y, paint);
+
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+
SkPath path;
path.setFillType(SkPath::kWinding_FillType);
path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction);
diff --git a/gm/system_preferences.h b/gm/system_preferences.h
new file mode 100644
index 0000000..0fcf489
--- /dev/null
+++ b/gm/system_preferences.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Set up system preferences with a known state.
+// This is implemented on a per-platform basis.
+// TODO(epoger): move this out of gm/ into a more common directory, so
+// that it can be used more broadly.
+void setSystemPreferences();
diff --git a/gm/system_preferences_default.cpp b/gm/system_preferences_default.cpp
new file mode 100644
index 0000000..1fc4e6c
--- /dev/null
+++ b/gm/system_preferences_default.cpp
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a default implementation of setSystemPreferences() that does nothing.
+void setSystemPreferences() {
+}
diff --git a/gm/system_preferences_mac.mm b/gm/system_preferences_mac.mm
new file mode 100644
index 0000000..2c772a1
--- /dev/null
+++ b/gm/system_preferences_mac.mm
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+void setSystemPreferences() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ // Set LCD font smoothing level for this application (does not affect other
+ // applications). Based on resetDefaultsToConsistentValues() in
+ // http://trac.webkit.org/browser/trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm
+ static const int NoFontSmoothing = 0;
+ static const int LightFontSmoothing = 1;
+ static const int MediumFontSmoothing = 2;
+ static const int StrongFontSmoothing = 3;
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setInteger:MediumFontSmoothing forKey:@"AppleFontSmoothing"];
+
+ [pool release];
+}
diff --git a/gm/texdata.cpp b/gm/texdata.cpp
index c68a16a..1fdae69 100644
--- a/gm/texdata.cpp
+++ b/gm/texdata.cpp
@@ -75,13 +75,13 @@ protected:
}
GrTextureDesc desc;
- desc.fAALevel = kNone_GrAALevel;
// use RT flag bit because in GL it makes the texture be bottom-up
desc.fFlags = i ? kRenderTarget_GrTextureFlagBit :
kNone_GrTextureFlags;
desc.fConfig = kSkia8888_PM_GrPixelConfig;
desc.fWidth = 2 * S;
desc.fHeight = 2 * S;
+ desc.fSampleCnt = 0;
GrTexture* texture =
ctx->createUncachedTexture(desc, gTextureData, 0);