1 /* 2 * Copyright 2011 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/gm.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkColor.h" 11 #include "include/core/SkColorSpace.h" 12 #include "include/core/SkFont.h" 13 #include "include/core/SkFontStyle.h" 14 #include "include/core/SkFontTypes.h" 15 #include "include/core/SkImageInfo.h" 16 #include "include/core/SkMatrix.h" 17 #include "include/core/SkPaint.h" 18 #include "include/core/SkPoint.h" 19 #include "include/core/SkRect.h" 20 #include "include/core/SkRefCnt.h" 21 #include "include/core/SkScalar.h" 22 #include "include/core/SkSize.h" 23 #include "include/core/SkString.h" 24 #include "include/core/SkSurface.h" 25 #include "include/core/SkSurfaceProps.h" 26 #include "include/core/SkTextBlob.h" 27 #include "include/core/SkTypeface.h" 28 #include "include/core/SkTypes.h" 29 #include "include/private/SkTemplates.h" 30 #include "include/private/SkTo.h" 31 #include "tools/ToolUtils.h" 32 33 #include <string.h> 34 35 class DFTextGM : public skiagm::GM { 36 public: DFTextGM()37 DFTextGM() { 38 this->setBGColor(0xFFFFFFFF); 39 } 40 41 protected: onOnceBeforeDraw()42 void onOnceBeforeDraw() override { 43 fEmojiTypeface = ToolUtils::emoji_typeface(); 44 fEmojiText = ToolUtils::emoji_sample_text(); 45 } 46 onShortName()47 SkString onShortName() override { 48 return SkString("dftext"); 49 } 50 onISize()51 SkISize onISize() override { 52 return SkISize::Make(1024, 768); 53 } 54 onDraw(SkCanvas * inputCanvas)55 void onDraw(SkCanvas* inputCanvas) override { 56 SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f }; 57 SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f }; 58 59 // set up offscreen rendering with distance field text 60 auto ctx = inputCanvas->recordingContext(); 61 SkISize size = onISize(); 62 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType, 63 inputCanvas->imageInfo().refColorSpace()); 64 SkSurfaceProps inputProps; 65 inputCanvas->getProps(&inputProps); 66 SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag | inputProps.flags(), 67 inputProps.pixelGeometry()); 68 auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props)); 69 SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas; 70 // init our new canvas with the old canvas's matrix 71 canvas->setMatrix(inputCanvas->getLocalToDeviceAs3x3()); 72 // apply global scale to test glyph positioning 73 canvas->scale(1.05f, 1.05f); 74 canvas->clear(0xffffffff); 75 76 SkPaint paint; 77 paint.setAntiAlias(true); 78 79 SkFont font(ToolUtils::create_portable_typeface("serif", SkFontStyle())); 80 font.setSubpixel(true); 81 82 const char* text = "Hamburgefons"; 83 const size_t textLen = strlen(text); 84 85 // check scaling up 86 SkScalar x = SkIntToScalar(0); 87 SkScalar y = SkIntToScalar(78); 88 for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) { 89 SkAutoCanvasRestore acr(canvas, true); 90 canvas->translate(x, y); 91 canvas->scale(scales[i], scales[i]); 92 font.setSize(textSizes[i]); 93 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); 94 y += font.getMetrics(nullptr)*scales[i]; 95 } 96 97 // check rotation 98 for (size_t i = 0; i < 5; ++i) { 99 SkScalar rotX = SkIntToScalar(10); 100 SkScalar rotY = y; 101 102 SkAutoCanvasRestore acr(canvas, true); 103 canvas->translate(SkIntToScalar(10 + i * 200), -80); 104 canvas->rotate(SkIntToScalar(i * 5), rotX, rotY); 105 for (int ps = 6; ps <= 32; ps += 3) { 106 font.setSize(SkIntToScalar(ps)); 107 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, rotX, rotY, font, paint); 108 rotY += font.getMetrics(nullptr); 109 } 110 } 111 112 // check scaling down 113 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 114 x = SkIntToScalar(680); 115 y = SkIntToScalar(20); 116 size_t arraySize = SK_ARRAY_COUNT(textSizes); 117 for (size_t i = 0; i < arraySize; ++i) { 118 SkAutoCanvasRestore acr(canvas, true); 119 canvas->translate(x, y); 120 SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]); 121 canvas->scale(scaleFactor, scaleFactor); 122 font.setSize(textSizes[i]); 123 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); 124 y += font.getMetrics(nullptr)*scaleFactor; 125 } 126 127 // check pos text 128 { 129 SkAutoCanvasRestore acr(canvas, true); 130 131 canvas->scale(2.0f, 2.0f); 132 133 SkAutoTArray<SkGlyphID> glyphs(SkToInt(textLen)); 134 int count = font.textToGlyphs(text, textLen, SkTextEncoding::kUTF8, glyphs.get(), textLen); 135 SkAutoTArray<SkPoint> pos(count); 136 font.setSize(textSizes[0]); 137 font.getPos(glyphs.get(), count, pos.get(), {340, 75}); 138 139 auto blob = SkTextBlob::MakeFromPosText(glyphs.get(), count * sizeof(SkGlyphID), 140 pos.get(), font, SkTextEncoding::kGlyphID); 141 canvas->drawTextBlob(blob, 0, 0, paint); 142 } 143 144 145 // check gamma-corrected blending 146 const SkColor fg[] = { 147 0xFFFFFFFF, 148 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 149 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 150 0xFF000000, 151 }; 152 153 paint.setColor(0xFFF7F3F7); 154 SkRect r = SkRect::MakeLTRB(670, 215, 820, 397); 155 canvas->drawRect(r, paint); 156 157 x = SkIntToScalar(680); 158 y = SkIntToScalar(235); 159 font.setSize(SkIntToScalar(19)); 160 for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { 161 paint.setColor(fg[i]); 162 163 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint); 164 y += font.getMetrics(nullptr); 165 } 166 167 paint.setColor(0xFF181C18); 168 r = SkRect::MakeLTRB(820, 215, 970, 397); 169 canvas->drawRect(r, paint); 170 171 x = SkIntToScalar(830); 172 y = SkIntToScalar(235); 173 font.setSize(SkIntToScalar(19)); 174 for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { 175 paint.setColor(fg[i]); 176 177 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint); 178 y += font.getMetrics(nullptr); 179 } 180 181 // check skew 182 { 183 font.setEdging(SkFont::Edging::kAntiAlias); 184 SkAutoCanvasRestore acr(canvas, true); 185 canvas->skew(0.0f, 0.151515f); 186 font.setSize(SkIntToScalar(32)); 187 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 745, 70, font, paint); 188 } 189 { 190 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 191 SkAutoCanvasRestore acr(canvas, true); 192 canvas->skew(0.5f, 0.0f); 193 font.setSize(SkIntToScalar(32)); 194 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 580, 125, font, paint); 195 } 196 197 // check perspective 198 { 199 font.setEdging(SkFont::Edging::kAntiAlias); 200 SkAutoCanvasRestore acr(canvas, true); 201 SkMatrix persp; 202 persp.setAll(0.9839f, 0, 0, 203 0.2246f, 0.6829f, 0, 204 0.0002352f, -0.0003844f, 1); 205 canvas->concat(persp); 206 canvas->translate(1100, -295); 207 font.setSize(37.5f); 208 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); 209 } 210 { 211 font.setSubpixel(false); 212 font.setEdging(SkFont::Edging::kAlias); 213 SkAutoCanvasRestore acr(canvas, true); 214 SkMatrix persp; 215 persp.setAll(0.9839f, 0, 0, 216 0.2246f, 0.6829f, 0, 217 0.0002352f, -0.0003844f, 1); 218 canvas->concat(persp); 219 canvas->translate(1075, -245); 220 canvas->scale(375, 375); 221 font.setSize(0.1f); 222 canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); 223 } 224 225 // check color emoji 226 if (fEmojiTypeface) { 227 SkFont emoiFont; 228 emoiFont.setSubpixel(true); 229 emoiFont.setTypeface(fEmojiTypeface); 230 emoiFont.setSize(SkIntToScalar(19)); 231 canvas->drawSimpleText(fEmojiText, strlen(fEmojiText), SkTextEncoding::kUTF8, 670, 90, emoiFont, paint); 232 } 233 234 // render offscreen buffer 235 if (surface) { 236 SkAutoCanvasRestore acr(inputCanvas, true); 237 // since we prepended this matrix already, we blit using identity 238 inputCanvas->resetMatrix(); 239 inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0); 240 } 241 } 242 243 private: 244 sk_sp<SkTypeface> fEmojiTypeface; 245 const char* fEmojiText; 246 247 using INHERITED = skiagm::GM; 248 }; 249 250 DEF_GM(return new DFTextGM;) 251