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