• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 "SkTestSVGTypeface.h"
9 
10 #ifdef SK_XML
11 
12 #include "Resources.h"
13 #include "SkAdvancedTypefaceMetrics.h"
14 #include "SkBitmap.h"
15 #include "SkCanvas.h"
16 #include "SkColor.h"
17 #include "SkData.h"
18 #include "SkEncodedImageFormat.h"
19 #include "SkFontDescriptor.h"
20 #include "SkFontPriv.h"
21 #include "SkFontStyle.h"
22 #include "SkGeometry.h"
23 #include "SkGlyph.h"
24 #include "SkImage.h"
25 #include "SkImageInfo.h"
26 #include "SkMask.h"
27 #include "SkMatrix.h"
28 #include "SkNoDrawCanvas.h"
29 #include "SkOTUtils.h"
30 #include "SkPaintPriv.h"
31 #include "SkPath.h"
32 #include "SkPathPriv.h"
33 #include "SkPathEffect.h"
34 #include "SkPathOps.h"
35 #include "SkPixmap.h"
36 #include "SkPointPriv.h"
37 #include "SkRRect.h"
38 #include "SkSVGDOM.h"
39 #include "SkScalerContext.h"
40 #include "SkSize.h"
41 #include "SkStream.h"
42 #include "SkSurface.h"
43 #include "SkTDArray.h"
44 #include "SkTemplates.h"
45 #include "SkUtils.h"
46 
47 #include <utility>
48 
49 class SkDescriptor;
50 
SkTestSVGTypeface(const char * name,int upem,const SkFontMetrics & fontMetrics,const SkSVGTestTypefaceGlyphData * data,int dataCount,const SkFontStyle & style)51 SkTestSVGTypeface::SkTestSVGTypeface(const char* name,
52                                      int upem,
53                                      const SkFontMetrics& fontMetrics,
54                                      const SkSVGTestTypefaceGlyphData* data, int dataCount,
55                                      const SkFontStyle& style)
56     : SkTypeface(style, false)
57     , fName(name)
58     , fUpem(upem)
59     , fFontMetrics(fontMetrics)
60     , fGlyphs(new Glyph[dataCount])
61     , fGlyphCount(dataCount)
62 {
63     for (int i = 0; i < dataCount; ++i) {
64         const SkSVGTestTypefaceGlyphData& datum = data[i];
65         std::unique_ptr<SkStreamAsset> stream = GetResourceAsStream(datum.fSvgResourcePath);
66         fCMap.set(datum.fUnicode, i);
67         fGlyphs[i].fAdvance = datum.fAdvance;
68         fGlyphs[i].fOrigin = datum.fOrigin;
69         if (!stream) {
70             continue;
71         }
72         sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(*stream.get());
73         if (!svg) {
74             continue;
75         }
76 
77         const SkSize& sz = svg->containerSize();
78         if (sz.isEmpty()) {
79             continue;
80         }
81 
82         fGlyphs[i].fSvg = std::move(svg);
83     }
84 }
85 
~SkTestSVGTypeface()86 SkTestSVGTypeface::~SkTestSVGTypeface() {}
87 
Glyph()88 SkTestSVGTypeface::Glyph::Glyph() : fOrigin{0,0}, fAdvance(0) {}
~Glyph()89 SkTestSVGTypeface::Glyph::~Glyph() {}
90 
getAdvance(SkGlyph * glyph) const91 void SkTestSVGTypeface::getAdvance(SkGlyph* glyph) const {
92     SkGlyphID glyphID = glyph->getGlyphID();
93     glyphID = glyphID < fGlyphCount ? glyphID : 0;
94 
95     glyph->fAdvanceX = fGlyphs[glyphID].fAdvance;
96     glyph->fAdvanceY = 0;
97 }
98 
getFontMetrics(SkFontMetrics * metrics) const99 void SkTestSVGTypeface::getFontMetrics(SkFontMetrics* metrics) const {
100     *metrics = fFontMetrics;
101 }
102 
onFilterRec(SkScalerContextRec * rec) const103 void SkTestSVGTypeface::onFilterRec(SkScalerContextRec* rec) const {
104     rec->setHinting(kNo_SkFontHinting);
105 }
106 
getGlyphToUnicodeMap(SkUnichar * glyphToUnicode) const107 void SkTestSVGTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
108     SkDEBUGCODE(unsigned glyphCount = this->countGlyphs());
109     fCMap.foreach([=](const SkUnichar& c, const SkGlyphID& g) {
110         SkASSERT(g < glyphCount);
111         glyphToUnicode[g] = c;
112     });
113 }
114 
onGetAdvancedMetrics() const115 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTestSVGTypeface::onGetAdvancedMetrics() const {
116     std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
117     info->fFontName = fName;
118     return info;
119 }
120 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocal) const121 void SkTestSVGTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
122     desc->setFamilyName(fName.c_str());
123     desc->setStyle(this->fontStyle());
124     *isLocal = false;
125 }
126 
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t glyphs[],int glyphCount) const127 int SkTestSVGTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
128                                     uint16_t glyphs[], int glyphCount) const {
129     auto utf8  = (const      char*)chars;
130     auto utf16 = (const  uint16_t*)chars;
131     auto utf32 = (const SkUnichar*)chars;
132 
133     for (int i = 0; i < glyphCount; i++) {
134         SkUnichar ch;
135         switch (encoding) {
136             case kUTF8_Encoding:  ch =  SkUTF8_NextUnichar(&utf8 ); break;
137             case kUTF16_Encoding: ch = SkUTF16_NextUnichar(&utf16); break;
138             case kUTF32_Encoding: ch =                    *utf32++; break;
139         }
140         if (glyphs) {
141             SkGlyphID* g = fCMap.find(ch);
142             glyphs[i] = g ? *g : 0;
143         }
144     }
145     return glyphCount;
146 }
147 
onGetFamilyName(SkString * familyName) const148 void SkTestSVGTypeface::onGetFamilyName(SkString* familyName) const {
149     *familyName = fName;
150 }
151 
onCreateFamilyNameIterator() const152 SkTypeface::LocalizedStrings* SkTestSVGTypeface::onCreateFamilyNameIterator() const {
153     SkString familyName(fName);
154     SkString language("und"); //undetermined
155     return new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
156 }
157 
158 class SkTestSVGScalerContext : public SkScalerContext {
159 public:
SkTestSVGScalerContext(sk_sp<SkTestSVGTypeface> face,const SkScalerContextEffects & effects,const SkDescriptor * desc)160     SkTestSVGScalerContext(sk_sp<SkTestSVGTypeface> face, const SkScalerContextEffects& effects,
161                            const SkDescriptor* desc)
162         : SkScalerContext(std::move(face), effects, desc)
163     {
164         fRec.getSingleMatrix(&fMatrix);
165         SkScalar upem = this->geTestSVGTypeface()->fUpem;
166         fMatrix.preScale(1.f/upem, 1.f/upem);
167     }
168 
169 protected:
geTestSVGTypeface() const170     SkTestSVGTypeface* geTestSVGTypeface() const {
171         return static_cast<SkTestSVGTypeface*>(this->getTypeface());
172     }
173 
generateGlyphCount()174     unsigned generateGlyphCount() override {
175         return this->geTestSVGTypeface()->onCountGlyphs();
176     }
177 
generateCharToGlyph(SkUnichar u)178     uint16_t generateCharToGlyph(SkUnichar u) override {
179         uint16_t g;
180         (void) this->geTestSVGTypeface()->onCharsToGlyphs(&u, SkTypeface::kUTF32_Encoding, &g, 1);
181         return g;
182     }
183 
generateAdvance(SkGlyph * glyph)184     bool generateAdvance(SkGlyph* glyph) override {
185         this->geTestSVGTypeface()->getAdvance(glyph);
186 
187         const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX),
188                                                SkFloatToScalar(glyph->fAdvanceY));
189         glyph->fAdvanceX = SkScalarToFloat(advance.fX);
190         glyph->fAdvanceY = SkScalarToFloat(advance.fY);
191         return true;
192     }
193 
generateMetrics(SkGlyph * glyph)194     void generateMetrics(SkGlyph* glyph) override {
195         SkGlyphID glyphID = glyph->getGlyphID();
196         glyphID = glyphID < this->geTestSVGTypeface()->fGlyphCount ? glyphID : 0;
197 
198         glyph->zeroMetrics();
199         glyph->fMaskFormat = SkMask::kARGB32_Format;
200         this->generateAdvance(glyph);
201 
202         SkTestSVGTypeface::Glyph& glyphData = this->geTestSVGTypeface()->fGlyphs[glyphID];
203         if (!glyphData.fSvg) {
204             return;
205         }
206 
207         SkSize containerSize = glyphData.fSvg->containerSize();
208         SkRect newBounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY,
209                                             containerSize.fWidth, containerSize.fHeight);
210         fMatrix.mapRect(&newBounds);
211         SkScalar dx = SkFixedToScalar(glyph->getSubXFixed());
212         SkScalar dy = SkFixedToScalar(glyph->getSubYFixed());
213         newBounds.offset(dx, dy);
214 
215         SkIRect ibounds;
216         newBounds.roundOut(&ibounds);
217         glyph->fLeft = ibounds.fLeft;
218         glyph->fTop = ibounds.fTop;
219         glyph->fWidth = ibounds.width();
220         glyph->fHeight = ibounds.height();
221     }
222 
generateImage(const SkGlyph & glyph)223     void generateImage(const SkGlyph& glyph) override {
224         SkGlyphID glyphID = glyph.getGlyphID();
225         glyphID = glyphID < this->geTestSVGTypeface()->fGlyphCount ? glyphID : 0;
226 
227         SkBitmap bm;
228         // TODO: this should be SkImageInfo::MakeS32 when that passes all the tests.
229         bm.installPixels(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType),
230                          glyph.fImage, glyph.rowBytes());
231         bm.eraseColor(0);
232 
233         SkTestSVGTypeface::Glyph& glyphData = this->geTestSVGTypeface()->fGlyphs[glyphID];
234 
235         SkScalar dx = SkFixedToScalar(glyph.getSubXFixed());
236         SkScalar dy = SkFixedToScalar(glyph.getSubYFixed());
237 
238         SkCanvas canvas(bm);
239         canvas.translate(-glyph.fLeft, -glyph.fTop);
240         canvas.translate(dx, dy);
241         canvas.concat(fMatrix);
242         canvas.translate(glyphData.fOrigin.fX, -glyphData.fOrigin.fY);
243 
244         if (glyphData.fSvg) {
245             SkAutoExclusive lock(glyphData.fSvgMutex);
246             glyphData.fSvg->render(&canvas);
247         }
248     }
249 
generatePath(SkGlyphID glyph,SkPath * path)250     bool generatePath(SkGlyphID glyph, SkPath* path) override {
251         path->reset();
252         return false;
253     }
254 
generateFontMetrics(SkFontMetrics * metrics)255     void generateFontMetrics(SkFontMetrics* metrics) override {
256         this->geTestSVGTypeface()->getFontMetrics(metrics);
257         SkFontPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
258     }
259 
260 private:
261     SkMatrix fMatrix;
262 };
263 
onCreateScalerContext(const SkScalerContextEffects & e,const SkDescriptor * desc) const264 SkScalerContext* SkTestSVGTypeface::onCreateScalerContext(
265     const SkScalerContextEffects& e, const SkDescriptor* desc) const
266 {
267     return new SkTestSVGScalerContext(sk_ref_sp(const_cast<SkTestSVGTypeface*>(this)), e, desc);
268 }
269 
270 // Recommended that the first four be .notdef, .null, CR, space
271 constexpr const static SkSVGTestTypefaceGlyphData gGlyphs[] = {
272     {"fonts/svg/notdef.svg", {100,800}, 800, 0x0}, // .notdef
273     {"fonts/svg/empty.svg", {0,0}, 800, 0x0020}, // space
274     {"fonts/svg/diamond.svg", {100, 800}, 800, 0x2662}, // ♢
275     {"fonts/svg/smile.svg", {0,800}, 800, 0x1F600}, // ��
276 };
277 
Default()278 sk_sp<SkTestSVGTypeface> SkTestSVGTypeface::Default() {
279     SkFontMetrics metrics;
280     metrics.fFlags = SkFontMetrics::kUnderlineThicknessIsValid_Flag |
281                      SkFontMetrics::kUnderlinePositionIsValid_Flag  |
282                      SkFontMetrics::kStrikeoutThicknessIsValid_Flag |
283                      SkFontMetrics::kStrikeoutPositionIsValid_Flag;
284     metrics.fTop = -800;
285     metrics.fAscent = -800;
286     metrics.fDescent = 200;
287     metrics.fBottom = 200;
288     metrics.fLeading = 100;
289     metrics.fAvgCharWidth = 1000;
290     metrics.fMaxCharWidth = 1000;
291     metrics.fXMin = 0;
292     metrics.fXMax = 1000;
293     metrics.fXHeight = 500;
294     metrics.fCapHeight = 700;
295     metrics.fUnderlineThickness = 40;
296     metrics.fUnderlinePosition = 20;
297     metrics.fStrikeoutThickness = 20;
298     metrics.fStrikeoutPosition = -400;
299     return sk_make_sp<SkTestSVGTypeface>("Emoji", 1000, metrics, gGlyphs, SK_ARRAY_COUNT(gGlyphs),
300                                          SkFontStyle::Normal());
301 }
302 
exportTtxCommon(SkWStream * out,const char * type,const SkTArray<GlyfInfo> * glyfInfo) const303 void SkTestSVGTypeface::exportTtxCommon(SkWStream* out, const char* type,
304                                         const SkTArray<GlyfInfo>* glyfInfo) const
305 {
306     int totalGlyphs = fGlyphCount;
307     out->writeText("  <GlyphOrder>\n");
308     for (int i = 0; i < fGlyphCount; ++i) {
309         out->writeText("    <GlyphID name=\"glyf");
310         out->writeHexAsText(i, 4);
311         out->writeText("\"/>\n");
312     }
313     if (glyfInfo) {
314         for (int i = 0; i < fGlyphCount; ++i) {
315             for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) {
316                 out->writeText("    <GlyphID name=\"glyf");
317                     out->writeHexAsText(i, 4);
318                     out->writeText("l");
319                     out->writeHexAsText(j, 4);
320                     out->writeText("\"/>\n");
321                 ++totalGlyphs;
322             }
323         }
324     }
325     out->writeText("  </GlyphOrder>\n");
326 
327     out->writeText("  <head>\n");
328     out->writeText("    <tableVersion value=\"1.0\"/>\n");
329     out->writeText("    <fontRevision value=\"1.0\"/>\n");
330     out->writeText("    <checkSumAdjustment value=\"0xa9c3274\"/>\n");
331     out->writeText("    <magicNumber value=\"0x5f0f3cf5\"/>\n");
332     out->writeText("    <flags value=\"00000000 00011011\"/>\n");
333     out->writeText("    <unitsPerEm value=\"");
334         out->writeDecAsText(fUpem);
335         out->writeText("\"/>\n");
336     out->writeText("    <created value=\"Thu Feb 15 12:55:49 2018\"/>\n");
337     out->writeText("    <modified value=\"Thu Feb 15 12:55:49 2018\"/>\n");
338     // TODO: not recalculated for bitmap fonts?
339     out->writeText("    <xMin value=\"");
340         out->writeScalarAsText(fFontMetrics.fXMin);
341         out->writeText("\"/>\n");
342     out->writeText("    <yMin value=\"");
343         out->writeScalarAsText(-fFontMetrics.fBottom);
344         out->writeText("\"/>\n");
345     out->writeText("    <xMax value=\"");
346         out->writeScalarAsText(fFontMetrics.fXMax);
347         out->writeText("\"/>\n");
348     out->writeText("    <yMax value=\"");
349         out->writeScalarAsText(-fFontMetrics.fTop);
350         out->writeText("\"/>\n");
351 
352     char macStyle[16] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
353     if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
354         macStyle[0xF - 0x0] = '1'; // Bold
355     }
356     switch (this->fontStyle().slant()) {
357         case SkFontStyle::kUpright_Slant:
358             break;
359         case SkFontStyle::kItalic_Slant:
360             macStyle[0xF - 0x1] = '1'; // Italic
361             break;
362         case SkFontStyle::kOblique_Slant:
363             macStyle[0xF - 0x1] = '1'; // Italic
364             break;
365         default:
366             SK_ABORT("Unknown slant.");
367     }
368     if (this->fontStyle().width() <= SkFontStyle::kCondensed_Width) {
369         macStyle[0xF - 0x5] = '1'; // Condensed
370     } else if (this->fontStyle().width() >= SkFontStyle::kExpanded_Width) {
371         macStyle[0xF - 0x6] = '1'; // Extended
372     }
373     out->writeText("    <macStyle value=\"");
374         out->write(macStyle, 8);
375         out->writeText(" ");
376         out->write(macStyle + 8, 8);
377         out->writeText("\"/>\n");
378     out->writeText("    <lowestRecPPEM value=\"8\"/>\n");
379     out->writeText("    <fontDirectionHint value=\"2\"/>\n");
380     out->writeText("    <indexToLocFormat value=\"0\"/>\n");
381     out->writeText("    <glyphDataFormat value=\"0\"/>\n");
382     out->writeText("  </head>\n");
383 
384     out->writeText("  <hhea>\n");
385     out->writeText("    <tableVersion value=\"0x00010000\"/>\n");
386     out->writeText("    <ascent value=\"");
387         out->writeDecAsText(-fFontMetrics.fAscent);
388         out->writeText("\"/>\n");
389     out->writeText("    <descent value=\"");
390         out->writeDecAsText(-fFontMetrics.fDescent);
391         out->writeText("\"/>\n");
392     out->writeText("    <lineGap value=\"");
393         out->writeDecAsText(fFontMetrics.fLeading);
394         out->writeText("\"/>\n");
395     out->writeText("    <advanceWidthMax value=\"0\"/>\n");
396     out->writeText("    <minLeftSideBearing value=\"0\"/>\n");
397     out->writeText("    <minRightSideBearing value=\"0\"/>\n");
398     out->writeText("    <xMaxExtent value=\"");
399         out->writeScalarAsText(fFontMetrics.fXMax - fFontMetrics.fXMin);
400         out->writeText("\"/>\n");
401     out->writeText("    <caretSlopeRise value=\"1\"/>\n");
402     out->writeText("    <caretSlopeRun value=\"0\"/>\n");
403     out->writeText("    <caretOffset value=\"0\"/>\n");
404     out->writeText("    <reserved0 value=\"0\"/>\n");
405     out->writeText("    <reserved1 value=\"0\"/>\n");
406     out->writeText("    <reserved2 value=\"0\"/>\n");
407     out->writeText("    <reserved3 value=\"0\"/>\n");
408     out->writeText("    <metricDataFormat value=\"0\"/>\n");
409     out->writeText("    <numberOfHMetrics value=\"0\"/>\n");
410     out->writeText("  </hhea>\n");
411 
412     // Some of this table is going to be re-calculated, but we have to write it out anyway.
413     out->writeText("  <maxp>\n");
414     out->writeText("    <tableVersion value=\"0x10000\"/>\n");
415     out->writeText("    <numGlyphs value=\"");
416         out->writeDecAsText(totalGlyphs);
417         out->writeText("\"/>\n");
418     out->writeText("    <maxPoints value=\"4\"/>\n");
419     out->writeText("    <maxContours value=\"1\"/>\n");
420     out->writeText("    <maxCompositePoints value=\"0\"/>\n");
421     out->writeText("    <maxCompositeContours value=\"0\"/>\n");
422     out->writeText("    <maxZones value=\"1\"/>\n");
423     out->writeText("    <maxTwilightPoints value=\"0\"/>\n");
424     out->writeText("    <maxStorage value=\"0\"/>\n");
425     out->writeText("    <maxFunctionDefs value=\"10\"/>\n");
426     out->writeText("    <maxInstructionDefs value=\"0\"/>\n");
427     out->writeText("    <maxStackElements value=\"512\"/>\n");
428     out->writeText("    <maxSizeOfInstructions value=\"24\"/>\n");
429     out->writeText("    <maxComponentElements value=\"0\"/>\n");
430     out->writeText("    <maxComponentDepth value=\"0\"/>\n");
431     out->writeText("  </maxp>\n");
432 
433     out->writeText("  <OS_2>\n");
434     out->writeText("    <version value=\"4\"/>\n");
435     out->writeText("    <xAvgCharWidth value=\"");
436         out->writeScalarAsText(fFontMetrics.fAvgCharWidth);
437         out->writeText("\"/>\n");
438     out->writeText("    <usWeightClass value=\"");
439         out->writeDecAsText(this->fontStyle().weight());
440         out->writeText("\"/>\n");
441     out->writeText("    <usWidthClass value=\"");
442         out->writeDecAsText(this->fontStyle().width());
443         out->writeText("\"/>\n");
444     out->writeText("    <fsType value=\"00000000 00000000\"/>\n");
445     out->writeText("    <ySubscriptXSize value=\"665\"/>\n");
446     out->writeText("    <ySubscriptYSize value=\"716\"/>\n");
447     out->writeText("    <ySubscriptXOffset value=\"0\"/>\n");
448     out->writeText("    <ySubscriptYOffset value=\"143\"/>\n");
449     out->writeText("    <ySuperscriptXSize value=\"665\"/>\n");
450     out->writeText("    <ySuperscriptYSize value=\"716\"/>\n");
451     out->writeText("    <ySuperscriptXOffset value=\"0\"/>\n");
452     out->writeText("    <ySuperscriptYOffset value=\"491\"/>\n");
453     out->writeText("    <yStrikeoutSize value=\"");
454         out->writeScalarAsText(fFontMetrics.fStrikeoutThickness);
455         out->writeText("\"/>\n");
456     out->writeText("    <yStrikeoutPosition value=\"");
457         out->writeScalarAsText(-fFontMetrics.fStrikeoutPosition);
458         out->writeText("\"/>\n");
459     out->writeText("    <sFamilyClass value=\"0\"/>\n");
460     out->writeText("    <panose>\n");
461     out->writeText("      <bFamilyType value=\"0\"/>\n");
462     out->writeText("      <bSerifStyle value=\"0\"/>\n");
463     out->writeText("      <bWeight value=\"0\"/>\n");
464     out->writeText("      <bProportion value=\"0\"/>\n");
465     out->writeText("      <bContrast value=\"0\"/>\n");
466     out->writeText("      <bStrokeVariation value=\"0\"/>\n");
467     out->writeText("      <bArmStyle value=\"0\"/>\n");
468     out->writeText("      <bLetterForm value=\"0\"/>\n");
469     out->writeText("      <bMidline value=\"0\"/>\n");
470     out->writeText("      <bXHeight value=\"0\"/>\n");
471     out->writeText("    </panose>\n");
472     out->writeText("    <ulUnicodeRange1 value=\"00000000 00000000 00000000 00000001\"/>\n");
473     out->writeText("    <ulUnicodeRange2 value=\"00010000 00000000 00000000 00000000\"/>\n");
474     out->writeText("    <ulUnicodeRange3 value=\"00000000 00000000 00000000 00000000\"/>\n");
475     out->writeText("    <ulUnicodeRange4 value=\"00000000 00000000 00000000 00000000\"/>\n");
476     out->writeText("    <achVendID value=\"Skia\"/>\n");
477     char fsSelection[16] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
478     fsSelection[0xF - 0x7] = '1'; // Use typo metrics
479     if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
480         fsSelection[0xF - 0x5] = '1'; // Bold
481     }
482     switch (this->fontStyle().slant()) {
483         case SkFontStyle::kUpright_Slant:
484             if (this->fontStyle().weight() < SkFontStyle::Bold().weight()) {
485                 fsSelection[0xF - 0x6] = '1'; // Not bold or italic, is regular
486             }
487             break;
488         case SkFontStyle::kItalic_Slant:
489             fsSelection[0xF - 0x0] = '1'; // Italic
490             break;
491         case SkFontStyle::kOblique_Slant:
492             fsSelection[0xF - 0x0] = '1'; // Italic
493             fsSelection[0xF - 0x9] = '1'; // Oblique
494             break;
495         default:
496             SK_ABORT("Unknown slant.");
497     }
498     out->writeText("    <fsSelection value=\"");
499         out->write(fsSelection, 8);
500         out->writeText(" ");
501         out->write(fsSelection + 8, 8);
502         out->writeText("\"/>\n");
503     out->writeText("    <usFirstCharIndex value=\"0\"/>\n");
504     out->writeText("    <usLastCharIndex value=\"0\"/>\n");
505     out->writeText("    <sTypoAscender value=\"");
506         out->writeScalarAsText(-fFontMetrics.fAscent);
507         out->writeText("\"/>\n");
508     out->writeText("    <sTypoDescender value=\"");
509         out->writeScalarAsText(-fFontMetrics.fDescent);
510         out->writeText("\"/>\n");
511     out->writeText("    <sTypoLineGap value=\"");
512         out->writeScalarAsText(fFontMetrics.fLeading);
513         out->writeText("\"/>\n");
514     out->writeText("    <usWinAscent value=\"");
515         out->writeScalarAsText(-fFontMetrics.fAscent);
516         out->writeText("\"/>\n");
517     out->writeText("    <usWinDescent value=\"");
518         out->writeScalarAsText(fFontMetrics.fDescent);
519         out->writeText("\"/>\n");
520     out->writeText("    <ulCodePageRange1 value=\"00000000 00000000 00000000 00000000\"/>\n");
521     out->writeText("    <ulCodePageRange2 value=\"00000000 00000000 00000000 00000000\"/>\n");
522     out->writeText("    <sxHeight value=\"");
523         out->writeScalarAsText(fFontMetrics.fXHeight);
524         out->writeText("\"/>\n");
525     out->writeText("    <sCapHeight value=\"");
526         out->writeScalarAsText(fFontMetrics.fCapHeight);
527         out->writeText("\"/>\n");
528     out->writeText("    <usDefaultChar value=\"0\"/>\n");
529     out->writeText("    <usBreakChar value=\"32\"/>\n");
530     out->writeText("    <usMaxContext value=\"0\"/>\n");
531     out->writeText("  </OS_2>\n");
532 
533     out->writeText("  <hmtx>\n");
534     for (int i = 0; i < fGlyphCount; ++i) {
535         out->writeText("    <mtx name=\"glyf");
536         out->writeHexAsText(i, 4);
537         out->writeText("\" width=\"");
538         out->writeDecAsText(fGlyphs[i].fAdvance);
539         out->writeText("\" lsb=\"");
540         int lsb = fGlyphs[i].fOrigin.fX;
541         if (glyfInfo) {
542             lsb += (*glyfInfo)[i].fBounds.fLeft;
543         }
544         out->writeDecAsText(lsb);
545         out->writeText("\"/>\n");
546     }
547     if (glyfInfo) {
548         for (int i = 0; i < fGlyphCount; ++i) {
549             for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) {
550                 out->writeText("    <mtx name=\"glyf");
551                     out->writeHexAsText(i, 4);
552                     out->writeText("l");
553                     out->writeHexAsText(j, 4);
554                     out->writeText("\" width=\"");
555                     out->writeDecAsText(fGlyphs[i].fAdvance);
556                     out->writeText("\" lsb=\"");
557                     int32_t lsb = fGlyphs[i].fOrigin.fX + (*glyfInfo)[i].fLayers[j].fBounds.fLeft;
558                     out->writeDecAsText(lsb);
559                     out->writeText("\"/>\n");
560             }
561         }
562     }
563     out->writeText("  </hmtx>\n");
564 
565     bool hasNonBMP = false;
566     out->writeText("  <cmap>\n");
567     out->writeText("    <tableVersion version=\"0\"/>\n");
568     out->writeText("    <cmap_format_4 platformID=\"3\" platEncID=\"1\" language=\"0\">\n");
569     fCMap.foreach([&out, &hasNonBMP](const SkUnichar& c, const SkGlyphID& g) {
570         if (0xFFFF < c) {
571             hasNonBMP = true;
572             return;
573         }
574         out->writeText("      <map code=\"0x");
575         out->writeHexAsText(c, 4);
576         out->writeText("\" name=\"glyf");
577         out->writeHexAsText(g, 4);
578         out->writeText("\"/>\n");
579     });
580     out->writeText("    </cmap_format_4>\n");
581     if (hasNonBMP) {
582         out->writeText("    <cmap_format_12 platformID=\"3\" platEncID=\"10\" format=\"12\" reserved=\"0\" length=\"1\" language=\"0\" nGroups=\"0\">\n");
583         fCMap.foreach([&out](const SkUnichar& c, const SkGlyphID& g) {
584             out->writeText("      <map code=\"0x");
585             out->writeHexAsText(c, 6);
586             out->writeText("\" name=\"glyf");
587             out->writeHexAsText(g, 4);
588             out->writeText("\"/>\n");
589         });
590         out->writeText("    </cmap_format_12>\n");
591     }
592     out->writeText("  </cmap>\n");
593 
594     out->writeText("  <name>\n");
595     out->writeText("    <namerecord nameID=\"1\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
596     out->writeText("      ");
597       out->writeText(fName.c_str());
598       out->writeText(" ");
599       out->writeText(type);
600       out->writeText("\n");
601     out->writeText("    </namerecord>\n");
602     out->writeText("    <namerecord nameID=\"2\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
603     out->writeText("      Regular\n");
604     out->writeText("    </namerecord>\n");
605     out->writeText("  </name>\n");
606 
607     out->writeText("  <post>\n");
608     out->writeText("    <formatType value=\"3.0\"/>\n");
609     out->writeText("    <italicAngle value=\"0.0\"/>\n");
610     out->writeText("    <underlinePosition value=\"");
611         out->writeScalarAsText(fFontMetrics.fUnderlinePosition);
612         out->writeText("\"/>\n");
613     out->writeText("    <underlineThickness value=\"");
614         out->writeScalarAsText(fFontMetrics.fUnderlineThickness);
615         out->writeText("\"/>\n");
616     out->writeText("    <isFixedPitch value=\"0\"/>\n");
617     out->writeText("    <minMemType42 value=\"0\"/>\n");
618     out->writeText("    <maxMemType42 value=\"0\"/>\n");
619     out->writeText("    <minMemType1 value=\"0\"/>\n");
620     out->writeText("    <maxMemType1 value=\"0\"/>\n");
621     out->writeText("  </post>\n");
622 }
623 
exportTtxCbdt(SkWStream * out) const624 void SkTestSVGTypeface::exportTtxCbdt(SkWStream* out) const {
625     out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
626     out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
627     this->exportTtxCommon(out, "CBDT");
628 
629     int strikeSizes[3] = { 16, 64, 128 };
630 
631     SkPaint paint;
632     SkFont font;
633     font.setTypeface(sk_ref_sp(const_cast<SkTestSVGTypeface*>(this)));
634 
635     out->writeText("  <CBDT>\n");
636     out->writeText("    <header version=\"2.0\"/>\n");
637     for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) {
638         font.setSize(strikeSizes[strikeIndex]);
639         out->writeText("    <strikedata index=\"");
640             out->writeDecAsText(strikeIndex);
641             out->writeText("\">\n");
642         for (int i = 0; i < fGlyphCount; ++i) {
643             SkGlyphID gid = i;
644             SkScalar advance;
645             SkRect bounds;
646             font.getWidthsBounds(&gid, 1, &advance, &bounds, nullptr);
647             SkIRect ibounds = bounds.roundOut();
648             if (ibounds.isEmpty()) {
649                 continue;
650             }
651             SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height());
652             sk_sp<SkSurface> surface(SkSurface::MakeRaster(image_info));
653             SkASSERT(surface);
654             SkCanvas* canvas = surface->getCanvas();
655             canvas->clear(0);
656             SkPixmap pix;
657             surface->peekPixels(&pix);
658             canvas->drawSimpleText(&gid, sizeof(gid), kGlyphID_SkTextEncoding,
659                                    -bounds.fLeft, -bounds.fTop, font, paint);
660             canvas->flush();
661             sk_sp<SkImage> image = surface->makeImageSnapshot();
662             sk_sp<SkData> data = image->encodeToData(SkEncodedImageFormat::kPNG, 100);
663 
664             out->writeText("      <cbdt_bitmap_format_17 name=\"glyf");
665                 out->writeHexAsText(i, 4);
666                 out->writeText("\">\n");
667             out->writeText("        <SmallGlyphMetrics>\n");
668             out->writeText("          <height value=\"");
669                 out->writeDecAsText(image->height());
670                 out->writeText("\"/>\n");
671             out->writeText("          <width value=\"");
672                 out->writeDecAsText(image->width());
673                 out->writeText("\"/>\n");
674             out->writeText("          <BearingX value=\"");
675                 out->writeDecAsText(bounds.fLeft);
676                 out->writeText("\"/>\n");
677             out->writeText("          <BearingY value=\"");
678                 out->writeScalarAsText(-bounds.fTop);
679                 out->writeText("\"/>\n");
680             out->writeText("          <Advance value=\"");
681                 out->writeScalarAsText(advance);
682                 out->writeText("\"/>\n");
683             out->writeText("        </SmallGlyphMetrics>\n");
684             out->writeText("        <rawimagedata>");
685             uint8_t const * bytes = data->bytes();
686             for (size_t i = 0; i < data->size(); ++i) {
687                 if ((i % 0x10) == 0x0) {
688                     out->writeText("\n          ");
689                 } else if (((i - 1) % 0x4) == 0x3) {
690                     out->writeText(" ");
691                 }
692                 out->writeHexAsText(bytes[i], 2);
693             }
694             out->writeText("\n");
695             out->writeText("        </rawimagedata>\n");
696             out->writeText("      </cbdt_bitmap_format_17>\n");
697         }
698         out->writeText("    </strikedata>\n");
699     }
700     out->writeText("  </CBDT>\n");
701 
702     SkFontMetrics fm;
703     out->writeText("  <CBLC>\n");
704     out->writeText("    <header version=\"2.0\"/>\n");
705     for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) {
706         font.setSize(strikeSizes[strikeIndex]);
707         font.getMetrics(&fm);
708         out->writeText("    <strike index=\"");
709             out->writeDecAsText(strikeIndex);
710             out->writeText("\">\n");
711         out->writeText("      <bitmapSizeTable>\n");
712         out->writeText("        <sbitLineMetrics direction=\"hori\">\n");
713         out->writeText("          <ascender value=\"");
714             out->writeScalarAsText(-fm.fTop);
715             out->writeText("\"/>\n");
716         out->writeText("          <descender value=\"");
717             out->writeScalarAsText(-fm.fBottom);
718             out->writeText("\"/>\n");
719         out->writeText("          <widthMax value=\"");
720             out->writeScalarAsText(fm.fXMax - fm.fXMin);
721             out->writeText("\"/>\n");
722         out->writeText("          <caretSlopeNumerator value=\"0\"/>\n");
723         out->writeText("          <caretSlopeDenominator value=\"0\"/>\n");
724         out->writeText("          <caretOffset value=\"0\"/>\n");
725         out->writeText("          <minOriginSB value=\"0\"/>\n");
726         out->writeText("          <minAdvanceSB value=\"0\"/>\n");
727         out->writeText("          <maxBeforeBL value=\"0\"/>\n");
728         out->writeText("          <minAfterBL value=\"0\"/>\n");
729         out->writeText("          <pad1 value=\"0\"/>\n");
730         out->writeText("          <pad2 value=\"0\"/>\n");
731         out->writeText("        </sbitLineMetrics>\n");
732         out->writeText("        <sbitLineMetrics direction=\"vert\">\n");
733         out->writeText("          <ascender value=\"");
734             out->writeScalarAsText(-fm.fTop);
735             out->writeText("\"/>\n");
736         out->writeText("          <descender value=\"");
737             out->writeScalarAsText(-fm.fBottom);
738             out->writeText("\"/>\n");
739         out->writeText("          <widthMax value=\"");
740             out->writeScalarAsText(fm.fXMax - fm.fXMin);
741             out->writeText("\"/>\n");
742         out->writeText("          <caretSlopeNumerator value=\"0\"/>\n");
743         out->writeText("          <caretSlopeDenominator value=\"0\"/>\n");
744         out->writeText("          <caretOffset value=\"0\"/>\n");
745         out->writeText("          <minOriginSB value=\"0\"/>\n");
746         out->writeText("          <minAdvanceSB value=\"0\"/>\n");
747         out->writeText("          <maxBeforeBL value=\"0\"/>\n");
748         out->writeText("          <minAfterBL value=\"0\"/>\n");
749         out->writeText("          <pad1 value=\"0\"/>\n");
750         out->writeText("          <pad2 value=\"0\"/>\n");
751         out->writeText("        </sbitLineMetrics>\n");
752         out->writeText("        <colorRef value=\"0\"/>\n");
753         out->writeText("        <startGlyphIndex value=\"1\"/>\n");
754         out->writeText("        <endGlyphIndex value=\"1\"/>\n");
755         out->writeText("        <ppemX value=\"");
756             out->writeDecAsText(strikeSizes[strikeIndex]);
757             out->writeText("\"/>\n");
758         out->writeText("        <ppemY value=\"");
759             out->writeDecAsText(strikeSizes[strikeIndex]);
760             out->writeText("\"/>\n");
761         out->writeText("        <bitDepth value=\"32\"/>\n");
762         out->writeText("        <flags value=\"1\"/>\n");
763         out->writeText("      </bitmapSizeTable>\n");
764         out->writeText("      <eblc_index_sub_table_1 imageFormat=\"17\" firstGlyphIndex=\"1\" lastGlyphIndex=\"1\">\n");
765         for (int i = 0; i < fGlyphCount; ++i) {
766             SkGlyphID gid = i;
767             SkRect bounds;
768             font.getBounds(&gid, 1, &bounds, nullptr);
769             if (bounds.isEmpty()) {
770                 continue;
771             }
772             out->writeText("        <glyphLoc name=\"glyf");
773                 out->writeHexAsText(i, 4);
774                 out->writeText("\"/>\n");
775         }
776         out->writeText("      </eblc_index_sub_table_1>\n");
777         out->writeText("    </strike>\n");
778     }
779     out->writeText("  </CBLC>\n");
780 
781     out->writeText("</ttFont>\n");
782 }
783 
784 /**
785  * UnitsPerEm is generally 1000 here. Versions of macOS older than 10.13
786  * have problems in CoreText determining the glyph bounds of bitmap glyphs
787  * with unitsPerEm set to 1024 or numbers not divisible by 100 when the
788  * contour is not closed. The bounds of sbix fonts on macOS appear to be those
789  * of the outline in the 'glyf' table. If this countour is closed it will be
790  * drawn, as the 'glyf' outline is to be drawn on top of any bitmap. (There is
791  * a bit which is supposed to control this, but it cannot be relied on.) So
792  * make the glyph contour a degenerate line with points at the edge of the
793  * bounding box of the glyph.
794  */
exportTtxSbix(SkWStream * out) const795 void SkTestSVGTypeface::exportTtxSbix(SkWStream* out) const {
796     out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
797     out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
798     this->exportTtxCommon(out, "sbix");
799 
800     SkPaint paint;
801     SkFont font;
802     font.setTypeface(sk_ref_sp(const_cast<SkTestSVGTypeface*>(this)));
803 
804     out->writeText("  <glyf>\n");
805     for (int i = 0; i < fGlyphCount; ++i) {
806         const SkTestSVGTypeface::Glyph& glyphData = this->fGlyphs[i];
807 
808         SkSize containerSize = glyphData.fSvg ? glyphData.fSvg->containerSize()
809                                               : SkSize::MakeEmpty();
810         SkRect bounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY,
811                                          containerSize.fWidth, containerSize.fHeight);
812         SkIRect ibounds = bounds.roundOut();
813         out->writeText("    <TTGlyph name=\"glyf");
814             out->writeHexAsText(i, 4);
815             out->writeText("\" xMin=\"");
816             out->writeDecAsText(ibounds.fLeft);
817             out->writeText("\" yMin=\"");
818             out->writeDecAsText(-ibounds.fBottom);
819             out->writeText("\" xMax=\"");
820             out->writeDecAsText(ibounds.fRight);
821             out->writeText("\" yMax=\"");
822             out->writeDecAsText(-ibounds.fTop);
823             out->writeText("\">\n");
824         out->writeText("      <contour>\n");
825         out->writeText("        <pt x=\"");
826             out->writeDecAsText(ibounds.fLeft);
827             out->writeText("\" y=\"");
828             out->writeDecAsText(-ibounds.fBottom);
829             out->writeText("\" on=\"1\"/>\n");
830         out->writeText("      </contour>\n");
831         out->writeText("      <contour>\n");
832         out->writeText("        <pt x=\"");
833             out->writeDecAsText(ibounds.fRight);
834             out->writeText("\" y=\"");
835             out->writeDecAsText(-ibounds.fTop);
836             out->writeText("\" on=\"1\"/>\n");
837         out->writeText("      </contour>\n");
838         out->writeText("      <instructions/>\n");
839         out->writeText("    </TTGlyph>\n");
840     }
841     out->writeText("  </glyf>\n");
842 
843     // The loca table will be re-calculated, but if we don't write one we don't get one.
844     out->writeText("  <loca/>\n");
845 
846     int strikeSizes[3] = { 16, 64, 128 };
847 
848     out->writeText("  <sbix>\n");
849     out->writeText("    <version value=\"1\"/>\n");
850     out->writeText("    <flags value=\"00000000 00000001\"/>\n");
851     for (size_t strikeIndex = 0; strikeIndex < SK_ARRAY_COUNT(strikeSizes); ++strikeIndex) {
852         font.setSize(strikeSizes[strikeIndex]);
853         out->writeText("    <strike>\n");
854         out->writeText("      <ppem value=\"");
855             out->writeDecAsText(strikeSizes[strikeIndex]);
856             out->writeText("\"/>\n");
857         out->writeText("      <resolution value=\"72\"/>\n");
858         for (int i = 0; i < fGlyphCount; ++i) {
859             SkGlyphID gid = i;
860             SkScalar advance;
861             SkRect bounds;
862             font.getWidthsBounds(&gid, 1, &advance, &bounds, nullptr);
863             SkIRect ibounds = bounds.roundOut();
864             if (ibounds.isEmpty()) {
865                 continue;
866             }
867             SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height());
868             sk_sp<SkSurface> surface(SkSurface::MakeRaster(image_info));
869             SkASSERT(surface);
870             SkCanvas* canvas = surface->getCanvas();
871             canvas->clear(0);
872             SkPixmap pix;
873             surface->peekPixels(&pix);
874             canvas->drawSimpleText(&gid, sizeof(gid), kGlyphID_SkTextEncoding,
875                                    -bounds.fLeft, -bounds.fTop, font, paint);
876             canvas->flush();
877             sk_sp<SkImage> image = surface->makeImageSnapshot();
878             sk_sp<SkData> data = image->encodeToData(SkEncodedImageFormat::kPNG, 100);
879 
880             out->writeText("      <glyph name=\"glyf");
881                 out->writeHexAsText(i, 4);
882                 out->writeText("\" graphicType=\"png \" originOffsetX=\"");
883                 out->writeDecAsText(bounds.fLeft);
884                 out->writeText("\" originOffsetY=\"");
885                 out->writeScalarAsText(bounds.fBottom);
886                 out->writeText("\">\n");
887 
888             out->writeText("        <hexdata>");
889             uint8_t const * bytes = data->bytes();
890             for (size_t i = 0; i < data->size(); ++i) {
891                 if ((i % 0x10) == 0x0) {
892                     out->writeText("\n          ");
893                 } else if (((i - 1) % 0x4) == 0x3) {
894                     out->writeText(" ");
895                 }
896                 out->writeHexAsText(bytes[i], 2);
897             }
898             out->writeText("\n");
899             out->writeText("        </hexdata>\n");
900             out->writeText("      </glyph>\n");
901         }
902         out->writeText("    </strike>\n");
903     }
904     out->writeText("  </sbix>\n");
905     out->writeText("</ttFont>\n");
906 }
907 
908 namespace {
909 
convert_noninflect_cubic_to_quads(const SkPoint p[4],SkScalar toleranceSqd,SkTArray<SkPoint,true> * quads,int sublevel=0)910 void convert_noninflect_cubic_to_quads(const SkPoint p[4],
911                                        SkScalar toleranceSqd,
912                                        SkTArray<SkPoint, true>* quads,
913                                        int sublevel = 0)
914 {
915     // Notation: Point a is always p[0]. Point b is p[1] unless p[1] == p[0], in which case it is
916     // p[2]. Point d is always p[3]. Point c is p[2] unless p[2] == p[3], in which case it is p[1].
917 
918     SkVector ab = p[1] - p[0];
919     SkVector dc = p[2] - p[3];
920 
921     if (SkPointPriv::LengthSqd(ab) < SK_ScalarNearlyZero) {
922         if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) {
923             SkPoint* degQuad = quads->push_back_n(3);
924             degQuad[0] = p[0];
925             degQuad[1] = p[0];
926             degQuad[2] = p[3];
927             return;
928         }
929         ab = p[2] - p[0];
930     }
931     if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) {
932         dc = p[1] - p[3];
933     }
934 
935     static const SkScalar kLengthScale = 3 * SK_Scalar1 / 2;
936     static const int kMaxSubdivs = 10;
937 
938     ab.scale(kLengthScale);
939     dc.scale(kLengthScale);
940 
941     // e0 and e1 are extrapolations along vectors ab and dc.
942     SkVector c0 = p[0];
943     c0 += ab;
944     SkVector c1 = p[3];
945     c1 += dc;
946 
947     SkScalar dSqd = sublevel > kMaxSubdivs ? 0 : SkPointPriv::DistanceToSqd(c0, c1);
948     if (dSqd < toleranceSqd) {
949         SkPoint cAvg = c0;
950         cAvg += c1;
951         cAvg.scale(SK_ScalarHalf);
952 
953         SkPoint* pts = quads->push_back_n(3);
954         pts[0] = p[0];
955         pts[1] = cAvg;
956         pts[2] = p[3];
957         return;
958     }
959     SkPoint choppedPts[7];
960     SkChopCubicAtHalf(p, choppedPts);
961     convert_noninflect_cubic_to_quads(choppedPts + 0, toleranceSqd, quads, sublevel + 1);
962     convert_noninflect_cubic_to_quads(choppedPts + 3, toleranceSqd, quads, sublevel + 1);
963 }
964 
convertCubicToQuads(const SkPoint p[4],SkScalar tolScale,SkTArray<SkPoint,true> * quads)965 void convertCubicToQuads(const SkPoint p[4], SkScalar tolScale, SkTArray<SkPoint, true>* quads) {
966     if (!p[0].isFinite() || !p[1].isFinite() || !p[2].isFinite() || !p[3].isFinite()) {
967         return;
968     }
969     SkPoint chopped[10];
970     int count = SkChopCubicAtInflections(p, chopped);
971 
972     const SkScalar tolSqd = SkScalarSquare(tolScale);
973 
974     for (int i = 0; i < count; ++i) {
975         SkPoint* cubic = chopped + 3*i;
976         convert_noninflect_cubic_to_quads(cubic, tolSqd, quads);
977     }
978 }
979 
path_to_quads(const SkPath & path,SkPath * quadPath)980 void path_to_quads(const SkPath& path, SkPath* quadPath) {
981     quadPath->reset();
982     SkTArray<SkPoint, true> qPts;
983     SkAutoConicToQuads converter;
984     const SkPoint* quadPts;
985     SkPath::RawIter iter(path);
986     uint8_t verb;
987     SkPoint pts[4];
988     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
989         switch (verb) {
990             case SkPath::kMove_Verb:
991                 quadPath->moveTo(pts[0].fX, pts[0].fY);
992                 break;
993             case SkPath::kLine_Verb:
994                 quadPath->lineTo(pts[1].fX, pts[1].fY);
995                 break;
996             case SkPath::kQuad_Verb:
997                 quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
998                 break;
999             case SkPath::kCubic_Verb:
1000                 qPts.reset();
1001                 convertCubicToQuads(pts, SK_Scalar1, &qPts);
1002                 for (int i = 0; i < qPts.count(); i += 3) {
1003                     quadPath->quadTo(qPts[i+1].fX, qPts[i+1].fY, qPts[i+2].fX, qPts[i+2].fY);
1004                 }
1005                 break;
1006             case SkPath::kConic_Verb:
1007                 quadPts = converter.computeQuads(pts, iter.conicWeight(), SK_Scalar1);
1008                 for (int i = 0; i < converter.countQuads(); ++i) {
1009                     quadPath->quadTo(quadPts[i*2+1].fX, quadPts[i*2+1].fY,
1010                                      quadPts[i*2+2].fX, quadPts[i*2+2].fY);
1011                 }
1012                 break;
1013             case SkPath::kClose_Verb:
1014                  quadPath->close();
1015                 break;
1016             default:
1017                 SkDEBUGFAIL("bad verb");
1018                 return;
1019         }
1020     }
1021 }
1022 
1023 class SkCOLRCanvas : public SkNoDrawCanvas {
1024 public:
SkCOLRCanvas(SkRect glyphBounds,SkGlyphID glyphId,SkTestSVGTypeface::GlyfInfo * glyf,SkTHashMap<SkColor,int> * colors,SkWStream * out)1025     SkCOLRCanvas(SkRect glyphBounds, SkGlyphID glyphId,
1026                  SkTestSVGTypeface::GlyfInfo* glyf, SkTHashMap<SkColor, int>* colors,
1027                  SkWStream* out)
1028         : SkNoDrawCanvas(glyphBounds.roundOut().width(), glyphBounds.roundOut().height())
1029         , fOut(out)
1030         , fGlyphId(glyphId)
1031         , fBaselineOffset(glyphBounds.top())
1032         , fLayerId(0)
1033         , fGlyf(glyf)
1034         , fColors(colors)
1035     { }
1036 
writePoint(SkScalar x,SkScalar y,bool on)1037     void writePoint(SkScalar x, SkScalar y, bool on) {
1038         fOut->writeText("        <pt x=\"");
1039         fOut->writeDecAsText(SkScalarRoundToInt(x));
1040         fOut->writeText("\" y=\"");
1041         fOut->writeDecAsText(SkScalarRoundToInt(y));
1042         fOut->writeText("\" on=\"");
1043         fOut->write8(on ? '1' : '0');
1044         fOut->writeText("\"/>\n");
1045     }
writePath(const SkPath & path,bool layer)1046     SkIRect writePath(const SkPath& path, bool layer) {
1047         // Convert to quads.
1048         SkPath quads;
1049         path_to_quads(path, &quads);
1050 
1051         SkRect bounds = quads.computeTightBounds();
1052         SkIRect ibounds = bounds.roundOut();
1053         // The bounds will be re-calculated anyway.
1054         fOut->writeText("    <TTGlyph name=\"glyf");
1055             fOut->writeHexAsText(fGlyphId, 4);
1056             if (layer) {
1057                 fOut->writeText("l");
1058                 fOut->writeHexAsText(fLayerId, 4);
1059             }
1060             fOut->writeText("\" xMin=\"");
1061             fOut->writeDecAsText(ibounds.fLeft);
1062             fOut->writeText("\" yMin=\"");
1063             fOut->writeDecAsText(ibounds.fTop);
1064             fOut->writeText("\" xMax=\"");
1065             fOut->writeDecAsText(ibounds.fRight);
1066             fOut->writeText("\" yMax=\"");
1067             fOut->writeDecAsText(ibounds.fBottom);
1068             fOut->writeText("\">\n");
1069 
1070         SkPath::RawIter iter(quads);
1071         uint8_t verb;
1072         SkPoint pts[4];
1073         bool contourOpen = false;
1074         while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
1075             switch (verb) {
1076                 case SkPath::kMove_Verb:
1077                     if (contourOpen) {
1078                         fOut->writeText("      </contour>\n");
1079                         contourOpen = false;
1080                     }
1081                     break;
1082                 case SkPath::kLine_Verb:
1083                     if (!contourOpen) {
1084                         fOut->writeText("      <contour>\n");
1085                         this->writePoint(pts[0].fX, pts[0].fY, true);
1086                         contourOpen = true;
1087                     }
1088                     this->writePoint(pts[1].fX, pts[1].fY, true);
1089                     break;
1090                 case SkPath::kQuad_Verb:
1091                     if (!contourOpen) {
1092                         fOut->writeText("      <contour>\n");
1093                         this->writePoint(pts[0].fX, pts[0].fY, true);
1094                         contourOpen = true;
1095                     }
1096                     this->writePoint(pts[1].fX, pts[1].fY, false);
1097                     this->writePoint(pts[2].fX, pts[2].fY, true);
1098                     break;
1099                 case SkPath::kClose_Verb:
1100                     if (contourOpen) {
1101                         fOut->writeText("      </contour>\n");
1102                         contourOpen = false;
1103                     }
1104                     break;
1105                 default:
1106                     SkDEBUGFAIL("bad verb");
1107                     return ibounds;
1108             }
1109         }
1110         if (contourOpen) {
1111             fOut->writeText("      </contour>\n");
1112         }
1113 
1114         // Required to write out an instructions tag.
1115         fOut->writeText("      <instructions/>\n");
1116         fOut->writeText("    </TTGlyph>\n");
1117         return ibounds;
1118     }
1119 
onDrawRect(const SkRect & rect,const SkPaint & paint)1120     void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
1121         SkPath path;
1122         path.addRect(rect);
1123         this->drawPath(path, paint);
1124     }
1125 
onDrawOval(const SkRect & oval,const SkPaint & paint)1126     void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
1127         SkPath path;
1128         path.addOval(oval);
1129         this->drawPath(path, paint);
1130     }
1131 
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)1132     void onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
1133                    const SkPaint& paint) override
1134     {
1135         SkPath path;
1136         bool fillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect();
1137         SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
1138                                     fillNoPathEffect);
1139         this->drawPath(path, paint);
1140     }
1141 
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)1142     void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
1143         SkPath path;
1144         path.addRRect(rrect);
1145         this->drawPath(path, paint);
1146     }
1147 
onDrawPath(const SkPath & platonicPath,const SkPaint & originalPaint)1148     void onDrawPath(const SkPath& platonicPath, const SkPaint& originalPaint) override {
1149         SkPaint paint = originalPaint;
1150         SkPath path = platonicPath;
1151 
1152         // Apply the path effect.
1153         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
1154             bool fill = paint.getFillPath(path, &path);
1155 
1156             paint.setPathEffect(nullptr);
1157             if (fill) {
1158                 paint.setStyle(SkPaint::kFill_Style);
1159             } else {
1160                 paint.setStyle(SkPaint::kStroke_Style);
1161                 paint.setStrokeWidth(0);
1162             }
1163         }
1164 
1165         // Apply the matrix.
1166         SkMatrix m = this->getTotalMatrix();
1167         // If done to the canvas then everything would get clipped out.
1168         m.postTranslate(0, fBaselineOffset); // put the baseline at 0
1169         m.postScale(1, -1); // and flip it since OpenType is y-up.
1170         path.transform(m);
1171 
1172         // While creating the default glyf, union with dark colors and intersect with bright colors.
1173         SkColor color = paint.getColor();
1174         if ((SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color)) / 3 > 0x20) {
1175             fBasePath.add(path, SkPathOp::kDifference_SkPathOp);
1176         } else {
1177             fBasePath.add(path, SkPathOp::kUnion_SkPathOp);
1178         }
1179 
1180         SkIRect bounds = this->writePath(path, true);
1181 
1182         // The CPAL table has the concept of a 'current color' which is index 0xFFFF.
1183         // Mark any layer drawn in 'currentColor' as having this special index.
1184         // The value of 'currentColor' here should a color which causes this layer to union into the
1185         // default glyf.
1186         constexpr SkColor currentColor = 0xFF2B0000;
1187 
1188         int colorIndex;
1189         if (color == currentColor) {
1190             colorIndex = 0xFFFF;
1191         } else {
1192             int* colorIndexPtr = fColors->find(color);
1193             if (colorIndexPtr) {
1194                 colorIndex = *colorIndexPtr;
1195             } else {
1196                 colorIndex = fColors->count();
1197                 fColors->set(color, colorIndex);
1198             }
1199         }
1200         fGlyf->fLayers.emplace_back(colorIndex, bounds);
1201 
1202         ++fLayerId;
1203     }
1204 
finishGlyph()1205     void finishGlyph() {
1206         SkPath baseGlyph;
1207         fBasePath.resolve(&baseGlyph);
1208         fGlyf->fBounds = this->writePath(baseGlyph, false);
1209     }
1210 
1211 private:
1212     SkWStream * const fOut;
1213     SkGlyphID fGlyphId;
1214     SkScalar fBaselineOffset;
1215     int fLayerId;
1216     SkOpBuilder fBasePath;
1217     SkTestSVGTypeface::GlyfInfo* fGlyf;
1218     SkTHashMap<SkColor, int>* fColors;
1219 };
1220 
1221 } // namespace
1222 
exportTtxColr(SkWStream * out) const1223 void SkTestSVGTypeface::exportTtxColr(SkWStream* out) const {
1224     out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1225     out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
1226 
1227     SkTHashMap<SkColor, int> colors;
1228     SkTArray<GlyfInfo> glyfInfos(fGlyphCount);
1229 
1230     // Need to know all the glyphs up front for the common tables.
1231     SkDynamicMemoryWStream glyfOut;
1232     glyfOut.writeText("  <glyf>\n");
1233     for (int i = 0; i < fGlyphCount; ++i) {
1234         const SkTestSVGTypeface::Glyph& glyphData = this->fGlyphs[i];
1235 
1236         SkSize containerSize = glyphData.fSvg ? glyphData.fSvg->containerSize()
1237                                               : SkSize::MakeEmpty();
1238         SkRect bounds = SkRect::MakeXYWH(glyphData.fOrigin.fX, -glyphData.fOrigin.fY,
1239                                          containerSize.fWidth, containerSize.fHeight);
1240         SkCOLRCanvas canvas(bounds, i, &glyfInfos.emplace_back(), &colors, &glyfOut);
1241         if (glyphData.fSvg) {
1242             glyphData.fSvg->render(&canvas);
1243         }
1244         canvas.finishGlyph();
1245     }
1246     glyfOut.writeText("  </glyf>\n");
1247 
1248     this->exportTtxCommon(out, "COLR", &glyfInfos);
1249 
1250     // The loca table will be re-calculated, but if we don't write one we don't get one.
1251     out->writeText("  <loca/>\n");
1252 
1253     std::unique_ptr<SkStreamAsset> glyfStream = glyfOut.detachAsStream();
1254     out->writeStream(glyfStream.get(), glyfStream->getLength());
1255 
1256     out->writeText("  <COLR>\n");
1257     out->writeText("    <version value=\"0\"/>\n");
1258     for (int i = 0; i < fGlyphCount; ++i) {
1259         if (glyfInfos[i].fBounds.isEmpty() || glyfInfos[i].fLayers.empty()) {
1260             continue;
1261         }
1262         out->writeText("    <ColorGlyph name=\"glyf");
1263             out->writeHexAsText(i, 4);
1264             out->writeText("\">\n");
1265         for (int j = 0; j < glyfInfos[i].fLayers.count(); ++j) {
1266             const int colorIndex = glyfInfos[i].fLayers[j].fLayerColorIndex;
1267             out->writeText("      <layer colorID=\"");
1268                 out->writeDecAsText(colorIndex);
1269                 out->writeText("\" name=\"glyf");
1270                 out->writeHexAsText(i, 4);
1271                 out->writeText("l");
1272                 out->writeHexAsText(j, 4);
1273                 out->writeText("\"/>\n");
1274         }
1275         out->writeText("    </ColorGlyph>\n");
1276     }
1277     out->writeText("  </COLR>\n");
1278 
1279     // The colors must be written in order, the 'index' is ignored by ttx.
1280     SkAutoTMalloc<SkColor> colorsInOrder(colors.count());
1281     colors.foreach([&colorsInOrder](const SkColor& c, const int* i) {
1282         colorsInOrder[*i] = c;
1283     });
1284     out->writeText("  <CPAL>\n");
1285     out->writeText("    <version value=\"0\"/>\n");
1286     out->writeText("    <numPaletteEntries value=\"");
1287         out->writeDecAsText(colors.count());
1288         out->writeText("\"/>\n");
1289     out->writeText("    <palette index=\"0\">\n");
1290     for (int i = 0; i < colors.count(); ++i) {
1291         SkColor c = colorsInOrder[i];
1292         out->writeText("      <color index=\"");
1293             out->writeDecAsText(i);
1294             out->writeText("\" value=\"#");
1295             out->writeHexAsText(SkColorGetR(c), 2);
1296             out->writeHexAsText(SkColorGetG(c), 2);
1297             out->writeHexAsText(SkColorGetB(c), 2);
1298             out->writeHexAsText(SkColorGetA(c), 2);
1299             out->writeText("\"/>\n");
1300     }
1301     out->writeText("    </palette>\n");
1302     out->writeText("  </CPAL>\n");
1303 
1304     out->writeText("</ttFont>\n");
1305 }
1306 #endif  // SK_XML
1307