Flutter Engine
The Flutter Engine
SBIXSlide.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google Inc.
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
10#include "include/core/SkFont.h"
15#include "src/base/SkTime.h"
24#include "tools/Resources.h"
28
29#if defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
31#endif
32#if defined(SK_FONTMGR_FONTATIONS_AVAILABLE)
34#endif
35
36namespace {
37
38constexpr SkScalar DX = 100;
39constexpr SkScalar DY = 300;
40constexpr int kPointSize = 5;
41constexpr SkScalar kFontSize = 200;
42
43constexpr char kFontFile[] = "fonts/sbix_uncompressed_flags.ttf";
44constexpr SkGlyphID kGlyphID = 2;
45constexpr uint16_t kStrikeIndex = 2;
46
47//constexpr char kFontFile[] = "fonts/HangingS.ttf";
48//constexpr SkGlyphID kGlyphID = 4;
49
50/**
51 * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN.
52 */
53static inline int16_t sk_float_saturate2int16(float x) {
54 x = x < SK_MaxS16 ? x : SK_MaxS16;
55 x = x > SK_MinS16 ? x : SK_MinS16;
56 return (int16_t)x;
57}
58
59struct ShortCoordinate { bool negative; uint8_t magnitude; };
60static inline ShortCoordinate sk_float_saturate2sm8(float x) {
61 bool negative = x < 0;
62 x = x < 255 ? x : 255;
63 x = x > -255 ? x : -255;
64 return ShortCoordinate{ negative, negative ? (uint8_t)-x : (uint8_t)x };
65}
66
67struct SBIXSlide : public ClickHandlerSlide {
68 struct Point {
69 SkPoint location;
71 } fPts[5] = {
72 {{0, 0}, SK_ColorBLACK }, // glyph x/y min
73 {{0, 0}, SK_ColorWHITE }, // glyph x/y max
74 {{0, 20}, SK_ColorGREEN }, // lsb (x only, y ignored)
75 {{0, 0}, SK_ColorBLUE }, // first point of glyph contour
76 {{0, 0}, SK_ColorRED }, // sbix glyph data's origin offset
77 };
78 static constexpr const int kGlyfXYMin = 0;
79 static constexpr const int kGlyfXYMax = 1;
80 static constexpr const int kGlyfLSB = 2;
81 static constexpr const int kGlyfFirstPoint = 3;
82 static constexpr const int kOriginOffset = 4;
83
84 std::vector<sk_sp<SkFontMgr>> fFontMgr;
85 std::vector<SkFont> fFonts;
86 sk_sp<SkData> fSBIXData;
87 bool fInputChanged = false;
88 bool fDirty = true;
89
90public:
91 SBIXSlide() { fName = "SBIX"; }
92
93 void load(SkScalar w, SkScalar h) override {
94 fFontMgr.emplace_back(ToolUtils::TestFontMgr());
95#if defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
96 fFontMgr.emplace_back(SkFontMgr_New_Custom_Empty());
97#endif
98#if defined(SK_FONTMGR_FONTATIONS_AVAILABLE)
99 fFontMgr.emplace_back(SkFontMgr_New_Fontations_Empty());
100#endif
101
102 // GetResourceAsData may be backed by a read only file mapping.
103 // For sanity always make a copy.
104 fSBIXData = GetResourceAsData(kFontFile);
105
106 updateSBIXData(fSBIXData.get(), true);
107 }
108
109 void draw(SkCanvas* canvas) override {
110 canvas->clear(SK_ColorGRAY);
111
112 canvas->translate(DX, DY);
113
115 SkPoint position{0, 0};
116 SkPoint origin{0, 0};
117
118 if (fDirty) {
119 sk_sp<SkData> data(updateSBIXData(fSBIXData.get(), false));
120 fFonts.clear();
121 for (auto&& fontmgr : fFontMgr) {
122 fFonts.emplace_back(fontmgr->makeFromData(data), kFontSize);
123 }
124 fDirty = false;
125 }
126 for (auto&& font : fFonts) {
127 paint.setStyle(SkPaint::kFill_Style);
128 paint.setColor(SK_ColorBLACK);
129 canvas->drawGlyphs(1, &kGlyphID, &position, origin, font, paint);
130
131 paint.setStrokeWidth(SkIntToScalar(kPointSize / 2));
133 SkScalar advance;
134 SkRect rect;
135 font.getWidthsBounds(&kGlyphID, 1, &advance, &rect, &paint);
136
137 paint.setColor(SK_ColorRED);
138 canvas->drawRect(rect, paint);
139 paint.setColor(SK_ColorGREEN);
140 canvas->drawLine(0, 0, advance, 0, paint);
141 paint.setColor(SK_ColorRED);
142 canvas->drawPoint(0, 0, paint);
143 canvas->drawPoint(advance, 0, paint);
144
145 paint.setStrokeWidth(SkIntToScalar(kPointSize));
146 for (auto&& pt : fPts) {
147 paint.setColor(pt.color);
148 canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, &pt.location, paint);
149 }
150
151 canvas->translate(kFontSize, 0);
152 }
153 }
154
155protected:
156 static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
157 return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(kPointSize);
158 }
159
160 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
161 x -= DX;
162 y -= DY;
163 // Look for hit in opposite of paint order
164 for (auto&& pt = std::rbegin(fPts); pt != std::rend(fPts); ++pt) {
165 if (hittest(pt->location, x, y)) {
166 return new PtClick(&*pt);
167 }
168 }
169 return nullptr;
170 }
171
172 bool onClick(Click* click) override {
173 ((PtClick*)click)->fPt->location.set(click->fCurr.fX - DX, click->fCurr.fY - DY);
174 fDirty = true;
175 return true;
176 }
177
178private:
179 class PtClick : public Click {
180 public:
181 Point* fPt;
182 PtClick(Point* pt) : fPt(pt) {}
183 };
184
185 sk_sp<SkData> updateSBIXData(SkData* originalData, bool setPts) {
186 // Lots of unlikely to be aligned pointers in here, which is UB. Total hack.
187
188 sk_sp<SkData> dataCopy = SkData::MakeWithCopy(originalData->data(), originalData->size());
189
190 SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(dataCopy->writable_data());
191
192 SkASSERT_RELEASE(memcmp(sfntHeader, originalData->data(), originalData->size()) == 0);
193
195 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
196 SkSFNTHeader::TableDirectoryEntry* glyfTableEntry = nullptr;
197 SkSFNTHeader::TableDirectoryEntry* headTableEntry = nullptr;
198 SkSFNTHeader::TableDirectoryEntry* hheaTableEntry = nullptr;
199 SkSFNTHeader::TableDirectoryEntry* hmtxTableEntry = nullptr;
200 SkSFNTHeader::TableDirectoryEntry* locaTableEntry = nullptr;
201 SkSFNTHeader::TableDirectoryEntry* maxpTableEntry = nullptr;
202 SkSFNTHeader::TableDirectoryEntry* sbixTableEntry = nullptr;
203 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
204 for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
205 if (SkOTTableGlyph::TAG == tableEntry[tableEntryIndex].tag) {
206 glyfTableEntry = tableEntry + tableEntryIndex;
207 }
208 if (SkOTTableHead::TAG == tableEntry[tableEntryIndex].tag) {
209 headTableEntry = tableEntry + tableEntryIndex;
210 }
211 if (SkOTTableHorizontalHeader::TAG == tableEntry[tableEntryIndex].tag) {
212 hheaTableEntry = tableEntry + tableEntryIndex;
213 }
214 if (SkOTTableHorizontalMetrics::TAG == tableEntry[tableEntryIndex].tag) {
215 hmtxTableEntry = tableEntry + tableEntryIndex;
216 }
217 if (SkOTTableIndexToLocation::TAG == tableEntry[tableEntryIndex].tag) {
218 locaTableEntry = tableEntry + tableEntryIndex;
219 }
220 if (SkOTTableMaximumProfile::TAG == tableEntry[tableEntryIndex].tag) {
221 maxpTableEntry = tableEntry + tableEntryIndex;
222 }
223 if (SkOTTableStandardBitmapGraphics::TAG == tableEntry[tableEntryIndex].tag) {
224 sbixTableEntry = tableEntry + tableEntryIndex;
225 }
226 }
227 SkASSERT_RELEASE(glyfTableEntry);
228 SkASSERT_RELEASE(headTableEntry);
229 SkASSERT_RELEASE(hheaTableEntry);
230 SkASSERT_RELEASE(hmtxTableEntry);
231 SkASSERT_RELEASE(locaTableEntry);
232 SkASSERT_RELEASE(maxpTableEntry);
233
234 size_t glyfTableOffset = SkEndian_SwapBE32(glyfTableEntry->offset);
235 SkOTTableGlyph* glyfTable =
236 SkTAddOffset<SkOTTableGlyph>(sfntHeader, glyfTableOffset);
237
238 size_t headTableOffset = SkEndian_SwapBE32(headTableEntry->offset);
239 SkOTTableHead* headTable =
240 SkTAddOffset<SkOTTableHead>(sfntHeader, headTableOffset);
241
242 size_t hheaTableOffset = SkEndian_SwapBE32(hheaTableEntry->offset);
243 SkOTTableHorizontalHeader* hheaTable =
244 SkTAddOffset<SkOTTableHorizontalHeader>(sfntHeader, hheaTableOffset);
245
246 size_t hmtxTableOffset = SkEndian_SwapBE32(hmtxTableEntry->offset);
247 SkOTTableHorizontalMetrics* hmtxTable =
248 SkTAddOffset<SkOTTableHorizontalMetrics>(sfntHeader, hmtxTableOffset);
249
250 size_t locaTableOffset = SkEndian_SwapBE32(locaTableEntry->offset);
251 SkOTTableIndexToLocation* locaTable =
252 SkTAddOffset<SkOTTableIndexToLocation>(sfntHeader, locaTableOffset);
253
254 size_t maxpTableOffset = SkEndian_SwapBE32(maxpTableEntry->offset);
255 SkOTTableMaximumProfile* maxpTable =
256 SkTAddOffset<SkOTTableMaximumProfile>(sfntHeader, maxpTableOffset);
257
258 SkASSERT_RELEASE(SkEndian_SwapBE32(maxpTable->version.version) == 0x00010000);
259 int numGlyphs = SkEndian_SwapBE16(maxpTable->version.tt.numGlyphs);
260 SkASSERT_RELEASE(kGlyphID < numGlyphs);
261
262 int emSize = SkEndian_SwapBE16(headTable->unitsPerEm);
263 SkScalar toEm = emSize / kFontSize;
264
265 if (sbixTableEntry) {
266 size_t sbixTableOffset = SkEndian_SwapBE32(sbixTableEntry->offset);
268 SkTAddOffset<SkOTTableStandardBitmapGraphics>(sfntHeader, sbixTableOffset);
269
270 uint32_t numStrikes = SkEndian_SwapBE32(sbixTable->numStrikes);
271 SkASSERT_RELEASE(kStrikeIndex < numStrikes);
272
273 uint32_t strikeOffset = SkEndian_SwapBE32(sbixTable->strikeOffset(kStrikeIndex));
275 SkTAddOffset<SkOTTableStandardBitmapGraphics::Strike>(sbixTable, strikeOffset);
276 uint16_t strikePpem = SkEndian_SwapBE16(strike->ppem);
277 SkScalar toStrikeEm = strikePpem / kFontSize;
278 uint32_t glyphDataOffset = SkEndian_SwapBE32(strike->glyphDataOffset(kGlyphID));
279 uint32_t glyphDataOffsetNext = SkEndian_SwapBE32(strike->glyphDataOffset(kGlyphID+1));
280 SkASSERT_RELEASE(glyphDataOffset < glyphDataOffsetNext);
282 SkTAddOffset<SkOTTableStandardBitmapGraphics::GlyphData>(strike, glyphDataOffset);
283 if (setPts) {
284 fPts[kOriginOffset].location.set((int16_t)SkEndian_SwapBE16(glyphData->originOffsetX) / toStrikeEm,
285 (int16_t)SkEndian_SwapBE16(glyphData->originOffsetY) / -toStrikeEm);
286 } else {
287 glyphData->originOffsetX = SkEndian_SwapBE16(sk_float_saturate2int16( fPts[kOriginOffset].location.x()*toStrikeEm));
288 glyphData->originOffsetY = SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[kOriginOffset].location.y()*toStrikeEm));
289 }
290 }
291
292 SkOTTableGlyph::Iterator glyphIter(*glyfTable, *locaTable, headTable->indexToLocFormat);
293 glyphIter.advance(kGlyphID);
294 SkOTTableGlyphData* glyphData = glyphIter.next();
295 if (glyphData) {
296 if (setPts) {
297 fPts[kGlyfXYMin].location.set((int16_t)SkEndian_SwapBE16(glyphData->xMin) / toEm,
298 (int16_t)SkEndian_SwapBE16(glyphData->yMin) / -toEm);
299 fPts[kGlyfXYMax].location.set((int16_t)SkEndian_SwapBE16(glyphData->xMax) / toEm,
300 (int16_t)SkEndian_SwapBE16(glyphData->yMax) / -toEm);
301 } else {
302 glyphData->xMin = SkEndian_SwapBE16(sk_float_saturate2int16( fPts[kGlyfXYMin].location.x()*toEm));
303 glyphData->yMin = SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[kGlyfXYMin].location.y()*toEm));
304 glyphData->xMax = SkEndian_SwapBE16(sk_float_saturate2int16( fPts[kGlyfXYMax].location.x()*toEm));
305 glyphData->yMax = SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[kGlyfXYMax].location.y()*toEm));
306 }
307
308 int contourCount = SkEndian_SwapBE16(glyphData->numberOfContours);
309 if (contourCount > 0) {
310 SK_OT_USHORT* endPtsOfContours = SkTAfter<SK_OT_USHORT>(glyphData);
311 SK_OT_USHORT* numInstructions = SkTAfter<SK_OT_USHORT>(endPtsOfContours,
312 contourCount);
313 SK_OT_BYTE* instructions = SkTAfter<SK_OT_BYTE>(numInstructions);
315 SkTAfter<SkOTTableGlyphData::Simple::Flags>(
316 instructions, SkEndian_SwapBE16(*numInstructions));
317
318 int numResultPoints = SkEndian_SwapBE16(endPtsOfContours[contourCount-1]) + 1;
319 struct Coordinate {
321 size_t offsetToXDelta;
322 size_t xDeltaSize;
323 size_t offsetToYDelta;
324 size_t yDeltaSize;
325 };
326 std::vector<Coordinate> coordinates(numResultPoints);
327
328 size_t offsetToXDelta = 0;
329 size_t offsetToYDelta = 0;
331 for (int i = 0; i < numResultPoints; ++i) {
333 int times = 1;
334 if (currentFlags->field.Repeat) {
335 SK_OT_BYTE* repeat = SkTAfter<SK_OT_BYTE>(currentFlags);
336 times += *repeat;
337 nextFlags = SkTAfter<SkOTTableGlyphData::Simple::Flags>(repeat);
338 } else {
339 nextFlags = SkTAfter<SkOTTableGlyphData::Simple::Flags>(currentFlags);
340 }
341
342 --i;
343 for (int time = 0; time < times; ++time) {
344 ++i;
345 coordinates[i].flags = currentFlags;
346 coordinates[i].offsetToXDelta = offsetToXDelta;
347 coordinates[i].offsetToYDelta = offsetToYDelta;
348
349 if (currentFlags->field.xShortVector) {
350 offsetToXDelta += 1;
351 coordinates[i].xDeltaSize = 1;
352 } else if (currentFlags->field.xIsSame_xShortVectorPositive) {
353 offsetToXDelta += 0;
354 if (i == 0) {
355 coordinates[i].xDeltaSize = 0;
356 } else {
357 coordinates[i].xDeltaSize = coordinates[i-1].xDeltaSize;
358 }
359 } else {
360 offsetToXDelta += 2;
361 coordinates[i].xDeltaSize = 2;
362 }
363
364 if (currentFlags->field.yShortVector) {
365 offsetToYDelta += 1;
366 coordinates[i].yDeltaSize = 1;
367 } else if (currentFlags->field.yIsSame_yShortVectorPositive) {
368 offsetToYDelta += 0;
369 if (i == 0) {
370 coordinates[i].yDeltaSize = 0;
371 } else {
372 coordinates[i].yDeltaSize = coordinates[i-1].yDeltaSize;
373 }
374 } else {
375 offsetToYDelta += 2;
376 coordinates[i].yDeltaSize = 2;
377 }
378 }
379 currentFlags = nextFlags;
380 }
381 SK_OT_BYTE* xCoordinates = reinterpret_cast<SK_OT_BYTE*>(currentFlags);
382 SK_OT_BYTE* yCoordinates = xCoordinates + offsetToXDelta;
383
384 int pointIndex = 0;
385 if (coordinates[pointIndex].xDeltaSize == 0) {
386 // Zero delta relative to the origin. There is no data to modify.
387 SkDebugf("Failed to move point in X at all.\n");
388 } else if (coordinates[pointIndex].xDeltaSize == 1) {
389 ShortCoordinate x = sk_float_saturate2sm8(fPts[kGlyfFirstPoint].location.x()*toEm);
390 xCoordinates[coordinates[pointIndex].offsetToXDelta] = x.magnitude;
391 coordinates[pointIndex].flags->field.xIsSame_xShortVectorPositive = !x.negative;
392 } else {
393 *reinterpret_cast<SK_OT_SHORT*>(xCoordinates + coordinates[pointIndex].offsetToXDelta) =
394 SkEndian_SwapBE16(sk_float_saturate2int16(fPts[kGlyfFirstPoint].location.x()*toEm));
395 }
396
397 if (coordinates[pointIndex].yDeltaSize == 0) {
398 // Zero delta relative to the origin. There is no data to modify.
399 SkDebugf("Failed to move point in Y at all.\n");
400 } else if (coordinates[pointIndex].yDeltaSize == 1) {
401 ShortCoordinate y = sk_float_saturate2sm8(-fPts[kGlyfFirstPoint].location.y()*toEm);
402 yCoordinates[coordinates[pointIndex].offsetToYDelta] = y.magnitude;
403 coordinates[pointIndex].flags->field.yIsSame_yShortVectorPositive = !y.negative;
404 } else {
405 *reinterpret_cast<SK_OT_SHORT*>(yCoordinates + coordinates[pointIndex].offsetToYDelta) =
406 SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[kGlyfFirstPoint].location.y()*toEm));
407 }
408 }
409 }
410
411 int numberOfFullMetrics = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
413 SK_OT_SHORT lsb = SkEndian_SwapBE16(sk_float_saturate2int16(fPts[kGlyfLSB].location.x()*toEm));
414 if (kGlyphID < numberOfFullMetrics) {
415 if (setPts) {
416 fPts[kGlyfLSB].location.fX = (int16_t)SkEndian_SwapBE16(fullMetrics[kGlyphID].lsb) / toEm;
417 } else {
418 fullMetrics[kGlyphID].lsb = lsb;
419 }
420 } else {
422 SkTAfter<SkOTTableHorizontalMetrics::ShortMetric>(fullMetrics, numberOfFullMetrics);
423 int shortMetricIndex = kGlyphID - numberOfFullMetrics;
424 if (setPts) {
425 fPts[kGlyfLSB].location.fX = (int16_t)SkEndian_SwapBE16(shortMetrics[shortMetricIndex].lsb) / toEm;
426 } else {
427 shortMetrics[shortMetricIndex].lsb = lsb;
428 }
429 }
430
431 headTable->flags.field.LeftSidebearingAtX0 = false;
432 return dataCopy;
433 }
434};
435} // namespace
436DEF_SLIDE( return new SBIXSlide(); )
SkPoint fPts[2]
static SkISize times(const SkISize &size, float factor)
const char * fName
static bool hittest(const SkPoint &target, SkScalar x, SkScalar y)
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition: Resources.cpp:42
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
static unsigned repeat(SkFixed fx, int max)
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorGRAY
Definition: SkColor.h:113
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkEndian_SwapBE32(n)
Definition: SkEndian.h:136
#define SkEndian_SwapBE16(n)
Definition: SkEndian.h:135
static double magnitude(double a)
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Fontations_Empty()
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Custom_Empty()
@ kGlyphID
uses two byte words to represent glyph indices
static constexpr int16_t SK_MaxS16
Definition: SkMath.h:18
static constexpr int16_t SK_MinS16
Definition: SkMath.h:19
uint8_t SK_OT_BYTE
uint16_t SK_OT_USHORT
uint16_t SK_OT_SHORT
#define SkIntToScalar(x)
Definition: SkScalar.h:57
uint16_t SkGlyphID
Definition: SkTypes.h:179
#define DEF_SLIDE(code)
Definition: Slide.h:25
virtual bool onClick(Click *)=0
virtual Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi)=0
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1710
void drawPoint(SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2695
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], const uint32_t clusters[], int textByteCount, const char utf8text[], SkPoint origin, const SkFont &font, const SkPaint &paint)
void clear(SkColor color)
Definition: SkCanvas.h:1199
@ kPoints_PointMode
draw each point separately
Definition: SkCanvas.h:1241
Definition: SkData.h:25
const void * data() const
Definition: SkData.h:37
void * writable_data()
Definition: SkData.h:52
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
size_t size() const
Definition: SkData.h:30
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
virtual void load(SkScalar winWidth, SkScalar winHeight)
Definition: Slide.h:40
virtual void draw(SkCanvas *canvas)=0
T * get() const
Definition: SkRefCnt.h:303
const Paint & paint
Definition: color_source.cc:38
DlColor color
float SkScalar
Definition: extension.cpp:12
FlutterSemanticsFlag flags
double y
double x
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
sk_sp< SkFontMgr > TestFontMgr()
font
Font Metadata and Metrics.
TPoint< Scalar > Point
Definition: point.h:322
constexpr int kPointSize
Definition: shaderpath.cpp:61
ModifierKey
Definition: ModifierKey.h:9
static double time(int loops, Benchmark *bench, Target *target)
Definition: nanobench.cpp:394
SkScalar w
SkScalar h
SK_OT_SHORT numberOfContours
static const SK_OT_ULONG TAG
struct SkOTTableHead::IndexToLocFormat indexToLocFormat
static const SK_OT_ULONG TAG
union SkOTTableHead::Flags flags
SK_OT_USHORT unitsPerEm
static const SK_OT_ULONG TAG
static const SK_OT_ULONG TAG
struct SkOTTableHorizontalMetrics::FullMetric longHorMetric[1/*hhea::numberOfHMetrics */]
static const SK_OT_ULONG TAG
union SkOTTableMaximumProfile::Version version
static const SK_OT_ULONG TAG
SK_OT_ULONG glyphDataOffset(int glyphId)
static const SK_OT_ULONG TAG
SK_OT_ULONG strikeOffset(int strikeIndex)
float fX
x-axis value
Definition: SkPoint_impl.h:164
void set(float x, float y)
Definition: SkPoint_impl.h:200
static float Length(float x, float y)
Definition: SkPoint.cpp:79
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
SK_SFNT_USHORT numTables
Definition: SkSFNTHeader.h:51
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
struct SkOTTableGlyphData::Simple::Flags::Field field
struct SkOTTableHead::Flags::Field field
SkOTTableMaximumProfile::Version::TT tt