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#include "sk_tool_utils.h" 10 11#include "Resources.h" 12#include "SkBlurImageFilter.h" 13#include "SkCanvas.h" 14#include "SkColorFilterImageFilter.h" 15#include "SkColorMatrixFilter.h" 16#include "SkGradientShader.h" 17#include "SkStream.h" 18#include "SkTypeface.h" 19 20/* 21 * Spits out a dummy gradient to test blur with shader on paint 22 */ 23static sk_sp<SkShader> MakeLinear() { 24 constexpr SkPoint kPts[] = { { 0, 0 }, { 32, 32 } }; 25 constexpr SkScalar kPos[] = { 0, SK_Scalar1/2, SK_Scalar1 }; 26 constexpr SkColor kColors[] = {0x80F00080, 0xF0F08000, 0x800080F0 }; 27 return SkGradientShader::MakeLinear(kPts, kColors, kPos, SK_ARRAY_COUNT(kColors), 28 SkShader::kClamp_TileMode); 29} 30 31static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input) { 32 SkScalar matrix[20]; 33 memset(matrix, 0, 20 * sizeof(SkScalar)); 34 matrix[0] = matrix[5] = matrix[10] = 0.2126f; 35 matrix[1] = matrix[6] = matrix[11] = 0.7152f; 36 matrix[2] = matrix[7] = matrix[12] = 0.0722f; 37 matrix[18] = 1.0f; 38 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix)); 39 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input)); 40} 41 42static sk_sp<SkImageFilter> make_blur(float amount, sk_sp<SkImageFilter> input) { 43 return SkBlurImageFilter::Make(amount, amount, std::move(input)); 44} 45 46static sk_sp<SkColorFilter> make_color_filter() { 47 return SkColorMatrixFilter::MakeLightingFilter(SkColorSetRGB(0x00, 0x80, 0xFF), 48 SkColorSetRGB(0xFF, 0x20, 0x00)); 49} 50 51namespace skiagm { 52 53class ColorEmojiGM : public GM { 54public: 55 ColorEmojiGM() { } 56 57protected: 58 struct EmojiFont { 59 sk_sp<SkTypeface> typeface; 60 const char* text; 61 } emojiFont; 62 virtual void onOnceBeforeDraw() override { 63 emojiFont.typeface = sk_tool_utils::emoji_typeface(); 64 emojiFont.text = sk_tool_utils::emoji_sample_text(); 65 } 66 67 SkString onShortName() override { 68 SkString name("coloremoji"); 69 name.append(sk_tool_utils::platform_font_manager()); 70 return name; 71 } 72 73 SkISize onISize() override { return SkISize::Make(650, 1200); } 74 75 void onDraw(SkCanvas* canvas) override { 76 77 canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorGRAY)); 78 79 SkPaint paint; 80 paint.setTypeface(emojiFont.typeface); 81 const char* text = emojiFont.text; 82 83 // draw text at different point sizes 84 constexpr SkScalar textSizes[] = { 10, 30, 50, }; 85 SkPaint::FontMetrics metrics; 86 SkScalar y = 0; 87 for (const bool& fakeBold : { false, true }) { 88 paint.setFakeBoldText(fakeBold); 89 for (const SkScalar& textSize : textSizes) { 90 paint.setTextSize(textSize); 91 paint.getFontMetrics(&metrics); 92 y += -metrics.fAscent; 93 canvas->drawString(text, 10, y, paint); 94 y += metrics.fDescent + metrics.fLeading; 95 } 96 } 97 98 y += 20; 99 SkScalar savedY = y; 100 // draw with shaders and image filters 101 for (int makeLinear = 0; makeLinear < 2; makeLinear++) { 102 for (int makeBlur = 0; makeBlur < 2; makeBlur++) { 103 for (int makeGray = 0; makeGray < 2; makeGray++) { 104 for (int makeMode = 0; makeMode < 2; ++makeMode) { 105 for (int alpha = 0; alpha < 2; ++alpha) { 106 SkPaint shaderPaint; 107 shaderPaint.setTypeface(sk_ref_sp(paint.getTypeface())); 108 if (SkToBool(makeLinear)) { 109 shaderPaint.setShader(MakeLinear()); 110 } 111 112 if (SkToBool(makeBlur) && SkToBool(makeGray)) { 113 sk_sp<SkImageFilter> grayScale(make_grayscale(nullptr)); 114 sk_sp<SkImageFilter> blur(make_blur(3.0f, std::move(grayScale))); 115 shaderPaint.setImageFilter(std::move(blur)); 116 } else if (SkToBool(makeBlur)) { 117 shaderPaint.setImageFilter(make_blur(3.0f, nullptr)); 118 } else if (SkToBool(makeGray)) { 119 shaderPaint.setImageFilter(make_grayscale(nullptr)); 120 } 121 if (makeMode) { 122 shaderPaint.setColorFilter(make_color_filter()); 123 } 124 if (alpha) { 125 shaderPaint.setAlpha(0x80); 126 } 127 shaderPaint.setTextSize(30); 128 shaderPaint.getFontMetrics(&metrics); 129 y += -metrics.fAscent; 130 canvas->drawString(text, 380, y, shaderPaint); 131 y += metrics.fDescent + metrics.fLeading; 132 } 133 } 134 } 135 } 136 } 137 // setup work needed to draw text with different clips 138 canvas->translate(10, savedY); 139 paint.setTextSize(40); 140 141 // compute the bounds of the text 142 SkRect bounds; 143 paint.measureText(text, strlen(text), &bounds); 144 145 const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; 146 const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; 147 const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf; 148 const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf; 149 150 SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(), 151 boundsHalfWidth, boundsHalfHeight); 152 SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(), 153 boundsHalfWidth, boundsHalfHeight); 154 SkRect interiorClip = bounds; 155 interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight); 156 157 const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip }; 158 159 SkPaint clipHairline; 160 clipHairline.setColor(SK_ColorWHITE); 161 clipHairline.setStyle(SkPaint::kStroke_Style); 162 163 for (const SkRect& clipRect : clipRects) { 164 canvas->translate(0, bounds.height()); 165 canvas->save(); 166 canvas->drawRect(clipRect, clipHairline); 167 paint.setAlpha(0x20); 168 canvas->drawString(text, 0, 0, paint); 169 canvas->clipRect(clipRect); 170 paint.setAlpha(0xFF); 171 canvas->drawString(text, 0, 0, paint); 172 canvas->restore(); 173 canvas->translate(0, SkIntToScalar(25)); 174 } 175 } 176 177 typedef GM INHERITED; 178}; 179 180////////////////////////////////////////////////////////////////////////////// 181 182DEF_GM(return new ColorEmojiGM;) 183 184} 185