Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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) {
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
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;
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
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; }
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
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
205
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
217 desc->setFactoryId(SkCustomTypefaceBuilder::FactoryId);
218 *isLocal = true;
219}
220
222 for (int i = 0; i < count; ++i) {
223 glyphs[i] = chars[i] < this->glyphCount() ? SkTo<SkGlyphID>(chars[i]) : 0;
224 }
225}
226
228 *familyName = "";
229}
230
232 return false;
233}
234
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:
405 AutoRestorePosition(SkStream* stream) : fStream(stream) {
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) {
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
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.
474 if (StreamRemainingLengthIsBelow(stream, sz)) {
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
508sk_sp<SkTypeface> SkCustomTypefaceBuilder::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
509 const SkFontArguments&) {
510 return Deserialize(stream.get());
511}
SkStrokeRec::Style fStyle
uint16_t glyphs[5]
int count
constexpr int kMaxGlyphCount
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
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
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)
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
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
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
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
void onFilterRec(SkScalerContextRec *rec) const override
void onCharsToGlyphs(const SkUnichar *chars, int count, SkGlyphID glyphs[]) const override
size_t onGetTableData(SkFontTableTag, size_t, size_t, void *) const override
bool onGetPostScriptName(SkString *) const override
SkTypeface::LocalizedStrings * onCreateFamilyNameIterator() const override
void getGlyphToUnicodeMap(SkUnichar *glyphToUnicode) const override
int onGetVariationDesignParameters(SkFontParameters::Variation::Axis[], int) const override
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[], int) const override
int onGetUPEM() const override
int onGetTableTags(SkFontTableTag tags[]) const override
void onGetFontDescriptor(SkFontDescriptor *desc, bool *isLocal) const override
bool onComputeBounds(SkRect *bounds) const override
std::unique_ptr< SkStreamAsset > onOpenStream(int *) const override
std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const override
bool onGlyphMaskNeedsCurrentColor() const override
void onGetFamilyName(SkString *familyName) const override
sk_sp< SkTypeface > onMakeClone(const SkFontArguments &args) const override
void getPostScriptGlyphNames(SkString *) const override
std::unique_ptr< SkStreamAsset > onOpenExistingStream(int *) const override
std::unique_ptr< SkScalerContext > onCreateScalerContext(const SkScalerContextEffects &, const SkDescriptor *desc) const override
int onCountGlyphs() const override
bool write32(uint32_t v)
Definition SkStream.h:243
bool writeScalar(SkScalar)
Definition SkStream.cpp:109
const Paint & paint
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
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 ...
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
@ kARGB32_Format
SkPMColor.
Definition SkMask.h:30
void getSingleMatrix(SkMatrix *) const
void setHinting(SkFontHinting)