/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm.h" #include "SkCanvas.h" #include "SkShader.h" #include "SkMaskFilter.h" namespace skiagm { /** * Simple MaskFilter that creates a screen door stipple pattern */ class SkStippleMaskFilter : public SkMaskFilter { public: SkStippleMaskFilter() : INHERITED() { } virtual ~SkStippleMaskFilter() { } virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint* margin) SK_OVERRIDE { if (src.fFormat != SkMask::kA8_Format) { return false; } dst->fBounds = src.fBounds; dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (NULL != src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(dstSize); uint8_t* srcScanLine = src.fImage; uint8_t* scanline = dst->fImage; for (int y = 0; y < src.fBounds.height(); ++y) { for (int x = 0; x < src.fBounds.width(); ++x) { SkASSERT(size_t(scanline - dst->fImage) < dstSize); scanline[x] = srcScanLine[x] && ((x+y) % 2) ? 0xFF : 0x00; } scanline += dst->fRowBytes; srcScanLine += src.fRowBytes; } } return true; } static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW(SkStippleMaskFilter); } virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {} // getFactory is from SkFlattenable virtual Factory getFactory() SK_OVERRIDE { return CreateProc; } // getFormat is from SkMaskFilter virtual SkMask::Format getFormat() SK_OVERRIDE { return SkMask::kA8_Format; } protected: private: typedef SkMaskFilter INHERITED; }; /** * Stress test the samplers by rendering a textured glyph with a mask and * an AA clip */ class SamplerStressGM : public GM { public: SamplerStressGM() : fTextureCreated(false) , fShader(NULL) , fMaskFilter(NULL) { } virtual ~SamplerStressGM() { } protected: virtual SkString onShortName() { return SkString("samplerstress"); } virtual SkISize onISize() { return make_isize(640, 480); } /** * Create a red & green stripes on black texture */ void createTexture() { if (fTextureCreated) { return; } static const int xSize = 16; static const int ySize = 16; fTexture.setConfig(SkBitmap::kARGB_8888_Config, xSize, ySize, xSize*sizeof(SkColor)); fTexture.allocPixels(); fTexture.lockPixels(); SkPMColor* addr = fTexture.getAddr32(0, 0); for (int y = 0; y < ySize; ++y) { for (int x = 0; x < xSize; ++x) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorBLACK); if ((y % 5) == 0) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorRED); } if ((x % 7) == 0) { addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorGREEN); } } } fTexture.unlockPixels(); fTextureCreated = true; } void createShader() { if (NULL != fShader.get()) { return; } createTexture(); fShader.reset(SkShader::CreateBitmapShader(fTexture, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); } void createMaskFilter() { if (NULL != fMaskFilter.get()) { return; } fMaskFilter.reset(SkNEW(SkStippleMaskFilter)); } virtual void onDraw(SkCanvas* canvas) { createShader(); createMaskFilter(); canvas->save(); // draw a letter "M" with a green & red striped texture and a // stipple mask with a round rect soft clip SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(72); paint.setShader(fShader.get()); paint.setMaskFilter(fMaskFilter.get()); SkRect temp; temp.set(SkIntToScalar(115), SkIntToScalar(75), SkIntToScalar(144), SkIntToScalar(110)); SkPath path; path.addRoundRect(temp, SkIntToScalar(5), SkIntToScalar(5)); canvas->clipPath(path, SkRegion::kReplace_Op, true); // AA is on canvas->drawText("M", 1, SkIntToScalar(100), SkIntToScalar(100), paint); canvas->restore(); // Now draw stroked versions of the "M" and the round rect so we can // see what is going on SkPaint paint2; paint2.setColor(SK_ColorBLACK); paint2.setAntiAlias(true); paint2.setTextSize(72); paint2.setStyle(SkPaint::kStroke_Style); paint2.setStrokeWidth(1); canvas->drawText("M", 1, SkIntToScalar(100), SkIntToScalar(100), paint2); paint2.setColor(SK_ColorGRAY); canvas->drawPath(path, paint2); } private: SkBitmap fTexture; bool fTextureCreated; SkAutoTUnref fShader; SkAutoTUnref fMaskFilter; typedef GM INHERITED; }; ////////////////////////////////////////////////////////////////////////////// static GM* MyFactory(void*) { return new SamplerStressGM; } static GMRegistry reg(MyFactory); }