blob: 64abeeccddba3e4b05bd83151cbaaa48d2ee723c [file] [log] [blame]
robertphillips@google.comd9d53852012-05-02 13:55:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
9#include "SkCanvas.h"
10#include "SkShader.h"
11#include "SkMaskFilter.h"
12
13namespace skiagm {
14
15
16/**
17 * Simple MaskFilter that creates a screen door stipple pattern
18 */
19class SkStippleMaskFilter : public SkMaskFilter {
20public:
21 SkStippleMaskFilter() : INHERITED() {
22 }
23
24 virtual ~SkStippleMaskFilter() {
25 }
26
27 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
28 SkIPoint* margin) SK_OVERRIDE {
29
30 if (src.fFormat != SkMask::kA8_Format) {
31 return false;
32 }
33
34 dst->fBounds = src.fBounds;
35 dst->fRowBytes = dst->fBounds.width();
36 dst->fFormat = SkMask::kA8_Format;
37 dst->fImage = NULL;
38
39 if (NULL != src.fImage) {
40 size_t dstSize = dst->computeImageSize();
41 if (0 == dstSize) {
42 return false; // too big to allocate, abort
43 }
44
45 dst->fImage = SkMask::AllocImage(dstSize);
46
47 uint8_t* srcScanLine = src.fImage;
48 uint8_t* scanline = dst->fImage;
49
50 for (int y = 0; y < src.fBounds.height(); ++y) {
51 for (int x = 0; x < src.fBounds.width(); ++x) {
52 SkASSERT(unsigned int(scanline - dst->fImage) < dstSize);
53 scanline[x] = srcScanLine[x] && ((x+y) % 2) ? 0xFF : 0x00;
54 }
55 scanline += dst->fRowBytes;
56 srcScanLine += src.fRowBytes;
57 }
58 }
59
60 return true;
61 }
62
63 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
64 return SkNEW(SkStippleMaskFilter);
65 }
66
67 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {}
68
69 // getFactory is from SkFlattenable
70 virtual Factory getFactory() SK_OVERRIDE {
71 return CreateProc;
72 }
73
74 // getFormat is from SkMaskFilter
75 virtual SkMask::Format getFormat() SK_OVERRIDE {
76 return SkMask::kA8_Format;
77 }
78protected:
79
80private:
81 typedef SkMaskFilter INHERITED;
82};
83
84/**
85 * Stress test the samplers by rendering a textured glyph with a mask and
86 * an AA clip
87 */
88class SamplerStressGM : public GM {
89public:
90 SamplerStressGM()
91 : fTextureCreated(false)
92 , fShader(NULL)
93 , fMaskFilter(NULL) {
94 }
95
96 virtual ~SamplerStressGM() {
97 }
98
99protected:
100 virtual SkString onShortName() {
101 return SkString("samplerstress");
102 }
103
104 virtual SkISize onISize() {
105 return make_isize(640, 480);
106 }
107
108 /**
109 * Create a red & green stripes on black texture
110 */
111 void createTexture() {
112 if (fTextureCreated) {
113 return;
114 }
115
116 static const int xSize = 16;
117 static const int ySize = 16;
118
119 fTexture.setConfig(SkBitmap::kARGB_8888_Config,
120 xSize,
121 ySize,
122 xSize*sizeof(SkColor));
123
124 fTexture.allocPixels();
125 fTexture.lockPixels();
126 SkPMColor* addr = fTexture.getAddr32(0, 0);
127
128 for (int y = 0; y < ySize; ++y) {
129 for (int x = 0; x < xSize; ++x) {
130 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorBLACK);
131
132 if ((y % 5) == 0) {
133 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorRED);
134 }
135 if ((x % 7) == 0) {
136 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorGREEN);
137 }
138 }
139 }
140
141 fTexture.unlockPixels();
142
143 fTextureCreated = true;
144 }
145
146 void createShader() {
147 if (NULL != fShader.get()) {
148 return;
149 }
150
151 createTexture();
152
153 fShader.reset(SkShader::CreateBitmapShader(fTexture,
154 SkShader::kRepeat_TileMode,
155 SkShader::kRepeat_TileMode));
156 }
157
158 void createMaskFilter() {
159 if (NULL != fMaskFilter.get()) {
160 return;
161 }
162
163 fMaskFilter.reset(SkNEW(SkStippleMaskFilter));
164 }
165
166 virtual void onDraw(SkCanvas* canvas) {
167
168 createShader();
169 createMaskFilter();
170
171 canvas->save();
172
173 // draw a letter "M" with a green & red striped texture and a
174 // stipple mask with a round rect soft clip
175 SkPaint paint;
176 paint.setAntiAlias(true);
177 paint.setTextSize(72);
178 paint.setShader(fShader.get());
179 paint.setMaskFilter(fMaskFilter.get());
180
181 SkRect temp;
182 temp.set(SkIntToScalar(115),
183 SkIntToScalar(75),
184 SkIntToScalar(144),
185 SkIntToScalar(110));
186
187 SkPath path;
188 path.addRoundRect(temp, SkIntToScalar(5), SkIntToScalar(5));
189
190 canvas->clipPath(path, SkRegion::kReplace_Op, true); // AA is on
191
192 canvas->drawText("M", 1,
193 SkIntToScalar(100), SkIntToScalar(100),
194 paint);
195
196 canvas->restore();
197
198 // Now draw stroked versions of the "M" and the round rect so we can
199 // see what is going on
200 SkPaint paint2;
201 paint2.setColor(SK_ColorBLACK);
202 paint2.setAntiAlias(true);
203 paint2.setTextSize(72);
204 paint2.setStyle(SkPaint::kStroke_Style);
205 paint2.setStrokeWidth(1);
206 canvas->drawText("M", 1,
207 SkIntToScalar(100), SkIntToScalar(100),
208 paint2);
209
210 paint2.setColor(SK_ColorGRAY);
211
212 canvas->drawPath(path, paint2);
213 }
214
215private:
216 SkBitmap fTexture;
217 bool fTextureCreated;
218 SkAutoTUnref<SkShader> fShader;
219 SkAutoTUnref<SkMaskFilter> fMaskFilter;
220
221 typedef GM INHERITED;
222};
223
224//////////////////////////////////////////////////////////////////////////////
225
226static GM* MyFactory(void*) { return new SamplerStressGM; }
227static GMRegistry reg(MyFactory);
228
229}