3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "SampleCode.h"
9 #include "SkBlurMask.h"
12 #include "Sk1DPathEffect.h"
13 #include "Sk2DPathEffect.h"
14 #include "SkBlurMaskFilter.h"
15 #include "SkColorFilter.h"
16 #include "SkColorPriv.h"
17 #include "SkCornerPathEffect.h"
18 #include "SkDashPathEffect.h"
19 #include "SkDiscretePathEffect.h"
20 #include "SkEmbossMaskFilter.h"
21 #include "SkReadBuffer.h"
22 #include "SkWriteBuffer.h"
23 #include "SkGradientShader.h"
24 #include "SkImageDecoder.h"
25 #include "SkLayerRasterizer.h"
28 #include "SkPictureRecorder.h"
31 #include "SkComposeShader.h"
32 #include "SkCornerPathEffect.h"
33 #include "SkPathMeasure.h"
34 #include "SkPicture.h"
36 #include "SkTransparentShader.h"
37 #include "SkTypeface.h"
39 #include "SkXfermode.h"
43 static inline SkPMColor rgb2gray(SkPMColor c) {
44 unsigned r = SkGetPackedR32(c);
45 unsigned g = SkGetPackedG32(c);
46 unsigned b = SkGetPackedB32(c);
48 unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
50 return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
53 class SkGrayScaleColorFilter : public SkColorFilter {
55 virtual void filterSpan(const SkPMColor src[], int count,
56 SkPMColor result[]) const SK_OVERRIDE {
57 for (int i = 0; i < count; i++)
58 result[i] = rgb2gray(src[i]);
62 class SkChannelMaskColorFilter : public SkColorFilter {
64 SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask) {
65 fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
68 virtual void filterSpan(const SkPMColor src[], int count,
69 SkPMColor result[]) const SK_OVERRIDE {
70 SkPMColor mask = fMask;
71 for (int i = 0; i < count; i++) {
72 result[i] = src[i] & mask;
80 ///////////////////////////////////////////////////////////
82 static void r0(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
83 p.setMaskFilter(SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
84 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)),
85 SkBlurMaskFilter::kNone_BlurFlag))->unref();
86 rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
88 p.setMaskFilter(NULL);
89 p.setStyle(SkPaint::kStroke_Style);
90 p.setStrokeWidth(SK_Scalar1);
91 rastBuilder->addLayer(p);
94 p.setStyle(SkPaint::kFill_Style);
95 p.setXfermodeMode(SkXfermode::kSrc_Mode);
96 rastBuilder->addLayer(p);
99 static void r1(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
100 rastBuilder->addLayer(p);
103 p.setXfermodeMode(SkXfermode::kSrc_Mode);
104 p.setStyle(SkPaint::kStroke_Style);
105 p.setStrokeWidth(SK_Scalar1*2);
106 rastBuilder->addLayer(p);
109 static void r2(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
110 p.setStyle(SkPaint::kStrokeAndFill_Style);
111 p.setStrokeWidth(SK_Scalar1*4);
112 rastBuilder->addLayer(p);
114 p.setStyle(SkPaint::kStroke_Style);
115 p.setStrokeWidth(SK_Scalar1*3/2);
116 p.setXfermodeMode(SkXfermode::kClear_Mode);
117 rastBuilder->addLayer(p);
120 static void r3(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
121 p.setStyle(SkPaint::kStroke_Style);
122 p.setStrokeWidth(SK_Scalar1*3);
123 rastBuilder->addLayer(p);
126 p.setStyle(SkPaint::kFill_Style);
127 p.setXfermodeMode(SkXfermode::kSrc_Mode);
128 rastBuilder->addLayer(p);
131 static void r4(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
133 rastBuilder->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
136 p.setXfermodeMode(SkXfermode::kClear_Mode);
137 rastBuilder->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
140 rastBuilder->addLayer(p);
143 static void r5(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
144 rastBuilder->addLayer(p);
146 p.setPathEffect(SkDiscretePathEffect::Create(SK_Scalar1*4, SK_Scalar1*3))->unref();
147 p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
148 rastBuilder->addLayer(p);
151 static void r6(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
152 rastBuilder->addLayer(p);
154 p.setAntiAlias(false);
155 SkLayerRasterizer::Builder rastBuilder2;
156 r5(&rastBuilder2, p);
157 p.setRasterizer(rastBuilder2.detachRasterizer())->unref();
158 p.setXfermodeMode(SkXfermode::kClear_Mode);
159 rastBuilder->addLayer(p);
162 class Dot2DPathEffect : public Sk2DPathEffect {
164 Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
165 : Sk2DPathEffect(matrix), fRadius(radius) {}
167 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Dot2DPathEffect)
170 void next(const SkPoint& loc, int u, int v, SkPath* dst) const SK_OVERRIDE {
171 dst->addCircle(loc.fX, loc.fY, fRadius);
174 void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
175 this->INHERITED::flatten(buffer);
176 buffer.writeScalar(fRadius);
182 typedef Sk2DPathEffect INHERITED;
185 static void r7(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
187 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
188 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
189 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
190 rastBuilder->addLayer(p);
193 static void r8(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
194 rastBuilder->addLayer(p);
197 lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
198 lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
199 p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
200 p.setXfermodeMode(SkXfermode::kClear_Mode);
201 rastBuilder->addLayer(p);
203 p.setPathEffect(NULL);
205 p.setStyle(SkPaint::kStroke_Style);
206 p.setStrokeWidth(SK_Scalar1);
207 rastBuilder->addLayer(p);
210 static void r9(SkLayerRasterizer::Builder* rastBuilder, SkPaint& p) {
211 rastBuilder->addLayer(p);
214 lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
215 lattice.postRotate(SkIntToScalar(30), 0, 0);
216 p.setPathEffect(SkLine2DPathEffect::Create(SK_Scalar1*2, lattice))->unref();
217 p.setXfermodeMode(SkXfermode::kClear_Mode);
218 rastBuilder->addLayer(p);
220 p.setPathEffect(NULL);
222 p.setStyle(SkPaint::kStroke_Style);
223 p.setStrokeWidth(SK_Scalar1);
224 rastBuilder->addLayer(p);
227 typedef void (*raster_proc)(SkLayerRasterizer::Builder*, SkPaint&);
229 static const raster_proc gRastProcs[] = {
230 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
233 static const struct {
235 } gLightingColors[] = {
236 { 0x808080, 0x800000 }, // general case
237 { 0x707070, 0x707070 }, // no-pin case
238 { 0xFFFFFF, 0x800000 }, // just-add case
239 { 0x808080, 0x000000 }, // just-mul case
240 { 0xFFFFFF, 0x000000 } // identity case
243 static void apply_shader(SkPaint* paint, int index) {
244 raster_proc proc = gRastProcs[index];
247 SkLayerRasterizer::Builder rastBuilder;
249 p.setAntiAlias(true);
250 proc(&rastBuilder, p);
251 paint->setRasterizer(rastBuilder.detachRasterizer())->unref();
255 SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
256 paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(
257 SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)), dir,
258 SK_Scalar1/4, SkIntToScalar(4)))->unref();
259 paint->setColor(SK_ColorBLUE);
263 class DemoView : public SampleView {
268 // overrides from SkEventSink
269 virtual bool onQuery(SkEvent* evt) {
270 if (SampleCode::TitleQ(*evt)) {
271 SampleCode::TitleR(evt, "Demo");
274 return this->INHERITED::onQuery(evt);
277 virtual bool onClick(Click* click) {
278 return this->INHERITED::onClick(click);
281 void makePath(SkPath& path) {
282 path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20),
283 SkPath::kCCW_Direction);
284 for (int index = 0; index < 10; index++) {
285 SkScalar x = (float) cos(index / 10.0f * 2 * 3.1415925358f);
286 SkScalar y = (float) sin(index / 10.0f * 2 * 3.1415925358f);
287 x *= index & 1 ? 7 : 14;
288 y *= index & 1 ? 7 : 14;
289 x += SkIntToScalar(20);
290 y += SkIntToScalar(20);
299 virtual void onDrawContent(SkCanvas* canvas) {
301 this->drawPicture(canvas, 0);
305 SkPictureRecorder recorder;
307 SkCanvas* record = recorder.beginRecording(320, 480, NULL, 0);
308 this->drawPicture(record, 120);
310 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
312 canvas->translate(0, SkIntToScalar(120));
315 clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
318 canvas->clipRect(clip);
319 picture->playback(canvas);
321 if (clip.fRight < SkIntToScalar(320))
322 clip.offset(SkIntToScalar(160), 0);
323 else if (clip.fBottom < SkIntToScalar(480))
324 clip.offset(-SkIntToScalar(320), SkIntToScalar(160));
331 void drawPicture(SkCanvas* canvas, int spriteOffset) {
332 SkMatrix matrix; matrix.reset();
335 SkPoint start = {0, 0};
336 SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) };
337 SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) };
338 SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) };
339 SkScalar left = 0, top = 0, x = 0, y = 0;
342 char ascii[] = "ascii...";
343 int asciiLength = sizeof(ascii) - 1;
344 char utf8[] = "utf8" "\xe2\x80\xa6";
345 short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 };
346 short utf16simple[] = {'u', 't', 'f', '1', '6', '!' };
349 SkTDArray<SkPoint>(pos);
350 pos.setCount(asciiLength);
351 for (index = 0; index < asciiLength; index++)
352 pos[index].set(SkIntToScalar((unsigned int)index * 10),
353 SkIntToScalar((unsigned int)index * 2));
354 SkTDArray<SkPoint>(pos2);
355 pos2.setCount(asciiLength);
356 for (index = 0; index < asciiLength; index++)
357 pos2[index].set(SkIntToScalar((unsigned int)index * 10),
361 SkPoint linearPoints[] = { { 0, 0, }, { SkIntToScalar(40), SkIntToScalar(40) } };
362 SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE };
363 SkScalar* linearPos = NULL;
365 SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
366 SkShader* linear = SkGradientShader::CreateLinear(linearPoints,
367 linearColors, linearPos, linearCount, linearMode);
369 SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
370 SkScalar radialRadius = SkIntToScalar(25);
371 SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED };
372 SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
374 SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
375 SkShader* radial = SkGradientShader::CreateRadial(radialCenter,
376 radialRadius, radialColors, radialPos, radialCount,
379 SkTransparentShader* transparentShader = new SkTransparentShader();
380 SkEmbossMaskFilter::Light light;
381 light.fDirection[0] = SK_Scalar1/2;
382 light.fDirection[1] = SK_Scalar1/2;
383 light.fDirection[2] = SK_Scalar1/3;
384 light.fAmbient = 0x48;
385 light.fSpecular = 0x80;
386 SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(12)/5);
387 SkEmbossMaskFilter* embossFilter = SkEmbossMaskFilter::Create(sigma, light);
389 SkXfermode* xfermode = SkXfermode::Create(SkXfermode::kXor_Mode);
390 SkColorFilter* lightingFilter = SkColorFilter::CreateLightingFilter(
391 0xff89bc45, 0xff112233);
394 canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
395 paint.setAntiAlias(true);
396 paint.setFilterQuality(kLow_SkFilterQuality);
397 // !!! draw through a clip
398 paint.setColor(SK_ColorLTGRAY);
399 paint.setStyle(SkPaint::kFill_Style);
400 SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)};
401 canvas->clipRect(clip);
402 paint.setShader(SkShader::CreateBitmapShader(fTx,
403 SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode))->unref();
404 canvas->drawPaint(paint);
407 // line (exercises xfermode, colorShader, colorFilter, filterShader)
408 paint.setColor(SK_ColorGREEN);
409 paint.setStrokeWidth(SkIntToScalar(10));
410 paint.setStyle(SkPaint::kStroke_Style);
411 paint.setXfermode(xfermode)->unref();
412 paint.setColorFilter(lightingFilter)->unref();
413 canvas->drawLine(start.fX, start.fY, stop.fX, stop.fY, paint); // should not be green
414 paint.setXfermode(NULL);
415 paint.setColorFilter(NULL);
418 paint.setStyle(SkPaint::kFill_Style);
419 canvas->translate(SkIntToScalar(50), 0);
420 paint.setColor(SK_ColorYELLOW);
421 paint.setShader(linear)->unref();
422 paint.setPathEffect(pathEffectTest())->unref();
423 canvas->drawRect(rect, paint);
424 paint.setPathEffect(NULL);
426 // circle w/ emboss & transparent (exercises 3dshader)
427 canvas->translate(SkIntToScalar(50), 0);
428 paint.setMaskFilter(embossFilter)->unref();
429 canvas->drawOval(rect, paint);
430 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
431 paint.setShader(transparentShader)->unref();
432 canvas->drawOval(rect, paint);
433 canvas->translate(0, SkIntToScalar(-10));
436 canvas->translate(SkIntToScalar(50), 0);
437 paint.setColor(SK_ColorRED);
438 paint.setStyle(SkPaint::kStroke_Style);
439 paint.setStrokeWidth(SkIntToScalar(5));
440 paint.setShader(radial)->unref();
441 paint.setMaskFilter(NULL);
442 canvas->drawPath(path, paint);
444 paint.setShader(NULL);
446 canvas->translate(SkIntToScalar(50), 0);
447 paint.setStyle(SkPaint::kFill_Style);
448 canvas->drawBitmap(fBug, left, top, &paint);
449 canvas->translate(SkIntToScalar(30), 0);
450 canvas->drawSprite(fTb,
451 SkScalarRoundToInt(canvas->getTotalMatrix().getTranslateX()),
452 spriteOffset + 10, &paint);
454 canvas->translate(-SkIntToScalar(30), SkIntToScalar(30));
455 paint.setShader(shaderTest())->unref(); // test compose shader
456 canvas->drawRect(rect2, paint);
457 paint.setShader(NULL);
461 canvas->translate(0, SkIntToScalar(60));
463 paint.setColor(SK_ColorGRAY);
464 canvas->drawPosText(ascii, asciiLength, pos.begin(), paint);
465 canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint);
467 canvas->translate(SkIntToScalar(50), 0);
468 paint.setColor(SK_ColorCYAN);
469 canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint);
471 canvas->translate(SkIntToScalar(30), 0);
472 paint.setColor(SK_ColorMAGENTA);
473 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
474 matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
475 canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint);
476 canvas->translate(0, SkIntToScalar(20));
477 canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint);
480 canvas->translate(0, SkIntToScalar(60));
481 paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
485 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
488 return this->INHERITED::onFindClickHandler(x, y, modi);
491 SkPathEffect* pathEffectTest() {
492 static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 };
495 path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
496 for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
497 path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
499 path.offset(SkIntToScalar(-6), 0);
500 SkPathEffect* outer = SkPath1DPathEffect::Create(path, SkIntToScalar(12),
501 gPhase, SkPath1DPathEffect::kRotate_Style);
502 SkPathEffect* inner = SkDiscretePathEffect::Create(SkIntToScalar(2),
503 SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2));
504 SkPathEffect* result = SkComposePathEffect::Create(outer, inner);
510 SkShader* shaderTest() {
511 SkPoint pts[] = { { 0, 0, }, { SkIntToScalar(100), 0 } };
512 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
513 SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL,
514 2, SkShader::kClamp_TileMode);
515 pts[1].set(0, SkIntToScalar(100));
516 SkColor colors2[] = {SK_ColorBLACK, SkColorSetARGB(0x80, 0, 0, 0)};
517 SkShader* shaderB = SkGradientShader::CreateLinear(pts, colors2, NULL,
518 2, SkShader::kClamp_TileMode);
519 SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstIn_Mode);
520 SkShader* result = new SkComposeShader(shaderA, shaderB, mode);
527 virtual void startTest() {
528 SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/bugcirc.gif", &fBug);
529 SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/tbcirc.gif", &fTb);
530 SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/05psp04.gif", &fTx);
533 void drawRaster(SkCanvas* canvas) {
534 for (size_t index = 0; index < SK_ARRAY_COUNT(gRastProcs); index++)
535 drawOneRaster(canvas);
538 void drawOneRaster(SkCanvas* canvas) {
541 SkScalar x = SkIntToScalar(20);
542 SkScalar y = SkIntToScalar(40);
545 paint.setAntiAlias(true);
546 paint.setTextSize(SkIntToScalar(48));
547 paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
550 SkString str("GOOGLE");
552 for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
553 apply_shader(&paint, (int)i);
555 // paint.setMaskFilter(NULL);
556 // paint.setColor(SK_ColorBLACK);
559 int index = i % SK_ARRAY_COUNT(gLightingColors);
560 paint.setColorFilter(SkColorFilter::CreateLightingFilter(
561 gLightingColors[index].fMul,
562 gLightingColors[index].fAdd))->unref();
565 canvas->drawText(str.c_str(), str.size(), x, y, paint);
566 SkRect oval = { x, y - SkIntToScalar(40), x + SkIntToScalar(40), y };
567 paint.setStyle(SkPaint::kStroke_Style);
568 canvas->drawOval(oval, paint);
569 paint.setStyle(SkPaint::kFill_Style);
571 y += paint.getFontSpacing();
579 SkBitmap fBug, fTb, fTx;
580 typedef SampleView INHERITED;
583 //////////////////////////////////////////////////////////////////////////////
585 static SkView* MyFactory() { return new DemoView; }
586 static SkViewRegister reg(MyFactory);