1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "gm/gm.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
11cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
12cb93a386Sopenharmony_ci#include "include/core/SkFontStyle.h"
13cb93a386Sopenharmony_ci#include "include/core/SkFontTypes.h"
14cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
15cb93a386Sopenharmony_ci#include "include/core/SkPoint.h"
16cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
17cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h"
18cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
19cb93a386Sopenharmony_ci#include "include/core/SkSize.h"
20cb93a386Sopenharmony_ci#include "include/core/SkString.h"
21cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
22cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
23cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
24cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h"
25cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci#include <cstring>
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cinamespace  {
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cienum Pos {
32cb93a386Sopenharmony_ci    kDefault_Pos = 0,
33cb93a386Sopenharmony_ci    kScalar_Pos  = 1,
34cb93a386Sopenharmony_ci    kPoint_Pos   = 2,
35cb93a386Sopenharmony_ci};
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ciconst struct BlobCfg {
38cb93a386Sopenharmony_ci    unsigned count;
39cb93a386Sopenharmony_ci    Pos      pos;
40cb93a386Sopenharmony_ci    SkScalar scale;
41cb93a386Sopenharmony_ci} blobConfigs[][3][3] = {
42cb93a386Sopenharmony_ci    {
43cb93a386Sopenharmony_ci        { { 1024, kDefault_Pos, 1 }, { 0, kDefault_Pos, 0 }, { 0, kDefault_Pos, 0 } },
44cb93a386Sopenharmony_ci        { { 1024,  kScalar_Pos, 1 }, { 0,  kScalar_Pos, 0 }, { 0,  kScalar_Pos, 0 } },
45cb93a386Sopenharmony_ci        { { 1024,   kPoint_Pos, 1 }, { 0,   kPoint_Pos, 0 }, { 0,   kPoint_Pos, 0 } },
46cb93a386Sopenharmony_ci    },
47cb93a386Sopenharmony_ci    {
48cb93a386Sopenharmony_ci        { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4, kDefault_Pos, 1 } },
49cb93a386Sopenharmony_ci        { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
50cb93a386Sopenharmony_ci        { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
51cb93a386Sopenharmony_ci    },
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    {
54cb93a386Sopenharmony_ci        { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
55cb93a386Sopenharmony_ci        { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
56cb93a386Sopenharmony_ci        { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
57cb93a386Sopenharmony_ci    },
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    {
60cb93a386Sopenharmony_ci        { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
61cb93a386Sopenharmony_ci        { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
62cb93a386Sopenharmony_ci        { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
63cb93a386Sopenharmony_ci    },
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    {
66cb93a386Sopenharmony_ci        { { 4, kDefault_Pos, .75f },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1.25f } },
67cb93a386Sopenharmony_ci        { { 4,  kScalar_Pos, .75f },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1.25f } },
68cb93a386Sopenharmony_ci        { { 4,   kPoint_Pos, .75f },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1.25f } },
69cb93a386Sopenharmony_ci    },
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    {
72cb93a386Sopenharmony_ci        { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, .75f },  { 4,   kPoint_Pos, 1.25f } },
73cb93a386Sopenharmony_ci        { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, .75f },  { 4, kDefault_Pos, 1.25f } },
74cb93a386Sopenharmony_ci        { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, .75f },  { 4,  kScalar_Pos, 1.25f } },
75cb93a386Sopenharmony_ci    },
76cb93a386Sopenharmony_ci};
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ciconst SkScalar kFontSize = 16;
79cb93a386Sopenharmony_ci}  // namespace
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ciclass TextBlobGM : public skiagm::GM {
82cb93a386Sopenharmony_cipublic:
83cb93a386Sopenharmony_ci    TextBlobGM(const char* txt)
84cb93a386Sopenharmony_ci        : fText(txt) {
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ciprotected:
88cb93a386Sopenharmony_ci    void onOnceBeforeDraw() override {
89cb93a386Sopenharmony_ci        fTypeface = ToolUtils::create_portable_typeface("serif", SkFontStyle());
90cb93a386Sopenharmony_ci        SkFont font(fTypeface);
91cb93a386Sopenharmony_ci        size_t txtLen = strlen(fText);
92cb93a386Sopenharmony_ci        int glyphCount = font.countText(fText, txtLen, SkTextEncoding::kUTF8);
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci        fGlyphs.append(glyphCount);
95cb93a386Sopenharmony_ci        font.textToGlyphs(fText, txtLen, SkTextEncoding::kUTF8, fGlyphs.begin(), glyphCount);
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    SkString onShortName() override {
99cb93a386Sopenharmony_ci        return SkString("textblob");
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci    SkISize onISize() override {
103cb93a386Sopenharmony_ci        return SkISize::Make(640, 480);
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    void onDraw(SkCanvas* canvas) override {
107cb93a386Sopenharmony_ci        for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
108cb93a386Sopenharmony_ci            sk_sp<SkTextBlob> blob(this->makeBlob(b));
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci            SkPaint p;
111cb93a386Sopenharmony_ci            p.setAntiAlias(true);
112cb93a386Sopenharmony_ci            SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)),
113cb93a386Sopenharmony_ci                                           SkIntToScalar(20 + 150 * (b / 2)));
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci            canvas->drawTextBlob(blob, offset.x(), offset.y(), p);
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci            p.setColor(SK_ColorBLUE);
118cb93a386Sopenharmony_ci            p.setStyle(SkPaint::kStroke_Style);
119cb93a386Sopenharmony_ci            SkRect box = blob->bounds();
120cb93a386Sopenharmony_ci            box.offset(offset);
121cb93a386Sopenharmony_ci            p.setAntiAlias(false);
122cb93a386Sopenharmony_ci            canvas->drawRect(box, p);
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci        }
125cb93a386Sopenharmony_ci    }
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ciprivate:
128cb93a386Sopenharmony_ci    sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) {
129cb93a386Sopenharmony_ci        SkTextBlobBuilder builder;
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci        SkFont font;
132cb93a386Sopenharmony_ci        font.setSubpixel(true);
133cb93a386Sopenharmony_ci        font.setEdging(SkFont::Edging::kAntiAlias);
134cb93a386Sopenharmony_ci        font.setTypeface(fTypeface);
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci        for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
137cb93a386Sopenharmony_ci            unsigned currentGlyph = 0;
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci            for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) {
140cb93a386Sopenharmony_ci                const BlobCfg* cfg = &blobConfigs[blobIndex][l][c];
141cb93a386Sopenharmony_ci                unsigned count = cfg->count;
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci                if (count > fGlyphs.count() - currentGlyph) {
144cb93a386Sopenharmony_ci                    count = fGlyphs.count() - currentGlyph;
145cb93a386Sopenharmony_ci                }
146cb93a386Sopenharmony_ci                if (0 == count) {
147cb93a386Sopenharmony_ci                    break;
148cb93a386Sopenharmony_ci                }
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci                font.setSize(kFontSize * cfg->scale);
151cb93a386Sopenharmony_ci                const SkScalar advanceX = font.getSize() * 0.85f;
152cb93a386Sopenharmony_ci                const SkScalar advanceY = font.getSize() * 1.5f;
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci                SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX,
155cb93a386Sopenharmony_ci                                               advanceY * l);
156cb93a386Sopenharmony_ci                switch (cfg->pos) {
157cb93a386Sopenharmony_ci                case kDefault_Pos: {
158cb93a386Sopenharmony_ci                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count,
159cb93a386Sopenharmony_ci                                                                               offset.x(),
160cb93a386Sopenharmony_ci                                                                               offset.y());
161cb93a386Sopenharmony_ci                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
162cb93a386Sopenharmony_ci                } break;
163cb93a386Sopenharmony_ci                case kScalar_Pos: {
164cb93a386Sopenharmony_ci                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count,
165cb93a386Sopenharmony_ci                                                                                   offset.y());
166cb93a386Sopenharmony_ci                    SkTDArray<SkScalar> pos;
167cb93a386Sopenharmony_ci                    for (unsigned i = 0; i < count; ++i) {
168cb93a386Sopenharmony_ci                        *pos.append() = offset.x() + i * advanceX;
169cb93a386Sopenharmony_ci                    }
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
172cb93a386Sopenharmony_ci                    memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar));
173cb93a386Sopenharmony_ci                } break;
174cb93a386Sopenharmony_ci                case kPoint_Pos: {
175cb93a386Sopenharmony_ci                    const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count);
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci                    SkTDArray<SkScalar> pos;
178cb93a386Sopenharmony_ci                    for (unsigned i = 0; i < count; ++i) {
179cb93a386Sopenharmony_ci                        *pos.append() = offset.x() + i * advanceX;
180cb93a386Sopenharmony_ci                        *pos.append() = offset.y() + i * (advanceY / count);
181cb93a386Sopenharmony_ci                    }
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci                    memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
184cb93a386Sopenharmony_ci                    memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2);
185cb93a386Sopenharmony_ci                } break;
186cb93a386Sopenharmony_ci                default:
187cb93a386Sopenharmony_ci                    SK_ABORT("unhandled pos value");
188cb93a386Sopenharmony_ci                }
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci                currentGlyph += count;
191cb93a386Sopenharmony_ci            }
192cb93a386Sopenharmony_ci        }
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci        return builder.make();
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci    SkTDArray<uint16_t> fGlyphs;
198cb93a386Sopenharmony_ci    sk_sp<SkTypeface>   fTypeface;
199cb93a386Sopenharmony_ci    const char*         fText;
200cb93a386Sopenharmony_ci    using INHERITED = skiagm::GM;
201cb93a386Sopenharmony_ci};
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ciDEF_GM(return new TextBlobGM("hamburgefons");)
204