blob: 832a604e6e11529d838cb17076301817ef87f214 [file] [log] [blame]
Brian Salomoncbcb0a12017-11-19 13:20:13 -05001/*
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
12#include "SkAtlasTextContext.h"
13#include "SkAtlasTextFont.h"
14#include "SkAtlasTextTarget.h"
15#include "SkBitmap.h"
16#include "SkCanvas.h"
17#include "SkTypeface.h"
Brian Salomon0c1c2b32017-11-20 13:13:01 -050018#include "SkUtils.h"
Brian Salomoncbcb0a12017-11-19 13:20:13 -050019#include "gpu/TestContext.h"
20#include "gpu/atlastext/GLTestAtlasTextRenderer.h"
21#include "gpu/atlastext/TestAtlasTextRenderer.h"
22#include "sk_tool_utils.h"
23
24// GM that draws text using the Atlas Text interface offscreen and then blits that to the canvas.
25
26static SkScalar draw_string(SkAtlasTextTarget* target, const SkString& text, SkScalar x, SkScalar y,
27 uint32_t color, sk_sp<SkTypeface> typeface, float size) {
Brian Salomona0ba7142017-11-20 13:17:43 -050028 if (!text.size()) {
29 return x;
30 }
Brian Salomon0c1c2b32017-11-20 13:13:01 -050031 auto font = SkAtlasTextFont::Make(typeface, size);
32 int cnt = SkUTF8_CountUnichars(text.c_str());
33 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[cnt]);
34 typeface->charsToGlyphs(text.c_str(), SkTypeface::Encoding::kUTF8_Encoding, glyphs.get(), cnt);
35
Brian Salomona0ba7142017-11-20 13:17:43 -050036 // Using a paint to get the positions for each glyph.
Brian Salomoncbcb0a12017-11-19 13:20:13 -050037 SkPaint paint;
38 paint.setTextSize(size);
Brian Salomon0c1c2b32017-11-20 13:13:01 -050039 paint.setTypeface(std::move(typeface));
Brian Salomona0ba7142017-11-20 13:17:43 -050040 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
41 std::unique_ptr<SkScalar[]> widths(new SkScalar[cnt]);
42 paint.getTextWidths(glyphs.get(), cnt * sizeof(SkGlyphID), widths.get(), nullptr);
43
44 std::unique_ptr<SkPoint[]> positions(new SkPoint[cnt]);
45 positions[0] = {x, y};
46 for (int i = 1; i < cnt; ++i) {
47 positions[i] = {positions[i - 1].fX + widths[i - 1], y};
48 }
49
50 target->drawText(glyphs.get(), positions.get(), cnt, color, *font);
51
52 return positions[cnt - 1].fX + widths[cnt - 1];
Brian Salomoncbcb0a12017-11-19 13:20:13 -050053}
54
55class AtlasTextGM : public skiagm::GM {
56public:
57 AtlasTextGM() = default;
58
59protected:
60 SkString onShortName() override { return SkString("atlastext"); }
61
62 SkISize onISize() override { return SkISize::Make(kSize, kSize); }
63
64 void onOnceBeforeDraw() override {
65 fRenderer = sk_gpu_test::MakeGLTestAtlasTextRenderer();
66 if (!fRenderer) {
67 return;
68 }
69 fContext = SkAtlasTextContext::Make(fRenderer);
70 auto targetHandle = fRenderer->makeTargetHandle(kSize, kSize);
71 fTarget = SkAtlasTextTarget::Make(fContext, kSize, kSize, targetHandle);
72
73 fTypefaces[0] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Italic());
74 fTypefaces[1] =
75 sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Italic());
76 fTypefaces[2] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Normal());
77 fTypefaces[3] =
78 sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Normal());
79 fTypefaces[4] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Bold());
80 fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
81 }
82
83 void onDraw(SkCanvas* canvas) override {
84 if (!fRenderer) {
85 canvas->clear(SK_ColorRED);
86 return;
87 }
Brian Salomon40dc8a72017-11-20 11:01:54 -050088 fRenderer->clearTarget(fTarget->handle(), 0xFF808080);
Brian Salomoncbcb0a12017-11-19 13:20:13 -050089 auto bmp = this->drawText();
90 SkPaint paint;
91 paint.setBlendMode(SkBlendMode::kSrc);
92 canvas->drawBitmap(bmp, 0, 0);
93 }
94
95private:
96 SkBitmap drawText() {
97 static const int kSizes[] = {8, 13, 18, 23, 30};
98
99 static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
100 SkString("abcdefghijklmnopqrstuvwxyz"),
101 SkString("0123456789"),
102 SkString("!@#$%^&*()<>[]{}")};
103 SkScalar x = 0;
104 SkScalar y = 10;
105
106 SkRandom random;
107 do {
108 for (auto s : kSizes) {
109 auto size = 2 * s;
110 for (const auto& typeface : fTypefaces) {
111 for (const auto& text : kTexts) {
112 uint32_t color = random.nextU();
113 x = size + draw_string(fTarget.get(), text, x, y, color, typeface, size);
114 x = SkScalarCeilToScalar(x);
Brian Salomoncf1aa532017-11-29 14:58:59 -0500115 // Flush periodically to test continued drawing after a flush. Using color
116 // to avoid churning the RNG and having to rebaseline images.
117 if (!(color & 0xf)) {
118 fTarget->flush();
119 }
Brian Salomoncbcb0a12017-11-19 13:20:13 -0500120 if (x + 100 > kSize) {
121 x = 0;
122 y += SkScalarCeilToScalar(size + 3);
123 if (y > kSize) {
124 fTarget->flush();
125 return fRenderer->readTargetHandle(fTarget->handle());
126 }
127 }
128 }
129 }
130 }
131 } while (true);
132 }
133
134 static constexpr int kSize = 1280;
135
136 sk_sp<SkTypeface> fTypefaces[6];
137 sk_sp<sk_gpu_test::TestAtlasTextRenderer> fRenderer;
138 std::unique_ptr<SkAtlasTextTarget> fTarget;
139 sk_sp<SkAtlasTextContext> fContext;
140
141 typedef GM INHERITED;
142};
143
144constexpr int AtlasTextGM::kSize;
145
146//////////////////////////////////////////////////////////////////////////////
147
148DEF_GM(return new AtlasTextGM;)
149
150#endif