1/*
2 * Copyright 2020 Google LLC
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 "include/core/SkCanvas.h"
9#include "include/core/SkData.h"
10#include "include/core/SkFontMetrics.h"
11#include "include/utils/SkCustomTypeface.h"
12#include "src/core/SkAdvancedTypefaceMetrics.h"
13
14static SkFontMetrics scale_fontmetrics(const SkFontMetrics& src, float sx, float sy) {
15 SkFontMetrics dst = src;
16
17 #define SCALE_X(field) dst.field *= sx
18 #define SCALE_Y(field) dst.field *= sy
19
20 SCALE_X(fAvgCharWidth);
21 SCALE_X(fMaxCharWidth);
22 SCALE_X(fXMin);
23 SCALE_X(fXMax);
24
25 SCALE_Y(fTop);
26 SCALE_Y(fAscent);
27 SCALE_Y(fDescent);
28 SCALE_Y(fBottom);
29 SCALE_Y(fLeading);
30 SCALE_Y(fXHeight);
31 SCALE_Y(fCapHeight);
32 SCALE_Y(fUnderlineThickness);
33 SCALE_Y(fUnderlinePosition);
34 SCALE_Y(fStrikeoutThickness);
35 SCALE_Y(fStrikeoutPosition);
36
37 #undef SCALE_X
38 #undef SCALE_Y
39
40 return dst;
41}
42
43class SkUserTypeface final : public SkTypeface {
44private:
45 friend class SkCustomTypefaceBuilder;
46 friend class SkUserScalerContext;
47
48 SkUserTypeface() : SkTypeface(SkFontStyle()) {}
49
50 std::vector<SkPath> fPaths;
51 std::vector<float> fAdvances;
52 SkFontMetrics fMetrics;
53
54 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
55 const SkDescriptor* desc) const override;
56 void onFilterRec(SkScalerContextRec* rec) const override;
57 void getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const override;
58 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
59
60 void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override;
61
62 void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
63
64 void onGetFamilyName(SkString* familyName) const override;
65 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
66
67 std::unique_ptr<SkStreamAsset> onOpenStream(int*) const override;
68
69 // trivial
70
71 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
72 return sk_ref_sp(this);
73 }
74 int onCountGlyphs() const override { return this->glyphCount(); }
75 int onGetUPEM() const override { return 2048; /* ?? */ }
76 bool onComputeBounds(SkRect* bounds) const override {
77 bounds->setLTRB(fMetrics.fXMin, fMetrics.fTop, fMetrics.fXMax, fMetrics.fBottom);
78 return true;
79 }
80
81 // noops
82
83 void getPostScriptGlyphNames(SkString*) const override {}
84 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[],
85 int) const override { return 0; }
86 int onGetVariationDesignParameters(SkFontParameters::Variation::Axis[],
87 int) const override { return 0; }
88 int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
89 size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
90
91 int glyphCount() const {
92 SkASSERT(fPaths.size() == fAdvances.size());
93 return SkToInt(fPaths.size());
94 }
95};
96
97SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() {
98 sk_bzero(&fMetrics, sizeof(fMetrics));
99}
100
101void SkCustomTypefaceBuilder::setMetrics(const SkFontMetrics& fm, float scale) {
102 fMetrics = scale_fontmetrics(fm, scale, scale);
103}
104
105void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) {
106 SkASSERT(fPaths.size() == fAdvances.size());
107 if (index >= fPaths.size()) {
108 fPaths.resize(SkToSizeT(index) + 1);
109 fAdvances.resize(SkToSizeT(index) + 1);
110 }
111 fAdvances[index] = advance;
112 fPaths[index] = path;
113}
114
115sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() {
116 SkASSERT(fPaths.size() == fAdvances.size());
117 if (fPaths.empty()) return nullptr;
118
119 sk_sp<SkUserTypeface> tf(new SkUserTypeface());
120 tf->fAdvances = std::move(fAdvances);
121 tf->fPaths = std::move(fPaths);
122 tf->fMetrics = fMetrics;
123
124 // initially inverted, so that any "union" will overwrite the first time
125 SkRect bounds = {SK_ScalarMax, SK_ScalarMax, -SK_ScalarMax, -SK_ScalarMax};
126
127 for (const auto& path : tf->fPaths) {
128 if (!path.isEmpty()) {
129 bounds.join(path.getBounds());
130 }
131 }
132 tf->fMetrics.fTop = bounds.top();
133 tf->fMetrics.fBottom = bounds.bottom();
134 tf->fMetrics.fXMin = bounds.left();
135 tf->fMetrics.fXMax = bounds.right();
136
137 return std::move(tf);
138}
139
140/////////////
141
142#include "src/core/SkScalerContext.h"
143
144void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const {
145 rec->setHinting(SkFontHinting::kNone);
146}
147
148void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
149 for (int gid = 0; gid < this->glyphCount(); ++gid) {
150 glyphToUnicode[gid] = SkTo<SkUnichar>(gid);
151 }
152}
153
154std::unique_ptr<SkAdvancedTypefaceMetrics> SkUserTypeface::onGetAdvancedMetrics() const {
155 return nullptr;
156}
157
158void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
159 *isLocal = true;
160}
161
162void SkUserTypeface::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
163 for (int i = 0; i < count; ++i) {
164 glyphs[i] = uni[i] < this->glyphCount() ? SkTo<SkGlyphID>(uni[i]) : 0;
165 }
166}
167
168void SkUserTypeface::onGetFamilyName(SkString* familyName) const {
169 *familyName = "";
170}
171
172SkTypeface::LocalizedStrings* SkUserTypeface::onCreateFamilyNameIterator() const {
173 return nullptr;
174}
175
176//////////////
177
178#include "src/core/SkScalerContext.h"
179
180class SkUserScalerContext : public SkScalerContext {
181public:
182 SkUserScalerContext(sk_sp<SkUserTypeface> face,
183 const SkScalerContextEffects& effects,
184 const SkDescriptor* desc)
185 : SkScalerContext(std::move(face), effects, desc) {
186 fRec.getSingleMatrix(&fMatrix);
187 this->forceGenerateImageFromPath();
188 }
189
190 const SkUserTypeface* userTF() const {
191 return static_cast<SkUserTypeface*>(this->getTypeface());
192 }
193
194protected:
195 unsigned generateGlyphCount() override {
196 return this->userTF()->glyphCount();
197 }
198
199 bool generateAdvance(SkGlyph* glyph) override {
200 const SkUserTypeface* tf = this->userTF();
201 auto advance = fMatrix.mapXY(tf->fAdvances[glyph->getGlyphID()], 0);
202
203 glyph->fAdvanceX = advance.fX;
204 glyph->fAdvanceY = advance.fY;
205 return true;
206 }
207
208 void generateMetrics(SkGlyph* glyph) override {
209 glyph->zeroMetrics();
210 this->generateAdvance(glyph);
211 // Always generates from paths, so SkScalerContext::getMetrics will figure the bounds.
212 }
213
214 void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); }
215
216 bool generatePath(SkGlyphID glyph, SkPath* path) override {
217 this->userTF()->fPaths[glyph].transform(fMatrix, path);
218 return true;
219 }
220
221 void generateFontMetrics(SkFontMetrics* metrics) override {
222 auto [sx, sy] = fMatrix.mapXY(1, 1);
223 *metrics = scale_fontmetrics(this->userTF()->fMetrics, sx, sy);
224 }
225
226private:
227 SkMatrix fMatrix;
228};
229
230SkScalerContext* SkUserTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
231 const SkDescriptor* desc) const {
232 return new SkUserScalerContext(sk_ref_sp(const_cast<SkUserTypeface*>(this)), effects, desc);
233}
234
235///////////////////////////////////////////////////////////////////////////////////////////////////
236
237#include "include/private/SkFloatingPoint.h"
238#include "src/core/SkAutoMalloc.h"
239#include "src/core/SkPathPriv.h"
240
241static void write_scaled_float_to_16(SkWStream* stream, float x, float scale) {
242 stream->write16(SkToS16(sk_float_round2int(x * scale)) & 0xFFFF);
243}
244
245enum PVerb {
246 kMove,
247 kLine,
248 kCurve,
249 kClose,
250};
251
252static void compress_write(SkWStream* stream, const SkPath& path, int upem) {
253 int pCount = 0;
254 std::vector<PVerb> verbs;
255 for (auto [v, p, w] : SkPathPriv::Iterate(path)) {
256 switch (v) {
257 default: break;
258 case SkPathVerb::kMove: verbs.push_back(kMove); pCount += 1; break;
259 case SkPathVerb::kQuad: verbs.push_back(kCurve); pCount += 2; break;
260 case SkPathVerb::kLine: verbs.push_back(kLine); pCount += 1; break;
261 case SkPathVerb::kClose: verbs.push_back(kClose); break;
262 }
263 }
264
265 int vCount = verbs.size();
266
267 stream->write16(upem); // share w/ other paths?
268 stream->write16(vCount);
269 stream->write16(pCount);
270 for (int i = 0; i < (vCount & ~3); i += 4) {
271 stream->write8((verbs[i+0]<<6) | (verbs[i+1]<<4) | (verbs[i+2]<<2) | verbs[i+3]);
272 }
273 if (vCount & 3) {
274 uint8_t b = 0;
275 int shift = 6;
276 for (int i = vCount & ~3; i < vCount; ++i) {
277 b |= verbs[i] << shift;
278 shift >>= 2;
279 }
280 stream->write8(b);
281 }
282 if (vCount & 1) {
283 stream->write8(0);
284 }
285
286 const float scale = (float)upem;
287 auto write_pts = [&](const SkPoint pts[], int count) {
288 for (int i = 0; i < count; ++i) {
289 write_scaled_float_to_16(stream, pts[i].fX, scale);
290 write_scaled_float_to_16(stream, pts[i].fY, scale);
291 }
292 };
293
294 for (auto [v, p, w] : SkPathPriv::Iterate(path)) {
295 switch (v) {
296 default: break;
297 case SkPathVerb::kMove: write_pts(&p[0], 1); break;
298 case SkPathVerb::kQuad: write_pts(&p[1], 2); break;
299 case SkPathVerb::kLine: write_pts(&p[1], 1); break;
300 case SkPathVerb::kClose: break;
301 }
302 }
303}
304
305static constexpr int kMaxGlyphCount = 65536;
306static constexpr size_t kHeaderSize = 16;
307static const char gHeaderString[] = "SkUserTypeface01";
308static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes");
309
310std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const {
311 SkDynamicMemoryWStream wstream;
312
313 wstream.write(gHeaderString, kHeaderSize);
314
315 wstream.write(&fMetrics, sizeof(fMetrics));
316
317 // just hacking around -- this makes the serialized font 1/2 size
318 const bool use_compression = false;
319
320 wstream.write32(this->glyphCount());
321
322 if (use_compression) {
323 for (float a : fAdvances) {
324 write_scaled_float_to_16(&wstream, a, 2048);
325 }
326 } else {
327 wstream.write(fAdvances.data(), this->glyphCount() * sizeof(float));
328 }
329
330 for (const auto& p : fPaths) {
331 if (use_compression) {
332 compress_write(&wstream, p, 2048);
333 } else {
334 auto data = p.serialize();
335 SkASSERT(SkIsAlign4(data->size()));
336 wstream.write(data->data(), data->size());
337 }
338 }
339// SkDebugf("%d glyphs, %d bytes\n", fGlyphCount, wstream.bytesWritten());
340 *ttcIndex = 0;
341 return wstream.detachAsStream();
342}
343
344class AutoRestorePosition {
345 SkStream* fStream;
346 size_t fPosition;
347public:
348 AutoRestorePosition(SkStream* stream) : fStream(stream) {
349 fPosition = stream->getPosition();
350 }
351
352 ~AutoRestorePosition() {
353 if (fStream) {
354 fStream->seek(fPosition);
355 }
356 }
357
358 // So we don't restore the position
359 void markDone() { fStream = nullptr; }
360};
361
362sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
363 AutoRestorePosition arp(stream);
364
365 char header[kHeaderSize];
366 if (stream->read(header, kHeaderSize) != kHeaderSize ||
367 memcmp(header, gHeaderString, kHeaderSize) != 0)
368 {
369 return nullptr;
370 }
371
372 SkFontMetrics metrics;
373 if (stream->read(&metrics, sizeof(metrics)) != sizeof(metrics)) {
374 return nullptr;
375 }
376
377 int glyphCount;
378 if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) {
379 return nullptr;
380 }
381
382 SkCustomTypefaceBuilder builder;
383
384 builder.setMetrics(metrics);
385
386 std::vector<float> advances(glyphCount);
387 if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) {
388 return nullptr;
389 }
390
391 // SkPath can read from a stream, so we have to page the rest into ram
392 const size_t offset = stream->getPosition();
393 const size_t length = stream->getLength() - offset;
394 SkAutoMalloc ram(length);
395 char* buffer = (char*)ram.get();
396
397 if (stream->read(buffer, length) != length) {
398 return nullptr;
399 }
400
401 size_t totalUsed = 0;
402 for (int i = 0; i < glyphCount; ++i) {
403 SkPath path;
404 size_t used = path.readFromMemory(buffer + totalUsed, length - totalUsed);
405 if (used == 0) {
406 return nullptr;
407 }
408 builder.setGlyph(i, advances[i], path);
409 totalUsed += used;
410 SkASSERT(length >= totalUsed);
411 }
412
413 // all done, update the stream to only reflect the bytes we needed
414 stream->seek(offset + totalUsed);
415
416 arp.markDone();
417 return builder.detach();
418}
419