Flutter Engine
The Flutter Engine
SkCustomTypeface.cpp
Go to the documentation of this file.
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
9
12#include "include/core/SkData.h"
21#include "include/core/SkPath.h"
23#include "include/core/SkRect.h"
34#include "src/core/SkAdvancedTypefaceMetrics.h" // IWYU pragma: keep
36#include "src/core/SkGlyph.h"
37#include "src/core/SkMask.h"
40
41#include <cstdint>
42#include <cstring>
43#include <memory>
44#include <utility>
45#include <vector>
46
47class SkArenaAlloc;
48class SkDescriptor;
49
50namespace {
51static inline const constexpr bool kSkShowTextBlitCoverage = false;
52}
53
54static SkFontMetrics scale_fontmetrics(const SkFontMetrics& src, float sx, float sy) {
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
83class SkUserTypeface final : public SkTypeface {
84private:
86 friend class SkUserScalerContext;
87
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
116 std::unique_ptr<SkStreamAsset> onOpenExistingStream(int*) const override { return nullptr; }
117
118 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
119 return sk_ref_sp(this);
120 }
121 int onCountGlyphs() const override { return this->glyphCount(); }
122 int onGetUPEM() const override { return 2048; /* ?? */ }
123 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
130 void getPostScriptGlyphNames(SkString*) const override {}
131 bool onGlyphMaskNeedsCurrentColor() const override { return false; }
132 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[],
133 int) const override { return 0; }
134 int onGetVariationDesignParameters(SkFontParameters::Variation::Axis[],
135 int) const override { return 0; }
136 int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
137 size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
138
139 int glyphCount() const {
140 return SkToInt(fGlyphRecs.size());
141 }
142};
143
145 sk_bzero(&fMetrics, sizeof(fMetrics));
146}
147
149 fMetrics = scale_fontmetrics(fm, scale, scale);
150}
151
153 fStyle = style;
154}
155
156SkCustomTypefaceBuilder::GlyphRec& SkCustomTypefaceBuilder::ensureStorage(SkGlyphID index) {
157 if (index >= fGlyphRecs.size()) {
158 fGlyphRecs.resize(SkToSizeT(index) + 1);
159 }
160
161 return fGlyphRecs[index];
162}
163
164void 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
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
181 if (fGlyphRecs.empty()) return nullptr;
182
183 // initially inverted, so that any "union" will overwrite the first time
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
202void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const {
204}
205
206void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
207 for (int gid = 0; gid < this->glyphCount(); ++gid) {
208 glyphToUnicode[gid] = SkTo<SkUnichar>(gid);
209 }
210}
211
212std::unique_ptr<SkAdvancedTypefaceMetrics> SkUserTypeface::onGetAdvancedMetrics() const {
213 return nullptr;
214}
215
216void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
218 *isLocal = true;
219}
220
221void 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
227void SkUserTypeface::onGetFamilyName(SkString* familyName) const {
228 *familyName = "";
229}
230
231bool SkUserTypeface::onGetPostScriptName(SkString*) const {
232 return false;
233}
234
235SkTypeface::LocalizedStrings* SkUserTypeface::onCreateFamilyNameIterator() const {
236 return nullptr;
237}
238
239//////////////
240
242public:
244 const SkScalerContextEffects& effects,
245 const SkDescriptor* desc)
246 : SkScalerContext(std::move(face), effects, desc) {
247 fRec.getSingleMatrix(&fMatrix);
249 }
250
251 const SkUserTypeface* userTF() const {
252 return static_cast<SkUserTypeface*>(this->getTypeface());
253 }
254
255protected:
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()) {
265
266 SkRect bounds = fMatrix.mapRect(rec.fBounds);
267 bounds.offset(SkFixedToScalar(glyph.getSubXFixed()),
269 bounds.roundOut(&mx.bounds);
270
271 // These do not have an outline path.
272 mx.neverRequestPath = true;
273 }
274 return mx;
275 }
276
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()),
293 canvas->drawDrawable(rec.fDrawable.get(), &fMatrix);
294 }
295
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
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) {
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
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
348private:
349 SkMatrix fMatrix;
350};
351
352std::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
361static constexpr int kMaxGlyphCount = 65536;
362static constexpr size_t kHeaderSize = 16;
363static const char gHeaderString[] = "SkUserTypeface01";
364static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes");
365
366enum GlyphType : uint32_t { kPath, kDrawable };
367
368std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const {
370
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
402 SkStream* fStream;
403 size_t fPosition;
404public:
406 fPosition = stream->getPosition();
407 }
408
410 if (fStream) {
411 fStream->seek(fPosition);
412 }
413 }
414
415 // So we don't restore the position
416 void markDone() { fStream = nullptr; }
417};
418
419sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* 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
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
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.
475 return nullptr;
476 }
477
479 if (stream->read(data->writable_data(), sz) != sz) {
480 return nullptr;
481 }
482
483 switch (gtype) {
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
509 const SkFontArguments&) {
510 return Deserialize(stream.get());
511}
SkStrokeRec::Style fStyle
sk_bzero(glyphs, sizeof(glyphs))
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
int count
Definition: FontMgrTest.cpp:50
static constexpr bool SkIsAlign4(T x)
Definition: SkAlign.h:20
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
uint32_t SkPMColor
Definition: SkColor.h:205
static const char gHeaderString[]
static constexpr int kMaxGlyphCount
#define SCALE_X(field)
#define SCALE_Y(field)
static SkFontMetrics scale_fontmetrics(const SkFontMetrics &src, float sx, float sy)
static constexpr size_t kHeaderSize
@ kDrawable
#define SkFixedToScalar(x)
Definition: SkFixed.h:124
@ kNone
glyph outlines unchanged
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SK_ScalarMax
Definition: SkScalar.h:24
bool StreamRemainingLengthIsBelow(SkStream *stream, size_t len)
Definition: SkStream.cpp:976
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31
constexpr int SkToInt(S x)
Definition: SkTo.h:29
uint32_t SkFontTableTag
Definition: SkTypeface.h:41
int32_t SkUnichar
Definition: SkTypes.h:175
uint16_t SkGlyphID
Definition: SkTypes.h:179
AutoRestorePosition(SkStream *stream)
static std::unique_ptr< SkCanvas > MakeRasterDirectN32(int width, int height, SkPMColor *pixels, size_t rowBytes)
Definition: SkCanvas.h:163
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
Definition: SkCanvas.cpp:2574
sk_sp< SkTypeface > detach()
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
void setGlyph(SkGlyphID, float advance, const SkPath &)
void setMetrics(const SkFontMetrics &fm, float scale=1)
void setFontStyle(SkFontStyle)
static constexpr SkTypeface::FactoryId FactoryId
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
static sk_sp< SkDrawable > Deserialize(const void *data, size_t size, const SkDeserialProcs *procs=nullptr)
Definition: SkDrawable.h:138
std::unique_ptr< SkStreamAsset > detachAsStream()
Definition: SkStream.cpp:876
bool write(const void *buffer, size_t size) override
Definition: SkStream.cpp:535
int top() const
Definition: SkGlyph.h:511
size_t rowBytes() const
Definition: SkGlyph.cpp:233
SkGlyphID getGlyphID() const
Definition: SkGlyph.h:429
SkMask::Format maskFormat() const
Definition: SkGlyph.h:500
int height() const
Definition: SkGlyph.h:513
SkFixed getSubYFixed() const
Definition: SkGlyph.h:432
SkFixed getSubXFixed() const
Definition: SkGlyph.h:431
int width() const
Definition: SkGlyph.h:512
int left() const
Definition: SkGlyph.h:510
void mapXY(SkScalar x, SkScalar y, SkPoint *result) const
Definition: SkMatrix.cpp:777
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
Definition: SkPath.h:59
void forceGenerateImageFromPath()
SkScalerContextRec fRec
SkTypeface * getTypeface() const
virtual bool seek(size_t)
Definition: SkStream.h:125
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
void generateFontMetrics(SkFontMetrics *metrics) override
SkUserScalerContext(sk_sp< SkUserTypeface > face, const SkScalerContextEffects &effects, const SkDescriptor *desc)
const SkUserTypeface * userTF() const
bool generatePath(const SkGlyph &glyph, SkPath *path) override
sk_sp< SkDrawable > generateDrawable(const SkGlyph &glyph) override
GlyphMetrics generateMetrics(const SkGlyph &glyph, SkArenaAlloc *) override
void generateImage(const SkGlyph &glyph, void *imageBuffer) override
bool write32(uint32_t v)
Definition: SkStream.h:243
bool writeScalar(SkScalar)
Definition: SkStream.cpp:109
const Paint & paint
Definition: color_source.cc:38
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
dst
Definition: cp.py:12
Definition: ref_ptr.h:256
static const char header[]
Definition: skpbench.cpp:88
const Scalar scale
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
Definition: SkFontMetrics.h:53
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
Definition: SkFontMetrics.h:56
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
Definition: SkFontMetrics.h:60
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
Definition: SkFontMetrics.h:61
@ kARGB32_Format
SkPMColor.
Definition: SkMask.h:30
void getSingleMatrix(SkMatrix *) const
void setHinting(SkFontHinting)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63