Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkTypeface.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
8
10#include "include/core/SkFont.h"
22#include "src/base/SkEndian.h"
24#include "src/base/SkUTF.h"
28#include "src/core/SkFontPriv.h"
32
33#ifdef SK_TYPEFACE_FACTORY_FREETYPE
35#endif
36
37#ifdef SK_TYPEFACE_FACTORY_CORETEXT
39#endif
40
41#ifdef SK_TYPEFACE_FACTORY_DIRECTWRITE
43#endif
44
45// TODO(https://crbug.com/skia/14338): This needs to be set by Bazel rules.
46#ifdef SK_TYPEFACE_FACTORY_FONTATIONS
48#endif
49
50#include <cstddef>
51#include <cstring>
52#include <vector>
53
54using namespace skia_private;
55
56SkTypeface::SkTypeface(const SkFontStyle& style, bool isFixedPitch)
57 : fUniqueID(SkTypefaceCache::NewTypefaceID()), fStyle(style), fIsFixedPitch(isFixedPitch) { }
58
60
61///////////////////////////////////////////////////////////////////////////////
62
63namespace {
64
65class SkEmptyTypeface : public SkTypeface {
66public:
67 static sk_sp<SkTypeface> Make() {
69 return sk_ref_sp(instance.get());
70 }
71
72 static constexpr SkTypeface::FactoryId FactoryId = SkSetFourByteTag('e','m','t','y');
73 static sk_sp<SkTypeface> MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
74 const SkFontArguments&) {
75 if (stream->getLength() == 0) {
76 return SkEmptyTypeface::Make();
77 }
78 return nullptr;
79 }
80protected:
82 SkEmptyTypeface() : SkTypeface(SkFontStyle(), true) { }
83
84 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override { return nullptr; }
85 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
86 return sk_ref_sp(this);
87 }
88 std::unique_ptr<SkScalerContext> onCreateScalerContext(
89 const SkScalerContextEffects& effects, const SkDescriptor* desc) const override
90 {
92 sk_ref_sp(const_cast<SkEmptyTypeface*>(this)), effects, desc);
93 }
94 void onFilterRec(SkScalerContextRec*) const override { }
95 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override {
96 return nullptr;
97 }
98 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
99 desc->setFactoryId(FactoryId);
100 *serialize = false;
101 }
102 void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override {
103 sk_bzero(glyphs, count * sizeof(glyphs[0]));
104 }
105 int onCountGlyphs() const override { return 0; }
106 void getPostScriptGlyphNames(SkString*) const override {}
107 void getGlyphToUnicodeMap(SkUnichar*) const override {}
108 int onGetUPEM() const override { return 0; }
109 bool onComputeBounds(SkRect* bounds) const override { return false; }
110
111 class EmptyLocalizedStrings : public SkTypeface::LocalizedStrings {
112 public:
113 bool next(SkTypeface::LocalizedString*) override { return false; }
114 };
115 void onGetFamilyName(SkString* familyName) const override {
116 familyName->reset();
117 }
118 bool onGetPostScriptName(SkString*) const override {
119 return false;
120 }
122 return new EmptyLocalizedStrings;
123 }
124 bool onGlyphMaskNeedsCurrentColor() const override {
125 return false;
126 }
128 int coordinateCount) const override
129 {
130 return 0;
131 }
133 int parameterCount) const override
134 {
135 return 0;
136 }
137 int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
138 size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override {
139 return 0;
140 }
141};
142
143} // namespace
144
146 return SkEmptyTypeface::Make();
147}
148
149bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
150 if (facea == faceb) {
151 return true;
152 }
153 if (!facea || !faceb) {
154 return false;
155 }
156 return facea->uniqueID() == faceb->uniqueID();
157}
158
159///////////////////////////////////////////////////////////////////////////////
160
161namespace {
162
163 struct DecoderProc {
165 sk_sp<SkTypeface> (*makeFromStream)(std::unique_ptr<SkStreamAsset>, const SkFontArguments&);
166 };
167
168 std::vector<DecoderProc>* decoders() {
170 { SkEmptyTypeface::FactoryId, SkEmptyTypeface::MakeFromStream },
172#ifdef SK_TYPEFACE_FACTORY_CORETEXT
173 { SkTypeface_Mac::FactoryId, SkTypeface_Mac::MakeFromStream },
174#endif
175#ifdef SK_TYPEFACE_FACTORY_DIRECTWRITE
177#endif
178#ifdef SK_TYPEFACE_FACTORY_FREETYPE
180#endif
181#ifdef SK_TYPEFACE_FACTORY_FONTATIONS
183#endif
184 }};
185 return decoders.get();
186 }
187
188} // namespace
189
191 return this->onMakeClone(args);
192}
193
194///////////////////////////////////////////////////////////////////////////////
195
197 FactoryId id,
198 sk_sp<SkTypeface> (*make)(std::unique_ptr<SkStreamAsset>, const SkFontArguments&)) {
199 decoders()->push_back(DecoderProc{id, make});
200}
201
202void SkTypeface::serialize(SkWStream* wstream, SerializeBehavior behavior) const {
203 bool isLocalData = false;
204 SkFontDescriptor desc;
205 this->onGetFontDescriptor(&desc, &isLocalData);
206 if (desc.getFactoryId() == 0) {
207 SkDEBUGF("Factory was not set for %s.\n", desc.getFamilyName());
208 }
209
210 bool shouldSerializeData = false;
211 switch (behavior) {
212 case SerializeBehavior::kDoIncludeData: shouldSerializeData = true; break;
213 case SerializeBehavior::kDontIncludeData: shouldSerializeData = false; break;
214 case SerializeBehavior::kIncludeDataIfLocal: shouldSerializeData = isLocalData; break;
215 }
216
217 if (shouldSerializeData) {
218 int index;
219 desc.setStream(this->openStream(&index));
220 if (desc.hasStream()) {
221 desc.setCollectionIndex(index);
222 }
223
224 int numAxes = this->getVariationDesignPosition(nullptr, 0);
225 if (0 < numAxes) {
226 numAxes = this->getVariationDesignPosition(desc.setVariationCoordinates(numAxes), numAxes);
227 if (numAxes <= 0) {
228 desc.setVariationCoordinates(0);
229 }
230 }
231 }
232 desc.serialize(wstream);
233}
234
237 this->serialize(&stream, behavior);
238 return stream.detachAsData();
239}
240
242 SkFontDescriptor desc;
243 if (!SkFontDescriptor::Deserialize(stream, &desc)) {
244 return nullptr;
245 }
246
247 if (desc.hasStream()) {
248 for (const DecoderProc& proc : *decoders()) {
249 if (proc.id == desc.getFactoryId()) {
250 return proc.makeFromStream(desc.detachStream(), desc.getFontArguments());
251 }
252 }
253
254 [[maybe_unused]] FactoryId id = desc.getFactoryId();
255 SkDEBUGF("Could not find factory %c%c%c%c for %s.\n",
256 (char)((id >> 24) & 0xFF),
257 (char)((id >> 16) & 0xFF),
258 (char)((id >> 8) & 0xFF),
259 (char)((id >> 0) & 0xFF),
260 desc.getFamilyName());
261
262 if (lastResortMgr) {
263 // If we've gotten to here, we will try desperately to find something that might match
264 // as a kind of last ditch effort to make something work (and maybe this SkFontMgr knows
265 // something about the serialization and can look up the right thing by name anyway if
266 // the user provides it).
267 // Any time it is used the user will probably get the wrong glyphs drawn (and if they're
268 // right it is totally by accident). But sometimes drawing something or getting lucky
269 // while debugging is better than drawing nothing at all.
270 sk_sp<SkTypeface> typeface = lastResortMgr->makeFromStream(desc.detachStream(),
271 desc.getFontArguments());
272 if (typeface) {
273 return typeface;
274 }
275 }
276 }
277 if (lastResortMgr) {
278 return lastResortMgr->legacyMakeTypeface(desc.getFamilyName(), desc.getStyle());
279 }
280 return SkEmptyTypeface::Make();
281}
282
283///////////////////////////////////////////////////////////////////////////////
284
285bool SkTypeface::glyphMaskNeedsCurrentColor() const {
286 return this->onGlyphMaskNeedsCurrentColor();
287}
288
290 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
291{
292 return this->onGetVariationDesignPosition(coordinates, coordinateCount);
293}
294
296 SkFontParameters::Variation::Axis parameters[], int parameterCount) const
297{
298 return this->onGetVariationDesignParameters(parameters, parameterCount);
299}
300
302 return this->onGetTableTags(nullptr);
303}
304
306 return this->onGetTableTags(tags);
307}
308
310 return this->onGetTableData(tag, 0, ~0U, nullptr);
311}
312
314 void* data) const {
315 return this->onGetTableData(tag, offset, length, data);
316}
317
321
323 size_t size = this->getTableSize(tag);
324 if (size) {
326 (void)this->getTableData(tag, 0, size, data->writable_data());
327 return data;
328 }
329 return nullptr;
330}
331
332std::unique_ptr<SkStreamAsset> SkTypeface::openStream(int* ttcIndex) const {
333 int ttcIndexStorage;
334 if (nullptr == ttcIndex) {
335 // So our subclasses don't need to check for null param
336 ttcIndex = &ttcIndexStorage;
337 }
338 return this->onOpenStream(ttcIndex);
339}
340
341std::unique_ptr<SkStreamAsset> SkTypeface::openExistingStream(int* ttcIndex) const {
342 int ttcIndexStorage;
343 if (nullptr == ttcIndex) {
344 // So our subclasses don't need to check for null param
345 ttcIndex = &ttcIndexStorage;
346 }
347 return this->onOpenExistingStream(ttcIndex);
348}
349
350std::unique_ptr<SkScalerContext> SkTypeface::createScalerContext(
351 const SkScalerContextEffects& effects, const SkDescriptor* desc) const {
352 std::unique_ptr<SkScalerContext> scalerContext = this->onCreateScalerContext(effects, desc);
353 SkASSERT(scalerContext);
354 return scalerContext;
355}
356
358 if (count > 0 && glyphs && uni) {
359 this->onCharsToGlyphs(uni, count, glyphs);
360 }
361}
362
364 SkGlyphID glyphs[1] = { 0 };
365 this->onCharsToGlyphs(&uni, 1, glyphs);
366 return glyphs[0];
367}
368
369namespace {
370class SkConvertToUTF32 {
371public:
372 SkConvertToUTF32() {}
373
374 const SkUnichar* convert(const void* text, size_t byteLength, SkTextEncoding encoding) {
375 const SkUnichar* uni;
376 switch (encoding) {
378 uni = fStorage.reset(byteLength);
379 const char* ptr = (const char*)text;
380 const char* end = ptr + byteLength;
381 for (int i = 0; ptr < end; ++i) {
382 fStorage[i] = SkUTF::NextUTF8(&ptr, end);
383 }
384 } break;
386 uni = fStorage.reset(byteLength);
387 const uint16_t* ptr = (const uint16_t*)text;
388 const uint16_t* end = ptr + (byteLength >> 1);
389 for (int i = 0; ptr < end; ++i) {
390 fStorage[i] = SkUTF::NextUTF16(&ptr, end);
391 }
392 } break;
394 uni = (const SkUnichar*)text;
395 break;
396 default:
397 SK_ABORT("unexpected enum");
398 }
399 return uni;
400 }
401
402private:
404};
405}
406
407int SkTypeface::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding,
408 SkGlyphID glyphs[], int maxGlyphCount) const {
409 if (0 == byteLength) {
410 return 0;
411 }
412
413 SkASSERT(text);
414
415 int count = SkFontPriv::CountTextElements(text, byteLength, encoding);
416 if (!glyphs || count > maxGlyphCount) {
417 return count;
418 }
419
420 if (encoding == SkTextEncoding::kGlyphID) {
421 memcpy(glyphs, text, count << 1);
422 return count;
423 }
424
425 SkConvertToUTF32 storage;
426 const SkUnichar* uni = storage.convert(text, byteLength, encoding);
427
428 this->unicharsToGlyphs(uni, count, glyphs);
429 return count;
430}
431
433 return this->onCountGlyphs();
434}
435
437 // should we try to cache this in the base-class?
438 return this->onGetUPEM();
439}
440
442 int32_t adjustments[]) const {
443 SkASSERT(count >= 0);
444 // check for the only legal way to pass a nullptr.. everything is 0
445 // in which case they just want to know if this face can possibly support
446 // kerning (true) or never (false).
447 if (nullptr == glyphs || nullptr == adjustments) {
448 SkASSERT(nullptr == glyphs);
449 SkASSERT(0 == count);
450 SkASSERT(nullptr == adjustments);
451 }
452 return this->onGetKerningPairAdjustments(glyphs, count, adjustments);
453}
454
458
460 SkASSERT(name);
461 this->onGetFamilyName(name);
462}
463
465 return this->onGetPostScriptName(name);
466}
467
469 sk_bzero(dst, sizeof(SkUnichar) * this->countGlyphs());
470}
471
472std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface::getAdvancedMetrics() const {
473 std::unique_ptr<SkAdvancedTypefaceMetrics> result = this->onGetAdvancedMetrics();
474 if (result && result->fPostScriptName.isEmpty()) {
475 if (!this->getPostScriptName(&result->fPostScriptName)) {
476 this->getFamilyName(&result->fPostScriptName);
477 }
478 }
481 SkOTTableOS2::Version::V2::Type::Field fsType;
483 constexpr size_t fsTypeOffset = offsetof(SkOTTableOS2::Version::V2, fsType);
484 if (this->getTableData(os2Tag, fsTypeOffset, sizeof(fsType), &fsType) == sizeof(fsType)) {
485 if (fsType.Bitmap || (fsType.Restricted && !(fsType.PreviewPrint || fsType.Editable))) {
487 }
488 if (fsType.NoSubsetting) {
490 }
491 }
492 }
493 return result;
494}
495
497 int32_t adjustments[]) const {
498 return false;
499}
500
501std::unique_ptr<SkStreamAsset> SkTypeface::onOpenExistingStream(int* ttcIndex) const {
502 return this->onOpenStream(ttcIndex);
503}
504
505///////////////////////////////////////////////////////////////////////////////
506
508 fBoundsOnce([this] {
509 if (!this->onComputeBounds(&fBounds)) {
510 fBounds.setEmpty();
511 }
512 });
513 return fBounds;
514}
515
517 // we use a big size to ensure lots of significant bits from the scalercontext.
518 // then we scale back down to return our final answer (at 1-pt)
519 const SkScalar textSize = 2048;
520 const SkScalar invTextSize = 1 / textSize;
521
522 SkFont font;
523 font.setTypeface(sk_ref_sp(const_cast<SkTypeface*>(this)));
524 font.setSize(textSize);
525 font.setLinearMetrics(true);
526
529
530 SkScalerContext::MakeRecAndEffectsFromFont(font, &rec, &effects);
531
533 SkScalerContextEffects noeffects;
535
536 std::unique_ptr<SkScalerContext> ctx = this->createScalerContext(noeffects, ad.getDesc());
537
538 SkFontMetrics fm;
539 ctx->getFontMetrics(&fm);
540 if (!fm.hasBounds()) {
541 return false;
542 }
543 bounds->setLTRB(fm.fXMin * invTextSize, fm.fTop * invTextSize,
544 fm.fXMax * invTextSize, fm.fBottom * invTextSize);
545 return true;
546}
SkStrokeRec::Style fStyle
uint16_t glyphs[5]
int count
static float next(float f)
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGF(...)
Definition SkDebug.h:24
#define SkTEndian_SwapBE32(n)
Definition SkEndian.h:143
SkTextEncoding
Definition SkFontTypes.h:11
@ kUTF8
uses bytes to represent UTF-8 or ASCII
@ kUTF16
uses two byte words to represent most of Unicode
@ kUTF32
uses four byte words to represent all of Unicode
@ kGlyphID
uses two byte words to represent glyph indices
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
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
uint32_t SkFontTableTag
Definition SkTypeface.h:41
int32_t SkUnichar
Definition SkTypes.h:175
uint16_t SkGlyphID
Definition SkTypes.h:179
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
static sk_sp< SkTypeface > SK_SPI MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
static constexpr SkTypeface::FactoryId FactoryId
SkDescriptor * getDesc() const
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
static constexpr SkTypeface::FactoryId FactoryId
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
SkFontArguments::VariationPosition::Coordinate * setVariationCoordinates(int coordinateCount)
static bool Deserialize(SkStream *, SkFontDescriptor *result)
static int CountTextElements(const void *text, size_t byteLength, SkTextEncoding)
Definition SkFont.cpp:381
static SkDescriptor * AutoDescriptorGivenRecAndEffects(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkAutoDescriptor *ad)
static void MakeRecAndEffectsFromFont(const SkFont &font, SkScalerContextRec *rec, SkScalerContextEffects *effects)
static std::unique_ptr< SkScalerContext > MakeEmpty(sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
void reset()
Definition SkString.cpp:358
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
static constexpr SkTypeface::FactoryId FactoryId
static constexpr SkTypeface::FactoryId FactoryId
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
int countGlyphs() const
virtual std::unique_ptr< SkStreamAsset > onOpenExistingStream(int *ttcIndex) const
LocalizedStrings * createFamilyNameIterator() const
std::unique_ptr< SkStreamAsset > openExistingStream(int *ttcIndex) const
sk_sp< SkData > copyTableData(SkFontTableTag tag) const
SkRect getBounds() const
virtual sk_sp< SkData > onCopyTableData(SkFontTableTag) const
virtual void getPostScriptGlyphNames(SkString *) const =0
~SkTypeface() override
SkTypefaceID uniqueID() const
Definition SkTypeface.h:101
virtual std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const =0
int getUnitsPerEm() const
virtual bool onGetKerningPairAdjustments(const SkGlyphID glyphs[], int count, int32_t adjustments[]) const
virtual void getGlyphToUnicodeMap(SkUnichar *dstArray) const =0
void getFamilyName(SkString *name) const
virtual std::unique_ptr< SkScalerContext > onCreateScalerContext(const SkScalerContextEffects &, const SkDescriptor *) const =0
virtual int onCountGlyphs() const =0
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const
virtual int onGetTableTags(SkFontTableTag tags[]) const =0
static void Register(FactoryId id, sk_sp< SkTypeface >(*make)(std::unique_ptr< SkStreamAsset >, const SkFontArguments &))
int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const
int textToGlyphs(const void *text, size_t byteLength, SkTextEncoding encoding, SkGlyphID glyphs[], int maxGlyphCount) const
bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count, int32_t adjustments[]) const
int getTableTags(SkFontTableTag tags[]) const
virtual std::unique_ptr< SkStreamAsset > onOpenStream(int *ttcIndex) const =0
virtual void onGetFontDescriptor(SkFontDescriptor *, bool *isLocal) const =0
size_t getTableSize(SkFontTableTag) const
int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
virtual sk_sp< SkTypeface > onMakeClone(const SkFontArguments &) const =0
static bool Equal(const SkTypeface *facea, const SkTypeface *faceb)
bool getPostScriptName(SkString *name) const
static sk_sp< SkTypeface > MakeDeserialize(SkStream *, sk_sp< SkFontMgr > lastResortMgr)
virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void *data) const =0
virtual bool onGetPostScriptName(SkString *) const =0
virtual void onGetFamilyName(SkString *familyName) const =0
virtual void onFilterRec(SkScalerContextRec *) const =0
static sk_sp< SkTypeface > MakeEmpty()
virtual bool onGlyphMaskNeedsCurrentColor() const =0
int countTables() const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
virtual bool onComputeBounds(SkRect *) const
virtual LocalizedStrings * onCreateFamilyNameIterator() const =0
virtual int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const =0
SkFourByteTag FactoryId
Definition SkTypeface.h:335
std::unique_ptr< SkScalerContext > createScalerContext(const SkScalerContextEffects &, const SkDescriptor *) const
size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, void *data) const
SkGlyphID unicharToGlyph(SkUnichar unichar) const
virtual void onCharsToGlyphs(const SkUnichar *chars, int count, SkGlyphID glyphs[]) const =0
virtual int onGetUPEM() const =0
void unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const
SkTypeface(const SkFontStyle &style, bool isFixedPitch=false)
virtual int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const =0
sk_sp< SkTypeface > makeClone(const SkFontArguments &) const
T * get() const
Definition SkRefCnt.h:303
static Editor::Movement convert(skui::Key key)
VkInstance instance
Definition main.cc:48
float SkScalar
Definition extension.cpp:12
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
const char * name
Definition fuchsia.cc:50
size_t length
std::u16string text
static sk_sp< SkImage > make(sk_sp< SkColorSpace > cs)
Definition mipmap.cpp:65
SK_SPI SkUnichar NextUTF16(const uint16_t **ptr, const uint16_t *end)
Definition SkUTF.cpp:159
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition SkUTF.cpp:118
Point offset
@ kNotEmbeddable_FontFlag
May not be embedded.
@ kNotSubsettable_FontFlag
May not be subset.
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
bool hasBounds() const
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...
static constexpr SK_OT_ULONG TAG
void setEmpty()
Definition SkRect.h:842
const uintptr_t id