1/*
2 * Copyright 2013 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
10#include "Resources.h"
11#include "SkBlurImageFilter.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
14#include "SkCanvas.h"
15#include "SkGradientShader.h"
16#include "SkStream.h"
17#include "SkTypeface.h"
18
19/*
20 * Spits out a dummy gradient to test blur with shader on paint
21 */
22static SkShader* MakeLinear() {
23    static const SkPoint     kPts[] = { { 0, 0 }, { 32, 32 } };
24    static const SkScalar    kPos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
25    static const SkColor kColors[] = {0x80F00080, 0xF0F08000, 0x800080F0 };
26    return SkGradientShader::CreateLinear(kPts, kColors, kPos,
27                                          SK_ARRAY_COUNT(kColors), SkShader::kClamp_TileMode);
28}
29
30static SkImageFilter* make_grayscale(SkImageFilter* input = NULL) {
31    SkScalar matrix[20];
32    memset(matrix, 0, 20 * sizeof(SkScalar));
33    matrix[0] = matrix[5] = matrix[10] = 0.2126f;
34    matrix[1] = matrix[6] = matrix[11] = 0.7152f;
35    matrix[2] = matrix[7] = matrix[12] = 0.0722f;
36    matrix[18] = 1.0f;
37    SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
38    return SkColorFilterImageFilter::Create(filter, input);
39}
40
41static SkImageFilter* make_blur(float amount, SkImageFilter* input = NULL) {
42    return SkBlurImageFilter::Create(amount, amount, input);
43}
44
45namespace skiagm {
46
47class ColorEmojiGM : public GM {
48public:
49    ColorEmojiGM() : fCBDT_CBLC_Typeface(NULL), fSBIX_Typeface(NULL) { }
50
51protected:
52    struct EmojiFont {
53        SkTypeface* typeface;
54        const char* text;
55    } emojiFonts[2];
56    virtual void onOnceBeforeDraw() override {
57        fCBDT_CBLC_Typeface.reset(GetResourceAsTypeface("/fonts/Funkster.ttf"));
58        emojiFonts[0].typeface = fCBDT_CBLC_Typeface;
59        emojiFonts[0].text = "hamburgerfons";
60
61        fSBIX_Typeface.reset(SkTypeface::CreateFromName("Apple Color Emoji", SkTypeface::kNormal));
62        emojiFonts[1].typeface = fSBIX_Typeface;
63        emojiFonts[1].text = "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85" // ������
64                             "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80" // ������
65                             "\xF0\x9F\x9A\xBB" "\xF0\x9F\x92\xA9" "\xF0\x9F\x93\xB7" // ������
66                             "\xF0\x9F\x93\xA6" // ��
67                             "\xF0\x9F\x87\xBA" "\xF0\x9F\x87\xB8" "\xF0\x9F\x87\xA6"; // ������
68    }
69
70    SkString onShortName() override {
71        return SkString("coloremoji");
72    }
73
74    SkISize onISize() override {
75        return SkISize::Make(650, 900);
76    }
77
78    void onDraw(SkCanvas* canvas) override {
79
80        canvas->drawColor(SK_ColorGRAY);
81
82        for (size_t i = 0; i < SK_ARRAY_COUNT(emojiFonts); ++i) {
83            SkPaint paint;
84            paint.setTypeface(emojiFonts[i].typeface);
85            const char* text = emojiFonts[i].text;
86
87            // draw text at different point sizes
88            const int textSize[] = { 10, 30, 50, };
89            const int textYOffset[] = { 10, 40, 100, };
90            SkASSERT(sizeof(textSize) == sizeof(textYOffset));
91            size_t y_offset = 0;
92            for (size_t y = 0; y < sizeof(textSize) / sizeof(int); y++) {
93                paint.setTextSize(SkIntToScalar(textSize[y]));
94                canvas->drawText(text, strlen(text), 10, SkIntToScalar(textYOffset[y]), paint);
95                y_offset += textYOffset[y];
96            }
97
98            // draw with shaders and image filters
99            for (int makeLinear = 0; makeLinear < 2; makeLinear++) {
100                for (int makeBlur = 0; makeBlur < 2; makeBlur++) {
101                    for (int makeGray = 0; makeGray < 2; makeGray++) {
102                        SkPaint shaderPaint;
103                        shaderPaint.setTypeface(paint.getTypeface());
104                        if (SkToBool(makeLinear)) {
105                            shaderPaint.setShader(MakeLinear())->unref();
106                        }
107
108                        if (SkToBool(makeBlur) && SkToBool(makeGray)) {
109                            SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(NULL));
110                            SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, grayScale));
111                            shaderPaint.setImageFilter(blur);
112                        } else if (SkToBool(makeBlur)) {
113                            SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, NULL));
114                            shaderPaint.setImageFilter(blur);
115                        } else if (SkToBool(makeGray)) {
116                            SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(NULL));
117                            shaderPaint.setImageFilter(grayScale);
118                        }
119                        shaderPaint.setTextSize(30);
120                        canvas->drawText(text, strlen(text), 380, SkIntToScalar(y_offset),
121                                         shaderPaint);
122                        y_offset += 32;
123                    }
124                }
125            }
126
127            // setup work needed to draw text with different clips
128            canvas->translate(10, 160);
129            paint.setTextSize(40);
130
131            // compute the bounds of the text
132            SkRect bounds;
133            paint.measureText(text, strlen(text), &bounds);
134
135            const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf;
136            const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf;
137            const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf;
138            const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf;
139
140            SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(),
141                                                    boundsHalfWidth, boundsHalfHeight);
142            SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(),
143                                                     boundsHalfWidth, boundsHalfHeight);
144            SkRect interiorClip = bounds;
145            interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight);
146
147            const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip };
148
149            SkPaint clipHairline;
150            clipHairline.setColor(SK_ColorWHITE);
151            clipHairline.setStyle(SkPaint::kStroke_Style);
152
153            for (size_t x = 0; x < sizeof(clipRects) / sizeof(SkRect); ++x) {
154                canvas->save();
155                canvas->drawRect(clipRects[x], clipHairline);
156                paint.setAlpha(0x20);
157                canvas->drawText(text, strlen(text), 0, 0, paint);
158                canvas->clipRect(clipRects[x]);
159                paint.setAlpha(0xFF);
160                canvas->drawText(text, strlen(text), 0, 0, paint);
161                canvas->restore();
162                canvas->translate(0, bounds.height() + SkIntToScalar(25));
163            }
164        }
165    }
166
167private:
168    SkAutoTUnref<SkTypeface> fCBDT_CBLC_Typeface;
169    SkAutoTUnref<SkTypeface> fSBIX_Typeface;
170
171    typedef GM INHERITED;
172};
173
174//////////////////////////////////////////////////////////////////////////////
175
176static GM* MyFactory(void*) { return new ColorEmojiGM; }
177static GMRegistry reg(MyFactory);
178
179}
180