• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkFont.h"
11 #include "include/core/SkFontMgr.h"
12 #include "include/core/SkGraphics.h"
13 #include "include/core/SkTime.h"
14 #include "include/core/SkTypeface.h"
15 #include "include/ports/SkFontMgr_empty.h"
16 #include "src/sfnt/SkOTTable_glyf.h"
17 #include "src/sfnt/SkOTTable_head.h"
18 #include "src/sfnt/SkOTTable_hhea.h"
19 #include "src/sfnt/SkOTTable_hmtx.h"
20 #include "src/sfnt/SkOTTable_loca.h"
21 #include "src/sfnt/SkOTTable_maxp.h"
22 #include "src/sfnt/SkSFNTHeader.h"
23 #include "tools/Resources.h"
24 #include "tools/timer/TimeUtils.h"
25 #include "tools/viewer/ClickHandlerSlide.h"
26 
27 namespace {
28 
29 constexpr SkScalar DX = 100;
30 constexpr SkScalar DY = 300;
31 constexpr int kPointSize = 5;
32 constexpr SkScalar kFontSize = 200;
33 
34 constexpr char kFontFile[] = "fonts/sbix_uncompressed_flags.ttf";
35 constexpr SkGlyphID kGlyphID = 2;
36 
37 //constexpr char kFontFile[] = "fonts/HangingS.ttf";
38 //constexpr SkGlyphID kGlyphID = 4;
39 
40 /**
41  *  Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN.
42  */
sk_float_saturate2int16(float x)43 static inline int16_t sk_float_saturate2int16(float x) {
44     x = x < SK_MaxS16 ? x : SK_MaxS16;
45     x = x > SK_MinS16 ? x : SK_MinS16;
46     return (int16_t)x;
47 }
48 
49 struct ShortCoordinate { bool negative; uint8_t magnitude; };
sk_float_saturate2sm8(float x)50 static inline ShortCoordinate sk_float_saturate2sm8(float x) {
51     bool negative = x < 0;
52     x = x <  255 ? x :  255;
53     x = x > -255 ? x : -255;
54     return ShortCoordinate{ negative, negative ? (uint8_t)-x : (uint8_t)x };
55 }
56 
57 struct SBIXSlide : public ClickHandlerSlide {
58     SkPoint  fPts[12] = {
59         {0, 0}, // min
60         {0, 0}, // max
61         {0, 20}, // lsb
62         {0, 0}, // point
63    };
64     std::vector<sk_sp<SkFontMgr>> fFontMgr;
65     std::vector<SkFont> fFonts;
66     sk_sp<SkData> fSBIXData;
67     bool fInputChanged = false;
68     bool fDirty = true;
69 
70 public:
SBIXSlide__anon278e10a60111::SBIXSlide71     SBIXSlide() { fName = "SBIX"; }
72 
load__anon278e10a60111::SBIXSlide73     void load(SkScalar w, SkScalar h) override {
74         fFontMgr.emplace_back(SkFontMgr::RefDefault());
75         //fFontMgr.emplace_back(SkFontMgr_New_Custom_Empty());
76         // GetResourceAsData may be backed by a read only file mapping.
77         // For sanity always make a copy.
78         fSBIXData = GetResourceAsData(kFontFile);
79 
80         updateSBIXData(fSBIXData.get(), true);
81     }
82 
draw__anon278e10a60111::SBIXSlide83     void draw(SkCanvas* canvas) override {
84         canvas->clear(SK_ColorGRAY);
85 
86         canvas->translate(DX, DY);
87 
88         SkPaint paint;
89         SkPoint position{0, 0};
90         SkPoint origin{0, 0};
91 
92         if (fDirty) {
93             sk_sp<SkData> data(updateSBIXData(fSBIXData.get(), false));
94             fFonts.clear();
95             for (auto&& fontmgr : fFontMgr) {
96                 fFonts.emplace_back(fontmgr->makeFromData(data), kFontSize);
97             }
98             fDirty = false;
99         }
100         for (auto&& font : fFonts) {
101             paint.setStyle(SkPaint::kFill_Style);
102             paint.setColor(SK_ColorBLACK);
103             canvas->drawGlyphs(1, &kGlyphID, &position, origin, font, paint);
104 
105             paint.setStrokeWidth(SkIntToScalar(kPointSize / 2));
106             paint.setStyle(SkPaint::kStroke_Style);
107             SkScalar advance;
108             SkRect rect;
109             font.getWidthsBounds(&kGlyphID, 1, &advance, &rect, &paint);
110 
111             paint.setColor(SK_ColorRED);
112             canvas->drawRect(rect, paint);
113             paint.setColor(SK_ColorGREEN);
114             canvas->drawLine(0, 0, advance, 0, paint);
115             paint.setColor(SK_ColorRED);
116             canvas->drawPoint(0, 0, paint);
117             canvas->drawPoint(advance, 0, paint);
118 
119             paint.setStrokeWidth(SkIntToScalar(kPointSize));
120             canvas->drawPoints(SkCanvas::kPoints_PointMode, std::size(fPts), fPts, paint);
121 
122             canvas->translate(kFontSize, 0);
123         }
124     }
125 
126 protected:
hittest__anon278e10a60111::SBIXSlide127     static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
128         return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(kPointSize);
129     }
130 
onFindClickHandler__anon278e10a60111::SBIXSlide131     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
132         x -= DX;
133         y -= DY;
134         for (size_t i = 0; i < std::size(fPts); i++) {
135             if (hittest(fPts[i], x, y)) {
136                 return new PtClick((int)i);
137             }
138         }
139         return nullptr;
140     }
141 
onClick__anon278e10a60111::SBIXSlide142     bool onClick(Click* click) override {
143         fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX - DX, click->fCurr.fY - DY);
144         fDirty = true;
145         return true;
146     }
147 
148 private:
149     class PtClick : public Click {
150     public:
151         int fIndex;
PtClick(int index)152         PtClick(int index) : fIndex(index) {}
153     };
154 
updateSBIXData__anon278e10a60111::SBIXSlide155     sk_sp<SkData> updateSBIXData(SkData* originalData, bool setPts) {
156         // Lots of unlikely to be aligned pointers in here, which is UB. Total hack.
157 
158         sk_sp<SkData> dataCopy = SkData::MakeWithCopy(originalData->data(), originalData->size());
159 
160         SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(dataCopy->writable_data());
161 
162         SkASSERT_RELEASE(memcmp(sfntHeader, originalData->data(), originalData->size()) == 0);
163 
164         SkSFNTHeader::TableDirectoryEntry* tableEntry =
165                 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
166         SkSFNTHeader::TableDirectoryEntry* glyfTableEntry = nullptr;
167         SkSFNTHeader::TableDirectoryEntry* headTableEntry = nullptr;
168         SkSFNTHeader::TableDirectoryEntry* hheaTableEntry = nullptr;
169         SkSFNTHeader::TableDirectoryEntry* hmtxTableEntry = nullptr;
170         SkSFNTHeader::TableDirectoryEntry* locaTableEntry = nullptr;
171         SkSFNTHeader::TableDirectoryEntry* maxpTableEntry = nullptr;
172         int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
173         for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) {
174             if (SkOTTableGlyph::TAG == tableEntry[tableEntryIndex].tag) {
175                 glyfTableEntry = tableEntry + tableEntryIndex;
176             }
177             if (SkOTTableHead::TAG == tableEntry[tableEntryIndex].tag) {
178                 headTableEntry = tableEntry + tableEntryIndex;
179             }
180             if (SkOTTableHorizontalHeader::TAG == tableEntry[tableEntryIndex].tag) {
181                 hheaTableEntry = tableEntry + tableEntryIndex;
182             }
183             if (SkOTTableHorizontalMetrics::TAG == tableEntry[tableEntryIndex].tag) {
184                 hmtxTableEntry = tableEntry + tableEntryIndex;
185             }
186             if (SkOTTableIndexToLocation::TAG == tableEntry[tableEntryIndex].tag) {
187                 locaTableEntry = tableEntry + tableEntryIndex;
188             }
189             if (SkOTTableMaximumProfile::TAG == tableEntry[tableEntryIndex].tag) {
190                 maxpTableEntry = tableEntry + tableEntryIndex;
191             }
192         }
193         SkASSERT_RELEASE(glyfTableEntry);
194         SkASSERT_RELEASE(headTableEntry);
195         SkASSERT_RELEASE(hheaTableEntry);
196         SkASSERT_RELEASE(hmtxTableEntry);
197         SkASSERT_RELEASE(locaTableEntry);
198         SkASSERT_RELEASE(maxpTableEntry);
199 
200         size_t glyfTableOffset = SkEndian_SwapBE32(glyfTableEntry->offset);
201         SkOTTableGlyph* glyfTable =
202                 SkTAddOffset<SkOTTableGlyph>(sfntHeader, glyfTableOffset);
203 
204         size_t headTableOffset = SkEndian_SwapBE32(headTableEntry->offset);
205         SkOTTableHead* headTable =
206                 SkTAddOffset<SkOTTableHead>(sfntHeader, headTableOffset);
207 
208         size_t hheaTableOffset = SkEndian_SwapBE32(hheaTableEntry->offset);
209         SkOTTableHorizontalHeader* hheaTable =
210                 SkTAddOffset<SkOTTableHorizontalHeader>(sfntHeader, hheaTableOffset);
211 
212         size_t hmtxTableOffset = SkEndian_SwapBE32(hmtxTableEntry->offset);
213         SkOTTableHorizontalMetrics* hmtxTable =
214                 SkTAddOffset<SkOTTableHorizontalMetrics>(sfntHeader, hmtxTableOffset);
215 
216         size_t locaTableOffset = SkEndian_SwapBE32(locaTableEntry->offset);
217         SkOTTableIndexToLocation* locaTable =
218                 SkTAddOffset<SkOTTableIndexToLocation>(sfntHeader, locaTableOffset);
219 
220         size_t maxpTableOffset = SkEndian_SwapBE32(maxpTableEntry->offset);
221         SkOTTableMaximumProfile* maxpTable =
222                 SkTAddOffset<SkOTTableMaximumProfile>(sfntHeader, maxpTableOffset);
223 
224         SkASSERT_RELEASE(SkEndian_SwapBE32(maxpTable->version.version) == 0x00010000);
225         int numGlyphs = SkEndian_SwapBE16(maxpTable->version.tt.numGlyphs);
226         SkASSERT_RELEASE(kGlyphID < numGlyphs);
227 
228         int emSize = SkEndian_SwapBE16(headTable->unitsPerEm);
229         SkScalar toEm = emSize / kFontSize;
230 
231         SkOTTableGlyph::Iterator glyphIter(*glyfTable, *locaTable, headTable->indexToLocFormat);
232         glyphIter.advance(kGlyphID);
233         SkOTTableGlyphData* glyphData = glyphIter.next();
234         if (glyphData) {
235             if (setPts) {
236                 fPts[0].set((int16_t)SkEndian_SwapBE16(glyphData->xMin) /  toEm,
237                             (int16_t)SkEndian_SwapBE16(glyphData->yMin) / -toEm);
238                 fPts[1].set((int16_t)SkEndian_SwapBE16(glyphData->xMax) /  toEm,
239                             (int16_t)SkEndian_SwapBE16(glyphData->yMax) / -toEm);
240             } else {
241                 glyphData->xMin = SkEndian_SwapBE16(sk_float_saturate2int16( fPts[0].x()*toEm));
242                 glyphData->yMin = SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[0].y()*toEm));
243                 glyphData->xMax = SkEndian_SwapBE16(sk_float_saturate2int16( fPts[1].x()*toEm));
244                 glyphData->yMax = SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[1].y()*toEm));
245             }
246 
247             int contourCount = SkEndian_SwapBE16(glyphData->numberOfContours);
248             if (contourCount > 0) {
249                 SK_OT_USHORT* endPtsOfContours = SkTAfter<SK_OT_USHORT>(glyphData);
250                 SK_OT_USHORT* numInstructions = SkTAfter<SK_OT_USHORT>(endPtsOfContours,
251                                                                        contourCount);
252                 SK_OT_BYTE* instructions = SkTAfter<SK_OT_BYTE>(numInstructions);
253                 SkOTTableGlyphData::Simple::Flags* flags =
254                         SkTAfter<SkOTTableGlyphData::Simple::Flags>(
255                                 instructions, SkEndian_SwapBE16(*numInstructions));
256 
257                 int numResultPoints = SkEndian_SwapBE16(endPtsOfContours[contourCount-1]) + 1;
258                 struct Coordinate {
259                     SkOTTableGlyphData::Simple::Flags* flags;
260                     size_t offsetToXDelta;
261                     size_t xDeltaSize;
262                     size_t offsetToYDelta;
263                     size_t yDeltaSize;
264                 };
265                 std::vector<Coordinate> coordinates(numResultPoints);
266 
267                 size_t offsetToXDelta = 0;
268                 size_t offsetToYDelta = 0;
269                 SkOTTableGlyphData::Simple::Flags* currentFlags = flags;
270                 for (int i = 0; i < numResultPoints; ++i) {
271                     SkOTTableGlyphData::Simple::Flags* nextFlags;
272                     int times = 1;
273                     if (currentFlags->field.Repeat) {
274                         SK_OT_BYTE* repeat = SkTAfter<SK_OT_BYTE>(currentFlags);
275                         times += *repeat;
276                         nextFlags = SkTAfter<SkOTTableGlyphData::Simple::Flags>(repeat);
277                     } else {
278                         nextFlags = SkTAfter<SkOTTableGlyphData::Simple::Flags>(currentFlags);
279                     }
280 
281                     --i;
282                     for (int time = 0; time < times; ++time) {
283                         ++i;
284                         coordinates[i].flags = currentFlags;
285                         coordinates[i].offsetToXDelta = offsetToXDelta;
286                         coordinates[i].offsetToYDelta = offsetToYDelta;
287 
288                         if (currentFlags->field.xShortVector) {
289                             offsetToXDelta += 1;
290                             coordinates[i].xDeltaSize = 1;
291                         } else if (currentFlags->field.xIsSame_xShortVectorPositive) {
292                             offsetToXDelta += 0;
293                             if (i == 0) {
294                                 coordinates[i].xDeltaSize = 0;
295                             } else {
296                                 coordinates[i].xDeltaSize = coordinates[i-1].xDeltaSize;
297                             }
298                         } else {
299                             offsetToXDelta += 2;
300                             coordinates[i].xDeltaSize = 2;
301                         }
302 
303                         if (currentFlags->field.yShortVector) {
304                             offsetToYDelta += 1;
305                             coordinates[i].yDeltaSize = 1;
306                         } else if (currentFlags->field.yIsSame_yShortVectorPositive) {
307                             offsetToYDelta += 0;
308                             if (i == 0) {
309                                 coordinates[i].yDeltaSize = 0;
310                             } else {
311                                 coordinates[i].yDeltaSize = coordinates[i-1].yDeltaSize;
312                             }
313                         } else {
314                             offsetToYDelta += 2;
315                             coordinates[i].yDeltaSize = 2;
316                         }
317                     }
318                     currentFlags = nextFlags;
319                 }
320                 SK_OT_BYTE* xCoordinates = reinterpret_cast<SK_OT_BYTE*>(currentFlags);
321                 SK_OT_BYTE* yCoordinates = xCoordinates + offsetToXDelta;
322 
323                 int pointIndex = 0;
324                 if (coordinates[pointIndex].xDeltaSize == 0) {
325                     // Zero delta relative to the origin. There is no data to modify.
326                     SkDebugf("Failed to move point in X at all.\n");
327                 } else if (coordinates[pointIndex].xDeltaSize == 1) {
328                     ShortCoordinate x = sk_float_saturate2sm8(fPts[3].x()*toEm);
329                     xCoordinates[coordinates[pointIndex].offsetToXDelta] = x.magnitude;
330                     coordinates[pointIndex].flags->field.xIsSame_xShortVectorPositive = !x.negative;
331                 } else {
332                     *reinterpret_cast<SK_OT_SHORT*>(xCoordinates + coordinates[pointIndex].offsetToXDelta) =
333                             SkEndian_SwapBE16(sk_float_saturate2int16(fPts[3].x()*toEm));
334                 }
335 
336                 if (coordinates[pointIndex].yDeltaSize == 0) {
337                     // Zero delta relative to the origin. There is no data to modify.
338                     SkDebugf("Failed to move point in Y at all.\n");
339                 } else if (coordinates[pointIndex].yDeltaSize == 1) {
340                     ShortCoordinate y = sk_float_saturate2sm8(-fPts[3].y()*toEm);
341                     yCoordinates[coordinates[pointIndex].offsetToYDelta] = y.magnitude;
342                     coordinates[pointIndex].flags->field.yIsSame_yShortVectorPositive = !y.negative;
343                 } else {
344                     *reinterpret_cast<SK_OT_SHORT*>(yCoordinates + coordinates[pointIndex].offsetToYDelta) =
345                             SkEndian_SwapBE16(sk_float_saturate2int16(-fPts[3].y()*toEm));
346                 }
347             }
348         }
349 
350         int numberOfFullMetrics = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
351         SkOTTableHorizontalMetrics::FullMetric* fullMetrics = hmtxTable->longHorMetric;
352         SK_OT_SHORT lsb = SkEndian_SwapBE16(sk_float_saturate2int16(fPts[2].x()*toEm));
353         if (kGlyphID < numberOfFullMetrics) {
354             if (setPts) {
355                 fPts[2].fX = (int16_t)SkEndian_SwapBE16(fullMetrics[kGlyphID].lsb) / toEm;
356             } else {
357                 fullMetrics[kGlyphID].lsb = lsb;
358             }
359         } else {
360             SkOTTableHorizontalMetrics::ShortMetric* shortMetrics =
361                     SkTAfter<SkOTTableHorizontalMetrics::ShortMetric>(fullMetrics, numberOfFullMetrics);
362             int shortMetricIndex = kGlyphID - numberOfFullMetrics;
363             if (setPts) {
364                 fPts[2].fX = (int16_t)SkEndian_SwapBE16(shortMetrics[shortMetricIndex].lsb) / toEm;
365             } else {
366                 shortMetrics[shortMetricIndex].lsb = lsb;
367             }
368         }
369 
370         headTable->flags.field.LeftSidebearingAtX0 = false;
371         return dataCopy;
372     }
373 };
374 }  // namespace
375 DEF_SLIDE( return new SBIXSlide(); )
376