blob: 733dd31c24cda140959a2e0800455275af35f39e [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
reed@google.comf2183392011-04-22 14:10:48 +000014static inline SkPMColor rgb2gray(SkPMColor c) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000015 unsigned r = SkGetPackedR32(c);
16 unsigned g = SkGetPackedG32(c);
17 unsigned b = SkGetPackedB32(c);
reed@google.com82065d62011-02-07 15:30:46 +000018
reed@google.com261b8e22011-04-14 17:53:24 +000019 unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
reed@google.com82065d62011-02-07 15:30:46 +000020
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
22}
23
24class SkGrayScaleColorFilter : public SkColorFilter {
25public:
reed@google.comf2183392011-04-22 14:10:48 +000026 virtual void filterSpan(const SkPMColor src[], int count,
27 SkPMColor result[]) {
28 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 result[i] = rgb2gray(src[i]);
reed@google.comf2183392011-04-22 14:10:48 +000030 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 }
32};
33
34class SkChannelMaskColorFilter : public SkColorFilter {
35public:
reed@google.comf2183392011-04-22 14:10:48 +000036 SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
38 }
39
reed@google.comf2183392011-04-22 14:10:48 +000040 virtual void filterSpan(const SkPMColor src[], int count,
41 SkPMColor result[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 SkPMColor mask = fMask;
reed@google.comf2183392011-04-22 14:10:48 +000043 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 result[i] = src[i] & mask;
reed@google.comf2183392011-04-22 14:10:48 +000045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 }
reed@google.com82065d62011-02-07 15:30:46 +000047
reed@android.com8a1c16f2008-12-17 15:59:43 +000048private:
49 SkPMColor fMask;
50};
51
52///////////////////////////////////////////////////////////
53
54#include "SkGradientShader.h"
55#include "SkLayerRasterizer.h"
56#include "SkBlurMaskFilter.h"
57
reed@google.comf2183392011-04-22 14:10:48 +000058static void r0(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
60 SkBlurMaskFilter::kNormal_BlurStyle))->unref();
61 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
62
63 p.setMaskFilter(NULL);
64 p.setStyle(SkPaint::kStroke_Style);
65 p.setStrokeWidth(SK_Scalar1);
66 rast->addLayer(p);
67
68 p.setAlpha(0x11);
69 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +000070 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 rast->addLayer(p);
72}
73
reed@google.comf2183392011-04-22 14:10:48 +000074static void r1(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 rast->addLayer(p);
76
77 p.setAlpha(0x40);
reed@android.com0baf1932009-06-24 12:41:42 +000078 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 p.setStyle(SkPaint::kStroke_Style);
80 p.setStrokeWidth(SK_Scalar1*2);
81 rast->addLayer(p);
82}
reed@google.com82065d62011-02-07 15:30:46 +000083
reed@google.comf2183392011-04-22 14:10:48 +000084static void r2(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 p.setStyle(SkPaint::kStrokeAndFill_Style);
86 p.setStrokeWidth(SK_Scalar1*4);
87 rast->addLayer(p);
88
89 p.setStyle(SkPaint::kStroke_Style);
90 p.setStrokeWidth(SK_Scalar1*3/2);
reed@android.com0baf1932009-06-24 12:41:42 +000091 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 rast->addLayer(p);
93}
94
reed@google.comf2183392011-04-22 14:10:48 +000095static void r3(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 p.setStyle(SkPaint::kStroke_Style);
97 p.setStrokeWidth(SK_Scalar1*3);
98 rast->addLayer(p);
99
100 p.setAlpha(0x20);
101 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +0000102 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 rast->addLayer(p);
104}
105
reed@google.comf2183392011-04-22 14:10:48 +0000106static void r4(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 p.setAlpha(0x60);
108 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
109
110 p.setAlpha(0xFF);
reed@android.com0baf1932009-06-24 12:41:42 +0000111 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
113
114 p.setXfermode(NULL);
115 rast->addLayer(p);
116}
117
118#include "SkDiscretePathEffect.h"
119
reed@google.comf2183392011-04-22 14:10:48 +0000120static void r5(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 rast->addLayer(p);
122
123 p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000124 p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 rast->addLayer(p);
126}
127
reed@google.comf2183392011-04-22 14:10:48 +0000128static void r6(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 p.setAntiAlias(false);
132 SkLayerRasterizer* rast2 = new SkLayerRasterizer;
133 r5(rast2, p);
134 p.setRasterizer(rast2)->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000135 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 rast->addLayer(p);
137}
138
139#include "Sk2DPathEffect.h"
140
141class Dot2DPathEffect : public Sk2DPathEffect {
142public:
143 Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
144 : Sk2DPathEffect(matrix), fRadius(radius) {}
145
reed@google.comf2183392011-04-22 14:10:48 +0000146 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 this->INHERITED::flatten(buffer);
reed@google.com82065d62011-02-07 15:30:46 +0000148
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 buffer.writeScalar(fRadius);
150 }
151 virtual Factory getFactory() { return CreateProc; }
152
153protected:
reed@google.comf2183392011-04-22 14:10:48 +0000154 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 dst->addCircle(loc.fX, loc.fY, fRadius);
156 }
reed@google.com82065d62011-02-07 15:30:46 +0000157
reed@google.comf2183392011-04-22 14:10:48 +0000158 Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 fRadius = buffer.readScalar();
160 }
161private:
162 SkScalar fRadius;
163
reed@google.comf2183392011-04-22 14:10:48 +0000164 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 return new Dot2DPathEffect(buffer);
166 }
167
168 typedef Sk2DPathEffect INHERITED;
169};
170
reed@google.comf2183392011-04-22 14:10:48 +0000171static void r7(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 SkMatrix lattice;
173 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
174 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
175 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
176 rast->addLayer(p);
177}
178
reed@google.comf2183392011-04-22 14:10:48 +0000179static void r8(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000181
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 SkMatrix lattice;
183 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
184 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
185 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000186 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 rast->addLayer(p);
188
189 p.setPathEffect(NULL);
190 p.setXfermode(NULL);
191 p.setStyle(SkPaint::kStroke_Style);
192 p.setStrokeWidth(SK_Scalar1);
193 rast->addLayer(p);
194}
195
196class Line2DPathEffect : public Sk2DPathEffect {
197public:
198 Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
199 : Sk2DPathEffect(matrix), fWidth(width) {}
200
reed@google.comf2183392011-04-22 14:10:48 +0000201 virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
202 if (this->INHERITED::filterPath(dst, src, width)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 *width = fWidth;
204 return true;
205 }
206 return false;
207 }
reed@google.com82065d62011-02-07 15:30:46 +0000208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 virtual Factory getFactory() { return CreateProc; }
reed@google.comf2183392011-04-22 14:10:48 +0000210 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 this->INHERITED::flatten(buffer);
212 buffer.writeScalar(fWidth);
213 }
reed@google.comf2183392011-04-22 14:10:48 +0000214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215protected:
reed@google.comf2183392011-04-22 14:10:48 +0000216 virtual void nextSpan(int u, int v, int ucount, SkPath* dst) {
217 if (ucount > 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 SkPoint src[2], dstP[2];
219
220 src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
221 SkIntToScalar(v) + SK_ScalarHalf);
222 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
223 SkIntToScalar(v) + SK_ScalarHalf);
224 this->getMatrix().mapPoints(dstP, src, 2);
reed@google.com82065d62011-02-07 15:30:46 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 dst->moveTo(dstP[0]);
227 dst->lineTo(dstP[1]);
228 }
229 }
reed@google.com82065d62011-02-07 15:30:46 +0000230
reed@google.comf2183392011-04-22 14:10:48 +0000231 Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 fWidth = buffer.readScalar();
233 }
reed@google.com82065d62011-02-07 15:30:46 +0000234
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235private:
236 SkScalar fWidth;
237
reed@google.comf2183392011-04-22 14:10:48 +0000238 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 return new Line2DPathEffect(buffer);
240 }
241
242 typedef Sk2DPathEffect INHERITED;
243};
244
reed@google.comf2183392011-04-22 14:10:48 +0000245static void r9(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000247
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkMatrix lattice;
249 lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
250 lattice.postRotate(SkIntToScalar(30), 0, 0);
251 p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000252 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 rast->addLayer(p);
254
255 p.setPathEffect(NULL);
256 p.setXfermode(NULL);
257 p.setStyle(SkPaint::kStroke_Style);
258 p.setStrokeWidth(SK_Scalar1);
259 rast->addLayer(p);
260}
261
262typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
263
264static const raster_proc gRastProcs[] = {
265 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
266};
267
268static const struct {
269 SkColor fMul, fAdd;
270} gLightingColors[] = {
271 { 0x808080, 0x800000 }, // general case
272 { 0x707070, 0x707070 }, // no-pin case
273 { 0xFFFFFF, 0x800000 }, // just-add case
274 { 0x808080, 0x000000 }, // just-mul case
275 { 0xFFFFFF, 0x000000 } // identity case
276};
277
278#include "SkXfermode.h"
279
reed@google.comf2183392011-04-22 14:10:48 +0000280static unsigned color_dist16(uint16_t a, uint16_t b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
282 unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
283 unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
reed@google.com82065d62011-02-07 15:30:46 +0000284
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 return SkMax32(dr, SkMax32(dg, db));
286}
287
reed@google.comf2183392011-04-22 14:10:48 +0000288static unsigned scale_dist(unsigned dist, unsigned scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 dist >>= 6;
290 dist = (dist << 2) | dist;
291 dist = (dist << 4) | dist;
292 return dist;
293
294// return SkAlphaMul(dist, scale);
295}
296
reed@google.comf2183392011-04-22 14:10:48 +0000297static void apply_shader(SkPaint* paint, int index) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 raster_proc proc = gRastProcs[index];
299 if (proc)
300 {
301 SkPaint p;
302 SkLayerRasterizer* rast = new SkLayerRasterizer;
303
304 p.setAntiAlias(true);
305 proc(rast, p);
306 paint->setRasterizer(rast)->unref();
307 }
308
309#if 0
310 SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
reed@google.com82065d62011-02-07 15:30:46 +0000311 paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312#endif
313 paint->setColor(SK_ColorBLUE);
314}
315
316static int gRastIndex;
317
reed@google.comf2183392011-04-22 14:10:48 +0000318class TextEffectView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319 SkTypeface* fFace;
320public:
reed@google.comf2183392011-04-22 14:10:48 +0000321 TextEffectView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
323 }
reed@google.com82065d62011-02-07 15:30:46 +0000324
reed@google.comf2183392011-04-22 14:10:48 +0000325 virtual ~TextEffectView() {
reed@google.com82065d62011-02-07 15:30:46 +0000326 SkSafeUnref(fFace);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
328
329protected:
330 // overrides from SkEventSink
reed@google.comf2183392011-04-22 14:10:48 +0000331 virtual bool onQuery(SkEvent* evt) {
332 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 SampleCode::TitleR(evt, "Text Effects");
334 return true;
335 }
336 return this->INHERITED::onQuery(evt);
337 }
reed@google.com82065d62011-02-07 15:30:46 +0000338
reed@google.comf2183392011-04-22 14:10:48 +0000339 virtual void onDrawContent(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 canvas->save();
341// canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 SkPaint paint;
reed@google.com82065d62011-02-07 15:30:46 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 paint.setAntiAlias(true);
reed@android.com0bb6d062010-05-17 14:50:04 +0000346 paint.setTextSize(SkIntToScalar(56));
reed@android.com069b8272009-03-04 15:31:48 +0000347 paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
348 SkTypeface::kBold));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349
reed@android.com0bb6d062010-05-17 14:50:04 +0000350 SkScalar x = SkIntToScalar(20);
351 SkScalar y = paint.getTextSize();
352
353 SkString str("TextEffects");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354
355 paint.setTypeface(fFace);
reed@google.com82065d62011-02-07 15:30:46 +0000356
reed@google.comf2183392011-04-22 14:10:48 +0000357 for (int i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 apply_shader(&paint, i);
reed@google.com82065d62011-02-07 15:30:46 +0000359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 // paint.setMaskFilter(NULL);
361 // paint.setColor(SK_ColorBLACK);
362
reed@google.comf2183392011-04-22 14:10:48 +0000363#if 1
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 int index = i % SK_ARRAY_COUNT(gLightingColors);
365 paint.setColorFilter(SkColorFilter::CreateLightingFilter(
366 gLightingColors[index].fMul,
367 gLightingColors[index].fAdd))->unref();
368#endif
reed@google.com82065d62011-02-07 15:30:46 +0000369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 canvas->drawText(str.c_str(), str.size(), x, y, paint);
371
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 y += paint.getFontSpacing();
373 }
374
375 canvas->restore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 }
reed@google.com82065d62011-02-07 15:30:46 +0000377
reed@google.comf2183392011-04-22 14:10:48 +0000378 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 gRastIndex = (gRastIndex + 1) % SK_ARRAY_COUNT(gRastProcs);
380 this->inval(NULL);
381
382 return this->INHERITED::onFindClickHandler(x, y);
383 }
reed@google.com82065d62011-02-07 15:30:46 +0000384
reed@google.comf2183392011-04-22 14:10:48 +0000385 virtual bool onClick(Click* click) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 return this->INHERITED::onClick(click);
387 }
reed@google.com82065d62011-02-07 15:30:46 +0000388
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389private:
reed@google.comf2183392011-04-22 14:10:48 +0000390 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391};
392
393//////////////////////////////////////////////////////////////////////////////
394
395static SkView* MyFactory() { return new TextEffectView; }
396static SkViewRegister reg(MyFactory);
397