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