blob: b5c006902ac862128b1788bb9d3b9d4a98ead92f [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) {
robertphillips@google.coma93f9c32012-05-02 14:05:47 +000052 SkASSERT(size_t(scanline - dst->fImage) < dstSize);
robertphillips@google.comd9d53852012-05-02 13:55:06 +000053 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
scroggo@google.com5af9b202012-06-04 17:17:36 +0000108 virtual uint32_t onGetFlags() const SK_OVERRIDE {
109 // Skip Pipe playback since we use a custom MaskFilter that will not be
110 // flattened correctly
111 return this->INHERITED::onGetFlags() | GM::kSkipPipe_Flag;
112 }
113
robertphillips@google.comd9d53852012-05-02 13:55:06 +0000114 /**
115 * Create a red & green stripes on black texture
116 */
117 void createTexture() {
118 if (fTextureCreated) {
119 return;
120 }
121
122 static const int xSize = 16;
123 static const int ySize = 16;
124
125 fTexture.setConfig(SkBitmap::kARGB_8888_Config,
126 xSize,
127 ySize,
128 xSize*sizeof(SkColor));
129
130 fTexture.allocPixels();
131 fTexture.lockPixels();
132 SkPMColor* addr = fTexture.getAddr32(0, 0);
133
134 for (int y = 0; y < ySize; ++y) {
135 for (int x = 0; x < xSize; ++x) {
136 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorBLACK);
137
138 if ((y % 5) == 0) {
139 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorRED);
140 }
141 if ((x % 7) == 0) {
142 addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorGREEN);
143 }
144 }
145 }
146
147 fTexture.unlockPixels();
148
149 fTextureCreated = true;
150 }
151
152 void createShader() {
153 if (NULL != fShader.get()) {
154 return;
155 }
156
157 createTexture();
158
159 fShader.reset(SkShader::CreateBitmapShader(fTexture,
160 SkShader::kRepeat_TileMode,
161 SkShader::kRepeat_TileMode));
162 }
163
164 void createMaskFilter() {
165 if (NULL != fMaskFilter.get()) {
166 return;
167 }
168
169 fMaskFilter.reset(SkNEW(SkStippleMaskFilter));
170 }
171
172 virtual void onDraw(SkCanvas* canvas) {
173
174 createShader();
175 createMaskFilter();
176
177 canvas->save();
178
179 // draw a letter "M" with a green & red striped texture and a
180 // stipple mask with a round rect soft clip
181 SkPaint paint;
182 paint.setAntiAlias(true);
183 paint.setTextSize(72);
184 paint.setShader(fShader.get());
185 paint.setMaskFilter(fMaskFilter.get());
186
187 SkRect temp;
188 temp.set(SkIntToScalar(115),
189 SkIntToScalar(75),
190 SkIntToScalar(144),
191 SkIntToScalar(110));
192
193 SkPath path;
194 path.addRoundRect(temp, SkIntToScalar(5), SkIntToScalar(5));
195
196 canvas->clipPath(path, SkRegion::kReplace_Op, true); // AA is on
197
198 canvas->drawText("M", 1,
199 SkIntToScalar(100), SkIntToScalar(100),
200 paint);
201
202 canvas->restore();
203
204 // Now draw stroked versions of the "M" and the round rect so we can
205 // see what is going on
206 SkPaint paint2;
207 paint2.setColor(SK_ColorBLACK);
208 paint2.setAntiAlias(true);
209 paint2.setTextSize(72);
210 paint2.setStyle(SkPaint::kStroke_Style);
211 paint2.setStrokeWidth(1);
212 canvas->drawText("M", 1,
213 SkIntToScalar(100), SkIntToScalar(100),
214 paint2);
215
216 paint2.setColor(SK_ColorGRAY);
217
218 canvas->drawPath(path, paint2);
219 }
220
221private:
222 SkBitmap fTexture;
223 bool fTextureCreated;
224 SkAutoTUnref<SkShader> fShader;
225 SkAutoTUnref<SkMaskFilter> fMaskFilter;
226
227 typedef GM INHERITED;
228};
229
230//////////////////////////////////////////////////////////////////////////////
231
232static GM* MyFactory(void*) { return new SamplerStressGM; }
233static GMRegistry reg(MyFactory);
234
235}