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