From 4f1dae40e24d57d647db01443b8bf2410514b8b5 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Tue, 6 Mar 2012 09:06:43 -0500 Subject: Skia Merge (revision 3312) This CL also includes changes made to Android's copy of Skia in their J release branch. Change-Id: Ib2baecf48004951a3ad4a1574cdc38790c814cbc --- gm/Android.mk | 30 +++++- gm/convexpaths.cpp | 202 ++++++++++++++++++++++++++++++++++++++ gm/gammatext.cpp | 192 ++++++++++++++++++++++++++++++++++++ gm/gmmain.cpp | 105 +++++++++++++++++--- gm/gradients.cpp | 44 +++++++++ gm/morphology.cpp | 98 ++++++++++++++++++ gm/patheffects.cpp | 160 ++++++++++++++++++++++++++++++ gm/strokefill.cpp | 35 ++++--- gm/system_preferences.h | 12 +++ gm/system_preferences_default.cpp | 10 ++ gm/system_preferences_mac.mm | 24 +++++ gm/texdata.cpp | 2 +- 12 files changed, 883 insertions(+), 31 deletions(-) create mode 100644 gm/convexpaths.cpp create mode 100644 gm/gammatext.cpp create mode 100644 gm/morphology.cpp create mode 100644 gm/patheffects.cpp create mode 100644 gm/system_preferences.h create mode 100644 gm/system_preferences_default.cpp create mode 100644 gm/system_preferences_mac.mm (limited to 'gm') 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 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 +#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 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 + +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); -- cgit v1.1