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 | |
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 | |
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 | |
97 | SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() { |
98 | sk_bzero(&fMetrics, sizeof(fMetrics)); |
99 | } |
100 | |
101 | void SkCustomTypefaceBuilder::setMetrics(const SkFontMetrics& fm, float scale) { |
102 | fMetrics = scale_fontmetrics(fm, scale, scale); |
103 | } |
104 | |
105 | void 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 | |
115 | sk_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 | |
144 | void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const { |
145 | rec->setHinting(SkFontHinting::kNone); |
146 | } |
147 | |
148 | void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const { |
149 | for (int gid = 0; gid < this->glyphCount(); ++gid) { |
150 | glyphToUnicode[gid] = SkTo<SkUnichar>(gid); |
151 | } |
152 | } |
153 | |
154 | std::unique_ptr<SkAdvancedTypefaceMetrics> SkUserTypeface::onGetAdvancedMetrics() const { |
155 | return nullptr; |
156 | } |
157 | |
158 | void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { |
159 | *isLocal = true; |
160 | } |
161 | |
162 | void 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 | |
168 | void SkUserTypeface::onGetFamilyName(SkString* familyName) const { |
169 | *familyName = "" ; |
170 | } |
171 | |
172 | SkTypeface::LocalizedStrings* SkUserTypeface::onCreateFamilyNameIterator() const { |
173 | return nullptr; |
174 | } |
175 | |
176 | ////////////// |
177 | |
178 | #include "src/core/SkScalerContext.h" |
179 | |
180 | class SkUserScalerContext : public SkScalerContext { |
181 | public: |
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 | |
194 | protected: |
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 | |
226 | private: |
227 | SkMatrix fMatrix; |
228 | }; |
229 | |
230 | SkScalerContext* 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 | |
241 | static void write_scaled_float_to_16(SkWStream* stream, float x, float scale) { |
242 | stream->write16(SkToS16(sk_float_round2int(x * scale)) & 0xFFFF); |
243 | } |
244 | |
245 | enum PVerb { |
246 | kMove, |
247 | kLine, |
248 | kCurve, |
249 | kClose, |
250 | }; |
251 | |
252 | static 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 | |
305 | static constexpr int kMaxGlyphCount = 65536; |
306 | static constexpr size_t = 16; |
307 | static const char [] = "SkUserTypeface01" ; |
308 | static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes" ); |
309 | |
310 | std::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 | |
344 | class AutoRestorePosition { |
345 | SkStream* fStream; |
346 | size_t fPosition; |
347 | public: |
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 | |
362 | sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) { |
363 | AutoRestorePosition arp(stream); |
364 | |
365 | char [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 | |