diff options
35 files changed, 402 insertions, 303 deletions
diff --git a/gm/aaclip.cpp b/gm/aaclip.cpp index ec29a4f896..5742902f09 100644 --- a/gm/aaclip.cpp +++ b/gm/aaclip.cpp @@ -9,203 +9,11 @@ #include "SkCanvas.h" #include "SkPath.h" -static void test_quadstroke(SkCanvas* canvas) { - SkPath path; - path.moveTo(6, 0); - path.quadTo(150, 150, 0, 6); - - SkPaint paint; - - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - canvas->translate(20, 20); - -#if 1 - canvas->drawPath(path, paint); - canvas->translate(100, 0); -#endif - - paint.setStrokeWidth(1.01f); - canvas->drawPath(path, paint); -} - -static void draw_conic(SkCanvas* canvas, SkScalar weight, const SkPaint& paint) { - SkPath path; - path.moveTo(100, 100); - path.conicTo(300, 100, 300, 300, weight); - canvas->drawPath(path, paint); -} - -static void test_conic(SkCanvas* canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - - static const struct { - SkScalar fWeight; - SkColor fColor; - } gRec[] = { - { 2 , SK_ColorRED }, - { 1 , SK_ColorGREEN }, - { 0.5f, SK_ColorBLUE }, - }; - - for (SkScalar width = 0; width <= 20; width += 20) { - canvas->save(); - paint.setStrokeWidth(width); - for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { - paint.setColor(gRec[i].fColor); - draw_conic(canvas, gRec[i].fWeight, paint); - canvas->translate(-30, 30); - } - canvas->restore(); - canvas->translate(300, 0); - } -} - -#include "SkGradientShader.h" -static void test_shallow_gradient(SkCanvas* canvas, SkScalar width, SkScalar height) { - SkColor colors[] = { 0xFF7F7F7F, 0xFF7F7F7F, 0xFF000000 }; - SkScalar pos[] = { 0, 0.35f, SK_Scalar1 }; - SkPoint pts[] = { { 0, 0 }, { width, height } }; - SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, - SK_ARRAY_COUNT(colors), - SkShader::kClamp_TileMode); - SkPaint paint; - paint.setShader(s)->unref(); - canvas->drawPaint(paint); -} - -#include "SkDashPathEffect.h" -static void test_giant_dash(SkCanvas* canvas) { - SkPaint paint; - const SkScalar intervals[] = { SK_Scalar1, SK_Scalar1 }; - - paint.setStrokeWidth(2); - paint.setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref(); - - SkScalar big = 500 * 1000; - - canvas->drawLine(10, 10, big, 10, paint); - canvas->drawLine(-big, 20, 500, 20, paint); - canvas->drawLine(-big, 30, big, 30, paint); - - const SkScalar intervals2[] = { 20, 5, 10, 5 }; - paint.setPathEffect(new SkDashPathEffect(intervals2, 4, 17))->unref(); - - canvas->translate(0, 40); - SkScalar x = -500; - SkScalar width = 3173; - for (int i = 0; i < 40; ++i) { - if (i > 10) - canvas->drawLine(x, 0, x + width, 0, paint); - x += 1; - canvas->translate(0, 4); - } -} - - - -// Reproduces bug found here: http://jsfiddle.net/R8Cu5/1/ -// -#include "SkGradientShader.h" -static void test_grad(SkCanvas* canvas) { - SkPoint pts[] = { - { 478.544067f, -84.2041016f }, - { 602.455933f, 625.204102f }, - }; - SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, SK_ColorRED, SK_ColorRED }; - SkScalar pos[] = { 0, 0.3f, 0.3f, 1.0f }; - SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, 4, SkShader::kClamp_TileMode); - SkPaint p; - p.setShader(s)->unref(); - canvas->drawPaint(p); -} - -static SkCanvas* MakeCanvas(const SkIRect& bounds) { - SkBitmap bm; - bm.allocN32Pixels(bounds.width(), bounds.height()); - bm.eraseColor(SK_ColorTRANSPARENT); - - SkCanvas* canvas = new SkCanvas(bm); - canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop)); - return canvas; -} - -#ifdef SK_DEBUG -static void GetBitmap(const SkCanvas* canvas, SkBitmap* bm) { - *bm = canvas->getDevice()->accessBitmap(false); -} -#endif - -static void compare_canvas(const SkCanvas* a, const SkCanvas* b) { -#ifdef SK_DEBUG - SkBitmap bma, bmb; - GetBitmap(a, &bma); - GetBitmap(b, &bmb); - - SkASSERT(bma.width() == bmb.width()); - SkASSERT(bma.height() == bmb.height()); - - bma.lockPixels(); - bmb.lockPixels(); - for (int y = 0; y < bma.height(); ++y) { - const SkPMColor* rowa = bma.getAddr32(0, y); - const SkPMColor* rowb = bmb.getAddr32(0, y); - SkASSERT(!memcmp(rowa, rowb, bma.width() << 2)); - - for (int x = 1; x < bma.width() - 1; ++x) { - SkASSERT(0xFF000000 == rowa[x]); - SkASSERT(0xFF000000 == rowb[x]); - } - } -#endif -} - -static void drawRectAsPath(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { - SkPath path; - path.addRect(r); - canvas->drawPath(path, p); -} - -static void test_maskFromPath(const SkPath& path) { - SkIRect bounds; - path.getBounds().roundOut(&bounds); - - SkPaint paint; - paint.setAntiAlias(true); - - SkAutoTUnref<SkCanvas> path_canvas(MakeCanvas(bounds)); - path_canvas->drawPath(path, paint); - - SkAutoTUnref<SkCanvas> rect_canvas(MakeCanvas(bounds)); - drawRectAsPath(rect_canvas, path.getBounds(), paint); - - compare_canvas(path_canvas, rect_canvas); -} - -static void test_mask() { - for (int i = 1; i <= 20; ++i) { - const SkScalar dx = SK_Scalar1 / i; - const SkRect constr = SkRect::MakeWH(dx, SkIntToScalar(2)); - for (int n = 2; n < 20; ++n) { - SkPath path; - path.setFillType(SkPath::kEvenOdd_FillType); - SkRect r = constr; - while (r.fRight < SkIntToScalar(4)) { - path.addRect(r); - r.offset(dx, 0); - } - test_maskFromPath(path); - } - } -} - /** 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. */ -static void draw (SkCanvas* canvas, SkRect& target, int x, int y) { +static void draw(SkCanvas* canvas, SkRect& target, int x, int y) { SkPaint borderPaint; borderPaint.setColor(SkColorSetRGB(0x0, 0xDD, 0x0)); borderPaint.setAntiAlias(true); @@ -228,22 +36,22 @@ static void draw (SkCanvas* canvas, SkRect& target, int x, int y) { canvas->restore(); } -static void draw_square (SkCanvas* canvas, int x, int y) { +static void draw_square(SkCanvas* canvas, int x, int y) { SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 10 * SK_Scalar1)); draw(canvas, target, x, y); } -static void draw_column (SkCanvas* canvas, int x, int y) { +static void draw_column(SkCanvas* canvas, int x, int y) { SkRect target (SkRect::MakeWH(1 * SK_Scalar1, 10 * SK_Scalar1)); draw(canvas, target, x, y); } -static void draw_bar (SkCanvas* canvas, int x, int y) { +static void draw_bar(SkCanvas* canvas, int x, int y) { SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 1 * SK_Scalar1)); draw(canvas, target, x, y); } -static void draw_rect_tests (SkCanvas* canvas) { +static void draw_rect_tests(SkCanvas* canvas) { draw_square(canvas, 10, 10); draw_column(canvas, 30, 10); draw_bar(canvas, 10, 30); @@ -272,23 +80,6 @@ protected: } virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { - if (false) { test_quadstroke(canvas); return; } - if (false) { test_conic(canvas); return; } - if (false) { - SkRect bounds; - canvas->getClipBounds(&bounds); - test_shallow_gradient(canvas, bounds.width(), bounds.height()); return; - } - if (false) { - test_giant_dash(canvas); return; - } - if (false) { - test_grad(canvas); return; - } - if (false) { // avoid bit rot, suppress warning - test_mask(); - } - // Initial pixel-boundary-aligned draw draw_rect_tests(canvas); diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp index 928b4037c1..f210b4aa5e 100644 --- a/gm/bitmapcopy.cpp +++ b/gm/bitmapcopy.cpp @@ -62,14 +62,14 @@ protected: virtual void onDraw(SkCanvas* canvas) { SkPaint paint; - SkScalar horizMargin(SkIntToScalar(10)); - SkScalar vertMargin(SkIntToScalar(10)); + SkScalar horizMargin = 10; + SkScalar vertMargin = 10; - SkBitmapDevice devTmp(SkBitmap::kARGB_8888_Config, 40, 40, false); - SkCanvas canvasTmp(&devTmp); + SkBitmap src; + src.allocN32Pixels(40, 40); + SkCanvas canvasTmp(src); draw_checks(&canvasTmp, 40, 40); - SkBitmap src = canvasTmp.getTopDevice()->accessBitmap(false); for (unsigned i = 0; i < NUM_CONFIGS; ++i) { if (!src.deepCopyTo(&fDst[i], gConfigs[i])) { diff --git a/gm/bitmapsource.cpp b/gm/bitmapsource.cpp index 6d575eb72e..f40cc15e90 100644 --- a/gm/bitmapsource.cpp +++ b/gm/bitmapsource.cpp @@ -23,8 +23,7 @@ protected: void makeBitmap() { fBitmap.allocN32Pixels(100, 100); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); diff --git a/gm/deviceproperties.cpp b/gm/deviceproperties.cpp index 8c4649c372..20839463ad 100644 --- a/gm/deviceproperties.cpp +++ b/gm/deviceproperties.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ #include "gm.h" +#include "SkBitmapDevice.h" #include "SkTypeface.h" namespace skiagm { diff --git a/gm/displacement.cpp b/gm/displacement.cpp index ef6207a20d..b1f097b8bf 100644 --- a/gm/displacement.cpp +++ b/gm/displacement.cpp @@ -33,8 +33,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(80, 80); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); @@ -46,8 +45,7 @@ protected: void make_checkerboard(SkBitmap* bitmap, int w, int h) { bitmap->allocN32Pixels(w, h); - SkBitmapDevice device(*bitmap); - SkCanvas canvas(&device); + SkCanvas canvas(*bitmap); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF804020); diff --git a/gm/gammatext.cpp b/gm/gammatext.cpp index 99642f6e3e..7ee55db2fb 100644 --- a/gm/gammatext.cpp +++ b/gm/gammatext.cpp @@ -38,14 +38,14 @@ static bool setFont(SkPaint* paint, const char name[]) { #import <ApplicationServices/ApplicationServices.h> #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) -static CGContextRef makeCG(const SkBitmap& bm) { - if (SkBitmap::kARGB_8888_Config != bm.config() || - NULL == bm.getPixels()) { +static CGContextRef makeCG(const SkImageInfo& info, const void* addr, + size_t rowBytes) { + if (kPMColor_SkColorType != info.colorType() || NULL == addr) { return NULL; } CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGContextRef cg = CGBitmapContextCreate(bm.getPixels(), bm.width(), bm.height(), - 8, bm.rowBytes(), space, BITMAP_INFO_RGB); + CGContextRef cg = CGBitmapContextCreate((void*)addr, info.width(), info.height(), + 8, rowBytes, space, BITMAP_INFO_RGB); CFRelease(space); CGContextSetAllowsFontSubpixelQuantization(cg, false); @@ -143,7 +143,15 @@ protected: virtual void onDraw(SkCanvas* canvas) { #ifdef SK_BUILD_FOR_MAC - CGContextRef cg = makeCG(canvas->getDevice()->accessBitmap(false)); + CGContextRef cg = 0; + { + SkImageInfo info; + size_t rowBytes; + const void* addr = canvas->peekPixels(&info, &rowBytes); + if (addr) { + cg = makeCG(info, addr, rowBytes); + } + } #endif drawGrad(canvas); @@ -1,15 +1,14 @@ - /* * 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 "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkPaint.h" #include "SkSize.h" diff --git a/gm/imagefiltersclipped.cpp b/gm/imagefiltersclipped.cpp index 82873ab372..331ea49061 100644 --- a/gm/imagefiltersclipped.cpp +++ b/gm/imagefiltersclipped.cpp @@ -35,8 +35,7 @@ protected: void make_checkerboard() { fCheckerboard.allocN32Pixels(64, 64); - SkBitmapDevice device(fCheckerboard); - SkCanvas canvas(&device); + SkCanvas canvas(fCheckerboard); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF404040); @@ -58,10 +57,9 @@ protected: void make_gradient_circle(int width, int height) { SkScalar x = SkIntToScalar(width / 2); SkScalar y = SkIntToScalar(height / 2); - SkScalar radius = SkScalarMul(SkMinScalar(x, y), SkIntToScalar(4) / SkIntToScalar(5)); + SkScalar radius = SkMinScalar(x, y) * 0.8f; fGradientCircle.allocN32Pixels(width, height); - SkBitmapDevice device(fGradientCircle); - SkCanvas canvas(&device); + SkCanvas canvas(fGradientCircle); canvas.clear(0x00000000); SkColor colors[2]; colors[0] = SK_ColorWHITE; diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp index 6d5105e304..882918cb7b 100644 --- a/gm/imagefiltersgraph.cpp +++ b/gm/imagefiltersgraph.cpp @@ -8,6 +8,7 @@ #include "gm.h" #include "SkArithmeticMode.h" +#include "SkDevice.h" #include "SkBitmapSource.h" #include "SkBlurImageFilter.h" #include "SkColorFilter.h" @@ -93,8 +94,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(100, 100); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); diff --git a/gm/imagefiltersscaled.cpp b/gm/imagefiltersscaled.cpp index a9c4a10587..28b3c9f171 100644 --- a/gm/imagefiltersscaled.cpp +++ b/gm/imagefiltersscaled.cpp @@ -35,8 +35,7 @@ protected: void make_checkerboard() { fCheckerboard.allocN32Pixels(64, 64); - SkBitmapDevice device(fCheckerboard); - SkCanvas canvas(&device); + SkCanvas canvas(fCheckerboard); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF404040); @@ -60,8 +59,7 @@ protected: SkScalar y = SkIntToScalar(height / 2); SkScalar radius = SkScalarMul(SkMinScalar(x, y), SkIntToScalar(4) / SkIntToScalar(5)); fGradientCircle.allocN32Pixels(width, height); - SkBitmapDevice device(fGradientCircle); - SkCanvas canvas(&device); + SkCanvas canvas(fGradientCircle); canvas.clear(0x00000000); SkColor colors[2]; colors[0] = SK_ColorWHITE; diff --git a/gm/lighting.cpp b/gm/lighting.cpp index 1cab55377a..858976b90f 100644 --- a/gm/lighting.cpp +++ b/gm/lighting.cpp @@ -26,8 +26,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(100, 100); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); @@ -38,7 +37,7 @@ protected: } virtual SkISize onISize() { - return make_isize(WIDTH, HEIGHT); + return SkISize::Make(WIDTH, HEIGHT); } void drawClippedBitmap(SkCanvas* canvas, const SkPaint& paint, int x, int y) { diff --git a/gm/matrixconvolution.cpp b/gm/matrixconvolution.cpp index 47a3581b64..b986cc1fc0 100644 --- a/gm/matrixconvolution.cpp +++ b/gm/matrixconvolution.cpp @@ -25,8 +25,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(80, 80); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); diff --git a/gm/morphology.cpp b/gm/morphology.cpp index 5cfb1c2902..a2206b8f52 100644 --- a/gm/morphology.cpp +++ b/gm/morphology.cpp @@ -27,8 +27,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(135, 135); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x0); SkPaint paint; paint.setAntiAlias(true); diff --git a/gm/ninepatchstretch.cpp b/gm/ninepatchstretch.cpp index a14af00a4e..74cc87f305 100644 --- a/gm/ninepatchstretch.cpp +++ b/gm/ninepatchstretch.cpp @@ -13,10 +13,7 @@ static void make_bitmap(SkBitmap* bitmap, SkIRect* center) { const int kSize = 2*kFixed + kStretchy; bitmap->allocN32Pixels(kSize, kSize); - SkBaseDevice* dev = new SkBitmapDevice(*bitmap); - - SkCanvas canvas(dev); - dev->unref(); + SkCanvas canvas(*bitmap); canvas.clear(SK_ColorTRANSPARENT); SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize)); diff --git a/gm/offsetimagefilter.cpp b/gm/offsetimagefilter.cpp index 1b76ba2bc9..0425311b0a 100644 --- a/gm/offsetimagefilter.cpp +++ b/gm/offsetimagefilter.cpp @@ -28,8 +28,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(80, 80); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); @@ -40,10 +39,8 @@ protected: } void make_checkerboard() { - fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config, 80, 80); - fCheckerboard.allocPixels(); - SkBitmapDevice device(fCheckerboard); - SkCanvas canvas(&device); + fCheckerboard.allocN32Pixels(80, 80); + SkCanvas canvas(fCheckerboard); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF404040); diff --git a/gm/peekpixels.cpp b/gm/peekpixels.cpp new file mode 100644 index 0000000000..c6744d3abe --- /dev/null +++ b/gm/peekpixels.cpp @@ -0,0 +1,78 @@ +/* + * 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 "SkSurface.h" +#include "SkPicture.h" + +static void draw_content(SkCanvas* canvas) { + SkImageInfo info = canvas->imageInfo(); + SkPaint paint; + paint.setAntiAlias(true); + canvas->drawCircle(SkScalarHalf(info.width()), SkScalarHalf(info.height()), + SkScalarHalf(info.width()), paint); +} + +class PeekPixelsGM : public skiagm::GM { +public: + PeekPixelsGM() {} + +protected: + virtual SkString onShortName() SK_OVERRIDE { + return SkString("peekpixels"); + } + + virtual SkISize onISize() SK_OVERRIDE { + return SkISize::Make(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { + SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); + SkAutoTUnref<SkSurface> surface(canvas->newSurface(info)); + if (surface.get()) { + SkCanvas* surfCanvas = surface->getCanvas(); + + draw_content(surfCanvas); + SkBitmap bitmap; + + // test peekPixels + { + SkImageInfo info; + size_t rowBytes; + const void* addr = surfCanvas->peekPixels(&info, &rowBytes); + if (addr && bitmap.installPixels(info, const_cast<void*>(addr), + rowBytes, NULL, NULL)) { + canvas->drawBitmap(bitmap, 0, 0, NULL); + } + } + + // test ROCanvasPixels + canvas->translate(120, 0); + SkAutoROCanvasPixels ropixels(surfCanvas); + if (ropixels.asROBitmap(&bitmap)) { + canvas->drawBitmap(bitmap, 0, 0, NULL); + } + + // test Surface + canvas->translate(120, 0); + surface->draw(canvas, 0, 0, NULL); + } + } + + virtual uint32_t onGetFlags() const { + // we explicitly test peekPixels and readPixels, neither of which + // return something for a picture-backed canvas, so we skip that test. + return kSkipPicture_Flag; + } + +private: + typedef skiagm::GM INHERITED; +}; + +DEF_GM( return SkNEW(PeekPixelsGM); ) diff --git a/gm/tileimagefilter.cpp b/gm/tileimagefilter.cpp index d0acad7e69..319aa3c9fa 100644 --- a/gm/tileimagefilter.cpp +++ b/gm/tileimagefilter.cpp @@ -28,8 +28,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(80, 80); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0xFF000000); SkPaint paint; paint.setAntiAlias(true); @@ -41,8 +40,7 @@ protected: void make_checkerboard() { fCheckerboard.allocN32Pixels(80, 80); - SkBitmapDevice device(fCheckerboard); - SkCanvas canvas(&device); + SkCanvas canvas(fCheckerboard); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF404040); diff --git a/gm/xfermodeimagefilter.cpp b/gm/xfermodeimagefilter.cpp index f843d40dae..4469618717 100644 --- a/gm/xfermodeimagefilter.cpp +++ b/gm/xfermodeimagefilter.cpp @@ -30,8 +30,7 @@ protected: void make_bitmap() { fBitmap.allocN32Pixels(80, 80); - SkBitmapDevice device(fBitmap); - SkCanvas canvas(&device); + SkCanvas canvas(fBitmap); canvas.clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); @@ -43,8 +42,7 @@ protected: void make_checkerboard() { fCheckerboard.allocN32Pixels(80, 80); - SkBitmapDevice device(fCheckerboard); - SkCanvas canvas(&device); + SkCanvas canvas(fCheckerboard); canvas.clear(0x00000000); SkPaint darkPaint; darkPaint.setColor(0xFF404040); diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index ca3a7f6e66..e95f59b34c 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -121,6 +121,7 @@ '../gm/pathopsinverse.cpp', '../gm/pathopsskpclip.cpp', '../gm/pathreverse.cpp', + '../gm/peekpixels.cpp', '../gm/perlinnoise.cpp', '../gm/pictureimagefilter.cpp', '../gm/points.cpp', diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 42ef8778bf..b6851def98 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -897,4 +897,11 @@ inline SkPMColor SkBitmap::getIndex8Color(int x, int y) const { return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)]; } +/////////////////////////////////////////////////////////////////////////////// +// +// Helpers until we can fully deprecate SkBitmap::Config +// +extern SkBitmap::Config SkColorTypeToBitmapConfig(SkColorType); +extern SkColorType SkBitmapConfigToColorType(SkBitmap::Config); + #endif diff --git a/include/core/SkBitmapDevice.h b/include/core/SkBitmapDevice.h index e4f9b88a5e..be98c95882 100644 --- a/include/core/SkBitmapDevice.h +++ b/include/core/SkBitmapDevice.h @@ -82,6 +82,8 @@ public: */ virtual SkBitmap::Config config() const SK_OVERRIDE { return fBitmap.config(); } + virtual SkImageInfo imageInfo() const SK_OVERRIDE; + /** * DEPRECATED: This will be made protected once WebKit stops using it. * Instead use Canvas' writePixels method. @@ -278,6 +280,7 @@ private: virtual void flush() SK_OVERRIDE {} virtual SkSurface* newSurface(const SkImageInfo&) SK_OVERRIDE; + virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes) SK_OVERRIDE; SkBitmap fBitmap; diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 7235efb2f0..971e4402d8 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -76,6 +76,12 @@ public: SkMetaData& getMetaData(); + /** + * Return ImageInfo for this canvas. If the canvas is not backed by pixels + * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. + */ + SkImageInfo imageInfo() const; + /////////////////////////////////////////////////////////////////////////// /** @@ -84,16 +90,19 @@ public: void flush(); /** + * DEPRECATED: call imageInfo() instead. * Return the width/height of the underlying device. The current drawable * area may be small (due to clipping or saveLayer). For a canvas with * no device, 0,0 will be returned. */ SkISize getDeviceSize() const; - /** Return the canvas' device object, which may be null. The device holds - the bitmap of the pixels that the canvas draws into. The reference count - of the returned device is not changed by this call. - */ + /** + * DEPRECATED. + * Return the canvas' device object, which may be null. The device holds + * the bitmap of the pixels that the canvas draws into. The reference count + * of the returned device is not changed by this call. + */ SkBaseDevice* getDevice() const; /** @@ -126,6 +135,20 @@ public: /////////////////////////////////////////////////////////////////////////// /** + * If the canvas has pixels (and is not recording to a picture or other + * non-raster target) and has direct access to its pixels (i.e. they are in + * local RAM) return the const-address of those pixels, and if not null, + * return the ImageInfo and rowBytes. The returned address is only valid + * while the canvas object is in scope and unchanged. Any API calls made on + * canvas (or its parent surface if any) will invalidate the + * returned address (and associated information). + * + * On failure, returns NULL and the info and rowBytes parameters are + * ignored. + */ + const void* peekPixels(SkImageInfo* info, size_t* rowBytes); + + /** * This enum can be used with read/writePixels to perform a pixel ops to or * from an 8888 config other than Skia's native config (SkPMColor). There * are three byte orders supported: native, BGRA, and RGBA. Each has a @@ -1019,6 +1042,9 @@ protected: // default impl defers to getDevice()->newSurface(info) virtual SkSurface* onNewSurface(const SkImageInfo&); + // default impl defers to its device + virtual const void* onPeekPixels(SkImageInfo*, size_t* rowBytes); + // Returns the canvas to be used by DrawIter. Default implementation // returns this. Subclasses that encapsulate an indirect canvas may // need to overload this method. The impl must keep track of this, as it @@ -1206,4 +1232,47 @@ private: }; #define SkAutoCommentBlock(...) SK_REQUIRE_LOCAL_VAR(SkAutoCommentBlock) +/** + * If the caller wants read-only access to the pixels in a canvas, it can just + * call canvas->peekPixels(), since that is the fastest way to "peek" at the + * pixels on a raster-backed canvas. + * + * If the canvas has pixels, but they are not readily available to the CPU + * (e.g. gpu-backed), then peekPixels() will fail, but readPixels() will + * succeed (though be slower, since it will return a copy of the pixels). + * + * SkAutoROCanvasPixels encapsulates these two techniques, trying first to call + * peekPixels() (for performance), but if that fails, calling readPixels() and + * storing the copy locally. + * + * The caller must respect the restrictions associated with peekPixels(), since + * that may have been called: The returned information is invalidated if... + * - any API is called on the canvas (or its parent surface if present) + * - the canvas goes out of scope + */ +class SkAutoROCanvasPixels : SkNoncopyable { +public: + SkAutoROCanvasPixels(SkCanvas* canvas); + + // returns NULL on failure + const void* addr() const { return fAddr; } + + // undefined if addr() == NULL + size_t rowBytes() const { return fRowBytes; } + + // undefined if addr() == NULL + const SkImageInfo& info() const { return fInfo; } + + // helper that, if returns true, installs the pixels into the bitmap. Note + // that the bitmap may reference the address returned by peekPixels(), so + // the caller must respect the restrictions associated with peekPixels(). + bool asROBitmap(SkBitmap*) const; + +private: + SkBitmap fBitmap; // used if peekPixels() fails + const void* fAddr; // NULL on failure + SkImageInfo fInfo; + size_t fRowBytes; +}; + #endif diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 016e2babc8..e3a23be6ca 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -77,6 +77,12 @@ public: } /** + * Return ImageInfo for this device. If the canvas is not backed by pixels + * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. + */ + virtual SkImageInfo imageInfo() const; + + /** * Return the bounds of the device in the coordinate space of the root * canvas. The root device will have its top-left at 0,0, but other devices * such as those associated with saveLayer may have a non-zero origin. @@ -369,7 +375,10 @@ protected: protected: // default impl returns NULL virtual SkSurface* newSurface(const SkImageInfo&); - + + // default impl returns NULL + virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes); + /** * Leaky properties are those which the device should be applying but it isn't. * These properties will be applied by the draw, when and as it can. diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h index 2f277b755d..74c5f083f4 100644 --- a/include/core/SkSurface.h +++ b/include/core/SkSurface.h @@ -151,6 +151,18 @@ public: */ void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); + /** + * If the surface has direct access to its pixels (i.e. they are in local + * RAM) return the const-address of those pixels, and if not null, return + * the ImageInfo and rowBytes. The returned address is only valid while + * the surface object is in scope, and no API call is made on the surface + * or its canvas. + * + * On failure, returns NULL and the info and rowBytes parameters are + * ignored. + */ + const void* peekPixels(SkImageInfo* info, size_t* rowBytes); + protected: SkSurface(int width, int height); SkSurface(const SkImageInfo&); diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 53e15a5fdf..15e56a3bb6 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -1128,8 +1128,9 @@ void SampleWindow::listTitles() { static SkBitmap capture_bitmap(SkCanvas* canvas) { SkBitmap bm; - const SkBitmap& src = canvas->getDevice()->accessBitmap(false); - src.copyTo(&bm, src.config()); + if (bm.allocPixels(canvas->imageInfo())) { + canvas->readPixels(&bm, 0, 0); + } return bm; } diff --git a/samplecode/SampleCircle.cpp b/samplecode/SampleCircle.cpp index b101a1f257..9cc927e47d 100644 --- a/samplecode/SampleCircle.cpp +++ b/samplecode/SampleCircle.cpp @@ -71,12 +71,6 @@ protected: } } - static void blowup(SkCanvas* canvas, const SkIRect& src, const SkRect& dst) { - SkBaseDevice* device = canvas->getDevice(); - const SkBitmap& bm = device->accessBitmap(false); - canvas->drawBitmapRect(bm, &src, dst, NULL); - } - static void make_poly(SkPath* path, int n) { if (n <= 0) { return; diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp index 483943d5d4..bc8b8730bb 100644 --- a/samplecode/SampleLayers.cpp +++ b/samplecode/SampleLayers.cpp @@ -42,10 +42,10 @@ static void dump_layers(const char label[], SkCanvas* canvas) { SkCanvas::LayerIter iter(canvas, true); int index = 0; while (!iter.done()) { - const SkBitmap& bm = iter.device()->accessBitmap(false); + SkImageInfo info = iter.device()->imageInfo(); const SkIRect& clip = iter.clip().getBounds(); SkDebugf("Layer[%d] bitmap [%d %d] X=%d Y=%d clip=[%d %d %d %d] alpha=%d\n", index++, - bm.width(), bm.height(), iter.x(), iter.y(), + info.width(), info.height(), iter.x(), iter.y(), clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, iter.paint().getAlpha()); iter.next(); diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 9dde6e172e..374bef98c1 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -54,6 +54,10 @@ SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, b SkBitmapDevice::~SkBitmapDevice() { } +SkImageInfo SkBitmapDevice::imageInfo() const { + return fBitmap.info(); +} + void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { SkASSERT(bm.width() == fBitmap.width()); SkASSERT(bm.height() == fBitmap.height()); @@ -386,6 +390,16 @@ SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) { return SkSurface::NewRaster(info); } +const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) { + if (fBitmap.getPixels() && fBitmap.asImageInfo(info)) { + if (rowBytes) { + *rowBytes = fBitmap.rowBytes(); + } + return fBitmap.getPixels(); + } + return NULL; +} + /////////////////////////////////////////////////////////////////////////////// bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index ed8274dc5d..f5e91ffc43 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -992,6 +992,55 @@ SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { return dev ? dev->newSurface(info) : NULL; } +SkImageInfo SkCanvas::imageInfo() const { + SkBaseDevice* dev = this->getDevice(); + if (dev) { + return dev->imageInfo(); + } else { + // TODO: need a real unknown for alphatype it seems. + SkAlphaType unknownAlphaType = kIgnore_SkAlphaType; + return SkImageInfo::Make(0, 0, kUnknown_SkColorType, unknownAlphaType); + } +} + +const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { + return this->onPeekPixels(info, rowBytes); +} + +const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { + SkBaseDevice* dev = this->getDevice(); + return dev ? dev->peekPixels(info, rowBytes) : NULL; +} + +SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { + fAddr = canvas->peekPixels(&fInfo, &fRowBytes); + if (NULL == fAddr) { + fInfo = canvas->imageInfo(); + if (kUnknown_SkColorType == fInfo.colorType() || + !fBitmap.allocPixels(fInfo)) + { + return; // failure, fAddr is NULL + } + fBitmap.lockPixels(); + if (!canvas->readPixels(&fBitmap, 0, 0)) { + return; // failure, fAddr is NULL + } + fAddr = fBitmap.getPixels(); + fRowBytes = fBitmap.rowBytes(); + } + SkASSERT(fAddr); // success +} + +bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { + if (fAddr) { + return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, + NULL, NULL); + } else { + bitmap->reset(); + return false; + } +} + ///////////////////////////////////////////////////////////////////////////// void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 9ce8b6b5df..364b106dd8 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -65,6 +65,12 @@ SkMetaData& SkBaseDevice::getMetaData() { return *fMetaData; } +// TODO: should make this guy pure-virtual. +SkImageInfo SkBaseDevice::imageInfo() const { + return SkImageInfo::Make(this->width(), this->height(), + kUnknown_SkColorType, kIgnore_SkAlphaType); +} + const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { const SkBitmap& bitmap = this->onAccessBitmap(); if (changePixels) { @@ -117,3 +123,5 @@ bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y, } SkSurface* SkBaseDevice::newSurface(const SkImageInfo&) { return NULL; } + +const void* SkBaseDevice::peekPixels(SkImageInfo*, size_t*) { return NULL; } diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index 0df120b31a..eaa5e73008 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -221,6 +221,9 @@ public: protected: virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE; + const void* onPeekPixels(SkImageInfo*, size_t*) SK_OVERRIDE { + return NULL; + } // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been // tweaked by paint.computeFastBounds(). diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h index 8883e2c070..bf28f598c5 100644 --- a/src/image/SkImagePriv.h +++ b/src/image/SkImagePriv.h @@ -14,8 +14,6 @@ class SkPicture; extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo&); -extern SkBitmap::Config SkColorTypeToBitmapConfig(SkColorType); -extern SkColorType SkBitmapConfigToColorType(SkBitmap::Config); // Call this if you explicitly want to use/share this pixelRef in the image extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*, diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp index cb029c8aea..4b5fb68134 100644 --- a/src/image/SkSurface.cpp +++ b/src/image/SkSurface.cpp @@ -121,3 +121,8 @@ void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) { return asSB(this)->onDraw(canvas, x, y, paint); } + +const void* SkSurface::peekPixels(SkImageInfo* info, size_t* rowBytes) { + return this->getCanvas()->peekPixels(info, rowBytes); +} + diff --git a/tests/SkpSkGrTest.cpp b/tests/SkpSkGrTest.cpp index 02aabbe2af..d1d38dfe8e 100644 --- a/tests/SkpSkGrTest.cpp +++ b/tests/SkpSkGrTest.cpp @@ -453,7 +453,11 @@ void TestResult::testOne() { SkGpuDevice grDevice(context, texture.get()); SkCanvas grCanvas(&grDevice); drawPict(pic, &grCanvas, fScaleOversized ? scale : 1); - const SkBitmap& grBitmap = grDevice.accessBitmap(false); + + SkBitmap grBitmap; + grBitmap.allocPixels(grCanvas.imageInfo()); + grCanvas.readPixels(&grBitmap, 0, 0); + if (fTestStep == kCompareBits) { fPixelError = similarBits(grBitmap, bitmap); int skTime = timePict(pic, &skCanvas); diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp index aa457c7dcc..fcd0986460 100644 --- a/tests/SurfaceTest.cpp +++ b/tests/SurfaceTest.cpp @@ -22,27 +22,37 @@ class GrContext; enum SurfaceType { kRaster_SurfaceType, + kRasterDirect_SurfaceType, kGpu_SurfaceType, kPicture_SurfaceType }; -static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context) { - static const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); +static const int gSurfaceSize = 10; +static SkPMColor gSurfaceStorage[gSurfaceSize * gSurfaceSize]; + +static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context, + SkImageInfo* requestedInfo = NULL) { + static const SkImageInfo info = SkImageInfo::MakeN32Premul(gSurfaceSize, + gSurfaceSize); + + if (requestedInfo) { + *requestedInfo = info; + } switch (surfaceType) { - case kRaster_SurfaceType: - return SkSurface::NewRaster(info); - case kGpu_SurfaceType: + case kRaster_SurfaceType: + return SkSurface::NewRaster(info); + case kRasterDirect_SurfaceType: + return SkSurface::NewRasterDirect(info, gSurfaceStorage, + info.minRowBytes()); + case kGpu_SurfaceType: #if SK_SUPPORT_GPU - SkASSERT(NULL != context); - return SkSurface::NewRenderTarget(context, info); -#else - SkASSERT(0); + return context ? SkSurface::NewRenderTarget(context, info) : NULL; #endif - case kPicture_SurfaceType: - return SkSurface::NewPicture(info.fWidth, info.fHeight); + break; + case kPicture_SurfaceType: + return SkSurface::NewPicture(info.fWidth, info.fHeight); } - SkASSERT(0); return NULL; } @@ -117,14 +127,14 @@ static void test_imagepeek(skiatest::Reporter* reporter) { { kPicture_ImageType, false }, { kCodec_ImageType, false }, }; - + const SkColor color = SK_ColorRED; const SkPMColor pmcolor = SkPreMultiplyColor(color); - + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { SkImageInfo info; size_t rowBytes; - + SkAutoTUnref<SkImage> image(createImage(gRec[i].fType, NULL, color)); if (!image.get()) { continue; // gpu may not be enabled @@ -137,13 +147,65 @@ static void test_imagepeek(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, 10 == info.fHeight); REPORTER_ASSERT(reporter, kPMColor_SkColorType == info.fColorType); REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.fAlphaType || - kOpaque_SkAlphaType == info.fAlphaType); + kOpaque_SkAlphaType == info.fAlphaType); REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); } } } +static void test_canvaspeek(skiatest::Reporter* reporter, + GrContextFactory* factory) { + static const struct { + SurfaceType fType; + bool fPeekShouldSucceed; + } gRec[] = { + { kRaster_SurfaceType, true }, + { kRasterDirect_SurfaceType, true }, +#if SK_SUPPORT_GPU + { kGpu_SurfaceType, false }, +#endif + { kPicture_SurfaceType, false }, + }; + + const SkColor color = SK_ColorRED; + const SkPMColor pmcolor = SkPreMultiplyColor(color); + + GrContext* context = NULL; +#if SK_SUPPORT_GPU + context = factory->get(GrContextFactory::kNative_GLContextType); +#endif + + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { + SkImageInfo info, requestInfo; + size_t rowBytes; + + SkAutoTUnref<SkSurface> surface(createSurface(gRec[i].fType, context, + &requestInfo)); + surface->getCanvas()->clear(color); + + const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes); + bool success = (NULL != addr); + REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); + + SkImageInfo info2; + size_t rb2; + const void* addr2 = surface->peekPixels(&info2, &rb2); + + if (success) { + REPORTER_ASSERT(reporter, requestInfo == info); + REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes); + REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); + + REPORTER_ASSERT(reporter, addr2 == addr); + REPORTER_ASSERT(reporter, info2 == info); + REPORTER_ASSERT(reporter, rb2 == rowBytes); + } else { + REPORTER_ASSERT(reporter, NULL == addr2); + } + } +} + static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType, GrContext* context) { // Verify that the right canvas commands trigger a copy on write @@ -335,7 +397,10 @@ DEF_GPUTEST(Surface, reporter, factory) { TestSurfaceWritableAfterSnapshotRelease(reporter, kPicture_SurfaceType, NULL); TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); + test_imagepeek(reporter); + test_canvaspeek(reporter, factory); + #if SK_SUPPORT_GPU TestGetTexture(reporter, kRaster_SurfaceType, NULL); TestGetTexture(reporter, kPicture_SurfaceType, NULL); |