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