blob: 2a573f87185518ba1df0138c5b27082a00501e6c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SampleCode.h"
9#include "SkView.h"
10#include "SkCanvas.h"
11#include "SkGradientShader.h"
12#include "SkPath.h"
13#include "SkRegion.h"
14#include "SkShader.h"
15#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkColorPriv.h"
17#include "SkColorFilter.h"
18#include "SkTypeface.h"
19#include "SkAvoidXfermode.h"
20
reed@google.comf2183392011-04-22 14:10:48 +000021static inline SkPMColor rgb2gray(SkPMColor c) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 unsigned r = SkGetPackedR32(c);
23 unsigned g = SkGetPackedG32(c);
24 unsigned b = SkGetPackedB32(c);
reed@google.com82065d62011-02-07 15:30:46 +000025
reed@google.com261b8e22011-04-14 17:53:24 +000026 unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
reed@google.com82065d62011-02-07 15:30:46 +000027
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
29}
30
31class SkGrayScaleColorFilter : public SkColorFilter {
32public:
reed@google.comf2183392011-04-22 14:10:48 +000033 virtual void filterSpan(const SkPMColor src[], int count,
34 SkPMColor result[]) {
35 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 result[i] = rgb2gray(src[i]);
reed@google.comf2183392011-04-22 14:10:48 +000037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 }
39};
40
41class SkChannelMaskColorFilter : public SkColorFilter {
42public:
reed@google.comf2183392011-04-22 14:10:48 +000043 SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
45 }
46
reed@google.comf2183392011-04-22 14:10:48 +000047 virtual void filterSpan(const SkPMColor src[], int count,
48 SkPMColor result[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 SkPMColor mask = fMask;
reed@google.comf2183392011-04-22 14:10:48 +000050 for (int i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 result[i] = src[i] & mask;
reed@google.comf2183392011-04-22 14:10:48 +000052 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 }
reed@google.com82065d62011-02-07 15:30:46 +000054
reed@android.com8a1c16f2008-12-17 15:59:43 +000055private:
56 SkPMColor fMask;
57};
58
59///////////////////////////////////////////////////////////
60
61#include "SkGradientShader.h"
62#include "SkLayerRasterizer.h"
63#include "SkBlurMaskFilter.h"
64
reed@google.comf2183392011-04-22 14:10:48 +000065static void r0(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
67 SkBlurMaskFilter::kNormal_BlurStyle))->unref();
68 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
69
70 p.setMaskFilter(NULL);
71 p.setStyle(SkPaint::kStroke_Style);
72 p.setStrokeWidth(SK_Scalar1);
73 rast->addLayer(p);
74
75 p.setAlpha(0x11);
76 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +000077 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 rast->addLayer(p);
79}
80
reed@google.comf2183392011-04-22 14:10:48 +000081static void r1(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 rast->addLayer(p);
83
84 p.setAlpha(0x40);
reed@android.com0baf1932009-06-24 12:41:42 +000085 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 p.setStyle(SkPaint::kStroke_Style);
87 p.setStrokeWidth(SK_Scalar1*2);
88 rast->addLayer(p);
89}
reed@google.com82065d62011-02-07 15:30:46 +000090
reed@google.comf2183392011-04-22 14:10:48 +000091static void r2(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 p.setStyle(SkPaint::kStrokeAndFill_Style);
93 p.setStrokeWidth(SK_Scalar1*4);
94 rast->addLayer(p);
95
96 p.setStyle(SkPaint::kStroke_Style);
97 p.setStrokeWidth(SK_Scalar1*3/2);
reed@android.com0baf1932009-06-24 12:41:42 +000098 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 rast->addLayer(p);
100}
101
reed@google.comf2183392011-04-22 14:10:48 +0000102static void r3(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 p.setStyle(SkPaint::kStroke_Style);
104 p.setStrokeWidth(SK_Scalar1*3);
105 rast->addLayer(p);
106
107 p.setAlpha(0x20);
108 p.setStyle(SkPaint::kFill_Style);
reed@android.com0baf1932009-06-24 12:41:42 +0000109 p.setXfermodeMode(SkXfermode::kSrc_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110 rast->addLayer(p);
111}
112
reed@google.comf2183392011-04-22 14:10:48 +0000113static void r4(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 p.setAlpha(0x60);
115 rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
116
117 p.setAlpha(0xFF);
reed@android.com0baf1932009-06-24 12:41:42 +0000118 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
120
121 p.setXfermode(NULL);
122 rast->addLayer(p);
123}
124
125#include "SkDiscretePathEffect.h"
126
reed@google.comf2183392011-04-22 14:10:48 +0000127static void r5(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 rast->addLayer(p);
129
130 p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000131 p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 rast->addLayer(p);
133}
134
reed@google.comf2183392011-04-22 14:10:48 +0000135static void r6(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000137
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 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
reed@google.comf2183392011-04-22 14:10:48 +0000153 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 this->INHERITED::flatten(buffer);
reed@google.com82065d62011-02-07 15:30:46 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 buffer.writeScalar(fRadius);
157 }
158 virtual Factory getFactory() { return CreateProc; }
159
160protected:
reed@google.comf2183392011-04-22 14:10:48 +0000161 virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 dst->addCircle(loc.fX, loc.fY, fRadius);
163 }
reed@google.com82065d62011-02-07 15:30:46 +0000164
reed@google.comf2183392011-04-22 14:10:48 +0000165 Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 fRadius = buffer.readScalar();
167 }
168private:
169 SkScalar fRadius;
170
reed@google.comf2183392011-04-22 14:10:48 +0000171 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 return new Dot2DPathEffect(buffer);
173 }
174
175 typedef Sk2DPathEffect INHERITED;
176};
177
reed@google.comf2183392011-04-22 14:10:48 +0000178static void r7(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 SkMatrix lattice;
180 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
181 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
182 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
183 rast->addLayer(p);
184}
185
reed@google.comf2183392011-04-22 14:10:48 +0000186static void r8(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000188
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 SkMatrix lattice;
190 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
191 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
192 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000193 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 rast->addLayer(p);
195
196 p.setPathEffect(NULL);
197 p.setXfermode(NULL);
198 p.setStyle(SkPaint::kStroke_Style);
199 p.setStrokeWidth(SK_Scalar1);
200 rast->addLayer(p);
201}
202
203class Line2DPathEffect : public Sk2DPathEffect {
204public:
205 Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
206 : Sk2DPathEffect(matrix), fWidth(width) {}
207
reed@google.comf2183392011-04-22 14:10:48 +0000208 virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
209 if (this->INHERITED::filterPath(dst, src, width)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 *width = fWidth;
211 return true;
212 }
213 return false;
214 }
reed@google.com82065d62011-02-07 15:30:46 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 virtual Factory getFactory() { return CreateProc; }
reed@google.comf2183392011-04-22 14:10:48 +0000217 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 this->INHERITED::flatten(buffer);
219 buffer.writeScalar(fWidth);
220 }
reed@google.comf2183392011-04-22 14:10:48 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222protected:
reed@google.comf2183392011-04-22 14:10:48 +0000223 virtual void nextSpan(int u, int v, int ucount, SkPath* dst) {
224 if (ucount > 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 SkPoint src[2], dstP[2];
226
227 src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
228 SkIntToScalar(v) + SK_ScalarHalf);
229 src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
230 SkIntToScalar(v) + SK_ScalarHalf);
231 this->getMatrix().mapPoints(dstP, src, 2);
reed@google.com82065d62011-02-07 15:30:46 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 dst->moveTo(dstP[0]);
234 dst->lineTo(dstP[1]);
235 }
236 }
reed@google.com82065d62011-02-07 15:30:46 +0000237
reed@google.comf2183392011-04-22 14:10:48 +0000238 Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 fWidth = buffer.readScalar();
240 }
reed@google.com82065d62011-02-07 15:30:46 +0000241
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242private:
243 SkScalar fWidth;
244
reed@google.comf2183392011-04-22 14:10:48 +0000245 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 return new Line2DPathEffect(buffer);
247 }
248
249 typedef Sk2DPathEffect INHERITED;
250};
251
reed@google.comf2183392011-04-22 14:10:48 +0000252static void r9(SkLayerRasterizer* rast, SkPaint& p) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 rast->addLayer(p);
reed@google.com82065d62011-02-07 15:30:46 +0000254
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 SkMatrix lattice;
256 lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
257 lattice.postRotate(SkIntToScalar(30), 0, 0);
258 p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
reed@android.com0baf1932009-06-24 12:41:42 +0000259 p.setXfermodeMode(SkXfermode::kClear_Mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 rast->addLayer(p);
261
262 p.setPathEffect(NULL);
263 p.setXfermode(NULL);
264 p.setStyle(SkPaint::kStroke_Style);
265 p.setStrokeWidth(SK_Scalar1);
266 rast->addLayer(p);
267}
268
269typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
270
271static const raster_proc gRastProcs[] = {
272 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
273};
274
275static const struct {
276 SkColor fMul, fAdd;
277} gLightingColors[] = {
278 { 0x808080, 0x800000 }, // general case
279 { 0x707070, 0x707070 }, // no-pin case
280 { 0xFFFFFF, 0x800000 }, // just-add case
281 { 0x808080, 0x000000 }, // just-mul case
282 { 0xFFFFFF, 0x000000 } // identity case
283};
284
285#include "SkXfermode.h"
286
reed@google.comf2183392011-04-22 14:10:48 +0000287static unsigned color_dist16(uint16_t a, uint16_t b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
289 unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
290 unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
reed@google.com82065d62011-02-07 15:30:46 +0000291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 return SkMax32(dr, SkMax32(dg, db));
293}
294
reed@google.comf2183392011-04-22 14:10:48 +0000295static unsigned scale_dist(unsigned dist, unsigned scale) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 dist >>= 6;
297 dist = (dist << 2) | dist;
298 dist = (dist << 4) | dist;
299 return dist;
300
301// return SkAlphaMul(dist, scale);
302}
303
reed@google.comf2183392011-04-22 14:10:48 +0000304static void apply_shader(SkPaint* paint, int index) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 raster_proc proc = gRastProcs[index];
306 if (proc)
307 {
308 SkPaint p;
309 SkLayerRasterizer* rast = new SkLayerRasterizer;
310
311 p.setAntiAlias(true);
312 proc(rast, p);
313 paint->setRasterizer(rast)->unref();
314 }
315
316#if 0
317 SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
reed@google.com82065d62011-02-07 15:30:46 +0000318 paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319#endif
320 paint->setColor(SK_ColorBLUE);
321}
322
323static int gRastIndex;
324
reed@google.comf2183392011-04-22 14:10:48 +0000325class TextEffectView : public SampleView {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 SkTypeface* fFace;
327public:
reed@google.comf2183392011-04-22 14:10:48 +0000328 TextEffectView() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
330 }
reed@google.com82065d62011-02-07 15:30:46 +0000331
reed@google.comf2183392011-04-22 14:10:48 +0000332 virtual ~TextEffectView() {
reed@google.com82065d62011-02-07 15:30:46 +0000333 SkSafeUnref(fFace);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
335
336protected:
337 // overrides from SkEventSink
reed@google.comf2183392011-04-22 14:10:48 +0000338 virtual bool onQuery(SkEvent* evt) {
339 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 SampleCode::TitleR(evt, "Text Effects");
341 return true;
342 }
343 return this->INHERITED::onQuery(evt);
344 }
reed@google.com82065d62011-02-07 15:30:46 +0000345
reed@google.comf2183392011-04-22 14:10:48 +0000346 virtual void onDrawContent(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 canvas->save();
348// canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 SkPaint paint;
reed@google.com82065d62011-02-07 15:30:46 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 paint.setAntiAlias(true);
reed@android.com0bb6d062010-05-17 14:50:04 +0000353 paint.setTextSize(SkIntToScalar(56));
reed@android.com069b8272009-03-04 15:31:48 +0000354 paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
355 SkTypeface::kBold));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356
reed@android.com0bb6d062010-05-17 14:50:04 +0000357 SkScalar x = SkIntToScalar(20);
358 SkScalar y = paint.getTextSize();
359
360 SkString str("TextEffects");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361
362 paint.setTypeface(fFace);
reed@google.com82065d62011-02-07 15:30:46 +0000363
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000364 for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 apply_shader(&paint, i);
reed@google.com82065d62011-02-07 15:30:46 +0000366
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 // paint.setMaskFilter(NULL);
368 // paint.setColor(SK_ColorBLACK);
369
reed@google.comf2183392011-04-22 14:10:48 +0000370#if 1
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 int index = i % SK_ARRAY_COUNT(gLightingColors);
372 paint.setColorFilter(SkColorFilter::CreateLightingFilter(
373 gLightingColors[index].fMul,
374 gLightingColors[index].fAdd))->unref();
375#endif
reed@google.com82065d62011-02-07 15:30:46 +0000376
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 canvas->drawText(str.c_str(), str.size(), x, y, paint);
378
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 y += paint.getFontSpacing();
380 }
381
382 canvas->restore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 }
reed@google.com82065d62011-02-07 15:30:46 +0000384
reed@google.comf2183392011-04-22 14:10:48 +0000385 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 gRastIndex = (gRastIndex + 1) % SK_ARRAY_COUNT(gRastProcs);
387 this->inval(NULL);
388
389 return this->INHERITED::onFindClickHandler(x, y);
390 }
reed@google.com82065d62011-02-07 15:30:46 +0000391
reed@google.comf2183392011-04-22 14:10:48 +0000392 virtual bool onClick(Click* click) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393 return this->INHERITED::onClick(click);
394 }
reed@google.com82065d62011-02-07 15:30:46 +0000395
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396private:
reed@google.comf2183392011-04-22 14:10:48 +0000397 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398};
399
400//////////////////////////////////////////////////////////////////////////////
401
402static SkView* MyFactory() { return new TextEffectView; }
403static SkViewRegister reg(MyFactory);
404