blob: b71f5b4c036d1f30241d63192ec008bd04cdcf4a [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkPath.h"
6#include "SkRegion.h"
7#include "SkShader.h"
8#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkColorPriv.h"
10#include "SkColorFilter.h"
11#include "SkTypeface.h"
12#include "SkAvoidXfermode.h"
13
14static inline SkPMColor rgb2gray(SkPMColor c)
15{
16 unsigned r = SkGetPackedR32(c);
17 unsigned g = SkGetPackedG32(c);
18 unsigned b = SkGetPackedB32(c);
19
20 unsigned x = r * 5 + g * 7 + b * 4 >> 4;
21
22 return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
23}
24
25class SkGrayScaleColorFilter : public SkColorFilter {
26public:
27 virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
28 {
29 for (int i = 0; i < count; i++)
30 result[i] = rgb2gray(src[i]);
31 }
32};
33
34class SkChannelMaskColorFilter : public SkColorFilter {
35public:
36 SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask)
37 {
38 fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
39 }
40
41 virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
42 {
43 SkPMColor mask = fMask;
44 for (int i = 0; i < count; i++)
45 result[i] = src[i] & mask;
46 }
47
48private:
49 SkPMColor fMask;
50};
51
52///////////////////////////////////////////////////////////
53
54#include "SkGradientShader.h"
55#include "SkLayerRasterizer.h"
56#include "SkBlurMaskFilter.h"
57
58static void r0(SkLayerRasterizer* rast, SkPaint& p)
59{
60 p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
61 SkBlurMaskFilter::kNormal_BlurStyle))->unref();
62 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
63
64 p.setMaskFilter(NULL);
65 p.setStyle(SkPaint::kStroke_Style);
66 p.setStrokeWidth(SK_Scalar1);
67 rast->addLayer(p);
68
69 p.setAlpha(0x11);
70 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +000071 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 rast->addLayer(p);
73}
74
75static void r1(SkLayerRasterizer* rast, SkPaint& p)
76{
77 rast->addLayer(p);
78
79 p.setAlpha(0x40);
reed@android.com0baf1932009-06-24 12:41:42 +000080 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 p.setStyle(SkPaint::kStroke_Style);
82 p.setStrokeWidth(SK_Scalar1*2);
83 rast->addLayer(p);
84}
85
86static void r2(SkLayerRasterizer* rast, SkPaint& p)
87{
88 p.setStyle(SkPaint::kStrokeAndFill_Style);
89 p.setStrokeWidth(SK_Scalar1*4);
90 rast->addLayer(p);
91
92 p.setStyle(SkPaint::kStroke_Style);
93 p.setStrokeWidth(SK_Scalar1*3/2);
reed@android.com0baf1932009-06-24 12:41:42 +000094 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 rast->addLayer(p);
96}
97
98static void r3(SkLayerRasterizer* rast, SkPaint& p)
99{
100 p.setStyle(SkPaint::kStroke_Style);
101 p.setStrokeWidth(SK_Scalar1*3);
102 rast->addLayer(p);
103
104 p.setAlpha(0x20);
105 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +0000106 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 rast->addLayer(p);
108}
109
110static void r4(SkLayerRasterizer* rast, SkPaint& p)
111{
112 p.setAlpha(0x60);
113 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
114
115 p.setAlpha(0xFF);
reed@android.com0baf1932009-06-24 12:41:42 +0000116 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
118
119 p.setXfermode(NULL);
120 rast->addLayer(p);
121}
122
123#include "SkDiscretePathEffect.h"
124
125static void r5(SkLayerRasterizer* rast, SkPaint& p)
126{
127 rast->addLayer(p);
128
129 p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000130 p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 rast->addLayer(p);
132}
133
134static void r6(SkLayerRasterizer* rast, SkPaint& p)
135{
136 rast->addLayer(p);
137
138 p.setAntiAlias(false);
139 SkLayerRasterizer* rast2 = new SkLayerRasterizer;
140 r5(rast2, p);
141 p.setRasterizer(rast2)->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000142 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 rast->addLayer(p);
144}
145
146#include "Sk2DPathEffect.h"
147
148class Dot2DPathEffect : public Sk2DPathEffect {
149public:
150 Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
151 : Sk2DPathEffect(matrix), fRadius(radius) {}
152
153 virtual void flatten(SkFlattenableWriteBuffer& buffer)
154 {
155 this->INHERITED::flatten(buffer);
156
157 buffer.writeScalar(fRadius);
158 }
159 virtual Factory getFactory() { return CreateProc; }
160
161protected:
162 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
163 {
164 dst->addCircle(loc.fX, loc.fY, fRadius);
165 }
166
167 Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
168 {
169 fRadius = buffer.readScalar();
170 }
171private:
172 SkScalar fRadius;
173
174 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
175 {
176 return new Dot2DPathEffect(buffer);
177 }
178
179 typedef Sk2DPathEffect INHERITED;
180};
181
182static void r7(SkLayerRasterizer* rast, SkPaint& p)
183{
184 SkMatrix lattice;
185 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
186 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
187 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
188 rast->addLayer(p);
189}
190
191static void r8(SkLayerRasterizer* rast, SkPaint& p)
192{
193 rast->addLayer(p);
194
195 SkMatrix lattice;
196 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
197 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
198 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000199 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 rast->addLayer(p);
201
202 p.setPathEffect(NULL);
203 p.setXfermode(NULL);
204 p.setStyle(SkPaint::kStroke_Style);
205 p.setStrokeWidth(SK_Scalar1);
206 rast->addLayer(p);
207}
208
209class Line2DPathEffect : public Sk2DPathEffect {
210public:
211 Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
212 : Sk2DPathEffect(matrix), fWidth(width) {}
213
214 virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
215 {
216 if (this->INHERITED::filterPath(dst, src, width))
217 {
218 *width = fWidth;
219 return true;
220 }
221 return false;
222 }
223
224 virtual Factory getFactory() { return CreateProc; }
225 virtual void flatten(SkFlattenableWriteBuffer& buffer)
226 {
227 this->INHERITED::flatten(buffer);
228 buffer.writeScalar(fWidth);
229 }
230protected:
231 virtual void nextSpan(int u, int v, int ucount, SkPath* dst)
232 {
233 if (ucount > 1)
234 {
235 SkPoint src[2], dstP[2];
236
237 src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
238 SkIntToScalar(v) + SK_ScalarHalf);
239 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
240 SkIntToScalar(v) + SK_ScalarHalf);
241 this->getMatrix().mapPoints(dstP, src, 2);
242
243 dst->moveTo(dstP[0]);
244 dst->lineTo(dstP[1]);
245 }
246 }
247
deanm@chromium.org1220e1c2009-06-11 12:26:47 +0000248 Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 {
250 fWidth = buffer.readScalar();
251 }
252
253private:
254 SkScalar fWidth;
255
256 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
257 {
258 return new Line2DPathEffect(buffer);
259 }
260
261 typedef Sk2DPathEffect INHERITED;
262};
263
264static void r9(SkLayerRasterizer* rast, SkPaint& p)
265{
266 rast->addLayer(p);
267
268 SkMatrix lattice;
269 lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
270 lattice.postRotate(SkIntToScalar(30), 0, 0);
271 p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000272 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 rast->addLayer(p);
274
275 p.setPathEffect(NULL);
276 p.setXfermode(NULL);
277 p.setStyle(SkPaint::kStroke_Style);
278 p.setStrokeWidth(SK_Scalar1);
279 rast->addLayer(p);
280}
281
282typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
283
284static const raster_proc gRastProcs[] = {
285 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
286};
287
288static const struct {
289 SkColor fMul, fAdd;
290} gLightingColors[] = {
291 { 0x808080, 0x800000 }, // general case
292 { 0x707070, 0x707070 }, // no-pin case
293 { 0xFFFFFF, 0x800000 }, // just-add case
294 { 0x808080, 0x000000 }, // just-mul case
295 { 0xFFFFFF, 0x000000 } // identity case
296};
297
298#include "SkXfermode.h"
299
300static unsigned color_dist16(uint16_t a, uint16_t b)
301{
302 unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
303 unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
304 unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
305
306 return SkMax32(dr, SkMax32(dg, db));
307}
308
309static unsigned scale_dist(unsigned dist, unsigned scale)
310{
311 dist >>= 6;
312 dist = (dist << 2) | dist;
313 dist = (dist << 4) | dist;
314 return dist;
315
316// return SkAlphaMul(dist, scale);
317}
318
319static void apply_shader(SkPaint* paint, int index)
320{
321 raster_proc proc = gRastProcs[index];
322 if (proc)
323 {
324 SkPaint p;
325 SkLayerRasterizer* rast = new SkLayerRasterizer;
326
327 p.setAntiAlias(true);
328 proc(rast, p);
329 paint->setRasterizer(rast)->unref();
330 }
331
332#if 0
333 SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
334 paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
335#endif
336 paint->setColor(SK_ColorBLUE);
337}
338
339static int gRastIndex;
340
341class TextEffectView : public SkView {
342 SkTypeface* fFace;
343public:
344 TextEffectView()
345 {
346 fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
347 }
348
349 virtual ~TextEffectView()
350 {
351 fFace->safeUnref();
352 }
353
354protected:
355 // overrides from SkEventSink
356 virtual bool onQuery(SkEvent* evt)
357 {
358 if (SampleCode::TitleQ(*evt))
359 {
360 SampleCode::TitleR(evt, "Text Effects");
361 return true;
362 }
363 return this->INHERITED::onQuery(evt);
364 }
365
366 void drawBG(SkCanvas* canvas)
367 {
368// canvas->drawColor(0xFFDDDDDD);
369 canvas->drawColor(SK_ColorWHITE);
370 }
371
372 virtual void onDraw(SkCanvas* canvas)
373 {
374 this->drawBG(canvas);
375
376 canvas->save();
377// canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
378
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 SkPaint paint;
380
381 paint.setAntiAlias(true);
reed@android.com0bb6d062010-05-17 14:50:04 +0000382 paint.setTextSize(SkIntToScalar(56));
reed@android.com069b8272009-03-04 15:31:48 +0000383 paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
384 SkTypeface::kBold));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385
reed@android.com0bb6d062010-05-17 14:50:04 +0000386 SkScalar x = SkIntToScalar(20);
387 SkScalar y = paint.getTextSize();
388
389 SkString str("TextEffects");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390
391 paint.setTypeface(fFace);
392
393 for (int i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++)
394 {
395 apply_shader(&paint, i);
396
397 // paint.setMaskFilter(NULL);
398 // paint.setColor(SK_ColorBLACK);
399
400#if 0
401 int index = i % SK_ARRAY_COUNT(gLightingColors);
402 paint.setColorFilter(SkColorFilter::CreateLightingFilter(
403 gLightingColors[index].fMul,
404 gLightingColors[index].fAdd))->unref();
405#endif
406
407 canvas->drawText(str.c_str(), str.size(), x, y, paint);
408
409 if (0)
410 {
411 SkPath path;
412 paint.getTextPath(str.c_str(), str.size(), x + SkIntToScalar(260), y, &path);
413 canvas->drawPath(path, paint);
414 }
415
416 y += paint.getFontSpacing();
417 }
418
419 canvas->restore();
420
421 if (0)
422 {
423 SkPoint pts[] = { 0, 0, 0, SkIntToScalar(150) };
424 SkColor colors[] = { 0xFFE6E6E6, 0xFFFFFFFF };
425 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
426
427 paint.reset();
428 paint.setShader(s);
429 canvas->drawRectCoords(0, 0, SkIntToScalar(120), SkIntToScalar(150), paint);
430 }
431
reed@android.com0bb6d062010-05-17 14:50:04 +0000432 if (0)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 {
434 SkAvoidXfermode mode(SK_ColorWHITE, 0xFF,
435 SkAvoidXfermode::kTargetColor_Mode);
436 SkPaint paint;
437 x += SkIntToScalar(20);
438 SkRect r = { x, 0, x + SkIntToScalar(360), SkIntToScalar(700) };
439 paint.setXfermode(&mode);
440 paint.setColor(SK_ColorGREEN);
441 paint.setAntiAlias(true);
442 canvas->drawOval(r, paint);
443 }
444 }
445
446 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)
447 {
448 gRastIndex = (gRastIndex + 1) % SK_ARRAY_COUNT(gRastProcs);
449 this->inval(NULL);
450
451 return this->INHERITED::onFindClickHandler(x, y);
452 }
453
454 virtual bool onClick(Click* click)
455 {
456 return this->INHERITED::onClick(click);
457 }
458
459private:
460 typedef SkView INHERITED;
461};
462
463//////////////////////////////////////////////////////////////////////////////
464
465static SkView* MyFactory() { return new TextEffectView; }
466static SkViewRegister reg(MyFactory);
467