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