diff options
author | Derek Sollenberger <djsollen@google.com> | 2012-01-18 08:56:56 -0500 |
---|---|---|
committer | Derek Sollenberger <derek@android.com> | 2012-02-06 14:14:40 -0500 |
commit | 1cab2921ab279367f8206cdadc9259d12e603548 (patch) | |
tree | 2852f9dc2481f639122e18fc7831ae6ca43d6d5a /gm | |
parent | d7176fd5571bc9878d3cdac8696eaa35ec170d9d (diff) | |
download | external_skia-1cab2921ab279367f8206cdadc9259d12e603548.zip external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.gz external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.bz2 |
Skia merge (revision 3022)
This CL has companion changes to account for API updates in...
(1) frameworks/base
(2) external/webkit
Change-Id: Ibb989e76e8bd24313849f9631dbef42cdef9eb7d
Diffstat (limited to 'gm')
49 files changed, 5171 insertions, 353 deletions
diff --git a/gm/Android.mk b/gm/Android.mk index acfb4a5..14f4d62 100644 --- a/gm/Android.mk +++ b/gm/Android.mk @@ -3,11 +3,21 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ + aarectmodes.cpp \ bitmapfilters.cpp \ + bitmapscroll.cpp \ blurs.cpp \ complexclip.cpp \ + complexclip2.cpp \ + emptypath.cpp \ filltypes.cpp \ + filltypespersp.cpp \ + gm.cpp \ + gmmain.cpp \ gradients.cpp \ + hairmodes.cpp \ + lcdtext.cpp \ + ninepatchstretch.cpp \ nocolorbleed.cpp \ pathfill.cpp \ points.cpp \ @@ -16,13 +26,11 @@ LOCAL_SRC_FILES := \ shadows.cpp \ shapes.cpp \ strokerects.cpp \ + strokes.cpp \ + texdata.cpp \ tilemodes.cpp \ - xfermodes.cpp \ - gmmain.cpp - -# additional optional class for this tool -LOCAL_SRC_FILES += \ - ../src/utils/SkEGLContext_none.cpp + tinybitmap.cpp \ + xfermodes.cpp LOCAL_STATIC_LIBRARIES := libskiagpu LOCAL_SHARED_LIBRARIES := \ @@ -35,11 +43,11 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES := \ external/skia/include/config \ external/skia/include/core \ + external/skia/include/effects \ + external/skia/include/gpu \ external/skia/include/images \ external/skia/include/utils \ - external/skia/include/effects \ - external/skia/gpu/include \ - external/skia/include/gpu + external/skia/gm #LOCAL_CFLAGS := diff --git a/gm/aaclip.cpp b/gm/aaclip.cpp new file mode 100644 index 0000000..2976560 --- /dev/null +++ b/gm/aaclip.cpp @@ -0,0 +1,115 @@ +/* + * 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" + +namespace skiagm { + +/** Draw a 2px border around the target, then red behind the target; + set the clip to match the target, then draw >> the target in blue. +*/ + +void draw (SkCanvas* canvas, SkRect& target, int x, int y) { + SkPaint borderPaint; + borderPaint.setColor(SkColorSetRGB(0x0, 0xDD, 0x0)); + borderPaint.setAntiAlias(true); + SkPaint backgroundPaint; + backgroundPaint.setColor(SkColorSetRGB(0xDD, 0x0, 0x0)); + backgroundPaint.setAntiAlias(true); + SkPaint foregroundPaint; + foregroundPaint.setColor(SkColorSetRGB(0x0, 0x0, 0xDD)); + foregroundPaint.setAntiAlias(true); + + canvas->save(); + canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); + target.inset(SkIntToScalar(-2), SkIntToScalar(-2)); + canvas->drawRect(target, borderPaint); + target.inset(SkIntToScalar(2), SkIntToScalar(2)); + canvas->drawRect(target, backgroundPaint); + canvas->clipRect(target, SkRegion::kIntersect_Op, true); + target.inset(SkIntToScalar(-4), SkIntToScalar(-4)); + canvas->drawRect(target, foregroundPaint); + canvas->restore(); +} + +void draw_square (SkCanvas* canvas, int x, int y) { + SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 10 * SK_Scalar1)); + draw(canvas, target, x, y); +} + +void draw_column (SkCanvas* canvas, int x, int y) { + SkRect target (SkRect::MakeWH(1 * SK_Scalar1, 10 * SK_Scalar1)); + draw(canvas, target, x, y); +} + +void draw_bar (SkCanvas* canvas, int x, int y) { + SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 1 * SK_Scalar1)); + draw(canvas, target, x, y); +} + +void draw_rect_tests (SkCanvas* canvas) { + draw_square(canvas, 10, 10); + draw_column(canvas, 30, 10); + draw_bar(canvas, 10, 30); +} + +/** + 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. +*/ + +class AAClipGM : public GM { +public: + AAClipGM() { + + } + +protected: + virtual SkString onShortName() { + return SkString("aaclip"); + } + + virtual SkISize onISize() { + return make_isize(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) { + // Initial pixel-boundary-aligned draw + draw_rect_tests(canvas); + + // Repeat 4x with .2, .4, .6, .8 px offsets + canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5); + canvas->translate(SkIntToScalar(50), 0); + draw_rect_tests(canvas); + + canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5); + canvas->translate(SkIntToScalar(50), 0); + draw_rect_tests(canvas); + + canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5); + canvas->translate(SkIntToScalar(50), 0); + draw_rect_tests(canvas); + + canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5); + canvas->translate(SkIntToScalar(50), 0); + draw_rect_tests(canvas); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new AAClipGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/aarectmodes.cpp b/gm/aarectmodes.cpp new file mode 100644 index 0000000..f518cae --- /dev/null +++ b/gm/aarectmodes.cpp @@ -0,0 +1,203 @@ +/* + * 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 "SkColorPriv.h" +#include "SkShader.h" + +static void test4(SkCanvas* canvas) { + SkPaint paint; + paint.setAntiAlias(true); + SkPoint pts[] = { + {10, 160}, {610, 160}, + {610, 160}, {10, 160}, + + {610, 160}, {610, 160}, + {610, 199}, {610, 199}, + + {10, 198}, {610, 198}, + {610, 199}, {10, 199}, + + {10, 160}, {10, 160}, + {10, 199}, {10, 199} + }; + char verbs[] = { + 0, 1, 1, 1, 4, + 0, 1, 1, 1, 4, + 0, 1, 1, 1, 4, + 0, 1, 1, 1, 4 + }; + SkPath path; + SkPoint* ptPtr = pts; + for (size_t i = 0; i < sizeof(verbs); ++i) { + switch ((SkPath::Verb) verbs[i]) { + case SkPath::kMove_Verb: + path.moveTo(ptPtr->fX, ptPtr->fY); + ++ptPtr; + break; + case SkPath::kLine_Verb: + path.lineTo(ptPtr->fX, ptPtr->fY); + ++ptPtr; + break; + case SkPath::kClose_Verb: + path.close(); + break; + default: + SkASSERT(false); + break; + } + } + SkRect clip = {0, 130, 772, 531}; + canvas->clipRect(clip); + canvas->drawPath(path, paint); +} + +static SkCanvas* create_canvas(int w, int h) { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, w, h); + bm.allocPixels(); + bm.eraseColor(0); + return new SkCanvas(bm); +} + +static const SkBitmap& extract_bitmap(SkCanvas* canvas) { + return canvas->getDevice()->accessBitmap(false); +} + +static 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" }, +}; + +const int gWidth = 64; +const int gHeight = 64; +const SkScalar W = SkIntToScalar(gWidth); +const SkScalar H = SkIntToScalar(gHeight); + +static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode, + SkAlpha a0, SkAlpha a1) { + + SkPaint paint; + paint.setAntiAlias(true); + + SkRect r = SkRect::MakeWH(W, H); + r.inset(W/10, H/10); + + paint.setColor(SK_ColorBLUE); + paint.setAlpha(a0); + canvas->drawOval(r, paint); + + paint.setColor(SK_ColorRED); + paint.setAlpha(a1); + paint.setXfermode(mode); + + SkScalar offset = SK_Scalar1 / 3; + SkRect rect = SkRect::MakeXYWH(W / 4 + offset, + H / 4 + offset, + W / 2, H / 2); + canvas->drawRect(rect, paint); + + return H; +} + +static SkShader* make_bg_shader() { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); + bm.allocPixels(); + *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF; + *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, + 0xCC, 0xCC); + + SkShader* s = SkShader::CreateBitmapShader(bm, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + + SkMatrix m; + m.setScale(SkIntToScalar(6), SkIntToScalar(6)); + s->setLocalMatrix(m); + return s; +} + +namespace skiagm { + + class AARectModesGM : public GM { + SkPaint fBGPaint; + public: + AARectModesGM () { + fBGPaint.setShader(make_bg_shader())->unref(); + } + + protected: + + virtual SkString onShortName() { + return SkString("aarectmodes"); + } + + virtual SkISize onISize() { return make_isize(640, 480); } + + virtual void onDraw(SkCanvas* canvas) { +// test4(canvas); + const SkRect bounds = SkRect::MakeWH(W, H); + static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 }; + + canvas->translate(SkIntToScalar(4), SkIntToScalar(4)); + + for (int alpha = 0; alpha < 4; ++alpha) { + canvas->save(); + canvas->save(); + for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) { + if (6 == i) { + canvas->restore(); + canvas->translate(W * 5, 0); + canvas->save(); + } + SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); + + canvas->drawRect(bounds, fBGPaint); + canvas->saveLayer(&bounds, NULL); + SkScalar dy = drawCell(canvas, mode, + gAlphaValue[alpha & 1], + gAlphaValue[alpha & 2]); + canvas->restore(); + + canvas->translate(0, dy * 5 / 4); + SkSafeUnref(mode); + } + canvas->restore(); + canvas->restore(); + canvas->translate(W * 5 / 4, 0); + } + } + + // disable pdf for now, since it crashes on mac + virtual uint32_t onGetFlags() const { return kSkipPDF_Flag; } + + private: + typedef GM INHERITED; + }; + +////////////////////////////////////////////////////////////////////////////// + + static GM* MyFactory(void*) { return new AARectModesGM; } + static GMRegistry reg(MyFactory); + +} + diff --git a/gm/arithmode.cpp b/gm/arithmode.cpp new file mode 100644 index 0000000..ea015c6 --- /dev/null +++ b/gm/arithmode.cpp @@ -0,0 +1,140 @@ +/* + * 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 "SkColorPriv.h" +#include "SkShader.h" + +#include "SkArithmeticMode.h" +#include "SkGradientShader.h" +#define WW 100 +#define HH 32 + +static SkBitmap make_bm() { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, WW, HH); + bm.allocPixels(); + bm.eraseColor(0); + return bm; +} + +static SkBitmap make_src() { + SkBitmap bm = make_bm(); + SkCanvas canvas(bm); + SkPaint paint; + SkPoint pts[] = { {0, 0}, {SkIntToScalar(WW), SkIntToScalar(HH)} }; + SkColor colors[] = { + SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN, + SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE + }; + SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + canvas.drawPaint(paint); + return bm; +} + +static SkBitmap make_dst() { + SkBitmap bm = make_bm(); + SkCanvas canvas(bm); + SkPaint paint; + SkPoint pts[] = { {0, SkIntToScalar(HH)}, {SkIntToScalar(WW), 0} }; + SkColor colors[] = { + SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, SK_ColorGRAY + }; + SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + canvas.drawPaint(paint); + return bm; +} + +static SkBitmap make_arith(const SkBitmap& src, const SkBitmap& dst, + const SkScalar k[]) { + SkBitmap bm = make_bm(); + SkCanvas canvas(bm); + SkPaint paint; + canvas.drawBitmap(dst, 0, 0, NULL); + SkXfermode* xfer = SkArithmeticMode::Create(k[0], k[1], k[2], k[3]); + paint.setXfermode(xfer)->unref(); + canvas.drawBitmap(src, 0, 0, &paint); + return bm; +} + +static void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) { + SkPaint paint; + paint.setTextSize(SkIntToScalar(24)); + paint.setAntiAlias(true); + for (int i = 0; i < 4; ++i) { + SkString str; + str.appendScalar(k[i]); + SkScalar width = paint.measureText(str.c_str(), str.size()); + canvas->drawText(str.c_str(), str.size(), x, y + paint.getTextSize(), paint); + x += width + SkIntToScalar(10); + } +} + +class ArithmodeGM : public skiagm::GM { +public: + ArithmodeGM () {} + +protected: + + virtual SkString onShortName() { + return SkString("arithmode"); + } + + virtual SkISize onISize() { return SkISize::Make(640, 480); } + + virtual void onDraw(SkCanvas* canvas) { + SkBitmap src = make_src(); + SkBitmap dst = make_dst(); + + const SkScalar one = SK_Scalar1; + static const SkScalar K[] = { + 0, 0, 0, 0, + 0, 0, 0, one, + 0, one, 0, 0, + 0, 0, one, 0, + 0, one, one, 0, + 0, one, -one, 0, + 0, one/2, one/2, 0, + 0, one/2, one/2, one/4, + 0, one/2, one/2, -one/4, + one/4, one/2, one/2, 0, + -one/4, one/2, one/2, 0, + }; + + const SkScalar* k = K; + const SkScalar* stop = k + SK_ARRAY_COUNT(K); + SkScalar y = 0; + SkScalar x = 0; + SkScalar gap = SkIntToScalar(src.width() + 20); + while (k < stop) { + SkScalar x = 0; + SkBitmap res = make_arith(src, dst, k); + canvas->drawBitmap(src, x, y, NULL); + x += gap; + canvas->drawBitmap(dst, x, y, NULL); + x += gap; + canvas->drawBitmap(res, x, y, NULL); + x += gap; + show_k_text(canvas, x, y, k); + k += 4; + y += SkIntToScalar(src.height() + 12); + } + } + +private: + typedef GM INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static skiagm::GM* MyFactory(void*) { return new ArithmodeGM; } +static skiagm::GMRegistry reg(MyFactory); diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp new file mode 100644 index 0000000..249ec43 --- /dev/null +++ b/gm/bitmapcopy.cpp @@ -0,0 +1,121 @@ + +/* + * 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" + +namespace skiagm { + +static const char* gConfigNames[] = { + "unknown config", + "A1", + "A8", + "Index8", + "565", + "4444", + "8888" +}; + +SkBitmap::Config gConfigs[] = { + SkBitmap::kRGB_565_Config, + SkBitmap::kARGB_4444_Config, + SkBitmap::kARGB_8888_Config, +}; + +#define NUM_CONFIGS (sizeof(gConfigs) / sizeof(SkBitmap::Config)) + +static void draw_checks(SkCanvas* canvas, int width, int height) { + SkPaint paint; + paint.setColor(SK_ColorRED); + canvas->drawRectCoords(0, 0, width / 2, height / 2, paint); + paint.setColor(SK_ColorGREEN); + canvas->drawRectCoords(width / 2, 0, width, height / 2, paint); + paint.setColor(SK_ColorBLUE); + canvas->drawRectCoords(0, height / 2, width / 2, height, paint); + paint.setColor(SK_ColorYELLOW); + canvas->drawRectCoords(width / 2, height / 2, width, height, paint); +} + +class BitmapCopyGM : public GM { +public: + SkBitmap fDst[NUM_CONFIGS]; + + BitmapCopyGM() { + this->setBGColor(0xFFDDDDDD); + } + +protected: + virtual SkString onShortName() { + return SkString("bitmapcopy"); + } + + virtual SkISize onISize() { + return make_isize(540, 330); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + SkScalar horizMargin(SkIntToScalar(10)); + SkScalar vertMargin(SkIntToScalar(10)); + + draw_checks(canvas, 40, 40); + SkBitmap src = canvas->getDevice()->accessBitmap(false); + + for (unsigned i = 0; i < NUM_CONFIGS; ++i) { + if (!src.deepCopyTo(&fDst[i], gConfigs[i])) { + src.copyTo(&fDst[i], gConfigs[i]); + } + } + + canvas->clear(0xFFDDDDDD); + paint.setAntiAlias(true); + SkScalar width = SkIntToScalar(40); + SkScalar height = SkIntToScalar(40); + if (paint.getFontSpacing() > height) { + height = paint.getFontSpacing(); + } + for (unsigned i = 0; i < NUM_CONFIGS; i++) { + const char* name = gConfigNames[src.config()]; + SkScalar textWidth = paint.measureText(name, strlen(name)); + if (textWidth > width) { + width = textWidth; + } + } + SkScalar horizOffset = width + horizMargin; + SkScalar vertOffset = height + vertMargin; + canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); + + for (unsigned i = 0; i < NUM_CONFIGS; i++) { + canvas->save(); + // Draw destination config name + const char* name = gConfigNames[fDst[i].config()]; + SkScalar textWidth = paint.measureText(name, strlen(name)); + SkScalar x = (width - textWidth) / SkScalar(2); + SkScalar y = paint.getFontSpacing() / SkScalar(2); + canvas->drawText(name, strlen(name), x, y, paint); + + // Draw destination bitmap + canvas->translate(0, vertOffset); + x = (width - 40) / SkScalar(2); + canvas->drawBitmap(fDst[i], x, 0, &paint); + canvas->restore(); + + canvas->translate(horizOffset, 0); + } + } + + virtual uint32_t onGetFlags() const { return kSkipPicture_Flag; } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new BitmapCopyGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp index 3903913..cf98dcd 100644 --- a/gm/bitmapfilters.cpp +++ b/gm/bitmapfilters.cpp @@ -1,3 +1,10 @@ + +/* + * 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" namespace skiagm { @@ -79,6 +86,7 @@ public: fBM8.copyTo(&fBM4444, SkBitmap::kARGB_4444_Config); fBM8.copyTo(&fBM16, SkBitmap::kRGB_565_Config); fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config); + this->setBGColor(0xFFDDDDDD); } protected: @@ -91,7 +99,6 @@ protected: } virtual void onDraw(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(10); diff --git a/gm/bitmapscroll.cpp b/gm/bitmapscroll.cpp new file mode 100644 index 0000000..70d1052 --- /dev/null +++ b/gm/bitmapscroll.cpp @@ -0,0 +1,147 @@ + +/* + * 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" + +namespace skiagm { + +/** Create a bitmap image suitable for testing SkBitmap::scrollRect(). + * + * @param quarterWidth bitmap will be 4x this many pixels wide + * @param quarterHeight bitmap will be 4x this many pixels tall + * @param bitmap the bitmap data is written into this object + */ +static void make_bitmap(int quarterWidth, int quarterHeight, SkBitmap *bitmap) { + SkPaint pRed, pWhite, pGreen, pBlue, pLine, pAlphaGray; + pRed.setColor(0xFFFF9999); + pWhite.setColor(0xFFFFFFFF); + pGreen.setColor(0xFF99FF99); + pBlue.setColor(0xFF9999FF); + pLine.setColor(0xFF000000); + pLine.setStyle(SkPaint::kStroke_Style); + pAlphaGray.setColor(0x66888888); + + // Prepare bitmap, and a canvas that draws into it. + bitmap->reset(); + bitmap->setConfig(SkBitmap::kARGB_8888_Config, + quarterWidth*4, quarterHeight*4); + bitmap->allocPixels(); + SkCanvas canvas(*bitmap); + + SkScalar w = SkIntToScalar(quarterWidth); + SkScalar h = SkIntToScalar(quarterHeight); + canvas.drawRectCoords( 0, 0, w*2, h*2, pRed); + canvas.drawRectCoords(w*2, 0, w*4, h*2, pGreen); + canvas.drawRectCoords( 0, h*2, w*2, h*4, pBlue); + canvas.drawRectCoords(w*2, h*2, w*4, h*4, pWhite); + canvas.drawRectCoords(w, h, w*3, h*3, pAlphaGray); + canvas.drawLine(w*2, 0, w*2, h*4, pLine); + canvas.drawLine( 0, h*2, w*4, h*2, pLine); + canvas.drawRectCoords(w, h, w*3, h*3, pLine); +} + +class BitmapScrollGM : public GM { +public: + BitmapScrollGM() { + // Create the original bitmap. + make_bitmap(quarterWidth, quarterHeight, &origBitmap); + this->setBGColor(0xFFDDDDDD); + } + +protected: + virtual SkString onShortName() { + return SkString("bitmapscroll"); + } + + virtual SkISize onISize() { + return make_isize(800, 600); + } + + virtual void onDraw(SkCanvas* canvas) { + SkIRect scrollCenterRegion = SkIRect::MakeXYWH( + quarterWidth, quarterHeight, quarterWidth*2+1, quarterHeight*2+1); + int x = quarterWidth; + int y = quarterHeight; + int xSpacing = quarterWidth * 20; + int ySpacing = quarterHeight * 16; + + // Draw left-hand text labels. + drawLabel(canvas, "scroll entire bitmap", + x, y, x, y + ySpacing); + drawLabel(canvas, "scroll part of bitmap", + x, y + ySpacing, x, y + ySpacing*2); + x += 30; + + // Draw various permutations of scrolled bitmaps, scrolling a bit + // further each time. + draw9(canvas, x, y, NULL, quarterWidth*1/2, quarterHeight*1/2); + draw9(canvas, x, y+ySpacing, &scrollCenterRegion, + quarterWidth*1/2, quarterHeight*1/2); + x += xSpacing; + draw9(canvas, x, y, NULL, quarterWidth*3/2, quarterHeight*3/2); + draw9(canvas, x, y+ySpacing, &scrollCenterRegion, + quarterWidth*3/2, quarterHeight*3/2); + x += xSpacing; + draw9(canvas, x, y, NULL, quarterWidth*5/2, quarterHeight*5/2); + draw9(canvas, x, y+ySpacing, &scrollCenterRegion, + quarterWidth*5/2, quarterHeight*5/2); + x += xSpacing; + draw9(canvas, x, y, NULL, quarterWidth*9/2, quarterHeight*9/2); + draw9(canvas, x, y+ySpacing, &scrollCenterRegion, + quarterWidth*9/2, quarterHeight*9/2); + } + + void drawLabel(SkCanvas* canvas, const char *text, int startX, int startY, + int endX, int endY) { + SkPaint paint; + paint.setColor(0xFF000000); + SkPath path; + path.moveTo(SkIntToScalar(startX), SkIntToScalar(startY)); + path.lineTo(SkIntToScalar(endX), SkIntToScalar(endY)); + canvas->drawTextOnPath(text, strlen(text), path, NULL, paint); + } + + /** Stamp out 9 copies of origBitmap, scrolled in each direction (and + * not scrolled at all). + */ + void draw9(SkCanvas* canvas, int x, int y, SkIRect* subset, + int scrollX, int scrollY) { + for (int yMult=-1; yMult<=1; yMult++) { + for (int xMult=-1; xMult<=1; xMult++) { + // Figure out the (x,y) to draw this copy at + SkScalar bitmapX = SkIntToScalar( + x + quarterWidth * 5 * (xMult+1)); + SkScalar bitmapY = SkIntToScalar( + y + quarterHeight * 5 * (yMult+1)); + + // Scroll a new copy of the bitmap, and then draw it. + // scrollRect() should always return true, even if it's a no-op + SkBitmap scrolledBitmap; + bool copyToReturnValue = origBitmap.copyTo( + &scrolledBitmap, origBitmap.config()); + SkASSERT(copyToReturnValue); + bool scrollRectReturnValue = scrolledBitmap.scrollRect( + subset, scrollX * xMult, scrollY * yMult); + SkASSERT(scrollRectReturnValue); + canvas->drawBitmap(scrolledBitmap, bitmapX, bitmapY); + } + } + } + +private: + typedef GM INHERITED; + static const int quarterWidth = 10; + static const int quarterHeight = 14; + SkBitmap origBitmap; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new BitmapScrollGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/blurs.cpp b/gm/blurs.cpp index c934178..69504f7 100644 --- a/gm/blurs.cpp +++ b/gm/blurs.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkBlurMaskFilter.h" @@ -5,7 +12,9 @@ namespace skiagm { class BlursGM : public GM { public: - BlursGM() {} + BlursGM() { + this->setBGColor(0xFFDDDDDD); + } protected: virtual SkString onShortName() { @@ -16,13 +25,7 @@ protected: return make_isize(700, 500); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } - virtual void onDraw(SkCanvas* canvas) { - drawBG(canvas); - SkBlurMaskFilter::BlurStyle NONE = SkBlurMaskFilter::BlurStyle(-999); static const struct { SkBlurMaskFilter::BlurStyle fStyle; diff --git a/gm/colormatrix.cpp b/gm/colormatrix.cpp new file mode 100644 index 0000000..0a4acfd --- /dev/null +++ b/gm/colormatrix.cpp @@ -0,0 +1,118 @@ +/* + * 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 "SkColorMatrixFilter.h" + +#define WIDTH 500 +#define HEIGHT 500 + +namespace skiagm { + +class ColorMatrixGM : public GM { +public: + ColorMatrixGM() { + this->setBGColor(0xFF808080); + fBitmap = createBitmap(64, 64); + } + +protected: + virtual SkString onShortName() { + return SkString("colormatrix"); + } + + virtual SkISize onISize() { + return make_isize(WIDTH, HEIGHT); + } + + SkBitmap createBitmap(int width, int height) { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, width, height); + bm.allocPixels(); + SkCanvas canvas(bm); + canvas.clear(0x0); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + SkPaint paint; + paint.setColor(SkColorSetARGB(255, x * 255 / width, y * 255 / height, 0)); + canvas.drawRect(SkRect::MakeXYWH(x, y, 1, 1), paint); + } + } + return bm; + } + virtual void onDraw(SkCanvas* canvas) { + + SkPaint paint; + SkColorMatrix matrix; + SkColorMatrixFilter* filter = new SkColorMatrixFilter(); + paint.setColorFilter(filter)->unref(); + + matrix.setIdentity(); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 0, 0, &paint); + + matrix.setRotate(SkColorMatrix::kR_Axis, 90); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 80, 0, &paint); + + matrix.setRotate(SkColorMatrix::kG_Axis, 90); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 160, 0, &paint); + + matrix.setRotate(SkColorMatrix::kB_Axis, 90); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 240, 0, &paint); + + matrix.setSaturation(SkFloatToScalar(0.0f)); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 0, 80, &paint); + + matrix.setSaturation(SkFloatToScalar(0.5f)); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 80, 80, &paint); + + matrix.setSaturation(SkFloatToScalar(1.0f)); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 160, 80, &paint); + + matrix.setSaturation(SkFloatToScalar(2.0f)); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 240, 80, &paint); + + matrix.setRGB2YUV(); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 0, 160, &paint); + + matrix.setYUV2RGB(); + filter->setMatrix(matrix); + canvas->drawBitmap(fBitmap, 80, 160, &paint); + + SkScalar s1 = SK_Scalar1; + SkScalar s255 = SkIntToScalar(255); + // Move red into alpha, set color to white + SkScalar data[20] = { + 0, 0, 0, 0, s255, + 0, 0, 0, 0, s255, + 0, 0, 0, 0, s255, + s1, 0, 0, 0, 0, + }; + + filter->setArray(data); + canvas->drawBitmap(fBitmap, 160, 160, &paint); + } + +private: + SkBitmap fBitmap; + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new ColorMatrixGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/complexclip.cpp b/gm/complexclip.cpp index 867d230..30bb50b 100644 --- a/gm/complexclip.cpp +++ b/gm/complexclip.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkParsePath.h" @@ -6,22 +13,27 @@ namespace skiagm { +static const SkColor gPathColor = SK_ColorBLACK; +static const SkColor gClipAColor = SK_ColorBLUE; +static const SkColor gClipBColor = SK_ColorRED; + class ComplexClipGM : public GM { + bool fDoAAClip; public: - ComplexClipGM() { + ComplexClipGM(bool aaclip) : fDoAAClip(aaclip) { + this->setBGColor(0xFFDDDDDD); +// this->setBGColor(SkColorSetRGB(0xB0,0xDD,0xB0)); } protected: SkString onShortName() { - return SkString("complexclip"); + SkString str; + str.printf("complexclip_%s", fDoAAClip ? "aa" : "bw"); + return str; } - SkISize onISize() { return make_isize(550, 1000); } - - void drawBG(SkCanvas* canvas) { - canvas->drawColor(SkColorSetRGB(0xA0,0xDD,0xA0)); - } + SkISize onISize() { return make_isize(970, 780); } virtual void onDraw(SkCanvas* canvas) { SkPath path; @@ -40,10 +52,9 @@ protected: path.lineTo(SkIntToScalar(50), SkIntToScalar(150)); path.close(); path.setFillType(SkPath::kEvenOdd_FillType); - SkColor pathColor = SK_ColorBLACK; SkPaint pathPaint; pathPaint.setAntiAlias(true); - pathPaint.setColor(pathColor); + pathPaint.setColor(gPathColor); SkPath clipA; clipA.moveTo(SkIntToScalar(10), SkIntToScalar(20)); @@ -52,7 +63,6 @@ protected: clipA.lineTo(SkIntToScalar(165), SkIntToScalar(177)); clipA.lineTo(SkIntToScalar(-5), SkIntToScalar(180)); clipA.close(); - SkColor colorA = SK_ColorCYAN; SkPath clipB; clipB.moveTo(SkIntToScalar(40), SkIntToScalar(10)); @@ -61,21 +71,10 @@ protected: clipB.lineTo(SkIntToScalar(40), SkIntToScalar(185)); clipB.lineTo(SkIntToScalar(155), SkIntToScalar(100)); clipB.close(); - SkColor colorB = SK_ColorRED; - drawBG(canvas); SkPaint paint; paint.setAntiAlias(true); - - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(0); - - canvas->translate(SkIntToScalar(10),SkIntToScalar(10)); - canvas->drawPath(path, pathPaint); - paint.setColor(colorA); - canvas->drawPath(clipA, paint); - paint.setColor(colorB); - canvas->drawPath(clipB, paint); + paint.setTextSize(SkIntToScalar(20)); static const struct { SkRegion::Op fOp; @@ -88,65 +87,77 @@ protected: {SkRegion::kReverseDifference_Op, "RDiff "} }; - canvas->translate(0, SkIntToScalar(40)); + canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4); - canvas->save(); - for (int invA = 0; invA < 2; ++invA) { + for (int invBits = 0; invBits < 4; ++invBits) { + canvas->save(); for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { - int idx = invA * SK_ARRAY_COUNT(gOps) + op; - if (!(idx % 3)) { - canvas->restore(); - canvas->translate(0, SkIntToScalar(250)); - canvas->save(); - } + this->drawHairlines(canvas, path, clipA, clipB); + + bool doInvA = SkToBool(invBits & 1); + bool doInvB = SkToBool(invBits & 2); canvas->save(); // set clip - clipA.setFillType(invA ? SkPath::kInverseEvenOdd_FillType : - SkPath::kEvenOdd_FillType); - canvas->clipPath(clipA); - canvas->clipPath(clipB, gOps[op].fOp); + clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType : + SkPath::kEvenOdd_FillType); + clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType : + SkPath::kEvenOdd_FillType); + canvas->clipPath(clipA, SkRegion::kIntersect_Op, fDoAAClip); + canvas->clipPath(clipB, gOps[op].fOp, fDoAAClip); // draw path clipped canvas->drawPath(path, pathPaint); canvas->restore(); - // draw path in hairline - paint.setColor(pathColor); - canvas->drawPath(path, paint); - // draw clips in hair line - paint.setColor(colorA); - canvas->drawPath(clipA, paint); - paint.setColor(colorB); - canvas->drawPath(clipB, paint); - - paint.setTextSize(SkIntToScalar(20)); - - SkScalar txtX = SkIntToScalar(55); - paint.setColor(colorA); - const char* aTxt = invA ? "InverseA " : "A "; + SkScalar txtX = SkIntToScalar(45); + paint.setColor(gClipAColor); + const char* aTxt = doInvA ? "InvA " : "A "; canvas->drawText(aTxt, strlen(aTxt), txtX, SkIntToScalar(220), paint); txtX += paint.measureText(aTxt, strlen(aTxt)); paint.setColor(SK_ColorBLACK); canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), txtX, SkIntToScalar(220), paint); txtX += paint.measureText(gOps[op].fName, strlen(gOps[op].fName)); - paint.setColor(colorB); - canvas->drawText("B", 1, txtX, SkIntToScalar(220), paint); + paint.setColor(gClipBColor); + const char* bTxt = doInvB ? "InvB " : "B "; + canvas->drawText(bTxt, strlen(bTxt), txtX, SkIntToScalar(220), paint); canvas->translate(SkIntToScalar(250),0); } + canvas->restore(); + canvas->translate(0, SkIntToScalar(250)); } - canvas->restore(); } private: + void drawHairlines(SkCanvas* canvas, const SkPath& path, + const SkPath& clipA, const SkPath& clipB) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + const SkAlpha fade = 0x33; + + // draw path in hairline + paint.setColor(gPathColor); paint.setAlpha(fade); + canvas->drawPath(path, paint); + + // draw clips in hair line + paint.setColor(gClipAColor); paint.setAlpha(fade); + canvas->drawPath(clipA, paint); + paint.setColor(gClipBColor); paint.setAlpha(fade); + canvas->drawPath(clipB, paint); + } + typedef GM INHERITED; }; ////////////////////////////////////////////////////////////////////////////// -static GM* MyFactory(void*) { return new ComplexClipGM; } -static GMRegistry reg(MyFactory); +static GM* gFact0(void*) { return new ComplexClipGM(false); } +static GM* gFact1(void*) { return new ComplexClipGM(true); } + +static GMRegistry gReg0(gFact0); +static GMRegistry gReg1(gFact1); } diff --git a/gm/complexclip2.cpp b/gm/complexclip2.cpp new file mode 100644 index 0000000..d6b653e --- /dev/null +++ b/gm/complexclip2.cpp @@ -0,0 +1,135 @@ +/* + * 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 "SkRandom.h" + +namespace skiagm { + +class ComplexClip2GM : public GM { +public: + ComplexClip2GM() { + this->setBGColor(SkColorSetRGB(0xDD,0xA0,0xDD)); + + SkScalar xA = 0 * SK_Scalar1; + SkScalar xB = 10 * SK_Scalar1; + SkScalar xC = 20 * SK_Scalar1; + SkScalar xD = 30 * SK_Scalar1; + SkScalar xE = 40 * SK_Scalar1; + SkScalar xF = 50 * SK_Scalar1; + + SkScalar yA = 0 * SK_Scalar1; + SkScalar yB = 10 * SK_Scalar1; + SkScalar yC = 20 * SK_Scalar1; + SkScalar yD = 30 * SK_Scalar1; + SkScalar yE = 40 * SK_Scalar1; + SkScalar yF = 50 * SK_Scalar1; + + fWidth = xF - xA; + fHeight = yF - yA; + + fRects[0].set(xB, yB, xE, yE); + fRectColors[0] = SK_ColorRED; + + fRects[1].set(xA, yA, xD, yD); + fRectColors[1] = SK_ColorGREEN; + + fRects[2].set(xC, yA, xF, yD); + fRectColors[2] = SK_ColorBLUE; + + fRects[3].set(xA, yC, xD, yF); + fRectColors[3] = SK_ColorYELLOW; + + fRects[4].set(xC, yC, xF, yF); + fRectColors[4] = SK_ColorCYAN; + + fTotalWidth = kCols * fWidth + SK_Scalar1 * (kCols + 1) * kPadX; + fTotalHeight = kRows * fHeight + SK_Scalar1 * (kRows + 1) * kPadY; + + SkRegion::Op ops[] = { + SkRegion::kDifference_Op, + SkRegion::kIntersect_Op, + SkRegion::kUnion_Op, + SkRegion::kXOR_Op, + SkRegion::kReverseDifference_Op, + SkRegion::kReplace_Op, + }; + + SkRandom r; + for (int i = 0; i < kRows; ++i) { + for (int j = 0; j < kCols; ++j) { + for (int k = 0; k < 5; ++k) { + fOps[j*kRows+i][k] = ops[r.nextU() % SK_ARRAY_COUNT(ops)]; + } + } + } + } + +protected: + + static const int kRows = 5; + static const int kCols = 5; + static const int kPadX = 20; + static const int kPadY = 20; + + virtual SkString onShortName() { + return SkString("complexclip2"); + } + + virtual SkISize onISize() { + return make_isize(SkScalarRoundToInt(fTotalWidth), + SkScalarRoundToInt(fTotalHeight)); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint rectPaint; + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + + SkPaint fillPaint; + fillPaint.setColor(SkColorSetRGB(0xA0,0xDD,0xA0)); + + for (int i = 0; i < kRows; ++i) { + for (int j = 0; j < kCols; ++j) { + canvas->save(); + canvas->translate(kPadX * SK_Scalar1 + (fWidth + kPadX * SK_Scalar1)*j, + kPadY * SK_Scalar1 + (fHeight + kPadY * SK_Scalar1)*i); + canvas->save(); + for (int k = 0; k < 5; ++k) { + canvas->clipRect(fRects[k], fOps[j*kRows+i][k]); + } + canvas->drawRect(SkRect::MakeWH(fWidth, fHeight), fillPaint); + canvas->restore(); + for (int k = 0; k < 5; ++k) { + rectPaint.setColor(fRectColors[k]); + canvas->drawRect(fRects[k], rectPaint); + } + canvas->restore(); + } + } + } +private: + SkRect fRects[5]; + SkColor fRectColors[5]; + SkRegion::Op fOps[kRows * kCols][5]; + SkScalar fWidth; + SkScalar fHeight; + SkScalar fTotalWidth; + SkScalar fTotalHeight; + + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new ComplexClip2GM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/cubicpaths.cpp b/gm/cubicpaths.cpp new file mode 100644 index 0000000..7cd3df1 --- /dev/null +++ b/gm/cubicpaths.cpp @@ -0,0 +1,309 @@ +/* + * 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 "SkPaint.h" +#include "SkRandom.h" + +namespace skiagm { + +class CubicPathGM : public GM { +public: + CubicPathGM() {} + +protected: + SkString onShortName() { + return SkString("cubicpath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); + path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, + 60*SK_Scalar1, 20*SK_Scalar1, + 75*SK_Scalar1, 10*SK_Scalar1); + path.fName = "moveTo-cubic"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Cubic Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +class CubicClosePathGM : public GM { +public: + CubicClosePathGM() {} + +protected: + SkString onShortName() { + return SkString("cubicclosepath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); + path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, + 60*SK_Scalar1, 20*SK_Scalar1, + 75*SK_Scalar1, 10*SK_Scalar1); + path.fPath.close(); + path.fName = "moveTo-cubic-close"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Cubic Closed Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* CubicPathFactory(void*) { return new CubicPathGM; } +static GMRegistry regCubicPath(CubicPathFactory); + +static GM* CubicClosePathFactory(void*) { return new CubicClosePathGM; } +static GMRegistry regCubicClosePath(CubicClosePathFactory); + +} diff --git a/gm/degeneratesegments.cpp b/gm/degeneratesegments.cpp new file mode 100644 index 0000000..63d9dba --- /dev/null +++ b/gm/degeneratesegments.cpp @@ -0,0 +1,400 @@ +/* + * 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 "SkPaint.h" +#include "SkRandom.h" + +namespace skiagm { + +class DegenerateSegmentsGM : public GM { +public: + DegenerateSegmentsGM() {} + +protected: + struct PathAndName { + SkPath fPath; + const char* fName1; + const char* fName2; + }; + + SkString onShortName() { + return SkString("degeneratesegments"); + } + + SkISize onISize() { return make_isize(896, 930); } + + typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&); + + // We need to use explicit commands here, instead of addPath, because we + // do not want the moveTo that is added at the beginning of a path to + // appear in the appended path. + static SkPoint AddMove(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + return moveToPt; + } + + static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.close(); + return moveToPt; + } + + static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) { + path.lineTo(startPt); + return startPt; + } + + static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.lineTo(moveToPt); + return moveToPt; + } + + static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.lineTo(moveToPt); + path.close(); + return moveToPt; + } + + static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) { + path.quadTo(startPt, startPt); + return startPt; + } + + static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.quadTo(moveToPt, moveToPt); + return moveToPt; + } + + static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.quadTo(moveToPt, moveToPt); + path.close(); + return moveToPt; + } + + static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) { + path.cubicTo(startPt, startPt, startPt); + return startPt; + } + + static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.cubicTo(moveToPt, moveToPt, moveToPt); + return moveToPt; + } + + static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + path.moveTo(moveToPt); + path.cubicTo(moveToPt, moveToPt, moveToPt); + path.close(); + return moveToPt; + } + + static SkPoint AddClose(SkPath& path, SkPoint& startPt) { + path.close(); + return startPt; + } + + static SkPoint AddLine(SkPath& path, SkPoint& startPt) { + SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); + path.lineTo(endPt); + return endPt; + } + + static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.lineTo(endPt); + return endPt; + } + + static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.lineTo(endPt); + path.close(); + return endPt; + } + + static SkPoint AddQuad(SkPath& path, SkPoint& startPt) { + SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); + path.quadTo(midPt, endPt); + return endPt; + } + + static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.quadTo(midPt, endPt); + return endPt; + } + + static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.quadTo(midPt, endPt); + path.close(); + return endPt; + } + + static SkPoint AddCubic(SkPath& path, SkPoint& startPt) { + SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); + SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); + path.cubicTo(t1Pt, t2Pt, endPt); + return endPt; + } + + static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); + SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.cubicTo(t1Pt, t2Pt, endPt); + return endPt; + } + + static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) { + SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); + SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); + SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); + SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); + path.moveTo(moveToPt); + path.cubicTo(t1Pt, t2Pt, endPt); + path.close(); + return endPt; + } + + void drawPath(SkPath& path, SkCanvas* canvas, SkColor color, + const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + static const AddSegmentFunc gSegmentFunctions[] = { + AddMove, + AddMoveClose, + AddDegenLine, + AddMoveDegenLine, + AddMoveDegenLineClose, + AddDegenQuad, + AddMoveDegenQuad, + AddMoveDegenQuadClose, + AddDegenCubic, + AddMoveDegenCubic, + AddMoveDegenCubicClose, + AddClose, + AddLine, + AddMoveLine, + AddMoveLineClose, + AddQuad, + AddMoveQuad, + AddMoveQuadClose, + AddCubic, + AddMoveCubic, + AddMoveCubicClose + }; + static const char* gSegmentNames[] = { + "Move", + "MoveClose", + "DegenLine", + "MoveDegenLine", + "MoveDegenLineClose", + "DegenQuad", + "MoveDegenQuad", + "MoveDegenQuadClose", + "DegenCubic", + "MoveDegenCubic", + "MoveDegenCubicClose", + "Close", + "Line", + "MoveLine", + "MoveLineClose", + "Quad", + "MoveQuad", + "MoveQuadClose", + "Cubic", + "MoveCubic", + "MoveCubicClose" + }; + + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"} + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke 10"}, + {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"} + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Random Paths Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, " + "with Stroke width 6"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1); + canvas->save(); + canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title + canvas->save(); + unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions); + unsigned numCaps = SK_ARRAY_COUNT(gCaps); + unsigned numStyles = SK_ARRAY_COUNT(gStyles); + unsigned numFills = SK_ARRAY_COUNT(gFills); + for (size_t row = 0; row < 6; ++row) { + if (0 < row) { + canvas->translate(0, rect.height() + 100*SK_Scalar1); + } + canvas->save(); + for (size_t column = 0; column < 4; ++column) { + if (0 < column) { + canvas->translate(rect.width() + 4*SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles]; + CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps]; + FillAndName fill = gFills[(rand.nextU() >> 16) % numFills]; + SkPath path; + unsigned s1 = (rand.nextU() >> 16) % numSegments; + unsigned s2 = (rand.nextU() >> 16) % numSegments; + unsigned s3 = (rand.nextU() >> 16) % numSegments; + unsigned s4 = (rand.nextU() >> 16) % numSegments; + unsigned s5 = (rand.nextU() >> 16) % numSegments; + SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0); + pt = gSegmentFunctions[s1](path, pt); + pt = gSegmentFunctions[s2](path, pt); + pt = gSegmentFunctions[s3](path, pt); + pt = gSegmentFunctions[s4](path, pt); + pt = gSegmentFunctions[s5](path, pt); + + this->drawPath(path, canvas, color, rect, + cap.fCap, cap.fJoin, style.fStyle, + fill.fFill, SK_Scalar1*6); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(style.fName, + strlen(style.fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(fill.fName, + strlen(fill.fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(cap.fName, + strlen(cap.fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + canvas->drawText(gSegmentNames[s1], + strlen(gSegmentNames[s1]), + 0, rect.height() + 48 * SK_Scalar1, + labelPaint); + canvas->drawText(gSegmentNames[s2], + strlen(gSegmentNames[s2]), + 0, rect.height() + 60 * SK_Scalar1, + labelPaint); + canvas->drawText(gSegmentNames[s3], + strlen(gSegmentNames[s3]), + 0, rect.height() + 72 * SK_Scalar1, + labelPaint); + canvas->drawText(gSegmentNames[s4], + strlen(gSegmentNames[s4]), + 0, rect.height() + 84 * SK_Scalar1, + labelPaint); + canvas->drawText(gSegmentNames[s5], + strlen(gSegmentNames[s5]), + 0, rect.height() + 96 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new DegenerateSegmentsGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/drawbitmaprect.cpp b/gm/drawbitmaprect.cpp new file mode 100644 index 0000000..5832a9c --- /dev/null +++ b/gm/drawbitmaprect.cpp @@ -0,0 +1,155 @@ + +/* + * 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 "SkShader.h" +#include "SkColorPriv.h" + +// effects +#include "SkGradientShader.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); + + SkScalar wScalar = SkIntToScalar(w); + SkScalar hScalar = SkIntToScalar(h); + + SkPoint pt = { wScalar / 2, hScalar / 2 }; + + SkScalar radius = 4 * SkMaxScalar(wScalar, hScalar); + + SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW, + SK_ColorGREEN, SK_ColorMAGENTA, + SK_ColorBLUE, SK_ColorCYAN, + SK_ColorRED}; + + SkScalar pos[] = {0, + SK_Scalar1 / 6, + 2 * SK_Scalar1 / 6, + 3 * SK_Scalar1 / 6, + 4 * SK_Scalar1 / 6, + 5 * SK_Scalar1 / 6, + SK_Scalar1}; + + SkPaint paint; + paint.setShader(SkGradientShader::CreateRadial( + pt, radius, + colors, pos, + SK_ARRAY_COUNT(colors), + SkShader::kRepeat_TileMode))->unref(); + SkRect rect = SkRect::MakeWH(wScalar, hScalar); + SkMatrix mat = SkMatrix::I(); + for (int i = 0; i < 4; ++i) { + paint.getShader()->setLocalMatrix(mat); + canvas.drawRect(rect, paint); + rect.inset(wScalar / 8, hScalar / 8); + mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4); + } +} + +static const int gSize = 1024; + +class DrawBitmapRectGM : public GM { +public: + DrawBitmapRectGM() { + } + + SkBitmap fLargeBitmap; + +protected: + SkString onShortName() { + return SkString("drawbitmaprect"); + } + + SkISize onISize() { return make_isize(gSize, gSize); } + + virtual void onDraw(SkCanvas* canvas) { + static const int kBmpSize = 2048; + if (fLargeBitmap.isNull()) { + makebm(&fLargeBitmap, + SkBitmap::kARGB_8888_Config, + kBmpSize, kBmpSize); + } + SkRect dstRect = { 0, 0, SkIntToScalar(64), SkIntToScalar(64)}; + static const int kMaxSrcRectSize = 1 << (SkNextLog2(kBmpSize) + 2); + + static const int kPadX = 30; + static const int kPadY = 40; + SkPaint paint; + paint.setAlpha(0x20); + canvas->drawBitmapRect(fLargeBitmap, NULL, + SkRect::MakeWH(gSize * SK_Scalar1, + gSize * SK_Scalar1), + &paint); + canvas->translate(SK_Scalar1 * kPadX / 2, + SK_Scalar1 * kPadY / 2); + SkPaint blackPaint; + SkScalar titleHeight = SK_Scalar1 * 24; + blackPaint.setColor(SK_ColorBLACK); + blackPaint.setTextSize(titleHeight); + blackPaint.setAntiAlias(true); + SkString title; + title.printf("Bitmap size: %d x %d", kBmpSize, kBmpSize); + canvas->drawText(title.c_str(), title.size(), 0, + titleHeight, blackPaint); + + canvas->translate(0, SK_Scalar1 * kPadY / 2 + titleHeight); + int rowCount = 0; + canvas->save(); + for (int w = 1; w <= kMaxSrcRectSize; w *= 4) { + for (int h = 1; h <= kMaxSrcRectSize; h *= 4) { + + SkIRect srcRect = SkIRect::MakeXYWH((kBmpSize - w) / 2, + (kBmpSize - h) / 2, + w, h); + canvas->drawBitmapRect(fLargeBitmap, &srcRect, dstRect); + + SkString label; + label.appendf("%d x %d", w, h); + blackPaint.setAntiAlias(true); + blackPaint.setStyle(SkPaint::kFill_Style); + blackPaint.setTextSize(SK_Scalar1 * 10); + SkScalar baseline = dstRect.height() + + blackPaint.getTextSize() + SK_Scalar1 * 3; + canvas->drawText(label.c_str(), label.size(), + 0, baseline, + blackPaint); + blackPaint.setStyle(SkPaint::kStroke_Style); + blackPaint.setStrokeWidth(SK_Scalar1); + blackPaint.setAntiAlias(false); + canvas->drawRect(dstRect, blackPaint); + + canvas->translate(dstRect.width() + SK_Scalar1 * kPadX, 0); + ++rowCount; + if ((dstRect.width() + kPadX) * rowCount > gSize) { + canvas->restore(); + canvas->translate(0, dstRect.height() + SK_Scalar1 * kPadY); + canvas->save(); + rowCount = 0; + } + } + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new DrawBitmapRectGM; } +static GMRegistry reg(MyFactory); + +} + diff --git a/gm/emptypath.cpp b/gm/emptypath.cpp new file mode 100644 index 0000000..c52932e --- /dev/null +++ b/gm/emptypath.cpp @@ -0,0 +1,133 @@ + +/* + * 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 "SkPaint.h" +#include "SkRandom.h" + +namespace skiagm { + +class EmptyPathGM : public GM { +public: + EmptyPathGM() {} + +protected: + SkString onShortName() { + return SkString("emptypath"); + } + + SkISize onISize() { return make_isize(600, 280); } + + void drawEmpty(SkCanvas* canvas, + SkColor color, + const SkRect& clip, + SkPaint::Style style, + SkPath::FillType fill) { + SkPath path; + path.setFillType(fill); + SkPaint paint; + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Empty Paths Drawn Into Rectangle Clips With " + "Indicated Style and Fill"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + int i = 0; + canvas->save(); + canvas->translate(10 * SK_Scalar1, 0); + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 == i % 4) { + canvas->restore(); + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + canvas->save(); + } else { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + ++i; + + + SkColor color = rand.nextU(); + color = 0xff000000| color; // force solid + this->drawEmpty(canvas, color, rect, + gStyles[style].fStyle, gFills[fill].fFill); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(12 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 15 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 28 * SK_Scalar1, + labelPaint); + } + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new EmptyPathGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/filltypes.cpp b/gm/filltypes.cpp index e723f16..73c718e 100644 --- a/gm/filltypes.cpp +++ b/gm/filltypes.cpp @@ -1,3 +1,10 @@ + +/* + * 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" namespace skiagm { @@ -6,6 +13,7 @@ class FillTypeGM : public GM { SkPath fPath; public: FillTypeGM() { + this->setBGColor(0xFFDDDDDD); const SkScalar radius = SkIntToScalar(45); fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius); fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius); @@ -49,8 +57,6 @@ protected: } virtual void onDraw(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); SkPaint paint; diff --git a/gm/filltypespersp.cpp b/gm/filltypespersp.cpp new file mode 100644 index 0000000..33f3242 --- /dev/null +++ b/gm/filltypespersp.cpp @@ -0,0 +1,128 @@ + +/* + * 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 "SkGradientShader.h" + +namespace skiagm { + +class FillTypePerspGM : public GM { + SkPath fPath; +public: + FillTypePerspGM() { + 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("filltypespersp"); + } + + 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, bool aa) { + + SkPaint paint; + SkPoint center = SkPoint::Make(SkIntToScalar(100), SkIntToScalar(100)); + SkColor colors[] = {SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN}; + SkScalar pos[] = {0, SK_ScalarHalf, SK_Scalar1}; + SkShader* s = SkGradientShader::CreateRadial(center, + SkIntToScalar(100), + colors, + pos, + SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + paint.setAntiAlias(aa); + + 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) { + // do perspective drawPaint as the background; + SkPaint bkgnrd; + SkPoint center = SkPoint::Make(SkIntToScalar(100), + SkIntToScalar(100)); + SkColor colors[] = {SK_ColorBLACK, SK_ColorCYAN, + SK_ColorYELLOW, SK_ColorWHITE}; + SkScalar pos[] = {0, SK_ScalarHalf / 2, + 3 * SK_ScalarHalf / 2, SK_Scalar1}; + SkShader* s = SkGradientShader::CreateRadial(center, + SkIntToScalar(1000), + colors, + pos, + SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + bkgnrd.setShader(s)->unref(); + canvas->save(); + canvas->translate(SkIntToScalar(100), SkIntToScalar(100)); + SkMatrix mat; + mat.reset(); + mat.setPerspY(SkScalarToPersp(SK_Scalar1 / 1000)); + canvas->concat(mat); + canvas->drawPaint(bkgnrd); + canvas->restore(); + + // draw the paths in perspective + SkMatrix persp; + persp.reset(); + persp.setPerspX(SkScalarToPersp(-SK_Scalar1 / 1800)); + persp.setPerspY(SkScalarToPersp(SK_Scalar1 / 500)); + canvas->concat(persp); + + canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); + const SkScalar scale = SkIntToScalar(5)/4; + + showFour(canvas, SK_Scalar1, false); + canvas->translate(SkIntToScalar(450), 0); + showFour(canvas, scale, false); + + canvas->translate(SkIntToScalar(-450), SkIntToScalar(450)); + showFour(canvas, SK_Scalar1, true); + canvas->translate(SkIntToScalar(450), 0); + showFour(canvas, scale, true); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new FillTypePerspGM; } +static GMRegistry reg(MyFactory); + +} + diff --git a/gm/fontscaler.cpp b/gm/fontscaler.cpp new file mode 100644 index 0000000..b331bde --- /dev/null +++ b/gm/fontscaler.cpp @@ -0,0 +1,93 @@ +/* + * 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 "SkTypeface.h" + +namespace skiagm { + +class FontScalerGM : public GM { +public: + FontScalerGM() { + this->setBGColor(0xFFFFFFFF); + } + + virtual ~FontScalerGM() { + } + +protected: + virtual SkString onShortName() { + return SkString("fontscaler"); + } + + virtual SkISize onISize() { + return make_isize(1450, 750); + } + + static void rotate_about(SkCanvas* canvas, + SkScalar degrees, + SkScalar px, SkScalar py) { + canvas->translate(px, py); + canvas->rotate(degrees); + canvas->translate(-px, -py); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + + paint.setAntiAlias(true); + paint.setLCDRenderText(true); + //With freetype the default (normal hinting) can be really ugly. + //Most distros now set slight (vertical hinting only) in any event. + paint.setHinting(SkPaint::kSlight_Hinting); + SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal))); + + const char* text = "Hamburgefons ooo mmm"; + const size_t textLen = strlen(text); + + for (int j = 0; j < 2; ++j) { + for (int i = 0; i < 6; ++i) { + SkScalar x = SkIntToScalar(10); + SkScalar y = SkIntToScalar(20); + + SkAutoCanvasRestore acr(canvas, true); + canvas->translate(SkIntToScalar(50 + i * 230), + SkIntToScalar(20)); + rotate_about(canvas, SkIntToScalar(i * 5), x, y * 10); + + { + SkPaint p; + p.setAntiAlias(true); + SkRect r; + r.set(x - SkIntToScalar(3), SkIntToScalar(15), + x - SkIntToScalar(1), SkIntToScalar(280)); + canvas->drawRect(r, p); + } + + int index = 0; + for (int ps = 6; ps <= 22; ps++) { + paint.setTextSize(SkIntToScalar(ps)); + canvas->drawText(text, textLen, x, y, paint); + y += paint.getFontMetrics(NULL); + index += 1; + } + } + canvas->translate(0, SkIntToScalar(360)); + paint.setSubpixelText(true); + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new FontScalerGM; } +static GMRegistry reg(MyFactory); + +} + diff --git a/gm/gm.cpp b/gm/gm.cpp new file mode 100644 index 0000000..f9c0e66 --- /dev/null +++ b/gm/gm.cpp @@ -0,0 +1,54 @@ +/* + * 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" +using namespace skiagm; + +GM::GM() { + fBGColor = SK_ColorWHITE; +} +GM::~GM() {} + +void GM::draw(SkCanvas* canvas) { + this->drawBackground(canvas); + this->drawContent(canvas); +} + +void GM::drawContent(SkCanvas* canvas) { + this->onDraw(canvas); +} + +void GM::drawBackground(SkCanvas* canvas) { + this->onDrawBackground(canvas); +} + +const char* GM::shortName() { + if (fShortName.size() == 0) { + fShortName = this->onShortName(); + } + return fShortName.c_str(); +} + +void GM::setBGColor(SkColor color) { + fBGColor = color; +} + +void GM::onDrawBackground(SkCanvas* canvas) { + canvas->drawColor(fBGColor); +} + +void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) { + SkISize size = this->getISize(); + SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + SkPaint paint; + paint.setColor(color); + canvas->drawRect(r, paint); +} + +// need to explicitly declare this, or we get some weird infinite loop llist +template GMRegistry* SkTRegistry<GM*, void*>::gHead; @@ -1,7 +1,16 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ #ifndef skiagm_DEFINED #define skiagm_DEFINED +#include "SkBitmap.h" #include "SkCanvas.h" +#include "SkDevice.h" #include "SkPaint.h" #include "SkRefCnt.h" #include "SkSize.h" @@ -21,22 +30,39 @@ namespace skiagm { GM(); virtual ~GM(); - void draw(SkCanvas*); + enum Flags { + kSkipPDF_Flag = 1 << 0, + kSkipPicture_Flag = 1 << 1 + }; + + void draw(SkCanvas*); + void drawBackground(SkCanvas*); + void drawContent(SkCanvas*); + SkISize getISize() { return this->onISize(); } - const char* shortName() { - if (fShortName.size() == 0) { - fShortName = this->onShortName(); - } - return fShortName.c_str(); + const char* shortName(); + + uint32_t getFlags() const { + return this->onGetFlags(); } + + SkColor getBGColor() const { return fBGColor; } + void setBGColor(SkColor); + + // helper: fill a rect in the specified color based on the + // GM's getISize bounds. + void drawSizeBounds(SkCanvas*, SkColor); protected: virtual void onDraw(SkCanvas*) = 0; + virtual void onDrawBackground(SkCanvas*); virtual SkISize onISize() = 0; virtual SkString onShortName() = 0; + virtual uint32_t onGetFlags() const { return 0; } private: SkString fShortName; + SkColor fBGColor; }; typedef SkTRegistry<GM*, void*> GMRegistry; diff --git a/gm/gm_files.mk b/gm/gm_files.mk deleted file mode 100644 index fec20b6..0000000 --- a/gm/gm_files.mk +++ /dev/null @@ -1,17 +0,0 @@ -SOURCE := \ - bitmapfilters.cpp \ - blurs.cpp \ - filltypes.cpp \ - gradients.cpp \ - nocolorbleed.cpp \ - pathfill.cpp \ - points.cpp \ - poly2poly.cpp \ - shadows.cpp \ - shapes.cpp \ - strokerects.cpp \ - tilemodes.cpp \ - xfermodes.cpp \ - shadertext.cpp \ - complexclip.cpp \ - gmmain.cpp diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index 37c3ee3..0af2933 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -1,31 +1,65 @@ +/* + * 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 "GrContext.h" +#include "GrRenderTarget.h" + #include "SkColorPriv.h" +#include "SkData.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 "SkPicture.h" #include "SkStream.h" #include "SkRefCnt.h" -#include "GrContext.h" -#include "SkGpuCanvas.h" -#include "SkGpuDevice.h" -#include "SkEGLContext.h" -#include "SkDevice.h" +static bool gForceBWtext; + +extern bool gSkSuppressFontCachePurgeSpew; #ifdef SK_SUPPORT_PDF #include "SkPDFDevice.h" #include "SkPDFDocument.h" #endif -using namespace skiagm; +#ifdef SK_SUPPORT_XPS + #include "SkXPSDevice.h" +#endif + +#ifdef SK_BUILD_FOR_MAC + #include "SkCGUtils.h" + #define CAN_IMAGE_PDF 1 +#else + #define CAN_IMAGE_PDF 0 +#endif + +typedef int ErrorBitfield; +const static ErrorBitfield ERROR_NONE = 0x00; +const static ErrorBitfield ERROR_NO_GPU_CONTEXT = 0x01; +const static ErrorBitfield ERROR_PIXEL_MISMATCH = 0x02; +const static ErrorBitfield ERROR_DIMENSION_MISMATCH = 0x04; +const static ErrorBitfield ERROR_READING_REFERENCE_IMAGE = 0x08; +const static ErrorBitfield ERROR_WRITING_REFERENCE_IMAGE = 0x10; -// need to explicitly declare this, or we get some weird infinite loop llist -template GMRegistry* GMRegistry::gHead; +using namespace skiagm; class Iter { public: Iter() { + this->reset(); + } + + void reset() { fReg = GMRegistry::Head(); } @@ -119,34 +153,42 @@ static void compute_diff(const SkBitmap& target, const SkBitmap& base, } } -static bool compare(const SkBitmap& target, const SkBitmap& base, - const SkString& name, const char* renderModeDescriptor, - SkBitmap* diff) { +static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base, + const SkString& name, + const char* renderModeDescriptor, + SkBitmap* diff) { SkBitmap copy; const SkBitmap* bm = ⌖ if (target.config() != SkBitmap::kARGB_8888_Config) { target.copyTo(©, SkBitmap::kARGB_8888_Config); bm = © } + SkBitmap baseCopy; + const SkBitmap* bp = &base; + if (base.config() != SkBitmap::kARGB_8888_Config) { + base.copyTo(&baseCopy, SkBitmap::kARGB_8888_Config); + bp = &baseCopy; + } force_all_opaque(*bm); + force_all_opaque(*bp); const int w = bm->width(); const int h = bm->height(); - if (w != base.width() || h != base.height()) { + if (w != bp->width() || h != bp->height()) { SkDebugf( "---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", renderModeDescriptor, name.c_str(), - base.width(), base.height(), w, h); - return false; + bp->width(), bp->height(), w, h); + return ERROR_DIMENSION_MISMATCH; } SkAutoLockPixels bmLock(*bm); - SkAutoLockPixels baseLock(base); + SkAutoLockPixels baseLock(*bp); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - SkPMColor c0 = *base.getAddr32(x, y); + SkPMColor c0 = *bp->getAddr32(x, y); SkPMColor c1 = *bm->getAddr32(x, y); if (c0 != c1) { SkDebugf( @@ -156,26 +198,29 @@ static bool compare(const SkBitmap& target, const SkBitmap& base, if (diff) { diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); diff->allocPixels(); - compute_diff(*bm, base, diff); + compute_diff(*bm, *bp, diff); } - return false; + return ERROR_PIXEL_MISMATCH; } } } // they're equal - return true; + return ERROR_NONE; } -static bool write_pdf(const SkString& path, const SkDynamicMemoryWStream& pdf) { +static bool write_document(const SkString& path, + const SkDynamicMemoryWStream& document) { SkFILEWStream stream(path.c_str()); - return stream.write(pdf.getStream(), pdf.getOffset()); + SkAutoDataUnref data(document.copyToData()); + return stream.writeData(data.get()); } enum Backend { kRaster_Backend, kGPU_Backend, kPDF_Backend, + kXPS_Backend, }; struct ConfigData { @@ -197,32 +242,54 @@ static void setup_bitmap(const ConfigData& gRec, SkISize& size, bitmap->eraseColor(0); } -// Returns true if the test should continue, false if the test should -// halt. -static bool generate_image(GM* gm, const ConfigData& gRec, - GrContext* context, - SkBitmap& bitmap) { +#include "SkDrawFilter.h" +class BWTextDrawFilter : public SkDrawFilter { +public: + virtual void filter(SkPaint*, Type) SK_OVERRIDE; +}; +void BWTextDrawFilter::filter(SkPaint* p, Type t) { + if (kText_Type == t) { + p->setAntiAlias(false); + } +} + +static void installFilter(SkCanvas* canvas) { + if (gForceBWtext) { + canvas->setDrawFilter(new BWTextDrawFilter)->unref(); + } +} + +static void invokeGM(GM* gm, SkCanvas* canvas) { + installFilter(canvas); + gm->draw(canvas); + canvas->setDrawFilter(NULL); +} + +static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec, + GrContext* context, + GrRenderTarget* rt, + SkBitmap* bitmap) { SkISize size (gm->getISize()); - setup_bitmap(gRec, size, &bitmap); - SkCanvas canvas(bitmap); + setup_bitmap(gRec, size, bitmap); + SkCanvas canvas(*bitmap); if (gRec.fBackend == kRaster_Backend) { - gm->draw(&canvas); + invokeGM(gm, &canvas); } else { // GPU if (NULL == context) { - return false; + return ERROR_NO_GPU_CONTEXT; } - SkGpuCanvas gc(context, - SkGpuDevice::Current3DApiRenderTarget()); - gc.setDevice(gc.createDevice(bitmap.config(), - bitmap.width(), - bitmap.height(), - bitmap.isOpaque(), - false))->unref(); - gm->draw(&gc); - gc.readPixels(&bitmap); // overwrite our previous allocation + SkGpuCanvas gc(context, rt); + 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); } - return true; + return ERROR_NONE; } static void generate_image_from_picture(GM* gm, const ConfigData& gRec, @@ -230,6 +297,7 @@ static void generate_image_from_picture(GM* gm, const ConfigData& gRec, SkISize size = gm->getISize(); setup_bitmap(gRec, size, bitmap); SkCanvas canvas(*bitmap); + installFilter(&canvas); canvas.drawPicture(*pict); } @@ -242,7 +310,7 @@ static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { SkAutoUnref aur(dev); SkCanvas c(dev); - gm->draw(&c); + invokeGM(gm, &c); SkPDFDocument doc; doc.appendPage(dev); @@ -250,78 +318,133 @@ static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { #endif } -static bool write_reference_image(const ConfigData& gRec, - const char writePath [], - const char renderModeDescriptor [], - const SkString& name, - SkBitmap& bitmap, - SkDynamicMemoryWStream* pdf) { +static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) { +#ifdef SK_SUPPORT_XPS + SkISize size = gm->getISize(); + + SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254); + static const SkScalar upm = 72 * inchesPerMeter; + SkVector unitsPerMeter = SkPoint::Make(upm, upm); + static const SkScalar ppm = 200 * inchesPerMeter; + SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm); + + SkXPSDevice* dev = new SkXPSDevice(); + SkAutoUnref aur(dev); + + SkCanvas c(dev); + dev->beginPortfolio(&xps); + dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize); + invokeGM(gm, &c); + dev->endSheet(); + dev->endPortfolio(); + +#endif +} + +static ErrorBitfield write_reference_image(const ConfigData& gRec, + const char writePath [], + const char renderModeDescriptor [], + const SkString& name, + SkBitmap& bitmap, + SkDynamicMemoryWStream* document) { SkString path; bool success = false; - if (gRec.fBackend != kPDF_Backend) { + if (gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend || + (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) { + path = make_filename(writePath, renderModeDescriptor, name, "png"); success = write_bitmap(path, bitmap); - } else if (pdf) { + } + if (kPDF_Backend == gRec.fBackend) { path = make_filename(writePath, renderModeDescriptor, name, "pdf"); - success = write_pdf(path, *pdf); + success = write_document(path, *document); } - if (!success) { + if (kXPS_Backend == gRec.fBackend) { + path = make_filename(writePath, renderModeDescriptor, name, "xps"); + success = write_document(path, *document); + } + if (success) { + return ERROR_NONE; + } else { fprintf(stderr, "FAILED to write %s\n", path.c_str()); + return ERROR_WRITING_REFERENCE_IMAGE; } - return success; } -static bool compare_to_reference_image(const char readPath [], - const SkString& name, - SkBitmap &bitmap, - const char diffPath [], - const char renderModeDescriptor []) { +static ErrorBitfield compare_to_reference_image(const SkString& name, + SkBitmap &bitmap, + const SkBitmap& comparisonBitmap, + const char diffPath [], + const char renderModeDescriptor []) { + ErrorBitfield errors; + SkBitmap diffBitmap; + errors = compare(bitmap, comparisonBitmap, name, renderModeDescriptor, + diffPath ? &diffBitmap : NULL); + if ((ERROR_NONE == errors) && diffPath) { + SkString diffName = make_filename(diffPath, "", name, ".diff.png"); + if (!write_bitmap(diffName, diffBitmap)) { + errors |= ERROR_WRITING_REFERENCE_IMAGE; + } + } + return errors; +} + +static ErrorBitfield compare_to_reference_image(const char readPath [], + const SkString& name, + SkBitmap &bitmap, + const char diffPath [], + const char renderModeDescriptor []) { SkString path = make_filename(readPath, "", name, "png"); SkBitmap orig; - bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig, - SkBitmap::kARGB_8888_Config, - SkImageDecoder::kDecodePixels_Mode, NULL); - if (success) { - SkBitmap diffBitmap; - success = compare(bitmap, orig, name, renderModeDescriptor, - diffPath ? &diffBitmap : NULL); - if (!success && diffPath) { - SkString diffName = make_filename(diffPath, "", name, ".diff.png"); - fprintf(stderr, "Writing %s\n", diffName.c_str()); - write_bitmap(diffName, diffBitmap); - } + if (SkImageDecoder::DecodeFile(path.c_str(), &orig, + SkBitmap::kARGB_8888_Config, + SkImageDecoder::kDecodePixels_Mode, NULL)) { + return compare_to_reference_image(name, bitmap, + orig, diffPath, + renderModeDescriptor); } else { fprintf(stderr, "FAILED to read %s\n", path.c_str()); + return ERROR_READING_REFERENCE_IMAGE; } - return success; } -static bool handle_test_results(GM* gm, - const ConfigData& gRec, - const char writePath [], - const char readPath [], - const char diffPath [], - const char renderModeDescriptor [], - SkBitmap& bitmap, - SkDynamicMemoryWStream* pdf) { +static ErrorBitfield handle_test_results(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + const char renderModeDescriptor [], + SkBitmap& bitmap, + SkDynamicMemoryWStream* pdf, + const SkBitmap* comparisonBitmap) { SkString name = make_name(gm->shortName(), gRec.fName); if (writePath) { - write_reference_image(gRec, writePath, renderModeDescriptor, - name, bitmap, pdf); - // TODO: Figure out a way to compare PDFs. - } else if (readPath && gRec.fBackend != kPDF_Backend) { + return write_reference_image(gRec, writePath, renderModeDescriptor, + name, bitmap, pdf); + } else if (readPath && ( + gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend || + (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF))) { return compare_to_reference_image(readPath, name, bitmap, diffPath, renderModeDescriptor); + } else if (comparisonBitmap) { + return compare_to_reference_image(name, bitmap, + *comparisonBitmap, diffPath, + renderModeDescriptor); + } else { + return ERROR_NONE; } - return true; } static SkPicture* generate_new_picture(GM* gm) { // Pictures are refcounted so must be on heap SkPicture* pict = new SkPicture; SkCanvas* cv = pict->beginRecording(1000, 1000); - gm->draw(cv); + invokeGM(gm, cv); pict->endRecording(); return pict; @@ -352,51 +475,60 @@ static SkPicture* stream_to_new_picture(const SkPicture& src) { // Test: draw into a bitmap or pdf. // Depending on flags, possibly compare to an expected image // and possibly output a diff image if it fails to match. -static bool test_drawing(GM* gm, - const ConfigData& gRec, - const char writePath [], - const char readPath [], - const char diffPath [], - GrContext* context) { - SkBitmap bitmap; - SkDynamicMemoryWStream pdf; +static ErrorBitfield test_drawing(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + GrContext* context, + GrRenderTarget* rt, + SkBitmap* bitmap) { + SkDynamicMemoryWStream document; if (gRec.fBackend == kRaster_Backend || - gRec.fBackend == kGPU_Backend) { - // 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, bitmap)) { - return true; + gRec.fBackend == kGPU_Backend) { + // Early exit if we can't generate the image. + ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap); + if (ERROR_NONE != errors) { + return errors; } - } - // TODO: Figure out a way to compare PDFs. - if (gRec.fBackend == kPDF_Backend && writePath) { - generate_pdf(gm, pdf); + } else if (gRec.fBackend == kPDF_Backend) { + generate_pdf(gm, document); +#if CAN_IMAGE_PDF + SkAutoDataUnref data(document.copyToData()); + SkMemoryStream stream(data.data(), data.size()); + SkPDFDocumentToBitmap(&stream, bitmap); +#endif + } else if (gRec.fBackend == kXPS_Backend) { + generate_xps(gm, document); } return handle_test_results(gm, gRec, writePath, readPath, diffPath, - "", bitmap, &pdf); + "", *bitmap, &document, NULL); } -static bool test_picture_playback(GM* gm, - const ConfigData& gRec, - const char readPath [], - const char diffPath []) { +static ErrorBitfield test_picture_playback(GM* gm, + const ConfigData& gRec, + const SkBitmap& comparisonBitmap, + const char readPath [], + const char diffPath []) { SkPicture* pict = generate_new_picture(gm); SkAutoUnref aur(pict); if (kRaster_Backend == gRec.fBackend) { SkBitmap bitmap; generate_image_from_picture(gm, gRec, pict, &bitmap); - return handle_test_results(gm, gRec, NULL, readPath, diffPath, - "-replay", bitmap, NULL); + return handle_test_results(gm, gRec, NULL, NULL, diffPath, + "-replay", bitmap, NULL, &comparisonBitmap); + } else { + return ERROR_NONE; } - return true; } -static bool test_picture_serialization(GM* gm, - const ConfigData& gRec, - const char readPath [], - const char diffPath []) { +static ErrorBitfield test_picture_serialization(GM* gm, + const ConfigData& gRec, + const SkBitmap& comparisonBitmap, + const char readPath [], + const char diffPath []) { SkPicture* pict = generate_new_picture(gm); SkAutoUnref aurp(pict); SkPicture* repict = stream_to_new_picture(*pict); @@ -405,10 +537,11 @@ static bool test_picture_serialization(GM* gm, if (kRaster_Backend == gRec.fBackend) { SkBitmap bitmap; generate_image_from_picture(gm, gRec, repict, &bitmap); - return handle_test_results(gm, gRec, NULL, readPath, diffPath, - "-serialize", bitmap, NULL); + return handle_test_results(gm, gRec, NULL, NULL, diffPath, + "-serialize", bitmap, NULL, &comparisonBitmap); + } else { + return ERROR_NONE; } - return true; } static void usage(const char * argv0) { @@ -422,27 +555,64 @@ static void usage(const char * argv0) { SkDebugf(" --replay: exercise SkPicture replay.\n"); SkDebugf( " --serialize: exercise SkPicture serialization & deserialization.\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 } static const ConfigData gRec[] = { { SkBitmap::kARGB_8888_Config, kRaster_Backend, "8888" }, { SkBitmap::kARGB_4444_Config, kRaster_Backend, "4444" }, { SkBitmap::kRGB_565_Config, kRaster_Backend, "565" }, +#ifdef SK_SCALAR_IS_FLOAT { SkBitmap::kARGB_8888_Config, kGPU_Backend, "gpu" }, +#endif #ifdef SK_SUPPORT_PDF { SkBitmap::kARGB_8888_Config, kPDF_Backend, "pdf" }, #endif +#ifdef SK_SUPPORT_XPS + { SkBitmap::kARGB_8888_Config, kXPS_Backend, "xps" }, +#endif }; +static bool skip_name(const SkTDArray<const char*> array, const char name[]) { + if (0 == array.count()) { + // no names, so don't skip anything + return false; + } + for (int i = 0; i < array.count(); ++i) { + if (strstr(name, array[i])) { + // found the name, so don't skip + return false; + } + } + return true; +} + +namespace skiagm { +static GrContext* gGrContext; +GrContext* GetGr() { + return gGrContext; +} +} + int main(int argc, char * const argv[]) { SkAutoGraphics ag; + // we don't need to see this during a run + gSkSuppressFontCachePurgeSpew = true; 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; + const char* const commandName = argv[0]; char* const* stop = argv + argc; for (++argv; argv < stop; ++argv) { @@ -461,10 +631,24 @@ int main(int argc, char * const argv[]) { if (argv < stop && **argv) { diffPath = *argv; } + } else if (strcmp(*argv, "--forceBWtext") == 0) { + gForceBWtext = true; } else if (strcmp(*argv, "--noreplay") == 0) { doReplay = false; + } else if (strcmp(*argv, "--nopdf") == 0) { + doPDF = false; } else if (strcmp(*argv, "--serialize") == 0) { doSerialize = true; + } else if (strcmp(*argv, "--match") == 0) { + ++argv; + if (argv < stop && **argv) { + // just record the ptr, no need for a deep copy + *fMatches.append() = *argv; + } +#if SK_MESA + } else if (strcmp(*argv, "--mesagl") == 0) { + useMesa = true; +#endif } else { usage(commandName); return -1; @@ -475,15 +659,39 @@ int main(int argc, char * const argv[]) { return -1; } + int maxW = -1; + int maxH = -1; + Iter iter; + GM* gm; + while ((gm = iter.next()) != NULL) { + SkISize size = gm->getISize(); + maxW = SkMax32(size.width(), maxW); + maxH = SkMax32(size.height(), maxH); + } // setup a GL context for drawing offscreen - GrContext* context = NULL; - SkEGLContext eglContext; - if (eglContext.init(1024, 1024)) { - context = GrContext::CreateGLShaderContext(); + SkAutoTUnref<SkGLContext> glContext; +#if SK_MESA + if (useMesa) { + glContext.reset(new SkMesaGLContext()); + } else +#endif + { + glContext.reset(new SkNativeGLContext()); } - Iter iter; - GM* gm; + GrPlatformRenderTargetDesc rtDesc; + if (glContext.get()->init(maxW, maxH)) { + GrPlatform3DContext ctx = + reinterpret_cast<GrPlatform3DContext>(glContext.get()->gl()); + gGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx); + if (NULL != gGrContext) { + rtDesc.fConfig = kSkia8888_PM_GrPixelConfig; + rtDesc.fStencilBits = 8; + rtDesc.fRenderTargetHandle = glContext.get()->getFBOID(); + } + } else { + fprintf(stderr, "could not create GL context.\n"); + } if (readPath) { fprintf(stderr, "reading from %s\n", readPath); @@ -491,45 +699,95 @@ int main(int argc, char * const argv[]) { fprintf(stderr, "writing to %s\n", writePath); } - // Accumulate success of all tests so we can flag error in any - // one with the return value. - bool overallSuccess = true; + // Accumulate success of all tests. + int testsRun = 0; + int testsPassed = 0; + int testsFailed = 0; + int testsMissingReferenceImages = 0; + + iter.reset(); while ((gm = iter.next()) != NULL) { + const char* shortName = gm->shortName(); + if (skip_name(fMatches, shortName)) { + SkDELETE(gm); + continue; + } + SkISize size = gm->getISize(); - SkDebugf("drawing... %s [%d %d]\n", gm->shortName(), + SkDebugf("drawing... %s [%d %d]\n", shortName, size.width(), size.height()); + SkBitmap forwardRenderedBitmap; + + // Above we created an fbo for the context at maxW x maxH size. + // Here we lie about the size of the rt. We claim it is the size + // desired by the test. The reason is that rasterization may change + // slightly when the viewport dimensions change. Previously, whenever + // a new test was checked in that bumped maxW or maxH several images + // would slightly change. + rtDesc.fWidth = size.width(); + rtDesc.fHeight = size.height(); + SkAutoTUnref<GrRenderTarget> rt; + if (gGrContext) { + rt.reset(gGrContext->createPlatformRenderTarget(rtDesc)); + } for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { - bool testSuccess = test_drawing(gm, gRec[i], - writePath, readPath, diffPath, context); - overallSuccess &= testSuccess; - - if (doReplay && testSuccess) { - testSuccess = test_picture_playback(gm, gRec[i], - readPath, diffPath); - overallSuccess &= testSuccess; + // Skip any tests that we don't even need to try. + uint32_t gmFlags = gm->getFlags(); + if ((kPDF_Backend == gRec[i].fBackend) && + (!doPDF || (gmFlags & GM::kSkipPDF_Flag))) + { + continue; } - if (doSerialize && testSuccess) { - overallSuccess &= test_picture_serialization(gm, gRec[i], - readPath, diffPath); + // Now we know that we want to run this test and record its + // success or failure. + ErrorBitfield testErrors = ERROR_NONE; + + if ((ERROR_NONE == testErrors) && + (kGPU_Backend == gRec[i].fBackend) && + (NULL == rt.get())) { + fprintf(stderr, "Could not create render target for gpu.\n"); + testErrors |= ERROR_NO_GPU_CONTEXT; } - } - SkDELETE(gm); - } - if (false == overallSuccess) { - return -1; - } - return 0; -} -/////////////////////////////////////////////////////////////////////////////// + if (ERROR_NONE == testErrors) { + testErrors |= test_drawing(gm, gRec[i], + writePath, readPath, diffPath, + gGrContext, + rt.get(), &forwardRenderedBitmap); + } -using namespace skiagm; + if ((ERROR_NONE == testErrors) && doReplay && + !(gmFlags & GM::kSkipPicture_Flag)) { + testErrors |= test_picture_playback(gm, gRec[i], + forwardRenderedBitmap, + readPath, diffPath); + } -GM::GM() {} -GM::~GM() {} + if ((ERROR_NONE == testErrors) && doSerialize) { + testErrors |= test_picture_serialization(gm, gRec[i], + forwardRenderedBitmap, + readPath, diffPath); + } -void GM::draw(SkCanvas* canvas) { - this->onDraw(canvas); + // Update overall results. + // We only tabulate the particular error types that we currently + // care about (e.g., missing reference images). Later on, if we + // want to also tabulate pixel mismatches vs dimension mistmatches + // (or whatever else), we can do so. + testsRun++; + if (ERROR_NONE == testErrors) { + testsPassed++; + } else if (ERROR_READING_REFERENCE_IMAGE & testErrors) { + testsMissingReferenceImages++; + } else { + testsFailed++; + } + } + SkDELETE(gm); + } + printf("Ran %d tests: %d passed, %d failed, %d missing reference images\n", + testsRun, testsPassed, testsFailed, testsMissingReferenceImages); + return (0 == testsFailed) ? 0 : -1; } diff --git a/gm/gradients.cpp b/gm/gradients.cpp index 26eee9d..aac8a96 100644 --- a/gm/gradients.cpp +++ b/gm/gradients.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkGradientShader.h" @@ -73,21 +80,18 @@ static const GradMaker gGradMakers[] = { class GradientsGM : public GM { public: - GradientsGM() {} + GradientsGM() { + this->setBGColor(0xFFDDDDDD); + } protected: SkString onShortName() { return SkString("gradients"); } - SkISize onISize() { return make_isize(640, 510); } - - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } - + virtual SkISize onISize() { return make_isize(640, 510); } + virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); SkPoint pts[2] = { { 0, 0 }, @@ -117,10 +121,109 @@ private: typedef GM INHERITED; }; +/* + Inspired by this <canvas> javascript, where we need to detect that we are not + solving a quadratic equation, but must instead solve a linear (since our X^2 + coefficient is 0) + + ctx.fillStyle = '#f00'; + ctx.fillRect(0, 0, 100, 50); + + var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150); + g.addColorStop(0, '#f00'); + g.addColorStop(0.01, '#0f0'); + g.addColorStop(0.99, '#0f0'); + g.addColorStop(1, '#f00'); + ctx.fillStyle = g; + ctx.fillRect(0, 0, 100, 50); + */ +class GradientsDegenrate2PointGM : public GM { +public: + GradientsDegenrate2PointGM() {} + +protected: + SkString onShortName() { + return SkString("gradients_degenerate_2pt"); + } + + virtual SkISize onISize() { return make_isize(320, 320); } + + void drawBG(SkCanvas* canvas) { + canvas->drawColor(SK_ColorBLUE); + } + + virtual void onDraw(SkCanvas* canvas) { + this->drawBG(canvas); + + SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED }; + SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 }; + SkPoint c0; + c0.iset(-80, 25); + SkScalar r0 = SkIntToScalar(70); + SkPoint c1; + c1.iset(0, 25); + SkScalar r1 = SkIntToScalar(150); + SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors, + pos, SK_ARRAY_COUNT(pos), + SkShader::kClamp_TileMode); + SkPaint paint; + paint.setShader(s)->unref(); + canvas->drawPaint(paint); + } + +private: + typedef GM INHERITED; +}; + +/// Tests correctness of *optimized* codepaths in gradients. + +class ClampedGradientsGM : public GM { +public: + ClampedGradientsGM() {} + +protected: + SkString onShortName() { return SkString("clamped_gradients"); } + + virtual SkISize onISize() { return make_isize(640, 510); } + + void drawBG(SkCanvas* canvas) { + canvas->drawColor(0xFFDDDDDD); + } + + virtual void onDraw(SkCanvas* canvas) { + this->drawBG(canvas); + + SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) }; + SkPaint paint; + paint.setAntiAlias(true); + + SkPoint center; + center.iset(0, 300); + canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); + SkShader* shader = SkGradientShader::CreateRadial( + SkPoint(center), + SkIntToScalar(200), gColors, NULL, 5, + SkShader::kClamp_TileMode, NULL); + paint.setShader(shader); + canvas->drawRect(r, paint); + shader->unref(); + } + +private: + typedef GM INHERITED; +}; + + /////////////////////////////////////////////////////////////////////////////// static GM* MyFactory(void*) { return new GradientsGM; } static GMRegistry reg(MyFactory); +static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; } +static GMRegistry reg2(MyFactory2); + +static GM* MyFactory3(void*) { return new ClampedGradientsGM; } +static GMRegistry reg3(MyFactory3); + } diff --git a/gm/gradtext.cpp b/gm/gradtext.cpp new file mode 100644 index 0000000..a3769d2 --- /dev/null +++ b/gm/gradtext.cpp @@ -0,0 +1,97 @@ +/* + * 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 "SkGradientShader.h" + +// test shader w/ transparency +static SkShader* make_grad(SkScalar width) { + SkColor colors[] = { SK_ColorRED, 0x0000FF00, SK_ColorBLUE }; + SkPoint pts[] = { { 0, 0 }, { width, 0 } }; + return SkGradientShader::CreateLinear(pts, colors, NULL, + SK_ARRAY_COUNT(colors), + SkShader::kMirror_TileMode); +} + +// test opaque shader +static SkShader* make_grad2(SkScalar width) { + SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE }; + SkPoint pts[] = { { 0, 0 }, { width, 0 } }; + return SkGradientShader::CreateLinear(pts, colors, NULL, + SK_ARRAY_COUNT(colors), + SkShader::kMirror_TileMode); +} + +namespace skiagm { + +class GradTextGM : public GM { +public: + GradTextGM () {} + +protected: + + virtual SkString onShortName() { + return SkString("gradtext"); + } + + virtual SkISize onISize() { return make_isize(500, 480); } + + static void draw_text(SkCanvas* canvas, const SkPaint& paint) { + const char* text = "When in the course of human events"; + size_t len = strlen(text); + canvas->drawText(text, len, 0, 0, paint); + } + + static void draw_text3(SkCanvas* canvas, const SkPaint& paint) { + SkPaint p(paint); + + p.setAntiAlias(false); + draw_text(canvas, p); + p.setAntiAlias(true); + canvas->translate(0, paint.getTextSize() * 4/3); + draw_text(canvas, p); + p.setLCDRenderText(true); + canvas->translate(0, paint.getTextSize() * 4/3); + draw_text(canvas, p); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + paint.setTextSize(SkIntToScalar(26)); + + const SkISize& size = this->getISize(); + SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()), + SkIntToScalar(size.height()) / 2); + canvas->drawRect(r, paint); + + canvas->translate(SkIntToScalar(20), paint.getTextSize()); + + for (int i = 0; i < 2; ++i) { + paint.setShader(make_grad(SkIntToScalar(80)))->unref(); + draw_text3(canvas, paint); + + canvas->translate(0, paint.getTextSize() * 2); + + paint.setShader(make_grad2(SkIntToScalar(80)))->unref(); + draw_text3(canvas, paint); + + canvas->translate(0, paint.getTextSize() * 2); + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new GradTextGM; } +static GMRegistry reg(MyFactory); + +} + diff --git a/gm/hairmodes.cpp b/gm/hairmodes.cpp new file mode 100644 index 0000000..8bfa186 --- /dev/null +++ b/gm/hairmodes.cpp @@ -0,0 +1,152 @@ +/* + * 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 "SkColorPriv.h" +#include "SkShader.h" + +static SkCanvas* create_canvas(int w, int h) { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, w, h); + bm.allocPixels(); + bm.eraseColor(0); + return new SkCanvas(bm); +} + +static const SkBitmap& extract_bitmap(SkCanvas* canvas) { + return canvas->getDevice()->accessBitmap(false); +} + +static 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" }, +}; + +const int gWidth = 64; +const int gHeight = 64; +const SkScalar W = SkIntToScalar(gWidth); +const SkScalar H = SkIntToScalar(gHeight); + +static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode, SkAlpha a0, SkAlpha a1) { + + SkPaint paint; + paint.setAntiAlias(true); + + SkRect r = SkRect::MakeWH(W, H); + r.inset(W/10, H/10); + + paint.setColor(SK_ColorBLUE); + paint.setAlpha(a0); + canvas->drawOval(r, paint); + + paint.setColor(SK_ColorRED); + paint.setAlpha(a1); + paint.setXfermode(mode); + for (int angle = 0; angle < 24; ++angle) { + SkScalar x = SkScalarCos(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gWidth; + SkScalar y = SkScalarSin(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gHeight; + paint.setStrokeWidth(SK_Scalar1 * angle * 2 / 24); + canvas->drawLine(W/2, H/2, W/2 + x, H/2 + y, paint); + } + + return H; +} + +static SkShader* make_bg_shader() { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); + bm.allocPixels(); + *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF; + *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, 0xCC, 0xCC); + + SkShader* s = SkShader::CreateBitmapShader(bm, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + + SkMatrix m; + m.setScale(SkIntToScalar(6), SkIntToScalar(6)); + s->setLocalMatrix(m); + return s; +} + +namespace skiagm { + + class HairModesGM : public GM { + SkPaint fBGPaint; + public: + HairModesGM() { + fBGPaint.setShader(make_bg_shader())->unref(); + } + + protected: + + virtual SkString onShortName() { + return SkString("hairmodes"); + } + + virtual SkISize onISize() { return make_isize(640, 480); } + + virtual void onDraw(SkCanvas* canvas) { + const SkRect bounds = SkRect::MakeWH(W, H); + static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 }; + + canvas->translate(SkIntToScalar(4), SkIntToScalar(4)); + + for (int alpha = 0; alpha < 4; ++alpha) { + canvas->save(); + canvas->save(); + for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) { + if (6 == i) { + canvas->restore(); + canvas->translate(W * 5, 0); + canvas->save(); + } + SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); + + canvas->drawRect(bounds, fBGPaint); + canvas->saveLayer(&bounds, NULL); + SkScalar dy = drawCell(canvas, mode, + gAlphaValue[alpha & 1], + gAlphaValue[alpha & 2]); + canvas->restore(); + + canvas->translate(0, dy * 5 / 4); + SkSafeUnref(mode); + } + canvas->restore(); + canvas->restore(); + canvas->translate(W * 5 / 4, 0); + } + } + + // disable pdf for now, since it crashes on mac + virtual uint32_t onGetFlags() const { return kSkipPDF_Flag; } + + private: + typedef GM INHERITED; + }; + + ////////////////////////////////////////////////////////////////////////////// + + static GM* MyFactory(void*) { return new HairModesGM; } + static GMRegistry reg(MyFactory); + +} diff --git a/gm/imageblur.cpp b/gm/imageblur.cpp new file mode 100644 index 0000000..841441e --- /dev/null +++ b/gm/imageblur.cpp @@ -0,0 +1,57 @@ +/* + * 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 "SkBlurImageFilter.h" + +#define WIDTH 500 +#define HEIGHT 500 + +namespace skiagm { + +class ImageBlurGM : public GM { +public: + ImageBlurGM() { + this->setBGColor(0xFF000000); + } + +protected: + virtual SkString onShortName() { + return SkString("imageblur"); + } + + virtual SkISize onISize() { + return make_isize(WIDTH, HEIGHT); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + paint.setImageFilter(new SkBlurImageFilter(24.0f, 0.0f))->unref(); + canvas->saveLayer(NULL, &paint); + paint.setAntiAlias(true); + const char* str = "The quick brown fox jumped over the lazy dog."; + srand(1234); + for (int i = 0; i < 25; ++i) { + int x = rand() % WIDTH; + int y = rand() % HEIGHT; + paint.setColor(rand() % 0x1000000 | 0xFF000000); + paint.setTextSize(rand() % 300); + canvas->drawText(str, strlen(str), x, y, paint); + } + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new ImageBlurGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/lcdtext.cpp b/gm/lcdtext.cpp new file mode 100644 index 0000000..ab8b8e4 --- /dev/null +++ b/gm/lcdtext.cpp @@ -0,0 +1,70 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +/* Tests text rendering with LCD and subpixel rendering turned on and off. + */ + +#include "gm.h" +#include "SkCanvas.h" + +namespace skiagm { + +class LcdTextGM : public GM { +public: + LcdTextGM() { + const int pointSize = 36; + textHeight = SkIntToScalar(pointSize); + } + +protected: + + SkString onShortName() { + return SkString("lcdtext"); + } + + SkISize onISize() { return make_isize(640, 480); } + + virtual void onDraw(SkCanvas* canvas) { + + y = textHeight; + drawText(canvas, SkString("TEXT: SubpixelTrue LCDRenderTrue"), + true, true); + drawText(canvas, SkString("TEXT: SubpixelTrue LCDRenderFalse"), + true, false); + drawText(canvas, SkString("TEXT: SubpixelFalse LCDRenderTrue"), + false, true); + drawText(canvas, SkString("TEXT: SubpixelFalse LCDRenderFalse"), + false, false); + } + + void drawText(SkCanvas* canvas, const SkString& string, + bool subpixelTextEnabled, bool lcdRenderTextEnabled) { + SkPaint paint; + paint.setColor(SK_ColorBLACK); + paint.setDither(true); + paint.setAntiAlias(true); + paint.setSubpixelText(subpixelTextEnabled); + paint.setLCDRenderText(lcdRenderTextEnabled); + paint.setTextSize(textHeight); + + canvas->drawText(string.c_str(), string.size(), 0, y, paint); + y += textHeight; + } + +private: + typedef GM INHERITED; + SkScalar y, textHeight; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new LcdTextGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/linepaths.cpp b/gm/linepaths.cpp new file mode 100644 index 0000000..3d84c37 --- /dev/null +++ b/gm/linepaths.cpp @@ -0,0 +1,305 @@ +/* + * 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 "SkPaint.h" +#include "SkRandom.h" + +namespace skiagm { + +class LinePathGM : public GM { +public: + LinePathGM() {} + +protected: + SkString onShortName() { + return SkString("linepath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1); + path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1); + path.fName = "moveTo-line"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Line Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +class LineClosePathGM : public GM { +public: + LineClosePathGM() {} + +protected: + SkString onShortName() { + return SkString("lineclosepath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1); + path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1); + path.fPath.close(); + path.fName = "moveTo-line-close"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Line Closed Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* LinePathFactory(void*) { return new LinePathGM; } +static GMRegistry regLinePath(LinePathFactory); + +static GM* LineClosePathFactory(void*) { return new LineClosePathGM; } +static GMRegistry regLineClosePath(LineClosePathFactory); + +} diff --git a/gm/ninepatchstretch.cpp b/gm/ninepatchstretch.cpp new file mode 100644 index 0000000..d1d4dda --- /dev/null +++ b/gm/ninepatchstretch.cpp @@ -0,0 +1,113 @@ +/* + * 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 "SkGpuDevice.h" + +static void make_bitmap(SkBitmap* bitmap, GrContext* ctx, SkIRect* center) { + SkDevice* dev; + SkCanvas canvas; + + const int kFixed = 28; + const int kStretchy = 8; + const int kSize = 2*kFixed + kStretchy; + + if (ctx) { + dev = new SkGpuDevice(ctx, SkBitmap::kARGB_8888_Config, kSize, kSize); + *bitmap = dev->accessBitmap(false); + } else { + bitmap->setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize); + bitmap->allocPixels(); + dev = new SkDevice(*bitmap); + } + + canvas.setDevice(dev)->unref(); + canvas.clear(0); + + SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize)); + const SkScalar strokeWidth = SkIntToScalar(6); + const SkScalar radius = SkIntToScalar(kFixed) - strokeWidth/2; + + center->setXYWH(kFixed, kFixed, kStretchy, kStretchy); + + SkPaint paint; + paint.setAntiAlias(true); + + paint.setColor(0xFFFF0000); + canvas.drawRoundRect(r, radius, radius, paint); + r.setXYWH(SkIntToScalar(kFixed), 0, SkIntToScalar(kStretchy), SkIntToScalar(kSize)); + paint.setColor(0x8800FF00); + canvas.drawRect(r, paint); + r.setXYWH(0, SkIntToScalar(kFixed), SkIntToScalar(kSize), SkIntToScalar(kStretchy)); + paint.setColor(0x880000FF); + canvas.drawRect(r, paint); +} + +namespace skiagm { + +class NinePatchStretchGM : public GM { +public: + SkBitmap fBM; + + NinePatchStretchGM() {} + +protected: + virtual SkString onShortName() { + return SkString("ninepatch-stretch"); + } + + virtual SkISize onISize() { + return make_isize(400, 400); + } + + virtual void onDraw(SkCanvas* canvas) { + SkBitmap bm; + SkIRect center; + make_bitmap(&bm, NULL /*SampleCode::GetGr()*/, ¢er); + + // amount of bm that should not be stretched (unless we have to) + const SkScalar fixed = SkIntToScalar(bm.width() - center.width()); + + const SkTSize<SkScalar> size[] = { + { fixed * 4 / 5, fixed * 4 / 5 }, // shrink in both axes + { fixed * 4 / 5, fixed * 4 }, // shrink in X + { fixed * 4, fixed * 4 / 5 }, // shrink in Y + { fixed * 4, fixed * 4 } + }; + + canvas->drawBitmap(bm, SkIntToScalar(10), SkIntToScalar(10), NULL); + + SkScalar x = SkIntToScalar(100); + SkScalar y = SkIntToScalar(100); + + SkPaint paint; + paint.setFilterBitmap(true); + + for (int iy = 0; iy < 2; ++iy) { + for (int ix = 0; ix < 2; ++ix) { + int i = ix * 2 + iy; + SkRect r = SkRect::MakeXYWH(x + ix * fixed, y + iy * fixed, + size[i].width(), size[i].height()); + canvas->drawBitmapNine(bm, center, r, &paint); + } + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new NinePatchStretchGM; } +static GMRegistry reg(MyFactory); + +} + + + diff --git a/gm/nocolorbleed.cpp b/gm/nocolorbleed.cpp index 3dec7cc..26b8184 100755 --- a/gm/nocolorbleed.cpp +++ b/gm/nocolorbleed.cpp @@ -1,10 +1,19 @@ + +/* + * 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" namespace skiagm { class NoColorBleedGM : public GM { public: - NoColorBleedGM() {} + NoColorBleedGM() { + this->setBGColor(0xFFDDDDDD); + } protected: virtual SkString onShortName() { @@ -15,13 +24,7 @@ protected: return make_isize(200, 200); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } - virtual void onDraw(SkCanvas* canvas) { - drawBG(canvas); - SkBitmap sprite; sprite.setConfig(SkBitmap::kARGB_8888_Config, 4, 4, 4*sizeof(SkColor)); const SkColor spriteData[16] = { diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp index 713847f..9d4b3c8 100644 --- a/gm/pathfill.cpp +++ b/gm/pathfill.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkPicture.h" #include "SkRectShape.h" @@ -118,13 +125,7 @@ protected: return make_isize(640, 480); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(SK_ColorWHITE); - } - virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - SkPaint paint; paint.setAntiAlias(true); diff --git a/gm/pathreverse.cpp b/gm/pathreverse.cpp new file mode 100644 index 0000000..fc8028e --- /dev/null +++ b/gm/pathreverse.cpp @@ -0,0 +1,118 @@ +/* + * 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 "SkTypeface.h" + +static void test_path(SkCanvas* canvas, const SkPath& path) { + SkPaint paint; + paint.setAntiAlias(true); + canvas->drawPath(path, paint); + + paint.setStyle(SkPaint::kStroke_Style); + paint.setColor(SK_ColorRED); + canvas->drawPath(path, paint); +} + +static void test_rev(SkCanvas* canvas, const SkPath& path) { + test_path(canvas, path); + + SkPath rev; + rev.reverseAddPath(path); + canvas->save(); + canvas->translate(150, 0); + test_path(canvas, rev); + canvas->restore(); +} + +static void test_rev(SkCanvas* canvas) { + SkRect r = { 10, 10, 100, 60 }; + + SkPath path; + + path.addRect(r); test_rev(canvas, path); + + canvas->translate(0, 100); + path.offset(20, 20); + path.addRect(r); test_rev(canvas, path); + + canvas->translate(0, 100); + path.reset(); + path.moveTo(10, 10); path.lineTo(30, 30); + path.addOval(r); + r.offset(50, 20); + path.addOval(r); + test_rev(canvas, path); + + SkPaint paint; + paint.setTextSize(SkIntToScalar(100)); + SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal); + SkSafeUnref(paint.setTypeface(hira)); + path.reset(); + paint.getTextPath("e", 1, 50, 50, &path); + canvas->translate(0, 100); + test_rev(canvas, path); +} + +namespace skiagm { + +class PathReverseGM : public GM { +public: + PathReverseGM() { + + } + +protected: + virtual SkString onShortName() { + return SkString("path-reverse"); + } + + virtual SkISize onISize() { + return make_isize(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) { + SkRect r = { 10, 10, 100, 60 }; + + SkPath path; + + path.addRect(r); test_rev(canvas, path); + + canvas->translate(0, 100); + path.offset(20, 20); + path.addRect(r); test_rev(canvas, path); + + canvas->translate(0, 100); + path.reset(); + path.moveTo(10, 10); path.lineTo(30, 30); + path.addOval(r); + r.offset(50, 20); + path.addOval(r); + test_rev(canvas, path); + + SkPaint paint; + paint.setTextSize(SkIntToScalar(100)); + SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal); + SkSafeUnref(paint.setTypeface(hira)); + path.reset(); + paint.getTextPath("e", 1, 50, 50, &path); + canvas->translate(0, 100); + test_rev(canvas, path); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new PathReverseGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/points.cpp b/gm/points.cpp index 48d8fec..e4f3c2e 100644 --- a/gm/points.cpp +++ b/gm/points.cpp @@ -1,3 +1,10 @@ + +/* + * 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" @@ -16,18 +23,18 @@ protected: return make_isize(640, 490); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(SK_ColorWHITE); - } - static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand) { - for (size_t i = 0; i < n; i++) - pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480); + for (size_t i = 0; i < n; i++) { + // Compute these independently and store in variables, rather + // than in the parameter-passing expression, to get consistent + // evaluation order across compilers. + SkScalar y = rand->nextUScalar1() * 480; + SkScalar x = rand->nextUScalar1() * 640; + pts[i].set(x, y); + } } virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - canvas->translate(SK_Scalar1, SK_Scalar1); SkRandom rand; diff --git a/gm/poly2poly.cpp b/gm/poly2poly.cpp index 193ede7..df824b5 100644 --- a/gm/poly2poly.cpp +++ b/gm/poly2poly.cpp @@ -1,3 +1,10 @@ + +/* + * 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" namespace skiagm { @@ -14,10 +21,6 @@ protected: virtual SkISize onISize() { return make_isize(835, 840); } - - void drawBG(SkCanvas* canvas) { - canvas->drawColor(SK_ColorWHITE); - } static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[], const int idst[], int count) { @@ -45,7 +48,7 @@ protected: paint->setColor(SK_ColorRED); paint->setStyle(SkPaint::kFill_Style); SkScalar x = D/2; - float y = D/2 - (fm.fAscent + fm.fDescent)/2; + SkScalar y = D/2 - (fm.fAscent + fm.fDescent)/2; SkString str; str.appendS32(count); canvas->drawText(str.c_str(), str.size(), x, y, *paint); @@ -53,9 +56,7 @@ protected: canvas->restore(); } - virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - + virtual void onDraw(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setStrokeWidth(SkIntToScalar(4)); diff --git a/gm/quadpaths.cpp b/gm/quadpaths.cpp new file mode 100644 index 0000000..f8b172b --- /dev/null +++ b/gm/quadpaths.cpp @@ -0,0 +1,307 @@ +/* + * 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 "SkPaint.h" +#include "SkRandom.h" + +namespace skiagm { + +class QuadPathGM : public GM { +public: + QuadPathGM() {} + +protected: + SkString onShortName() { + return SkString("quadpath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); + path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1, + 75*SK_Scalar1, 10*SK_Scalar1); + path.fName = "moveTo-quad"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Quad Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +class QuadClosePathGM : public GM { +public: + QuadClosePathGM() {} + +protected: + SkString onShortName() { + return SkString("quadclosepath"); + } + + SkISize onISize() { return make_isize(1240, 390); } + + void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, + const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, + SkPaint::Style style, SkPath::FillType fill, + SkScalar strokeWidth) { + path.setFillType(fill); + SkPaint paint; + paint.setStrokeCap(cap); + paint.setStrokeWidth(strokeWidth); + paint.setStrokeJoin(join); + paint.setColor(color); + paint.setStyle(style); + canvas->save(); + canvas->clipRect(clip); + canvas->drawPath(path, paint); + canvas->restore(); + } + + virtual void onDraw(SkCanvas* canvas) { + struct FillAndName { + SkPath::FillType fFill; + const char* fName; + }; + static const FillAndName gFills[] = { + {SkPath::kWinding_FillType, "Winding"}, + {SkPath::kEvenOdd_FillType, "Even / Odd"}, + {SkPath::kInverseWinding_FillType, "Inverse Winding"}, + {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, + }; + struct StyleAndName { + SkPaint::Style fStyle; + const char* fName; + }; + static const StyleAndName gStyles[] = { + {SkPaint::kFill_Style, "Fill"}, + {SkPaint::kStroke_Style, "Stroke"}, + {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, + }; + struct CapAndName { + SkPaint::Cap fCap; + SkPaint::Join fJoin; + const char* fName; + }; + static const CapAndName gCaps[] = { + {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, + {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, + {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} + }; + struct PathAndName { + SkPath fPath; + const char* fName; + }; + PathAndName path; + path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); + path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1, + 75*SK_Scalar1, 10*SK_Scalar1); + path.fPath.close(); + path.fName = "moveTo-quad-close"; + + SkPaint titlePaint; + titlePaint.setColor(SK_ColorBLACK); + titlePaint.setAntiAlias(true); + titlePaint.setLCDRenderText(true); + titlePaint.setTextSize(15 * SK_Scalar1); + const char title[] = "Quad Closed Drawn Into Rectangle Clips With " + "Indicated Style, Fill and Linecaps, with stroke width 10"; + canvas->drawText(title, strlen(title), + 20 * SK_Scalar1, + 20 * SK_Scalar1, + titlePaint); + + SkRandom rand; + SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); + canvas->save(); + canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); + canvas->save(); + for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { + if (0 < cap) { + canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); + } + canvas->save(); + for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { + if (0 < fill) { + canvas->translate(0, rect.height() + 40 * SK_Scalar1); + } + canvas->save(); + for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { + if (0 < style) { + canvas->translate(rect.width() + 40 * SK_Scalar1, 0); + } + + SkColor color = 0xff007000; + this->drawPath(path.fPath, canvas, color, rect, + gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, + gFills[fill].fFill, SK_Scalar1*10); + + SkPaint rectPaint; + rectPaint.setColor(SK_ColorBLACK); + rectPaint.setStyle(SkPaint::kStroke_Style); + rectPaint.setStrokeWidth(-1); + rectPaint.setAntiAlias(true); + canvas->drawRect(rect, rectPaint); + + SkPaint labelPaint; + labelPaint.setColor(color); + labelPaint.setAntiAlias(true); + labelPaint.setLCDRenderText(true); + labelPaint.setTextSize(10 * SK_Scalar1); + canvas->drawText(gStyles[style].fName, + strlen(gStyles[style].fName), + 0, rect.height() + 12 * SK_Scalar1, + labelPaint); + canvas->drawText(gFills[fill].fName, + strlen(gFills[fill].fName), + 0, rect.height() + 24 * SK_Scalar1, + labelPaint); + canvas->drawText(gCaps[cap].fName, + strlen(gCaps[cap].fName), + 0, rect.height() + 36 * SK_Scalar1, + labelPaint); + } + canvas->restore(); + } + canvas->restore(); + } + canvas->restore(); + canvas->restore(); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* QuadPathFactory(void*) { return new QuadPathGM; } +static GMRegistry regQuadPath(QuadPathFactory); + +static GM* QuadClosePathFactory(void*) { return new QuadClosePathGM; } +static GMRegistry regQuadClosePath(QuadClosePathFactory); + +} diff --git a/gm/shadertext.cpp b/gm/shadertext.cpp index ea87823..b574ab6 100644 --- a/gm/shadertext.cpp +++ b/gm/shadertext.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkGradientShader.h" @@ -102,7 +109,9 @@ static const GradMaker gGradMakers[] = { class ShaderTextGM : public GM { public: - ShaderTextGM() {} + ShaderTextGM() { + this->setBGColor(0xFFDDDDDD); + } protected: @@ -110,18 +119,12 @@ protected: return SkString("shadertext"); } - SkISize onISize() { return make_isize(950, 500); } - - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } + SkISize onISize() { return make_isize(1450, 500); } virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - const char text[] = "Shaded Text"; const int textLen = SK_ARRAY_COUNT(text) - 1; - const int pointSize = 48; + const int pointSize = 36; int w = pointSize * textLen; int h = pointSize; @@ -169,19 +172,34 @@ protected: canvas->save(); canvas->translate(SkIntToScalar(20), SkIntToScalar(10)); + SkPath path; + path.arcTo(SkRect::MakeXYWH(SkIntToScalar(-40), SkIntToScalar(15), + SkIntToScalar(300), SkIntToScalar(90)), + SkIntToScalar(225), SkIntToScalar(90), + false); + path.close(); + static const int testsPerCol = 8; static const int rowHeight = 60; static const int colWidth = 300; canvas->save(); for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) { canvas->save(); - canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth), - SkIntToScalar((s % testsPerCol) * rowHeight)); - paint.setShader(shaders[s])->ref(); + int i = 2*s; + canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth), + SkIntToScalar((i % testsPerCol) * rowHeight)); + paint.setShader(shaders[s])->unref(); canvas->drawText(text, textLen, 0, textBase, paint); canvas->restore(); + canvas->save(); + ++i; + canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth), + SkIntToScalar((i % testsPerCol) * rowHeight)); + canvas->drawTextOnPath(text, textLen, path, NULL, paint); + canvas->restore(); } canvas->restore(); + } private: diff --git a/gm/shadows.cpp b/gm/shadows.cpp index bba997f..d4dd72f 100644 --- a/gm/shadows.cpp +++ b/gm/shadows.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkBlurDrawLooper.h" @@ -21,6 +28,7 @@ public: SkRect fRect; ShadowsGM() { + this->setBGColor(0xFFDDDDDD); fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) ); fRect.set(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(30), SkIntToScalar(30)); @@ -35,13 +43,7 @@ protected: return make_isize(200, 80); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } - virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - SkBlurDrawLooper* shadowLoopers[5]; shadowLoopers[0] = new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5), diff --git a/gm/shapes.cpp b/gm/shapes.cpp index 5daea0a..0f46355 100644 --- a/gm/shapes.cpp +++ b/gm/shapes.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkPicture.h" #include "SkRectShape.h" @@ -43,6 +50,8 @@ class ShapesGM : public GM { SkMatrixRef* fMatrixRefs[4]; public: ShapesGM() { + this->setBGColor(0xFFDDDDDD); + SkMatrix m; fGroup.appendShape(make_shape0(false))->unref(); m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50)); @@ -76,13 +85,7 @@ protected: return make_isize(380, 480); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(0xFFDDDDDD); - } - virtual void onDraw(SkCanvas* canvas) { - this->drawBG(canvas); - SkMatrix matrix; SkGroupShape* gs = new SkGroupShape; @@ -95,16 +98,14 @@ protected: matrix.preScale(SK_Scalar1*2, SK_Scalar1*2); gs->appendShape(&fGroup, matrix); -#if 0 - canvas->drawShape(gs); -#else +#if 1 SkPicture* pict = new SkPicture; SkCanvas* cv = pict->beginRecording(1000, 1000); cv->scale(SK_ScalarHalf, SK_ScalarHalf); - cv->drawShape(gs); + gs->draw(cv); cv->translate(SkIntToScalar(680), SkIntToScalar(480)); cv->scale(-SK_Scalar1, SK_Scalar1); - cv->drawShape(gs); + gs->draw(cv); pict->endRecording(); canvas->drawPicture(*pict); pict->unref(); diff --git a/gm/strokefill.cpp b/gm/strokefill.cpp new file mode 100644 index 0000000..a37af80 --- /dev/null +++ b/gm/strokefill.cpp @@ -0,0 +1,81 @@ +/* + * 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 "SkTypeface.h" + +namespace skiagm { + +class StrokeFillGM : public GM { +public: + StrokeFillGM() { + + } + +protected: + virtual SkString onShortName() { + return SkString("stroke-fill"); + } + + virtual SkISize onISize() { + return make_isize(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) { + 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)); + + SkPath path; + path.setFillType(SkPath::kWinding_FillType); + path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction); + path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCCW_Direction); + canvas->drawPath(path, paint); + + SkPath path2; + path2.setFillType(SkPath::kWinding_FillType); + path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction); + path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCW_Direction); + canvas->drawPath(path2, paint); + + path2.reset(); + path2.addCircle(x + SkIntToScalar(240), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction); + canvas->drawPath(path2, paint); + SkASSERT(path2.cheapIsDirection(SkPath::kCCW_Direction)); + + path2.reset(); + SkASSERT(!path2.cheapComputeDirection(NULL)); + path2.addCircle(x + SkIntToScalar(360), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction); + SkASSERT(path2.cheapIsDirection(SkPath::kCW_Direction)); + canvas->drawPath(path2, paint); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new StrokeFillGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/strokerects.cpp b/gm/strokerects.cpp index 891b95a..92f2a18 100644 --- a/gm/strokerects.cpp +++ b/gm/strokerects.cpp @@ -1,20 +1,13 @@ -/* - Copyright 2011 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/* + * 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" @@ -45,14 +38,14 @@ protected: SkScalar y = rand.nextUScalar1() * H; SkScalar w = rand.nextUScalar1() * (W >> 2); SkScalar h = rand.nextUScalar1() * (H >> 2); + SkScalar hoffset = rand.nextSScalar1(); + SkScalar woffset = rand.nextSScalar1(); r->set(x, y, x + w, y + h); - r->offset(-w/2 + rand.nextSScalar1(), -h/2 + + rand.nextSScalar1()); + r->offset(-w/2 + woffset, -h/2 + hoffset); } virtual void onDraw(SkCanvas* canvas) { - canvas->drawColor(SK_ColorWHITE); - SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); diff --git a/gm/strokes.cpp b/gm/strokes.cpp new file mode 100644 index 0000000..ec265ad --- /dev/null +++ b/gm/strokes.cpp @@ -0,0 +1,149 @@ + +/* + * 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" + +namespace skiagm { + +#define W 400 +#define H 400 +#define N 50 + +static const SkScalar SW = SkIntToScalar(W); +static const SkScalar SH = SkIntToScalar(H); + +static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) { + SkScalar x = rand.nextUScalar1() * W; + SkScalar y = rand.nextUScalar1() * H; + SkScalar w = rand.nextUScalar1() * (W >> 2); + SkScalar h = rand.nextUScalar1() * (H >> 2); + SkScalar hoffset = rand.nextSScalar1(); + SkScalar woffset = rand.nextSScalar1(); + + r->set(x, y, x + w, y + h); + r->offset(-w/2 + woffset, -h/2 + hoffset); + + paint->setColor(rand.nextU()); + paint->setAlpha(0xFF); +} + + +class StrokesGM : public GM { +public: + StrokesGM() {} + +protected: + virtual SkString onShortName() { + return SkString("strokes_round"); + } + + virtual SkISize onISize() { + return make_isize(W, H*2); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(9)/2); + + for (int y = 0; y < 2; y++) { + paint.setAntiAlias(!!y); + SkAutoCanvasRestore acr(canvas, true); + canvas->translate(0, SH * y); + canvas->clipRect(SkRect::MakeLTRB( + SkIntToScalar(2), SkIntToScalar(2) + , SW - SkIntToScalar(2), SH - SkIntToScalar(2) + )); + + SkRandom rand; + for (int i = 0; i < N; i++) { + SkRect r; + rnd_rect(&r, &paint, rand); + canvas->drawOval(r, paint); + rnd_rect(&r, &paint, rand); + canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint); + rnd_rect(&r, &paint, rand); + } + } + } + +private: + typedef GM INHERITED; +}; + +class Strokes2GM : public GM { + SkPath fPath; +public: + Strokes2GM() { + SkRandom rand; + fPath.moveTo(0, 0); + for (int i = 0; i < 13; i++) { + SkScalar x = rand.nextUScalar1() * (W >> 1); + SkScalar y = rand.nextUScalar1() * (H >> 1); + fPath.lineTo(x, y); + } + } + +protected: + virtual SkString onShortName() { + return SkString("strokes_poly"); + } + + virtual SkISize onISize() { + return make_isize(W, H*2); + } + + static void rotate(SkScalar angle, SkScalar px, SkScalar py, SkCanvas* canvas) { + SkMatrix matrix; + matrix.setRotate(angle, px, py); + canvas->concat(matrix); + } + + virtual void onDraw(SkCanvas* canvas) { + canvas->drawColor(SK_ColorWHITE); + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(9)/2); + + for (int y = 0; y < 2; y++) { + paint.setAntiAlias(!!y); + SkAutoCanvasRestore acr(canvas, true); + canvas->translate(0, SH * y); + canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2), + SkIntToScalar(2), + SW - SkIntToScalar(2), + SH - SkIntToScalar(2))); + + SkRandom rand; + for (int i = 0; i < N/2; i++) { + SkRect r; + rnd_rect(&r, &paint, rand); + rotate(SkIntToScalar(15), SW/2, SH/2, canvas); + canvas->drawPath(fPath, paint); + } + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new StrokesGM; } +static GMRegistry reg(MyFactory); + +static GM* MyFactory2(void*) { return new Strokes2GM; } +static GMRegistry reg2(MyFactory2); + +} + diff --git a/gm/tablecolorfilter.cpp b/gm/tablecolorfilter.cpp new file mode 100644 index 0000000..df33337 --- /dev/null +++ b/gm/tablecolorfilter.cpp @@ -0,0 +1,139 @@ +/* + * 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 "SkGradientShader.h" +#include "SkTableColorFilter.h" + +static void make_bm0(SkBitmap* bm) { + int W = 120; + int H = 120; + bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); + bm->allocPixels(); + bm->eraseColor(0); + + SkCanvas canvas(*bm); + SkPaint paint; + SkPoint pts[] = { {0, 0}, {SkIntToScalar(W), SkIntToScalar(H)} }; + SkColor colors[] = { + SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN, + SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE + }; + SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + canvas.drawPaint(paint); +} +static void make_bm1(SkBitmap* bm) { + int W = 120; + int H = 120; + bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); + bm->allocPixels(); + bm->eraseColor(0); + + SkCanvas canvas(*bm); + SkPaint paint; + SkScalar cx = SkIntToScalar(W)/2; + SkScalar cy = SkIntToScalar(H)/2; + SkColor colors[] = { + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, + }; + SkShader* s = SkGradientShader::CreateRadial(SkPoint::Make(SkIntToScalar(W)/2, + SkIntToScalar(H)/2), + SkIntToScalar(W)/2, colors, NULL, SK_ARRAY_COUNT(colors), + SkShader::kClamp_TileMode); + paint.setShader(s)->unref(); + paint.setAntiAlias(true); + canvas.drawCircle(cx, cy, cx, paint); +} + +static void make_table0(uint8_t table[]) { + for (int i = 0; i < 256; ++i) { + int n = i >> 5; + table[i] = (n << 5) | (n << 2) | (n >> 1); + } +} +static void make_table1(uint8_t table[]) { + for (int i = 0; i < 256; ++i) { + table[i] = i * i / 255; + } +} +static void make_table2(uint8_t table[]) { + for (int i = 0; i < 256; ++i) { + float fi = i / 255.0f; + table[i] = sqrtf(fi) * 255; + } +} + +static SkColorFilter* make_cf0() { + uint8_t table[256]; make_table0(table); + return SkTableColorFilter::Create(table); +} +static SkColorFilter* make_cf1() { + uint8_t table[256]; make_table1(table); + return SkTableColorFilter::Create(table); +} +static SkColorFilter* make_cf2() { + uint8_t table[256]; make_table2(table); + return SkTableColorFilter::Create(table); +} +static SkColorFilter* make_cf3() { + uint8_t table0[256]; make_table0(table0); + uint8_t table1[256]; make_table1(table1); + uint8_t table2[256]; make_table2(table2); + return SkTableColorFilter::CreateARGB(NULL, table0, table1, table2); +} + +class TableColorFilterGM : public skiagm::GM { +public: + TableColorFilterGM() {} + +protected: + virtual SkString onShortName() { + return SkString("tablecolorfilter"); + } + + virtual SkISize onISize() { + return SkISize::Make(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) { + canvas->drawColor(0xFFDDDDDD); + canvas->translate(20, 20); + + SkScalar x = 0, y = 0; + + static void (*gMakers[])(SkBitmap*) = { make_bm0, make_bm1 }; + for (size_t maker = 0; maker < SK_ARRAY_COUNT(gMakers); ++maker) { + SkBitmap bm; + gMakers[maker](&bm); + + SkPaint paint; + x = 0; + canvas->drawBitmap(bm, x, y, &paint); + paint.setColorFilter(make_cf0())->unref(); x += bm.width() * 9 / 8; + canvas->drawBitmap(bm, x, y, &paint); + paint.setColorFilter(make_cf1())->unref(); x += bm.width() * 9 / 8; + canvas->drawBitmap(bm, x, y, &paint); + paint.setColorFilter(make_cf2())->unref(); x += bm.width() * 9 / 8; + canvas->drawBitmap(bm, x, y, &paint); + paint.setColorFilter(make_cf3())->unref(); x += bm.width() * 9 / 8; + canvas->drawBitmap(bm, x, y, &paint); + + y += bm.height() * 9 / 8; + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static skiagm::GM* MyFactory(void*) { return new TableColorFilterGM; } +static skiagm::GMRegistry reg(MyFactory); diff --git a/gm/testimagefilters.cpp b/gm/testimagefilters.cpp new file mode 100644 index 0000000..fc71d30 --- /dev/null +++ b/gm/testimagefilters.cpp @@ -0,0 +1,143 @@ +/* + * 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 "SkColorFilter.h" +#include "SkColorPriv.h" +#include "SkShader.h" + +#include "SkBlurImageFilter.h" +#include "SkTestImageFilters.h" + +#define FILTER_WIDTH SkIntToScalar(150) +#define FILTER_HEIGHT SkIntToScalar(200) + +static SkImageFilter* make0() { return new SkDownSampleImageFilter(SK_Scalar1 / 5); } +static SkImageFilter* make1() { return new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); } +static SkImageFilter* make2() { + SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorBLUE, + SkXfermode::kSrcIn_Mode); + SkAutoUnref aur(cf); + return new SkColorFilterImageFilter(cf); +} +static SkImageFilter* make3() { + return new SkBlurImageFilter(8, 0); +} + +static SkImageFilter* make4() { + SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); + SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5); + SkAutoUnref aur0(outer); + SkAutoUnref aur1(inner); + return new SkComposeImageFilter(outer, inner); +} +static SkImageFilter* make5() { + SkImageFilter* first = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); + SkImageFilter* second = new SkDownSampleImageFilter(SK_Scalar1 / 5); + SkAutoUnref aur0(first); + SkAutoUnref aur1(second); + return new SkMergeImageFilter(first, second); +} + +static SkImageFilter* make6() { + SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); + SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5); + SkAutoUnref aur0(outer); + SkAutoUnref aur1(inner); + SkImageFilter* compose = new SkComposeImageFilter(outer, inner); + SkAutoUnref aur2(compose); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF, + SkXfermode::kSrcIn_Mode); + SkAutoUnref aur3(cf); + SkImageFilter* blue = new SkColorFilterImageFilter(cf); + SkAutoUnref aur4(blue); + + return new SkMergeImageFilter(compose, blue); +} + +static SkImageFilter* make7() { + SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); + SkImageFilter* inner = make3(); + SkAutoUnref aur0(outer); + SkAutoUnref aur1(inner); + SkImageFilter* compose = new SkComposeImageFilter(outer, inner); + SkAutoUnref aur2(compose); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF, + SkXfermode::kSrcIn_Mode); + SkAutoUnref aur3(cf); + SkImageFilter* blue = new SkColorFilterImageFilter(cf); + SkAutoUnref aur4(blue); + + return new SkMergeImageFilter(compose, blue); +} + +static void draw0(SkCanvas* canvas) { + SkPaint p; + p.setAntiAlias(true); + SkRect r = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT); + r.inset(SK_Scalar1 * 12, SK_Scalar1 * 12); + p.setColor(SK_ColorRED); + canvas->drawOval(r, p); +} + +class TestImageFiltersGM : public skiagm::GM { +public: + TestImageFiltersGM () {} + +protected: + + virtual SkString onShortName() { + return SkString("testimagefilters"); + } + + virtual SkISize onISize() { return SkISize::Make(700, 460); } + + virtual void onDraw(SkCanvas* canvas) { +// this->drawSizeBounds(canvas, 0xFFCCCCCC); + + static SkImageFilter* (*gFilterProc[])() = { + make0, make1, make2, make3, make4, make5, make6, make7 + }; + + const SkRect bounds = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT); + + const SkScalar dx = bounds.width() * 8 / 7; + const SkScalar dy = bounds.height() * 8 / 7; + + canvas->translate(SkIntToScalar(8), SkIntToScalar(8)); + + for (size_t i = 0; i < SK_ARRAY_COUNT(gFilterProc); ++i) { + int ix = i % 4; + int iy = i / 4; + + SkAutoCanvasRestore acr(canvas, true); + canvas->translate(ix * dx, iy * dy); + + SkPaint p; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawRect(bounds, p); + + SkPaint paint; + paint.setImageFilter(gFilterProc[i]())->unref(); + canvas->saveLayer(&bounds, &paint); + draw0(canvas); + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static skiagm::GM* MyFactory(void*) { return new TestImageFiltersGM; } +static skiagm::GMRegistry reg(MyFactory); + + diff --git a/gm/texdata.cpp b/gm/texdata.cpp new file mode 100644 index 0000000..c68a16a --- /dev/null +++ b/gm/texdata.cpp @@ -0,0 +1,146 @@ + +/* + * 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 "GrContext.h" +#include "SkColorPriv.h" +#include "SkDevice.h" + +namespace skiagm { + +extern GrContext* GetGr(); + +static const int S = 200; + +class TexDataGM : public GM { +public: + TexDataGM() { + this->setBGColor(0xff000000); + } + +protected: + virtual SkString onShortName() { + return SkString("texdata"); + } + + virtual SkISize onISize() { + return make_isize(2*S, 2*S); + } + + virtual void onDraw(SkCanvas* canvas) { + SkDevice* device = canvas->getDevice(); + GrRenderTarget* target = (GrRenderTarget*) device->accessRenderTarget(); + GrContext* ctx = GetGr(); + if (ctx && target) { + SkPMColor gTextureData[(2 * S) * (2 * S)]; + static const int stride = 2 * S; + static const SkPMColor gray = SkPackARGB32(0x40, 0x40, 0x40, 0x40); + static const SkPMColor white = SkPackARGB32(0xff, 0xff, 0xff, 0xff); + static const SkPMColor red = SkPackARGB32(0x80, 0x80, 0x00, 0x00); + static const SkPMColor blue = SkPackARGB32(0x80, 0x00, 0x00, 0x80); + static const SkPMColor green = SkPackARGB32(0x80, 0x00, 0x80, 0x00); + static const SkPMColor black = SkPackARGB32(0x00, 0x00, 0x00, 0x00); + for (int i = 0; i < 2; ++i) { + int offset = 0; + // fill upper-left + for (int y = 0; y < S; ++y) { + for (int x = 0; x < S; ++x) { + gTextureData[offset + y * stride + x] = gray; + } + } + // fill upper-right + offset = S; + for (int y = 0; y < S; ++y) { + for (int x = 0; x < S; ++x) { + gTextureData[offset + y * stride + x] = white; + } + } + // fill lower left + offset = S * stride; + for (int y = 0; y < S; ++y) { + for (int x = 0; x < S; ++x) { + gTextureData[offset + y * stride + x] = black; + } + } + // fill lower right + offset = S * stride + S; + for (int y = 0; y < S; ++y) { + for (int x = 0; x < S; ++x) { + gTextureData[offset + y * stride + x] = gray; + } + } + + 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; + GrTexture* texture = + ctx->createUncachedTexture(desc, gTextureData, 0); + + if (!texture) { + return; + } + GrAutoUnref au(texture); + + ctx->setClip(GrRect::MakeWH(2*S, 2*S)); + ctx->setRenderTarget(target); + + GrPaint paint; + paint.reset(); + paint.fColor = 0xffffffff; + paint.fSrcBlendCoeff = kOne_BlendCoeff; + paint.fDstBlendCoeff = kISA_BlendCoeff; + GrMatrix vm; + if (i) { + vm.setRotate(90 * SK_Scalar1, + S * SK_Scalar1, + S * SK_Scalar1); + } else { + vm.reset(); + } + ctx->setMatrix(vm); + GrMatrix tm; + tm = vm; + GrMatrix* sampleMat = paint.textureSampler(0)->matrix(); + *sampleMat = vm; + sampleMat->postIDiv(2*S, 2*S); + paint.setTexture(0, texture); + + ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S)); + + // now update the lower right of the texture in first pass + // or upper right in second pass + offset = 0; + for (int y = 0; y < S; ++y) { + for (int x = 0; x < S; ++x) { + gTextureData[offset + y * stride + x] = + ((x + y) % 2) ? (i ? green : red) : blue; + } + } + texture->writePixels(S, (i ? 0 : S), S, S, + texture->config(), gTextureData, + 4 * stride); + ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S)); + } + } + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new TexDataGM; } +static GMRegistry reg(MyFactory); + +} + diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp index d836ea5..289caae 100644 --- a/gm/tilemodes.cpp +++ b/gm/tilemodes.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkPath.h" #include "SkRegion.h" @@ -73,12 +80,7 @@ protected: 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) }; diff --git a/gm/tinybitmap.cpp b/gm/tinybitmap.cpp new file mode 100644 index 0000000..d532b5b --- /dev/null +++ b/gm/tinybitmap.cpp @@ -0,0 +1,68 @@ + +/* + * 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 "SkColorPriv.h" +#include "SkShader.h" +#include "SkCanvas.h" +#include "SkUtils.h" + +namespace skiagm { + +static SkBitmap make_bitmap() { + SkBitmap bm; + + SkColorTable* ctable = new SkColorTable(1); + SkPMColor* c = ctable->lockColors(); + c[0] = SkPackARGB32(0x80, 0x80, 0, 0); + ctable->unlockColors(true); + + bm.setConfig(SkBitmap::kIndex8_Config, 1, 1); + bm.allocPixels(ctable); + ctable->unref(); + + bm.lockPixels(); + *bm.getAddr8(0, 0) = 0; + bm.unlockPixels(); + return bm; +} + +class TinyBitmapGM : public GM { + SkBitmap fBM; +public: + TinyBitmapGM() { + this->setBGColor(0xFFDDDDDD); + fBM = make_bitmap(); + } + +protected: + SkString onShortName() { + return SkString("tinybitmap"); + } + + virtual SkISize onISize() { return make_isize(100, 100); } + + virtual void onDraw(SkCanvas* canvas) { + SkShader* s = + SkShader::CreateBitmapShader(fBM, SkShader::kRepeat_TileMode, + SkShader::kMirror_TileMode); + SkPaint paint; + paint.setAlpha(0x80); + paint.setShader(s)->unref(); + canvas->drawPaint(paint); + } + +private: + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new TinyBitmapGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/verttext.cpp b/gm/verttext.cpp new file mode 100644 index 0000000..0f3cb3b --- /dev/null +++ b/gm/verttext.cpp @@ -0,0 +1,90 @@ +/* + * 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" + +namespace skiagm { + +#define TEXT_SIZE 48 +static const char gText[] = "Hello"; +static const size_t gLen = sizeof(gText) - 1; + +class VertTextGM : public GM { +public: + VertTextGM() {} + +protected: + + SkString onShortName() { + return SkString("verttext"); + } + + SkISize onISize() { return make_isize(640, 480); } + + static void drawBaseline(SkCanvas* canvas, const SkPaint& paint, + SkScalar x, SkScalar y) { + SkScalar total = paint.measureText(gText, gLen); + + SkPaint p; + p.setAntiAlias(true); + p.setColor(0x80FF0000); + canvas->drawLine(x, y, + paint.isVerticalText() ? x : x + total, + paint.isVerticalText() ? y + total : y, + p); + + p.setColor(0xFF0000FF); + SkScalar adv[gLen]; + paint.getTextWidths(gText, gLen, adv, NULL); + for (size_t i = 0; i < gLen; ++i) { + canvas->drawCircle(x, y, SK_Scalar1 * 3 / 2, p); + if (paint.isVerticalText()) { + y += adv[i]; + } else { + x += adv[i]; + } + } + canvas->drawCircle(x, y, SK_Scalar1 * 3 / 2, p); + } + + virtual void onDraw(SkCanvas* canvas) { + SkScalar x = SkIntToScalar(100); + SkScalar y = SkIntToScalar(50); + + for (int i = 0; i < 4; ++i) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTextSize(SkIntToScalar(TEXT_SIZE)); + + + paint.setVerticalText(false); + drawBaseline(canvas, paint, x, y); + canvas->drawText(gText, gLen, x, y, paint); + + paint.setVerticalText(true); + drawBaseline(canvas, paint, x, y); + canvas->drawText(gText, gLen, x, y, paint); + + x += SkIntToScalar(40); + y += SkIntToScalar(120); + + canvas->rotate(SkIntToScalar(-15)); + } + } + +private: + typedef GM INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new VertTextGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/verttext2.cpp b/gm/verttext2.cpp new file mode 100644 index 0000000..3bfb471 --- /dev/null +++ b/gm/verttext2.cpp @@ -0,0 +1,92 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +/* Tests text vertical text rendering with different fonts and centering. + */ + +#include "gm.h" +#include "SkCanvas.h" +#include "SkTypeface.h" + +namespace skiagm { + +class VertText2GM : public GM { +public: + VertText2GM() { + const int pointSize = 24; + textHeight = SkIntToScalar(pointSize); + prop = SkTypeface::CreateFromName("Helvetica", SkTypeface::kNormal); + mono = SkTypeface::CreateFromName("Courier New", SkTypeface::kNormal); + } + +protected: + + SkString onShortName() { + return SkString("verttext2"); + } + + SkISize onISize() { return make_isize(640, 480); } + + virtual void onDraw(SkCanvas* canvas) { + + for (int i = 0; i < 3; ++i) { + SkPaint paint; + paint.setColor(SK_ColorRED); + paint.setAntiAlias(true); + y = textHeight; + canvas->drawLine(0, SkIntToScalar(10), + SkIntToScalar(110), SkIntToScalar(10), paint); + canvas->drawLine(0, SkIntToScalar(240), + SkIntToScalar(110), SkIntToScalar(240), paint); + canvas->drawLine(0, SkIntToScalar(470), + SkIntToScalar(110), SkIntToScalar(470), paint); + drawText(canvas, SkString("Proportional / Top Aligned"), + prop, SkPaint::kLeft_Align); + drawText(canvas, SkString("< Proportional / Centered >"), + prop, SkPaint::kCenter_Align); + drawText(canvas, SkString("Monospaced / Top Aligned"), + mono, SkPaint::kLeft_Align); + drawText(canvas, SkString("< Monospaced / Centered >"), + mono, SkPaint::kCenter_Align); + canvas->rotate(SkIntToScalar(-15)); + canvas->translate(textHeight * 4, SkIntToScalar(50)); + if (i > 0) { + canvas->translate(0, SkIntToScalar(50)); + } + } + } + + void drawText(SkCanvas* canvas, const SkString& string, + SkTypeface* family, SkPaint::Align alignment) { + SkPaint paint; + paint.setColor(SK_ColorBLACK); + paint.setAntiAlias(true); + paint.setVerticalText(true); + paint.setTextAlign(alignment); + paint.setTypeface(family); + paint.setTextSize(textHeight); + + canvas->drawText(string.c_str(), string.size(), y, + alignment == SkPaint::kLeft_Align ? 10 : 240, paint); + y += textHeight; + } + +private: + typedef GM INHERITED; + SkScalar y, textHeight; + SkTypeface* prop; + SkTypeface* mono; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new VertText2GM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp index b8565a3..42b8a6a 100644 --- a/gm/xfermodes.cpp +++ b/gm/xfermodes.cpp @@ -1,3 +1,10 @@ + +/* + * 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 "SkBitmap.h" #include "SkShader.h" @@ -31,11 +38,10 @@ static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) { c.drawRect(r, p); } -static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF }; - class XfermodesGM : public GM { SkBitmap fBG; SkBitmap fSrcB, fDstB; + bool fOnce; void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha, SkScalar x, SkScalar y) { @@ -47,20 +53,25 @@ class XfermodesGM : public GM { canvas->drawBitmap(fDstB, x, y, &p); } + void init() { + if (!fOnce) { + // Do all this work in a temporary so we get a deep copy + uint16_t localData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF }; + SkBitmap scratchBitmap; + scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4); + scratchBitmap.setPixels(localData); + scratchBitmap.setIsOpaque(true); + scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config); + + make_bitmaps(W, H, &fSrcB, &fDstB); + fOnce = true; + } + } + public: const static int W = 64; const static int H = 64; - XfermodesGM() { - // Do all this work in a temporary so we get a deep copy, - // especially of gBG. - SkBitmap scratchBitmap; - scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4); - scratchBitmap.setPixels(gBG); - scratchBitmap.setIsOpaque(true); - scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config); - - make_bitmaps(W, H, &fSrcB, &fDstB); - } + XfermodesGM() : fOnce(false) {} protected: virtual SkString onShortName() { @@ -71,14 +82,10 @@ protected: return make_isize(790, 640); } - void drawBG(SkCanvas* canvas) { - canvas->drawColor(SK_ColorWHITE); - } - virtual void onDraw(SkCanvas* canvas) { - canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); + this->init(); - this->drawBG(canvas); + canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); const struct { SkXfermode::Mode fMode; |