xref: /aosp_15_r20/external/skia/src/utils/SkCustomTypeface.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/utils/SkCustomTypeface.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkDrawable.h"
14 #include "include/core/SkFontArguments.h"
15 #include "include/core/SkFontMetrics.h"
16 #include "include/core/SkFontParameters.h"
17 #include "include/core/SkFontStyle.h"
18 #include "include/core/SkFontTypes.h"
19 #include "include/core/SkMatrix.h"
20 #include "include/core/SkPaint.h"
21 #include "include/core/SkPath.h"
22 #include "include/core/SkPoint.h"
23 #include "include/core/SkRect.h"
24 #include "include/core/SkRefCnt.h"
25 #include "include/core/SkScalar.h"
26 #include "include/core/SkSerialProcs.h"
27 #include "include/core/SkStream.h"
28 #include "include/core/SkString.h"
29 #include "include/core/SkTypeface.h"
30 #include "include/core/SkTypes.h"
31 #include "include/private/base/SkAlign.h"
32 #include "include/private/base/SkFixed.h"
33 #include "include/private/base/SkMalloc.h"
34 #include "include/private/base/SkTo.h"
35 #include "src/core/SkAdvancedTypefaceMetrics.h" // IWYU pragma: keep
36 #include "src/core/SkFontDescriptor.h"
37 #include "src/core/SkGlyph.h"
38 #include "src/core/SkMask.h"
39 #include "src/core/SkScalerContext.h"
40 #include "src/core/SkStreamPriv.h"
41 
42 #include <cstdint>
43 #include <cstring>
44 #include <memory>
45 #include <utility>
46 #include <vector>
47 
48 class SkArenaAlloc;
49 class SkDescriptor;
50 
51 namespace {
52 static inline const constexpr bool kSkShowTextBlitCoverage = false;
53 }
54 
scale_fontmetrics(const SkFontMetrics & src,float sx,float sy)55 static SkFontMetrics scale_fontmetrics(const SkFontMetrics& src, float sx, float sy) {
56     SkFontMetrics dst = src;
57 
58     #define SCALE_X(field)  dst.field *= sx
59     #define SCALE_Y(field)  dst.field *= sy
60 
61     SCALE_X(fAvgCharWidth);
62     SCALE_X(fMaxCharWidth);
63     SCALE_X(fXMin);
64     SCALE_X(fXMax);
65 
66     SCALE_Y(fTop);
67     SCALE_Y(fAscent);
68     SCALE_Y(fDescent);
69     SCALE_Y(fBottom);
70     SCALE_Y(fLeading);
71     SCALE_Y(fXHeight);
72     SCALE_Y(fCapHeight);
73     SCALE_Y(fUnderlineThickness);
74     SCALE_Y(fUnderlinePosition);
75     SCALE_Y(fStrikeoutThickness);
76     SCALE_Y(fStrikeoutPosition);
77 
78     #undef SCALE_X
79     #undef SCALE_Y
80 
81     return dst;
82 }
83 
84 class SkUserTypeface final : public SkTypeface {
85 private:
86     friend class SkCustomTypefaceBuilder;
87     friend class SkUserScalerContext;
88 
SkUserTypeface(SkFontStyle style,const SkFontMetrics & metrics,std::vector<SkCustomTypefaceBuilder::GlyphRec> && recs)89     explicit SkUserTypeface(SkFontStyle style, const SkFontMetrics& metrics,
90                             std::vector<SkCustomTypefaceBuilder::GlyphRec>&& recs)
91         : SkTypeface(style)
92         , fGlyphRecs(std::move(recs))
93         , fMetrics(metrics)
94     {}
95 
96     const std::vector<SkCustomTypefaceBuilder::GlyphRec> fGlyphRecs;
97     const SkFontMetrics                                  fMetrics;
98 
99     std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
100                                                            const SkDescriptor* desc) const override;
101     void onFilterRec(SkScalerContextRec* rec) const override;
102     void getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const override;
103     std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
104 
105     void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override;
106 
107     void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
108 
109     void onGetFamilyName(SkString* familyName) const override;
110     bool onGetPostScriptName(SkString*) const override;
111     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
112 
113     std::unique_ptr<SkStreamAsset> onOpenStream(int*) const override;
114 
115     // trivial
116 
onOpenExistingStream(int *) const117     std::unique_ptr<SkStreamAsset> onOpenExistingStream(int*) const override { return nullptr; }
118 
onMakeClone(const SkFontArguments & args) const119     sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
120         return sk_ref_sp(this);
121     }
onCountGlyphs() const122     int onCountGlyphs() const override { return this->glyphCount(); }
onGetUPEM() const123     int onGetUPEM() const override { return 2048; /* ?? */ }
onComputeBounds(SkRect * bounds) const124     bool onComputeBounds(SkRect* bounds) const override {
125         bounds->setLTRB(fMetrics.fXMin, fMetrics.fTop, fMetrics.fXMax, fMetrics.fBottom);
126         return true;
127     }
128 
129     // noops
130 
getPostScriptGlyphNames(SkString *) const131     void getPostScriptGlyphNames(SkString*) const override {}
onGlyphMaskNeedsCurrentColor() const132     bool onGlyphMaskNeedsCurrentColor() const override { return false; }
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[],int) const133     int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[],
134                                      int) const override { return 0; }
onGetVariationDesignParameters(SkFontParameters::Variation::Axis[],int) const135     int onGetVariationDesignParameters(SkFontParameters::Variation::Axis[],
136                                        int) const override { return 0; }
onGetTableTags(SkFontTableTag tags[]) const137     int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
onGetTableData(SkFontTableTag,size_t,size_t,void *) const138     size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
139 
glyphCount() const140     int glyphCount() const {
141         return SkToInt(fGlyphRecs.size());
142     }
143 };
144 
SkCustomTypefaceBuilder()145 SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() {
146     sk_bzero(&fMetrics, sizeof(fMetrics));
147 }
148 
setMetrics(const SkFontMetrics & fm,float scale)149 void SkCustomTypefaceBuilder::setMetrics(const SkFontMetrics& fm, float scale) {
150     fMetrics = scale_fontmetrics(fm, scale, scale);
151 }
152 
setFontStyle(SkFontStyle style)153 void SkCustomTypefaceBuilder::setFontStyle(SkFontStyle style) {
154     fStyle = style;
155 }
156 
ensureStorage(SkGlyphID index)157 SkCustomTypefaceBuilder::GlyphRec& SkCustomTypefaceBuilder::ensureStorage(SkGlyphID index) {
158     if (index >= fGlyphRecs.size()) {
159            fGlyphRecs.resize(SkToSizeT(index) + 1);
160     }
161 
162     return fGlyphRecs[index];
163 }
164 
setGlyph(SkGlyphID index,float advance,const SkPath & path)165 void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) {
166     auto& rec = this->ensureStorage(index);
167     rec.fAdvance  = advance;
168     rec.fPath     = path;
169     rec.fDrawable = nullptr;
170 }
171 
setGlyph(SkGlyphID index,float advance,sk_sp<SkDrawable> drawable,const SkRect & bounds)172 void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance,
173                                        sk_sp<SkDrawable> drawable, const SkRect& bounds) {
174     auto& rec = this->ensureStorage(index);
175     rec.fAdvance  = advance;
176     rec.fDrawable = std::move(drawable);
177     rec.fBounds   = bounds;
178     rec.fPath.reset();
179 }
180 
detach()181 sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() {
182     if (fGlyphRecs.empty()) return nullptr;
183 
184     // initially inverted, so that any "union" will overwrite the first time
185     SkRect bounds = {SK_ScalarMax, SK_ScalarMax, -SK_ScalarMax, -SK_ScalarMax};
186 
187     for (const auto& rec : fGlyphRecs) {
188         bounds.join(rec.isDrawable()
189                         ? rec.fBounds
190                         : rec.fPath.getBounds());
191     }
192 
193     fMetrics.fTop    = bounds.top();
194     fMetrics.fBottom = bounds.bottom();
195     fMetrics.fXMin   = bounds.left();
196     fMetrics.fXMax   = bounds.right();
197 
198     return sk_sp<SkUserTypeface>(new SkUserTypeface(fStyle, fMetrics, std::move(fGlyphRecs)));
199 }
200 
201 /////////////
202 
onFilterRec(SkScalerContextRec * rec) const203 void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const {
204     rec->useStrokeForFakeBold();
205     rec->setHinting(SkFontHinting::kNone);
206 }
207 
getGlyphToUnicodeMap(SkUnichar * glyphToUnicode) const208 void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
209     for (int gid = 0; gid < this->glyphCount(); ++gid) {
210         glyphToUnicode[gid] = SkTo<SkUnichar>(gid);
211     }
212 }
213 
onGetAdvancedMetrics() const214 std::unique_ptr<SkAdvancedTypefaceMetrics> SkUserTypeface::onGetAdvancedMetrics() const {
215     return nullptr;
216 }
217 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocal) const218 void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
219     desc->setFactoryId(SkCustomTypefaceBuilder::FactoryId);
220     *isLocal = true;
221 }
222 
onCharsToGlyphs(const SkUnichar * chars,int count,SkGlyphID glyphs[]) const223 void SkUserTypeface::onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const {
224     for (int i = 0; i < count; ++i) {
225         glyphs[i] = chars[i] < this->glyphCount() ? SkTo<SkGlyphID>(chars[i]) : 0;
226     }
227 }
228 
onGetFamilyName(SkString * familyName) const229 void SkUserTypeface::onGetFamilyName(SkString* familyName) const {
230     *familyName = "";
231 }
232 
onGetPostScriptName(SkString *) const233 bool SkUserTypeface::onGetPostScriptName(SkString*) const {
234     return false;
235 }
236 
onCreateFamilyNameIterator() const237 SkTypeface::LocalizedStrings* SkUserTypeface::onCreateFamilyNameIterator() const {
238     return nullptr;
239 }
240 
241 //////////////
242 
243 class SkUserScalerContext : public SkScalerContext {
244 public:
SkUserScalerContext(sk_sp<SkUserTypeface> face,const SkScalerContextEffects & effects,const SkDescriptor * desc)245     SkUserScalerContext(sk_sp<SkUserTypeface>           face,
246                         const SkScalerContextEffects& effects,
247                         const SkDescriptor*           desc)
248             : SkScalerContext(std::move(face), effects, desc) {
249         fRec.getSingleMatrix(&fMatrix);
250         this->forceGenerateImageFromPath();
251     }
252 
userTF() const253     const SkUserTypeface* userTF() const {
254         return static_cast<SkUserTypeface*>(this->getTypeface());
255     }
256 
257 protected:
generateMetrics(const SkGlyph & glyph,SkArenaAlloc *)258     GlyphMetrics generateMetrics(const SkGlyph& glyph, SkArenaAlloc*) override {
259         GlyphMetrics mx(glyph.maskFormat());
260 
261         const SkUserTypeface* tf = this->userTF();
262         const SkGlyphID gid = glyph.getGlyphID();
263         if (gid >= tf->fGlyphRecs.size()) {
264             mx.neverRequestPath = true;
265             return mx;
266         }
267 
268         const auto& rec = tf->fGlyphRecs[gid];
269         mx.advance = fMatrix.mapXY(rec.fAdvance, 0);
270 
271         if (rec.isDrawable()) {
272             mx.maskFormat = SkMask::kARGB32_Format;
273 
274             SkRect bounds = fMatrix.mapRect(rec.fBounds);
275             bounds.offset(SkFixedToScalar(glyph.getSubXFixed()),
276                           SkFixedToScalar(glyph.getSubYFixed()));
277             bounds.roundOut(&mx.bounds);
278 
279             // These do not have an outline path.
280             mx.neverRequestPath = true;
281         }
282         return mx;
283     }
284 
generateImage(const SkGlyph & glyph,void * imageBuffer)285     void generateImage(const SkGlyph& glyph, void* imageBuffer) override {
286         const auto& rec = this->userTF()->fGlyphRecs[glyph.getGlyphID()];
287         SkASSERTF(rec.isDrawable(), "Only drawable-backed glyphs should reach generateImage.");
288 
289         auto canvas = SkCanvas::MakeRasterDirectN32(glyph.width(), glyph.height(),
290                                                     static_cast<SkPMColor*>(imageBuffer),
291                                                     glyph.rowBytes());
292         if constexpr (kSkShowTextBlitCoverage) {
293             canvas->clear(0x33FF0000);
294         } else {
295             canvas->clear(SK_ColorTRANSPARENT);
296         }
297 
298         canvas->translate(-glyph.left(), -glyph.top());
299         canvas->translate(SkFixedToScalar(glyph.getSubXFixed()),
300                           SkFixedToScalar(glyph.getSubYFixed()));
301         canvas->drawDrawable(rec.fDrawable.get(), &fMatrix);
302     }
303 
generatePath(const SkGlyph & glyph,SkPath * path,bool * modified)304     bool generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) override {
305         const auto& rec = this->userTF()->fGlyphRecs[glyph.getGlyphID()];
306 
307         SkASSERT(!rec.isDrawable());
308 
309         rec.fPath.transform(fMatrix, path);
310 
311         return true;
312     }
313 
generateDrawable(const SkGlyph & glyph)314     sk_sp<SkDrawable> generateDrawable(const SkGlyph& glyph) override {
315         class DrawableMatrixWrapper final : public SkDrawable {
316         public:
317             DrawableMatrixWrapper(sk_sp<SkDrawable> drawable, const SkMatrix& m)
318                 : fDrawable(std::move(drawable))
319                 , fMatrix(m)
320             {}
321 
322             SkRect onGetBounds() override {
323                 return fMatrix.mapRect(fDrawable->getBounds());
324             }
325 
326             size_t onApproximateBytesUsed() override {
327                 return fDrawable->approximateBytesUsed() + sizeof(DrawableMatrixWrapper);
328             }
329 
330             void onDraw(SkCanvas* canvas) override {
331                 if constexpr (kSkShowTextBlitCoverage) {
332                     SkPaint paint;
333                     paint.setColor(0x3300FF00);
334                     paint.setStyle(SkPaint::kFill_Style);
335                     canvas->drawRect(this->onGetBounds(), paint);
336                 }
337                 canvas->drawDrawable(fDrawable.get(), &fMatrix);
338             }
339         private:
340             const sk_sp<SkDrawable> fDrawable;
341             const SkMatrix          fMatrix;
342         };
343 
344         const auto& rec = this->userTF()->fGlyphRecs[glyph.getGlyphID()];
345 
346         return rec.fDrawable
347             ? sk_make_sp<DrawableMatrixWrapper>(rec.fDrawable, fMatrix)
348             : nullptr;
349     }
350 
generateFontMetrics(SkFontMetrics * metrics)351     void generateFontMetrics(SkFontMetrics* metrics) override {
352         auto [sx, sy] = fMatrix.mapXY(1, 1);
353         *metrics = scale_fontmetrics(this->userTF()->fMetrics, sx, sy);
354     }
355 
356 private:
357     SkMatrix fMatrix;
358 };
359 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const360 std::unique_ptr<SkScalerContext> SkUserTypeface::onCreateScalerContext(
361     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
362 {
363     return std::make_unique<SkUserScalerContext>(
364             sk_ref_sp(const_cast<SkUserTypeface*>(this)), effects, desc);
365 }
366 
367 ///////////////////////////////////////////////////////////////////////////////////////////////////
368 
369 static constexpr int kMaxGlyphCount = 65536;
370 static constexpr size_t kHeaderSize = 16;
371 static const char gHeaderString[] = "SkUserTypeface01";
372 static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes");
373 
374 enum GlyphType : uint32_t { kPath, kDrawable };
375 
onOpenStream(int * ttcIndex) const376 std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const {
377     SkDynamicMemoryWStream wstream;
378 
379     wstream.write(gHeaderString, kHeaderSize);
380 
381     wstream.write(&fMetrics, sizeof(fMetrics));
382 
383     SkFontStyle style = this->fontStyle();
384     wstream.write(&style, sizeof(style));
385 
386     wstream.write32(this->glyphCount());
387 
388     for (const auto& rec : fGlyphRecs) {
389         wstream.write32(rec.isDrawable() ? GlyphType::kDrawable : GlyphType::kPath);
390 
391         wstream.writeScalar(rec.fAdvance);
392 
393         wstream.write(&rec.fBounds, sizeof(rec.fBounds));
394 
395         auto data = rec.isDrawable()
396                 ? rec.fDrawable->serialize()
397                 : rec.fPath.serialize();
398 
399         const size_t sz = data->size();
400         SkASSERT(SkIsAlign4(sz));
401         wstream.write(&sz, sizeof(sz));
402         wstream.write(data->data(), sz);
403     }
404 
405     *ttcIndex = 0;
406     return wstream.detachAsStream();
407 }
408 
409 class AutoRestorePosition {
410     SkStream* fStream;
411     size_t fPosition;
412 public:
AutoRestorePosition(SkStream * stream)413     AutoRestorePosition(SkStream* stream) : fStream(stream) {
414         fPosition = stream->getPosition();
415     }
416 
~AutoRestorePosition()417     ~AutoRestorePosition() {
418         if (fStream) {
419             fStream->seek(fPosition);
420         }
421     }
422 
423     // So we don't restore the position
markDone()424     void markDone() { fStream = nullptr; }
425 };
426 
Deserialize(SkStream * stream)427 sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
428     AutoRestorePosition arp(stream);
429 
430     char header[kHeaderSize];
431     if (stream->read(header, kHeaderSize) != kHeaderSize ||
432         0 != memcmp(header, gHeaderString, kHeaderSize))
433     {
434         return nullptr;
435     }
436 
437     SkFontMetrics metrics;
438     if (stream->read(&metrics, sizeof(metrics)) != sizeof(metrics)) {
439         return nullptr;
440     }
441 
442     SkFontStyle style;
443     if (stream->read(&style, sizeof(style)) != sizeof(style)) {
444         return nullptr;
445     }
446 
447     int glyphCount;
448     if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) {
449         return nullptr;
450     }
451 
452     SkCustomTypefaceBuilder builder;
453 
454     builder.setMetrics(metrics);
455     builder.setFontStyle(style);
456 
457     for (int i = 0; i < glyphCount; ++i) {
458         uint32_t gtype;
459         if (!stream->readU32(&gtype) ||
460             (gtype != GlyphType::kDrawable && gtype != GlyphType::kPath)) {
461             return nullptr;
462         }
463 
464         float advance;
465         if (!stream->readScalar(&advance)) {
466             return nullptr;
467         }
468 
469         SkRect bounds;
470         if (stream->read(&bounds, sizeof(bounds)) != sizeof(bounds) || !bounds.isFinite()) {
471             return nullptr;
472         }
473 
474         // SkPath and SkDrawable cannot read from a stream, so we have to page them into ram
475         size_t sz;
476         if (stream->read(&sz, sizeof(sz)) != sizeof(sz)) {
477             return nullptr;
478         }
479 
480         // The amount of bytes in the stream must be at least as big as sz, otherwise
481         // sz is invalid.
482         if (StreamRemainingLengthIsBelow(stream, sz)) {
483             return nullptr;
484         }
485 
486         auto data = SkData::MakeUninitialized(sz);
487         if (stream->read(data->writable_data(), sz) != sz) {
488             return nullptr;
489         }
490 
491         switch (gtype) {
492         case GlyphType::kDrawable: {
493             SkDeserialProcs procs;
494             procs.fAllowSkSL = false;
495             auto drawable = SkDrawable::Deserialize(data->data(), data->size(), &procs);
496             if (!drawable) {
497                 return nullptr;
498             }
499             builder.setGlyph(i, advance, std::move(drawable), bounds);
500         } break;
501         case GlyphType::kPath: {
502             SkPath path;
503             if (path.readFromMemory(data->data(), data->size()) != data->size()) {
504                 return nullptr;
505             }
506 
507             builder.setGlyph(i, advance, path);
508         } break;
509         default:
510             return nullptr;
511         }
512     }
513 
514     arp.markDone();
515     return builder.detach();
516 }
517 
MakeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments &)518 sk_sp<SkTypeface> SkCustomTypefaceBuilder::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
519                                                           const SkFontArguments&) {
520     return Deserialize(stream.get());
521 }
522