1 /* 2 * Copyright 2017 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 #if SK_SUPPORT_ATLAS_TEXT 11 #include "GrContext.h" 12 13 #include "SkAtlasTextContext.h" 14 #include "SkAtlasTextFont.h" 15 #include "SkAtlasTextTarget.h" 16 #include "SkBitmap.h" 17 #include "SkCanvas.h" 18 #include "SkFont.h" 19 #include "SkTypeface.h" 20 #include "SkUTF.h" 21 #include "gpu/TestContext.h" 22 #include "gpu/atlastext/GLTestAtlasTextRenderer.h" 23 #include "gpu/atlastext/TestAtlasTextRenderer.h" 24 #include "sk_tool_utils.h" 25 26 // GM that draws text using the Atlas Text interface offscreen and then blits that to the canvas. 27 draw_string(SkAtlasTextTarget * target,const SkString & text,SkScalar x,SkScalar y,uint32_t color,sk_sp<SkTypeface> typeface,float size)28 static SkScalar draw_string(SkAtlasTextTarget* target, const SkString& text, SkScalar x, SkScalar y, 29 uint32_t color, sk_sp<SkTypeface> typeface, float size) { 30 if (!text.size()) { 31 return x; 32 } 33 auto atlas_font = SkAtlasTextFont::Make(typeface, size); 34 int cnt = SkUTF::CountUTF8(text.c_str(), text.size()); 35 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[cnt]); 36 typeface->charsToGlyphs(text.c_str(), SkTypeface::Encoding::kUTF8_Encoding, glyphs.get(), cnt); 37 38 // Using a paint to get the positions for each glyph. 39 SkFont font; 40 font.setSize(size); 41 font.setTypeface(std::move(typeface)); 42 std::unique_ptr<SkScalar[]> widths(new SkScalar[cnt]); 43 font.getWidths(glyphs.get(), cnt, widths.get()); 44 45 std::unique_ptr<SkPoint[]> positions(new SkPoint[cnt]); 46 positions[0] = {x, y}; 47 for (int i = 1; i < cnt; ++i) { 48 positions[i] = {positions[i - 1].fX + widths[i - 1], y}; 49 } 50 51 target->drawText(glyphs.get(), positions.get(), cnt, color, *atlas_font); 52 53 // Return the width of the of draw. 54 return positions[cnt - 1].fX + widths[cnt - 1] - positions[0].fX; 55 } 56 57 class AtlasTextGM : public skiagm::GM { 58 public: 59 AtlasTextGM() = default; 60 61 protected: onShortName()62 SkString onShortName() override { return SkString("atlastext"); } 63 onISize()64 SkISize onISize() override { return SkISize::Make(kSize, kSize); } 65 onOnceBeforeDraw()66 void onOnceBeforeDraw() override { 67 fRenderer = sk_gpu_test::MakeGLTestAtlasTextRenderer(); 68 if (!fRenderer) { 69 return; 70 } 71 fContext = SkAtlasTextContext::Make(fRenderer); 72 auto targetHandle = fRenderer->makeTargetHandle(kSize, kSize); 73 if (!targetHandle) { 74 return; 75 } 76 77 fTarget = SkAtlasTextTarget::Make(fContext, kSize, kSize, targetHandle); 78 79 fTypefaces[0] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Italic()); 80 fTypefaces[1] = 81 sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Italic()); 82 fTypefaces[2] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Normal()); 83 fTypefaces[3] = 84 sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Normal()); 85 fTypefaces[4] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Bold()); 86 fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold()); 87 } 88 onDraw(SkCanvas * canvas)89 void onDraw(SkCanvas* canvas) override { 90 if (!fRenderer || !fTarget || !fTarget->handle()) { 91 canvas->clear(SK_ColorRED); 92 return; 93 } 94 fRenderer->clearTarget(fTarget->handle(), 0xFF808080); 95 auto bmp = this->drawText(); 96 SkPaint paint; 97 paint.setBlendMode(SkBlendMode::kSrc); 98 canvas->drawBitmap(bmp, 0, 0); 99 } 100 101 private: drawText()102 SkBitmap drawText() { 103 static const int kSizes[] = {8, 13, 18, 23, 30}; 104 105 static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 106 SkString("abcdefghijklmnopqrstuvwxyz"), 107 SkString("0123456789"), 108 SkString("!@#$%^&*()<>[]{}")}; 109 SkScalar x = 0; 110 SkScalar y = 10; 111 112 SkRandom random; 113 do { 114 for (auto s : kSizes) { 115 auto size = 2 * s; 116 for (const auto& typeface : fTypefaces) { 117 for (const auto& text : kTexts) { 118 // Choose a random color but don't let alpha be too small to see. 119 uint32_t color = random.nextU() | 0x40000000; 120 fTarget->save(); 121 // Randomly add a little bit of perspective 122 if (random.nextBool()) { 123 SkMatrix persp; 124 persp.reset(); 125 persp.setPerspY(0.0005f); 126 persp.preTranslate(-x, -y + s); 127 persp.postTranslate(x, y - s); 128 fTarget->concat(persp); 129 } 130 // Randomly switch between positioning with a matrix vs x, y passed to draw. 131 SkScalar drawX = x, drawY = y; 132 if (random.nextBool()) { 133 fTarget->translate(x, y); 134 drawX = drawY = 0; 135 } 136 x += size + 137 draw_string(fTarget.get(), text, drawX, drawY, color, typeface, size); 138 x = SkScalarCeilToScalar(x); 139 fTarget->restore(); 140 // Flush periodically to test continued drawing after a flush. 141 if ((random.nextU() % 8) == 0) { 142 fTarget->flush(); 143 } 144 if (x + 100 > kSize) { 145 x = 0; 146 y += SkScalarCeilToScalar(size + 3); 147 if (y > kSize) { 148 fTarget->flush(); 149 return fRenderer->readTargetHandle(fTarget->handle()); 150 } 151 } 152 } 153 } 154 } 155 } while (true); 156 } 157 158 static constexpr int kSize = 1280; 159 160 sk_sp<SkTypeface> fTypefaces[6]; 161 sk_sp<sk_gpu_test::TestAtlasTextRenderer> fRenderer; 162 std::unique_ptr<SkAtlasTextTarget> fTarget; 163 sk_sp<SkAtlasTextContext> fContext; 164 165 typedef GM INHERITED; 166 }; 167 168 constexpr int AtlasTextGM::kSize; 169 170 ////////////////////////////////////////////////////////////////////////////// 171 172 DEF_GM(return new AtlasTextGM;) 173 174 #endif 175