[SVG -> OTF Converter] Glyphs get clipped weirdly
[WebKit-https.git] / Source / WebCore / svg / SVGToOTFFontConversion.cpp
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SVGToOTFFontConversion.h"
28
29 #include "CSSStyleDeclaration.h"
30 #include "ElementChildIterator.h"
31 #include "SVGFontElement.h"
32 #include "SVGFontFaceElement.h"
33 #include "SVGGlyphElement.h"
34 #include "SVGHKernElement.h"
35 #include "SVGMissingGlyphElement.h"
36 #include "SVGPathBuilder.h"
37 #include "SVGPathParser.h"
38 #include "SVGPathStringSource.h"
39 #include "SVGVKernElement.h"
40
41 namespace WebCore {
42
43 template <typename V>
44 static inline void append32(V& result, uint32_t value)
45 {
46     result.append(value >> 24);
47     result.append(value >> 16);
48     result.append(value >> 8);
49     result.append(value);
50 }
51
52 class SVGToOTFFontConverter {
53 public:
54     SVGToOTFFontConverter(const SVGFontElement&);
55     void convertSVGToOTFFont();
56
57     Vector<char> releaseResult()
58     {
59         return WTF::move(m_result);
60     }
61
62 private:
63     struct GlyphData {
64         GlyphData(Vector<char>&& charString, const SVGGlyphElement* glyphElement, float horizontalAdvance, float verticalAdvance, FloatRect boundingBox, const String& codepoints)
65             : boundingBox(boundingBox)
66             , charString(charString)
67             , codepoints(codepoints)
68             , glyphElement(glyphElement)
69             , horizontalAdvance(horizontalAdvance)
70             , verticalAdvance(verticalAdvance)
71         {
72         }
73         FloatRect boundingBox;
74         Vector<char> charString;
75         String codepoints;
76         const SVGGlyphElement* glyphElement;
77         float horizontalAdvance;
78         float verticalAdvance;
79     };
80
81     class Placeholder {
82     public:
83         Placeholder(SVGToOTFFontConverter& converter, size_t baseOfOffset)
84             : m_converter(converter)
85             , m_baseOfOffset(baseOfOffset)
86             , m_location(m_converter.m_result.size())
87         {
88             m_converter.append16(0);
89         }
90
91         Placeholder(Placeholder&& other)
92             : m_converter(other.m_converter)
93             , m_baseOfOffset(other.m_baseOfOffset)
94             , m_location(other.m_location)
95 #if !ASSERT_DISABLED
96             , m_active(other.m_active)
97 #endif
98         {
99 #if !ASSERT_DISABLED
100             other.m_active = false;
101 #endif
102         }
103
104         void populate()
105         {
106             ASSERT(m_active);
107             size_t delta = m_converter.m_result.size() - m_baseOfOffset;
108             ASSERT(delta < std::numeric_limits<uint16_t>::max());
109             m_converter.overwrite16(m_location, delta);
110 #if !ASSERT_DISABLED
111             m_active = false;
112 #endif
113         }
114
115         ~Placeholder()
116         {
117             ASSERT(!m_active);
118         }
119
120     private:
121         SVGToOTFFontConverter& m_converter;
122         const size_t m_baseOfOffset;
123         const size_t m_location;
124 #if !ASSERT_DISABLED
125         bool m_active = { true };
126 #endif
127     };
128
129     struct KerningData {
130         KerningData(uint16_t glyph1, uint16_t glyph2, int16_t adjustment)
131             : glyph1(glyph1)
132             , glyph2(glyph2)
133             , adjustment(adjustment)
134         {
135         }
136         uint16_t glyph1;
137         uint16_t glyph2;
138         int16_t adjustment;
139     };
140
141     Placeholder placeholder(size_t baseOfOffset)
142     {
143         return Placeholder(*this, baseOfOffset);
144     }
145
146     void append32(uint32_t value)
147     {
148         WebCore::append32(m_result, value);
149     }
150
151     void append32BitCode(const char code[4])
152     {
153         m_result.append(code[0]);
154         m_result.append(code[1]);
155         m_result.append(code[2]);
156         m_result.append(code[3]);
157     }
158
159     void append16(uint16_t value)
160     {
161         m_result.append(value >> 8);
162         m_result.append(value);
163     }
164
165     void grow(size_t delta)
166     {
167         m_result.grow(m_result.size() + delta);
168     }
169
170     void overwrite32(unsigned location, uint32_t value)
171     {
172         ASSERT(m_result.size() >= location + 4);
173         m_result[location] = value >> 24;
174         m_result[location + 1] = value >> 16;
175         m_result[location + 2] = value >> 8;
176         m_result[location + 3] = value;
177     }
178
179     void overwrite16(unsigned location, uint16_t value)
180     {
181         ASSERT(m_result.size() >= location + 2);
182         m_result[location] = value >> 8;
183         m_result[location + 1] = value;
184     }
185
186     static const size_t headerSize = 12;
187     static const size_t directoryEntrySize = 16;
188
189     uint32_t calculateChecksum(size_t startingOffset, size_t endingOffset) const;
190
191     void processGlyphElement(const SVGElement& glyphOrMissingGlyphElement, const SVGGlyphElement*, float defaultHorizontalAdvance, float defaultVerticalAdvance, const String& codepoints, bool& initialGlyph);
192
193     typedef void (SVGToOTFFontConverter::*FontAppendingFunction)();
194     void appendTable(const char identifier[4], FontAppendingFunction);
195     void appendCMAPTable();
196     void appendGSUBTable();
197     void appendHEADTable();
198     void appendHHEATable();
199     void appendHMTXTable();
200     void appendVHEATable();
201     void appendVMTXTable();
202     void appendKERNTable();
203     void appendMAXPTable();
204     void appendNAMETable();
205     void appendOS2Table();
206     void appendPOSTTable();
207     void appendCFFTable();
208     void appendVORGTable();
209
210     void appendLigatureGlyphs();
211     static bool compareCodepointsLexicographically(const GlyphData&, const GlyphData&);
212
213     void appendValidCFFString(const String&);
214
215     Vector<char> transcodeGlyphPaths(float width, const SVGElement& glyphOrMissingGlyphElement, FloatRect& boundingBox) const;
216
217     void addCodepointRanges(const UnicodeRanges&, HashSet<Glyph>& glyphSet) const;
218     void addCodepoints(const HashSet<String>& codepoints, HashSet<Glyph>& glyphSet) const;
219     void addGlyphNames(const HashSet<String>& glyphNames, HashSet<Glyph>& glyphSet) const;
220     void addKerningPair(Vector<KerningData>&, const SVGKerningPair&) const;
221     template<typename T> size_t appendKERNSubtable(bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage);
222     size_t finishAppendingKERNSubtable(Vector<KerningData>, uint16_t coverage);
223
224     void appendLigatureSubtable(size_t subtableRecordLocation);
225     void appendArabicReplacementSubtable(size_t subtableRecordLocation, const char arabicForm[]);
226     void appendScriptSubtable(unsigned featureCount);
227     Vector<Glyph, 1> glyphsForCodepoint(UChar32) const;
228     Glyph firstGlyph(const Vector<Glyph, 1>&, UChar32) const;
229
230     Vector<GlyphData> m_glyphs;
231     HashMap<String, Glyph> m_glyphNameToIndexMap; // SVG 1.1: "It is recommended that glyph names be unique within a font."
232     HashMap<String, Vector<Glyph, 1>> m_codepointsToIndicesMap;
233     Vector<char> m_result;
234     Vector<char, 17> m_emptyGlyphCharString;
235     FloatRect m_boundingBox;
236     const SVGFontElement& m_fontElement;
237     const SVGFontFaceElement* m_fontFaceElement;
238     const SVGMissingGlyphElement* m_missingGlyphElement;
239     String m_fontFamily;
240     float m_advanceWidthMax;
241     float m_advanceHeightMax;
242     float m_minRightSideBearing;
243     unsigned m_unitsPerEm;
244     unsigned m_featureCountGSUB;
245     int m_tablesAppendedCount;
246     char m_weight;
247     bool m_italic;
248 };
249
250 static uint16_t roundDownToPowerOfTwo(uint16_t x)
251 {
252     x |= x >> 1;
253     x |= x >> 2;
254     x |= x >> 4;
255     x |= x >> 8;
256     return (x >> 1) + 1;
257 }
258
259 static uint16_t integralLog2(uint16_t x)
260 {
261     uint16_t result = 0;
262     while (x >>= 1)
263         ++result;
264     return result;
265 }
266
267 void SVGToOTFFontConverter::appendCMAPTable()
268 {
269     auto startingOffset = m_result.size();
270     append16(0);
271     append16(1); // Number subtables
272
273     append16(0); // Unicode
274     append16(3); // Unicode version 2.2+
275     append32(m_result.size() - startingOffset + sizeof(uint32_t)); // Byte offset of subtable
276
277     // Braindead scheme: One segment for each character
278     ASSERT(m_glyphs.size() < 0xFFFF);
279     auto subtableLocation = m_result.size();
280     append32(12 << 16); // Format 12
281     append32(0); // Placeholder for byte length
282     append32(0); // Language independent
283     append32(0); // Placeholder for nGroups
284
285     uint16_t nGroups = 0;
286     UChar32 previousCodepoint = std::numeric_limits<UChar32>::max();
287     for (size_t i = 0; i < m_glyphs.size(); ++i) {
288         auto& glyph = m_glyphs[i];
289         UChar32 codepoint;
290         auto codePoints = StringView(glyph.codepoints).codePoints();
291         auto iterator = codePoints.begin();
292         if (iterator == codePoints.end())
293             codepoint = 0;
294         else {
295             codepoint = *iterator;
296             ++iterator;
297             // Don't map ligatures here.
298             if (iterator != codePoints.end() || codepoint == previousCodepoint)
299                 continue;
300         }
301
302         append32(codepoint); // startCharCode
303         append32(codepoint); // endCharCode
304         append32(i); // startGlyphCode
305         ++nGroups;
306         previousCodepoint = codepoint;
307     }
308     overwrite32(subtableLocation + 4, m_result.size() - subtableLocation);
309     overwrite32(subtableLocation + 12, nGroups);
310 }
311
312 void SVGToOTFFontConverter::appendHEADTable()
313 {
314     append32(0x00010000); // Version
315     append32(0x00010000); // Revision
316     append32(0); // Checksum placeholder; to be overwritten by the caller.
317     append32(0x5F0F3CF5); // Magic number.
318     append16((1 << 9) | 1);
319
320     append16(m_unitsPerEm);
321     append32(0); // First half of creation date
322     append32(0); // Last half of creation date
323     append32(0); // First half of modification date
324     append32(0); // Last half of modification date
325     append16(clampTo<int16_t>(m_boundingBox.x()));
326     append16(clampTo<int16_t>(m_boundingBox.y()));
327     append16(clampTo<int16_t>(m_boundingBox.maxX()));
328     append16(clampTo<int16_t>(m_boundingBox.maxY()));
329     append16((m_italic ? 1 << 1 : 0) | (m_weight >= 7 ? 1 : 0));
330     append16(3); // Smallest readable size in pixels
331     append16(0); // Might contain LTR or RTL glyphs
332     append16(0); // Short offsets in the 'loca' table. However, OTF fonts don't have a 'loca' table so this is irrelevant
333     append16(0); // Glyph data format
334 }
335
336 // Assumption: T2 can hold every value that a T1 can hold.
337 template<typename T1, typename T2> static inline T1 clampTo(T2 x)
338 {
339     x = std::min(x, static_cast<T2>(std::numeric_limits<T1>::max()));
340     x = std::max(x, static_cast<T2>(std::numeric_limits<T1>::min()));
341     return static_cast<T1>(x);
342 }
343
344 void SVGToOTFFontConverter::appendHHEATable()
345 {
346     int16_t ascent;
347     int16_t descent;
348     if (!m_fontFaceElement) {
349         ascent = m_unitsPerEm;
350         descent = 1;
351     } else {
352         ascent = m_fontFaceElement->ascent();
353         descent = m_fontFaceElement->descent();
354
355         // Some platforms, including OS X, use 0 ascent and descent to mean that the platform should synthesize
356         // a value based on a heuristic. However, SVG fonts can legitimately have 0 for ascent or descent.
357         // Specifing a single FUnit gets us as close to 0 as we can without triggering the synthesis.
358         if (!ascent)
359             ascent = 1;
360         if (!descent)
361             descent = 1;
362     }
363
364     append32(0x00010000); // Version
365     append16(ascent);
366     append16(descent);
367     // WebKit SVG font rendering has hard coded the line gap to be 1/10th of the font size since 2008 (see r29719).
368     append16(m_unitsPerEm / 10); // Line gap
369     append16(clampTo<uint16_t>(m_advanceWidthMax));
370     append16(clampTo<int16_t>(m_boundingBox.x())); // Minimum left side bearing
371     append16(clampTo<int16_t>(m_minRightSideBearing)); // Minimum right side bearing
372     append16(clampTo<int16_t>(m_boundingBox.maxX())); // X maximum extent
373     // Since WebKit draws the caret and ignores the following values, it doesn't matter what we set them to.
374     append16(1); // Vertical caret
375     append16(0); // Vertical caret
376     append16(0); // "Set value to 0 for non-slanted fonts"
377     append32(0); // Reserved
378     append32(0); // Reserved
379     append16(0); // Current format
380     append16(m_glyphs.size()); // Number of advance widths in HMTX table
381 }
382
383 void SVGToOTFFontConverter::appendHMTXTable()
384 {
385     for (auto& glyph : m_glyphs) {
386         append16(clampTo<uint16_t>(glyph.horizontalAdvance));
387         append16(clampTo<int16_t>(glyph.boundingBox.x()));
388     }
389 }
390
391 void SVGToOTFFontConverter::appendMAXPTable()
392 {
393     append32(0x00010000); // Version
394     append16(m_glyphs.size());
395     append16(0xFFFF); // Maximum number of points in non-compound glyph
396     append16(0xFFFF); // Maximum number of contours in non-compound glyph
397     append16(0xFFFF); // Maximum number of points in compound glyph
398     append16(0xFFFF); // Maximum number of contours in compound glyph
399     append16(2); // Maximum number of zones
400     append16(0); // Maximum number of points used in zone 0
401     append16(0); // Maximum number of storage area locations
402     append16(0); // Maximum number of function definitions
403     append16(0); // Maximum number of instruction definitions
404     append16(0); // Maximum stack depth
405     append16(0); // Maximum size of instructions
406     append16(m_glyphs.size()); // Maximum number of glyphs referenced at top level
407     append16(0); // No compound glyphs
408 }
409
410 void SVGToOTFFontConverter::appendNAMETable()
411 {
412     append16(0); // Format selector
413     append16(1); // Number of name records in table
414     append16(18); // Offset in bytes to the beginning of name character strings
415
416     append16(0); // Unicode
417     append16(3); // Unicode version 2.0 or later
418     append16(0); // Language
419     append16(1); // Name identifier. 1 = Font family
420     append16(m_fontFamily.length());
421     append16(0); // Offset into name data
422
423     for (auto codeUnit : StringView(m_fontFamily).codeUnits())
424         append16(codeUnit);
425 }
426
427 void SVGToOTFFontConverter::appendOS2Table()
428 {
429     int16_t averageAdvance = m_unitsPerEm;
430     bool ok;
431     int value = m_fontElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&ok);
432     if (!ok && m_missingGlyphElement)
433         value = m_missingGlyphElement->fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&ok);
434     if (ok)
435         averageAdvance = clampTo<int16_t>(value);
436
437     append16(0); // Version
438     append16(averageAdvance);
439     append16(m_weight); // Weight class
440     append16(5); // Width class
441     append16(0); // Protected font
442     // WebKit handles these superscripts and subscripts
443     append16(0); // Subscript X Size
444     append16(0); // Subscript Y Size
445     append16(0); // Subscript X Offset
446     append16(0); // Subscript Y Offset
447     append16(0); // Superscript X Size
448     append16(0); // Superscript Y Size
449     append16(0); // Superscript X Offset
450     append16(0); // Superscript Y Offset
451     append16(0); // Strikeout width
452     append16(0); // Strikeout Position
453     append16(0); // No classification
454
455     unsigned numPanoseBytes = 0;
456     const unsigned panoseSize = 10;
457     char panoseBytes[panoseSize];
458     if (m_fontFaceElement) {
459         Vector<String> segments;
460         m_fontFaceElement->fastGetAttribute(SVGNames::panose_1Attr).string().split(' ', segments);
461         if (segments.size() == panoseSize) {
462             for (auto& segment : segments) {
463                 bool ok;
464                 int value = segment.toInt(&ok);
465                 if (ok && value >= 0 && value <= 0xFF)
466                     panoseBytes[numPanoseBytes++] = value;
467             }
468         }
469     }
470     if (numPanoseBytes != panoseSize)
471         memset(panoseBytes, 0, panoseSize);
472     m_result.append(panoseBytes, panoseSize);
473
474     for (int i = 0; i < 4; ++i)
475         append32(0); // "Bit assignments are pending. Set to 0"
476     append32(0x544B4257); // Font Vendor. "WBKT"
477     append16((m_weight >= 7 ? 1 << 5 : 0) | (m_italic ? 1 : 0)); // Font Patterns.
478     append16(0); // First unicode index
479     append16(0xFFFF); // Last unicode index
480 }
481
482 void SVGToOTFFontConverter::appendPOSTTable()
483 {
484     append32(0x00030000); // Format. Printing is undefined
485     append32(0); // Italic angle in degrees
486     append16(0); // Underline position
487     append16(0); // Underline thickness
488     append32(0); // Monospaced
489     append32(0); // "Minimum memory usage when a TrueType font is downloaded as a Type 42 font"
490     append32(0); // "Maximum memory usage when a TrueType font is downloaded as a Type 42 font"
491     append32(0); // "Minimum memory usage when a TrueType font is downloaded as a Type 1 font"
492     append32(0); // "Maximum memory usage when a TrueType font is downloaded as a Type 1 font"
493 }
494
495 static bool isValidStringForCFF(const String& string)
496 {
497     for (auto c : StringView(string).codeUnits()) {
498         if (c < 33 || c > 126)
499             return false;
500     }
501     return true;
502 }
503
504 void SVGToOTFFontConverter::appendValidCFFString(const String& string)
505 {
506     ASSERT(isValidStringForCFF(string));
507     for (auto c : StringView(string).codeUnits())
508         m_result.append(c);
509 }
510
511 void SVGToOTFFontConverter::appendCFFTable()
512 {
513     auto startingOffset = m_result.size();
514
515     // Header
516     m_result.append(1); // Major version
517     m_result.append(0); // Minor version
518     m_result.append(4); // Header size
519     m_result.append(4); // Offsets within CFF table are 4 bytes long
520
521     // Name INDEX
522     String fontName;
523     if (m_fontFaceElement) {
524         // FIXME: fontFamily() here might not be quite what we want.
525         String potentialFontName = m_fontFamily;
526         if (isValidStringForCFF(potentialFontName))
527             fontName = potentialFontName;
528     }
529     append16(1); // INDEX contains 1 element
530     m_result.append(4); // Offsets in this INDEX are 4 bytes long
531     append32(1); // 1-index offset of name data
532     append32(fontName.length() + 1); // 1-index offset just past end of name data
533     appendValidCFFString(fontName);
534
535     String weight;
536     if (m_fontFaceElement) {
537         auto& potentialWeight = m_fontFaceElement->fastGetAttribute(SVGNames::font_weightAttr);
538         if (isValidStringForCFF(potentialWeight))
539             weight = potentialWeight;
540     }
541
542     bool hasWeight = !weight.isNull();
543
544     const char operand32Bit = 29;
545     const char fullNameKey = 2;
546     const char familyNameKey = 3;
547     const char weightKey = 4;
548     const char fontBBoxKey = 5;
549     const char charsetIndexKey = 15;
550     const char charstringsIndexKey = 17;
551     const uint32_t userDefinedStringStartIndex = 391;
552     const unsigned sizeOfTopIndex = 45 + (hasWeight ? 6 : 0);
553
554     // Top DICT INDEX.
555     append16(1); // INDEX contains 1 element
556     m_result.append(4); // Offsets in this INDEX are 4 bytes long
557     append32(1); // 1-index offset of DICT data
558     append32(1 + sizeOfTopIndex); // 1-index offset just past end of DICT data
559
560     // DICT information
561 #if !ASSERT_DISABLED
562     unsigned topDictStart = m_result.size();
563 #endif
564     m_result.append(operand32Bit);
565     append32(userDefinedStringStartIndex);
566     m_result.append(fullNameKey);
567     m_result.append(operand32Bit);
568     append32(userDefinedStringStartIndex);
569     m_result.append(familyNameKey);
570     if (hasWeight) {
571         m_result.append(operand32Bit);
572         append32(userDefinedStringStartIndex + 1);
573         m_result.append(weightKey);
574     }
575     m_result.append(operand32Bit);
576     append32(clampTo<int32_t>(m_boundingBox.x()));
577     m_result.append(operand32Bit);
578     append32(clampTo<int32_t>(m_boundingBox.y()));
579     m_result.append(operand32Bit);
580     append32(clampTo<int32_t>(m_boundingBox.width()));
581     m_result.append(operand32Bit);
582     append32(clampTo<int32_t>(m_boundingBox.height()));
583     m_result.append(fontBBoxKey);
584     m_result.append(operand32Bit);
585     unsigned charsetOffsetLocation = m_result.size();
586     append32(0); // Offset of Charset info. Will be overwritten later.
587     m_result.append(charsetIndexKey);
588     m_result.append(operand32Bit);
589     unsigned charstringsOffsetLocation = m_result.size();
590     append32(0); // Offset of CharStrings INDEX. Will be overwritten later.
591     m_result.append(charstringsIndexKey);
592     ASSERT(m_result.size() == topDictStart + sizeOfTopIndex);
593
594     // String INDEX
595     append16(1 + (hasWeight ? 1 : 0)); // Number of elements in INDEX
596     m_result.append(4); // Offsets in this INDEX are 4 bytes long
597     uint32_t offset = 1;
598     append32(offset);
599     offset += fontName.length();
600     append32(offset);
601     if (hasWeight) {
602         offset += weight.length();
603         append32(offset);
604     }
605     appendValidCFFString(fontName);
606     appendValidCFFString(weight);
607
608     append16(0); // Empty subroutine INDEX
609
610     // Charset info
611     overwrite32(charsetOffsetLocation, m_result.size() - startingOffset);
612     m_result.append(0);
613     for (Glyph i = 1; i < m_glyphs.size(); ++i)
614         append16(i);
615
616     // CharStrings INDEX
617     overwrite32(charstringsOffsetLocation, m_result.size() - startingOffset);
618     append16(m_glyphs.size());
619     m_result.append(4); // Offsets in this INDEX are 4 bytes long
620     offset = 1;
621     append32(offset);
622     for (auto& glyph : m_glyphs) {
623         offset += glyph.charString.size();
624         append32(offset);
625     }
626     for (auto& glyph : m_glyphs)
627         m_result.appendVector(glyph.charString);
628 }
629
630 Glyph SVGToOTFFontConverter::firstGlyph(const Vector<Glyph, 1>& v, UChar32 codepoint) const
631 {
632 #if ASSERT_DISABLED
633     UNUSED_PARAM(codepoint);
634 #endif
635     ASSERT(!v.isEmpty());
636     if (v.isEmpty())
637         return 0;
638 #if !ASSERT_DISABLED
639     auto codePoints = StringView(m_glyphs[v[0]].codepoints).codePoints();
640     auto codePointsIterator = codePoints.begin();
641     ASSERT(codePointsIterator != codePoints.end());
642     ASSERT(codepoint = *codePointsIterator);
643 #endif
644     return v[0];
645 }
646
647 void SVGToOTFFontConverter::appendLigatureSubtable(size_t subtableRecordLocation)
648 {
649     typedef std::pair<Vector<Glyph, 3>, Glyph> LigaturePair;
650     Vector<LigaturePair> ligaturePairs;
651     for (Glyph glyphIndex = 0; glyphIndex < m_glyphs.size(); ++glyphIndex) {
652         ligaturePairs.append(LigaturePair(Vector<Glyph, 3>(), glyphIndex));
653         Vector<Glyph, 3>& ligatureGlyphs = ligaturePairs.last().first;
654         auto codePoints = StringView(m_glyphs[glyphIndex].codepoints).codePoints();
655         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=138592 This needs to be done in codepoint space, not glyph space
656         for (auto codePoint : codePoints)
657             ligatureGlyphs.append(firstGlyph(glyphsForCodepoint(codePoint), codePoint));
658         if (ligatureGlyphs.size() < 2)
659             ligaturePairs.removeLast();
660     }
661     if (ligaturePairs.size() > std::numeric_limits<uint16_t>::max())
662         ligaturePairs.clear();
663     std::sort(ligaturePairs.begin(), ligaturePairs.end(), [](LigaturePair& lhs, LigaturePair& rhs) {
664         return lhs.first[0] < rhs.first[0];
665     });
666     Vector<size_t> overlappingFirstGlyphSegmentLengths;
667     if (!ligaturePairs.isEmpty()) {
668         Glyph previousFirstGlyph = ligaturePairs[0].first[0];
669         size_t segmentStart = 0;
670         for (size_t i = 0; i < ligaturePairs.size(); ++i) {
671             auto& ligaturePair = ligaturePairs[i];
672             if (ligaturePair.first[0] != previousFirstGlyph) {
673                 overlappingFirstGlyphSegmentLengths.append(i - segmentStart);
674                 segmentStart = i;
675                 previousFirstGlyph = ligaturePairs[0].first[0];
676             }
677         }
678         overlappingFirstGlyphSegmentLengths.append(ligaturePairs.size() - segmentStart);
679     }
680
681     overwrite16(subtableRecordLocation + 6, m_result.size() - subtableRecordLocation);
682     auto subtableLocation = m_result.size();
683     append16(1); // Format 1
684     append16(0); // Placeholder for offset to coverage table, relative to beginning of substitution table
685     append16(ligaturePairs.size()); // Number of LigatureSet tables
686     grow(overlappingFirstGlyphSegmentLengths.size() * 2); // Placeholder for offset to LigatureSet table
687
688     Vector<size_t> ligatureSetTableLocations;
689     for (size_t i = 0; i < overlappingFirstGlyphSegmentLengths.size(); ++i) {
690         overwrite16(subtableLocation + 6 + 2 * i, m_result.size() - subtableLocation);
691         ligatureSetTableLocations.append(m_result.size());
692         append16(overlappingFirstGlyphSegmentLengths[i]); // LigatureCount
693         grow(overlappingFirstGlyphSegmentLengths[i] * 2); // Placeholder for offset to Ligature table
694     }
695     ASSERT(ligatureSetTableLocations.size() == overlappingFirstGlyphSegmentLengths.size());
696
697     size_t ligaturePairIndex = 0;
698     for (size_t i = 0; i < overlappingFirstGlyphSegmentLengths.size(); ++i) {
699         for (size_t j = 0; j < overlappingFirstGlyphSegmentLengths[i]; ++j) {
700             overwrite16(ligatureSetTableLocations[i] + 2 + 2 * j, m_result.size() - ligatureSetTableLocations[i]);
701             auto& ligaturePair = ligaturePairs[ligaturePairIndex];
702             append16(ligaturePair.second);
703             append16(ligaturePair.first.size());
704             for (size_t k = 1; k < ligaturePair.first.size(); ++k)
705                 append16(ligaturePair.first[k]);
706             ++ligaturePairIndex;
707         }
708     }
709     ASSERT(ligaturePairIndex == ligaturePairs.size());
710
711     // Coverage table
712     overwrite16(subtableLocation + 2, m_result.size() - subtableLocation);
713     append16(1); // CoverageFormat
714     append16(ligatureSetTableLocations.size()); // GlyphCount
715     ligaturePairIndex = 0;
716     for (auto segmentLength : overlappingFirstGlyphSegmentLengths) {
717         auto& ligaturePair = ligaturePairs[ligaturePairIndex];
718         ASSERT(ligaturePair.first.size() > 1);
719         append16(ligaturePair.first[0]);
720         ligaturePairIndex += segmentLength;
721     }
722 }
723
724 void SVGToOTFFontConverter::appendArabicReplacementSubtable(size_t subtableRecordLocation, const char arabicForm[])
725 {
726     Vector<std::pair<Glyph, Glyph>> arabicFinalReplacements;
727     for (auto& pair : m_codepointsToIndicesMap) {
728         for (auto glyphIndex : pair.value) {
729             auto& glyph = m_glyphs[glyphIndex];
730             if (glyph.glyphElement && equalIgnoringCase(glyph.glyphElement->fastGetAttribute(SVGNames::arabic_formAttr), arabicForm))
731                 arabicFinalReplacements.append(std::make_pair(pair.value[0], glyphIndex));
732         }
733     }
734     if (arabicFinalReplacements.size() > std::numeric_limits<uint16_t>::max())
735         arabicFinalReplacements.clear();
736
737     overwrite16(subtableRecordLocation + 6, m_result.size() - subtableRecordLocation);
738     auto subtableLocation = m_result.size();
739     append16(2); // Format 2
740     Placeholder toCoverageTable = placeholder(subtableLocation);
741     append16(arabicFinalReplacements.size()); // GlyphCount
742     for (auto& pair : arabicFinalReplacements)
743         append16(pair.second);
744
745     toCoverageTable.populate();
746     append16(1); // CoverageFormat
747     append16(arabicFinalReplacements.size()); // GlyphCount
748     for (auto& pair : arabicFinalReplacements)
749         append16(pair.first);
750 }
751
752 void SVGToOTFFontConverter::appendScriptSubtable(unsigned featureCount)
753 {
754     auto dfltScriptTableLocation = m_result.size();
755     append16(0); // Placeholder for offset of default language system table, relative to beginning of Script table
756     append16(0); // Number of following language system tables
757
758     // LangSys table
759     overwrite16(dfltScriptTableLocation, m_result.size() - dfltScriptTableLocation);
760     append16(0); // LookupOrder "= NULL ... reserved"
761     append16(0xFFFF); // No features are required
762     append16(featureCount); // Number of FeatureIndex values
763     for (uint16_t i = 0; i < featureCount; ++i)
764         append16(m_featureCountGSUB++); // Features indices
765 }
766
767 void SVGToOTFFontConverter::appendGSUBTable()
768 {
769     auto tableLocation = m_result.size();
770     auto headerSize = 10;
771
772     append32(0x00010000); // Version
773     append16(headerSize); // Offset to ScriptList
774     Placeholder toFeatureList = placeholder(tableLocation);
775     Placeholder toLookupList = placeholder(tableLocation);
776     ASSERT(tableLocation + headerSize == m_result.size());
777
778     // ScriptList
779     auto scriptListLocation = m_result.size();
780     append16(2); // Number of ScriptRecords
781     append32BitCode("DFLT");
782     append16(0); // Placeholder for offset of Script table, relative to beginning of ScriptList
783     append32BitCode("arab");
784     append16(0); // Placeholder for offset of Script table, relative to beginning of ScriptList
785
786     overwrite16(scriptListLocation + 6, m_result.size() - scriptListLocation);
787     appendScriptSubtable(1);
788     overwrite16(scriptListLocation + 12, m_result.size() - scriptListLocation);
789     appendScriptSubtable(4);
790
791     unsigned featureCount = 5;
792
793     // FeatureList
794     toFeatureList.populate();
795     auto featureListLocation = m_result.size();
796     size_t featureListSize = 2 + 6 * featureCount;
797     size_t featureTableSize = 6;
798     append16(featureCount); // FeatureCount
799     append32BitCode("liga");
800     append16(featureListSize + featureTableSize * 0); // Offset of feature table, relative to beginning of FeatureList table
801     append32BitCode("fina");
802     append16(featureListSize + featureTableSize * 1); // Offset of feature table, relative to beginning of FeatureList table
803     append32BitCode("medi");
804     append16(featureListSize + featureTableSize * 2); // Offset of feature table, relative to beginning of FeatureList table
805     append32BitCode("init");
806     append16(featureListSize + featureTableSize * 3); // Offset of feature table, relative to beginning of FeatureList table
807     append32BitCode("rlig");
808     append16(featureListSize + featureTableSize * 4); // Offset of feature table, relative to beginning of FeatureList table
809     ASSERT_UNUSED(featureListLocation, featureListLocation + featureListSize == m_result.size());
810
811     for (unsigned i = 0; i < featureCount; ++i) {
812         auto featureTableStart = m_result.size();
813         append16(0); // FeatureParams "= NULL ... reserved"
814         append16(1); // LookupCount
815         append16(i); // LookupListIndex
816         ASSERT_UNUSED(featureTableStart, featureTableStart + featureTableSize == m_result.size());
817     }
818
819     // LookupList
820     toLookupList.populate();
821     auto lookupListLocation = m_result.size();
822     append16(featureCount); // LookupCount
823     for (unsigned i = 0; i < featureCount; ++i)
824         append16(0); // Placeholder for offset to feature table, relative to beginning of LookupList
825     size_t subtableRecordLocations[featureCount];
826     for (unsigned i = 0; i < featureCount; ++i) {
827         subtableRecordLocations[i] = m_result.size();
828         overwrite16(lookupListLocation + 2 + 2 * i, m_result.size() - lookupListLocation);
829         switch (i) {
830         case 4:
831             append16(3); // Type 3: "Replace one glyph with one of many glyphs"
832             break;
833         case 0:
834             append16(4); // Type 4: "Replace multiple glyphs with one glyph"
835             break;
836         default:
837             append16(1); // Type 1: "Replace one glyph with one glyph"
838             break;
839         }
840         append16(0); // LookupFlag
841         append16(1); // SubTableCount
842         append16(0); // Placeholder for offset to subtable, relative to beginning of Lookup table
843     }
844
845     appendLigatureSubtable(subtableRecordLocations[0]);
846     appendArabicReplacementSubtable(subtableRecordLocations[1], "terminal");
847     appendArabicReplacementSubtable(subtableRecordLocations[2], "medial");
848     appendArabicReplacementSubtable(subtableRecordLocations[3], "initial");
849
850     // Manually append empty "rlig" subtable
851     overwrite16(subtableRecordLocations[4] + 6, m_result.size() - subtableRecordLocations[4]);
852     append16(1); // Format 1
853     append16(6); // offset to coverage table, relative to beginning of substitution table
854     append16(0); // AlternateSetCount
855     append16(1); // CoverageFormat
856     append16(0); // GlyphCount
857 }
858
859 void SVGToOTFFontConverter::appendVORGTable()
860 {
861     append16(1); // Major version
862     append16(0); // Minor version
863
864     bool ok;
865     int16_t defaultVerticalOriginY = clampTo<int16_t>(m_fontElement.fastGetAttribute(SVGNames::vert_origin_yAttr).toInt(&ok));
866     if (!ok && m_missingGlyphElement)
867         defaultVerticalOriginY = clampTo<int16_t>(m_missingGlyphElement->fastGetAttribute(SVGNames::vert_origin_yAttr).toInt());
868     append16(defaultVerticalOriginY);
869
870     auto tableSizeOffset = m_result.size();
871     append16(0); // Place to write table size.
872     for (Glyph i = 0; i < m_glyphs.size(); ++i) {
873         if (auto* glyph = m_glyphs[i].glyphElement) {
874             if (int16_t verticalOriginY = clampTo<int16_t>(glyph->fastGetAttribute(SVGNames::vert_origin_yAttr).toInt())) {
875                 append16(i);
876                 append16(verticalOriginY);
877             }
878         }
879     }
880     ASSERT(!((m_result.size() - tableSizeOffset - 2) % 4));
881     overwrite16(tableSizeOffset, (m_result.size() - tableSizeOffset - 2) / 4);
882 }
883
884 void SVGToOTFFontConverter::appendVHEATable()
885 {
886     append32(0x00011000); // Version
887     append16(m_unitsPerEm / 2); // Vertical typographic ascender (vertical baseline to the right)
888     append16(clampTo<int16_t>(-static_cast<int>(m_unitsPerEm / 2))); // Vertical typographic descender
889     append16(m_unitsPerEm / 10); // Vertical typographic line gap
890     // FIXME: m_unitsPerEm is almost certainly not correct
891     append16(clampTo<int16_t>(m_advanceHeightMax));
892     append16(clampTo<int16_t>(m_unitsPerEm - m_boundingBox.maxY())); // Minimum top side bearing
893     append16(clampTo<int16_t>(m_boundingBox.y())); // Minimum bottom side bearing
894     append16(clampTo<int16_t>(m_unitsPerEm - m_boundingBox.y())); // Y maximum extent
895     // Since WebKit draws the caret and ignores the following values, it doesn't matter what we set them to.
896     append16(1); // Vertical caret
897     append16(0); // Vertical caret
898     append16(0); // "Set value to 0 for non-slanted fonts"
899     append32(0); // Reserved
900     append32(0); // Reserved
901     append16(0); // "Set to 0"
902     append16(m_glyphs.size()); // Number of advance heights in VMTX table
903 }
904
905 void SVGToOTFFontConverter::appendVMTXTable()
906 {
907     for (auto& glyph : m_glyphs) {
908         append16(clampTo<uint16_t>(glyph.verticalAdvance));
909         append16(clampTo<int16_t>(m_unitsPerEm - glyph.boundingBox.maxY())); // top side bearing
910     }
911 }
912
913 static String codepointToString(UChar32 codepoint)
914 {
915     UChar buffer[2];
916     uint8_t length = 0;
917     UBool error = false;
918     U16_APPEND(buffer, length, 2, codepoint, error);
919     return error ? String() : String(buffer, length);
920 }
921
922 Vector<Glyph, 1> SVGToOTFFontConverter::glyphsForCodepoint(UChar32 codepoint) const
923 {
924     return m_codepointsToIndicesMap.get(codepointToString(codepoint));
925 }
926
927 void SVGToOTFFontConverter::addCodepointRanges(const UnicodeRanges& unicodeRanges, HashSet<Glyph>& glyphSet) const
928 {
929     for (auto& unicodeRange : unicodeRanges) {
930         for (auto codepoint = unicodeRange.first; codepoint <= unicodeRange.second; ++codepoint) {
931             for (auto index : glyphsForCodepoint(codepoint))
932                 glyphSet.add(index);
933         }
934     }
935 }
936
937 void SVGToOTFFontConverter::addCodepoints(const HashSet<String>& codepoints, HashSet<Glyph>& glyphSet) const
938 {
939     for (auto& codepointString : codepoints) {
940         for (auto index : m_codepointsToIndicesMap.get(codepointString))
941             glyphSet.add(index);
942     }
943 }
944
945 void SVGToOTFFontConverter::addGlyphNames(const HashSet<String>& glyphNames, HashSet<Glyph>& glyphSet) const
946 {
947     for (auto& glyphName : glyphNames) {
948         if (Glyph glyph = m_glyphNameToIndexMap.get(glyphName))
949             glyphSet.add(glyph);
950     }
951 }
952
953 void SVGToOTFFontConverter::addKerningPair(Vector<KerningData>& data, const SVGKerningPair& kerningPair) const
954 {
955     HashSet<Glyph> glyphSet1;
956     HashSet<Glyph> glyphSet2;
957
958     addCodepointRanges(kerningPair.unicodeRange1, glyphSet1);
959     addCodepointRanges(kerningPair.unicodeRange2, glyphSet2);
960     addGlyphNames(kerningPair.glyphName1, glyphSet1);
961     addGlyphNames(kerningPair.glyphName2, glyphSet2);
962     addCodepoints(kerningPair.unicodeName1, glyphSet1);
963     addCodepoints(kerningPair.unicodeName2, glyphSet2);
964
965     // FIXME: Use table format 2 so we don't have to append each of these one by one.
966     for (auto& glyph1 : glyphSet1) {
967         for (auto& glyph2 : glyphSet2)
968             data.append(KerningData(glyph1, glyph2, clampTo<int16_t>(-kerningPair.kerning)));
969     }
970 }
971
972 template<typename T> inline size_t SVGToOTFFontConverter::appendKERNSubtable(bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage)
973 {
974     Vector<KerningData> kerningData;
975     for (auto& element : childrenOfType<T>(m_fontElement)) {
976         SVGKerningPair kerningPair;
977         if ((element.*buildKerningPair)(kerningPair))
978             addKerningPair(kerningData, kerningPair);
979     }
980     return finishAppendingKERNSubtable(WTF::move(kerningData), coverage);
981 }
982
983 size_t SVGToOTFFontConverter::finishAppendingKERNSubtable(Vector<KerningData> kerningData, uint16_t coverage)
984 {
985     std::sort(kerningData.begin(), kerningData.end(), [](const KerningData& a, const KerningData& b) {
986         return a.glyph1 < b.glyph1 || (a.glyph1 == b.glyph1 && a.glyph2 < b.glyph2);
987     });
988
989     size_t sizeOfKerningDataTable = 14 + 6 * kerningData.size();
990     if (sizeOfKerningDataTable > std::numeric_limits<uint16_t>::max()) {
991         kerningData.clear();
992         sizeOfKerningDataTable = 14;
993     }
994
995     append16(0); // Version of subtable
996     append16(sizeOfKerningDataTable); // Length of this subtable
997     append16(coverage); // Table coverage bitfield
998
999     uint16_t roundedNumKerningPairs = roundDownToPowerOfTwo(kerningData.size());
1000
1001     append16(kerningData.size());
1002     append16(roundedNumKerningPairs * 6); // searchRange: "The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the table."
1003     append16(integralLog2(roundedNumKerningPairs)); // entrySelector: "log2 of the largest power of two less than or equal to the value of nPairs."
1004     append16((kerningData.size() - roundedNumKerningPairs) * 6); // rangeShift: "The value of nPairs minus the largest power of two less than or equal to nPairs,
1005                                                                         // and then multiplied by the size in bytes of an entry in the table."
1006
1007     for (auto& kerningData : kerningData) {
1008         append16(kerningData.glyph1);
1009         append16(kerningData.glyph2);
1010         append16(kerningData.adjustment);
1011     }
1012
1013     return sizeOfKerningDataTable;
1014 }
1015
1016 void SVGToOTFFontConverter::appendKERNTable()
1017 {
1018     append16(0); // Version
1019     append16(2); // Number of subtables
1020
1021 #if !ASSERT_DISABLED
1022     auto subtablesOffset = m_result.size();
1023 #endif
1024
1025     size_t sizeOfHorizontalSubtable = appendKERNSubtable<SVGHKernElement>(&SVGHKernElement::buildHorizontalKerningPair, 1);
1026     ASSERT_UNUSED(sizeOfHorizontalSubtable, subtablesOffset + sizeOfHorizontalSubtable == m_result.size());
1027     size_t sizeOfVerticalSubtable = appendKERNSubtable<SVGVKernElement>(&SVGVKernElement::buildVerticalKerningPair, 0);
1028     ASSERT_UNUSED(sizeOfVerticalSubtable, subtablesOffset + sizeOfHorizontalSubtable + sizeOfVerticalSubtable == m_result.size());
1029
1030     // Work around a bug in Apple's font parser by adding some padding bytes. <rdar://problem/18401901>
1031     for (int i = 0; i < 6; ++i)
1032         m_result.append(0);
1033 }
1034
1035 template <typename V>
1036 static void writeCFFEncodedNumber(V& vector, float number)
1037 {
1038     vector.append(0xFF);
1039     append32(vector, number * 0x10000);
1040 }
1041
1042 static const char rLineTo = 0x05;
1043 static const char rrCurveTo = 0x08;
1044 static const char endChar = 0x0e;
1045 static const char rMoveTo = 0x15;
1046
1047 class CFFBuilder : public SVGPathBuilder {
1048 public:
1049     CFFBuilder(Vector<char>& cffData, float width, FloatPoint origin)
1050         : m_cffData(cffData)
1051         , m_hasBoundingBox(false)
1052     {
1053         // FIXME: Moving to the origin isn't going to work for subsequent absolute coordinates
1054         writeCFFEncodedNumber(m_cffData, width);
1055         writeCFFEncodedNumber(m_cffData, origin.x());
1056         writeCFFEncodedNumber(m_cffData, origin.y());
1057         m_cffData.append(rMoveTo);
1058     }
1059
1060     FloatRect boundingBox() const
1061     {
1062         return m_boundingBox;
1063     }
1064
1065 private:
1066     void updateBoundingBox(FloatPoint point)
1067     {
1068         if (!m_hasBoundingBox) {
1069             m_boundingBox = FloatRect(point, FloatSize());
1070             m_hasBoundingBox = true;
1071             return;
1072         }
1073         m_boundingBox.extend(point);
1074     }
1075
1076     void writePoint(FloatPoint destination)
1077     {
1078         updateBoundingBox(destination);
1079
1080         FloatSize delta = destination - m_current;
1081         writeCFFEncodedNumber(m_cffData, delta.width());
1082         writeCFFEncodedNumber(m_cffData, delta.height());
1083
1084         m_current = destination;
1085     }
1086
1087     virtual void moveTo(const FloatPoint& targetPoint, bool closed, PathCoordinateMode mode) override
1088     {
1089         if (closed && !m_cffData.isEmpty())
1090             closePath();
1091
1092         FloatPoint destination = mode == AbsoluteCoordinates ? targetPoint : m_current + targetPoint;
1093
1094         writePoint(destination);
1095         m_cffData.append(rMoveTo);
1096
1097         m_startingPoint = m_current;
1098     }
1099
1100     virtual void lineTo(const FloatPoint& targetPoint, PathCoordinateMode mode) override
1101     {
1102         FloatPoint destination = mode == AbsoluteCoordinates ? targetPoint : m_current + targetPoint;
1103
1104         writePoint(destination);
1105         m_cffData.append(rLineTo);
1106     }
1107
1108     virtual void curveToCubic(const FloatPoint& point1, const FloatPoint& point2, const FloatPoint& targetPoint, PathCoordinateMode mode) override
1109     {
1110         FloatPoint destination1 = point1;
1111         FloatPoint destination2 = point2;
1112         FloatPoint destination3 = targetPoint;
1113         if (mode == RelativeCoordinates) {
1114             destination1 += m_current;
1115             destination2 += m_current;
1116             destination3 += m_current;
1117         }
1118
1119         writePoint(destination1);
1120         writePoint(destination2);
1121         writePoint(destination3);
1122         m_cffData.append(rrCurveTo);
1123     }
1124
1125     virtual void closePath() override
1126     {
1127         if (m_current != m_startingPoint)
1128             lineTo(m_startingPoint, AbsoluteCoordinates);
1129     }
1130
1131     Vector<char>& m_cffData;
1132     FloatPoint m_startingPoint;
1133     FloatRect m_boundingBox;
1134     bool m_hasBoundingBox;
1135 };
1136
1137 Vector<char> SVGToOTFFontConverter::transcodeGlyphPaths(float width, const SVGElement& glyphOrMissingGlyphElement, FloatRect& boundingBox) const
1138 {
1139     Vector<char> result;
1140
1141     auto& dAttribute = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::dAttr);
1142     if (dAttribute.isEmpty()) {
1143         writeCFFEncodedNumber(result, width);
1144         writeCFFEncodedNumber(result, 0);
1145         writeCFFEncodedNumber(result, 0);
1146         result.append(rMoveTo);
1147         result.append(endChar);
1148         return result;
1149     }
1150
1151     // FIXME: If we are vertical, use vert_origin_x and vert_origin_y
1152     bool ok;
1153     float horizontalOriginX = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_xAttr).toFloat(&ok);
1154     if (!ok && m_fontFaceElement)
1155         horizontalOriginX = m_fontFaceElement->horizontalOriginX();
1156     float horizontalOriginY = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_yAttr).toFloat(&ok);
1157     if (!ok && m_fontFaceElement)
1158         horizontalOriginY = m_fontFaceElement->horizontalOriginY();
1159
1160     CFFBuilder builder(result, width, FloatPoint(horizontalOriginX, horizontalOriginY));
1161     SVGPathStringSource source(dAttribute);
1162
1163     SVGPathParser parser;
1164     parser.setCurrentSource(&source);
1165     parser.setCurrentConsumer(&builder);
1166
1167     ok = parser.parsePathDataFromSource(NormalizedParsing);
1168     parser.cleanup();
1169
1170     if (!ok)
1171         result.clear();
1172
1173     boundingBox = builder.boundingBox();
1174
1175     result.append(endChar);
1176     return result;
1177 }
1178
1179 void SVGToOTFFontConverter::processGlyphElement(const SVGElement& glyphOrMissingGlyphElement, const SVGGlyphElement* glyphElement, float defaultHorizontalAdvance, float defaultVerticalAdvance, const String& codepoints, bool& initialGlyph)
1180 {
1181     bool ok;
1182     float horizontalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toFloat(&ok);
1183     if (!ok)
1184         horizontalAdvance = defaultHorizontalAdvance;
1185     m_advanceWidthMax = std::max(m_advanceWidthMax, horizontalAdvance);
1186     float verticalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::vert_adv_yAttr).toFloat(&ok);
1187     if (!ok)
1188         verticalAdvance = defaultVerticalAdvance;
1189     m_advanceHeightMax = std::max(m_advanceHeightMax, verticalAdvance);
1190
1191     FloatRect glyphBoundingBox;
1192     auto path = transcodeGlyphPaths(horizontalAdvance, glyphOrMissingGlyphElement, glyphBoundingBox);
1193     if (initialGlyph)
1194         m_boundingBox = glyphBoundingBox;
1195     else
1196         m_boundingBox.unite(glyphBoundingBox);
1197     m_minRightSideBearing = std::min(m_minRightSideBearing, horizontalAdvance - glyphBoundingBox.maxX());
1198     initialGlyph = false;
1199
1200     m_glyphs.append(GlyphData(WTF::move(path), glyphElement, horizontalAdvance, verticalAdvance, glyphBoundingBox, codepoints));
1201 }
1202
1203 void SVGToOTFFontConverter::appendLigatureGlyphs()
1204 {
1205     HashSet<UChar32> ligatureCodepoints;
1206     HashSet<UChar32> nonLigatureCodepoints;
1207     for (auto& glyph : m_glyphs) {
1208         auto codePoints = StringView(glyph.codepoints).codePoints();
1209         auto codePointsIterator = codePoints.begin();
1210         if (codePointsIterator == codePoints.end())
1211             continue;
1212         UChar32 codepoint = *codePointsIterator;
1213         ++codePointsIterator;
1214         if (codePointsIterator == codePoints.end())
1215             nonLigatureCodepoints.add(codepoint);
1216         else {
1217             ligatureCodepoints.add(codepoint);
1218             for (; codePointsIterator != codePoints.end(); ++codePointsIterator)
1219                 ligatureCodepoints.add(*codePointsIterator);
1220         }
1221     }
1222
1223     for (auto codepoint : nonLigatureCodepoints)
1224         ligatureCodepoints.remove(codepoint);
1225     for (auto codepoint : ligatureCodepoints) {
1226         auto codepoints = codepointToString(codepoint);
1227         if (!codepoints.isNull())
1228             m_glyphs.append(GlyphData(Vector<char, 17>(m_emptyGlyphCharString), nullptr, m_unitsPerEm, m_unitsPerEm, FloatRect(), codepoints));
1229     }
1230 }
1231
1232 bool SVGToOTFFontConverter::compareCodepointsLexicographically(const GlyphData& data1, const GlyphData& data2)
1233 {
1234     auto codePoints1 = StringView(data1.codepoints).codePoints();
1235     auto codePoints2 = StringView(data2.codepoints).codePoints();
1236     auto iterator1 = codePoints1.begin();
1237     auto iterator2 = codePoints2.begin();
1238     unsigned length1 = data1.codepoints.length();
1239     unsigned length2 = data2.codepoints.length();
1240     while (iterator1 != codePoints1.end() && iterator2 != codePoints2.end()) {
1241         UChar32 codepoint1, codepoint2;
1242         codepoint1 = *iterator1;
1243         codepoint2 = *iterator2;
1244
1245         if (codepoint1 < codepoint2)
1246             return true;
1247         if (codepoint1 > codepoint2)
1248             return false;
1249
1250         ++iterator1;
1251         ++iterator2;
1252     }
1253
1254     if (length1 == length2 && data1.glyphElement
1255         && equalIgnoringCase(data1.glyphElement->fastGetAttribute(SVGNames::arabic_formAttr), "isolated"))
1256         return true;
1257     return length1 < length2;
1258 }
1259
1260 static void populateEmptyGlyphCharString(Vector<char, 17>& o, unsigned unitsPerEm)
1261 {
1262     writeCFFEncodedNumber(o, unitsPerEm);
1263     writeCFFEncodedNumber(o, 0);
1264     writeCFFEncodedNumber(o, 0);
1265     o.append(rMoveTo);
1266     o.append(endChar);
1267 }
1268
1269 SVGToOTFFontConverter::SVGToOTFFontConverter(const SVGFontElement& fontElement)
1270     : m_fontElement(fontElement)
1271     , m_fontFaceElement(childrenOfType<SVGFontFaceElement>(m_fontElement).first())
1272     , m_missingGlyphElement(childrenOfType<SVGMissingGlyphElement>(m_fontElement).first())
1273     , m_advanceWidthMax(0)
1274     , m_advanceHeightMax(0)
1275     , m_minRightSideBearing(std::numeric_limits<float>::max())
1276     , m_unitsPerEm(0)
1277     , m_featureCountGSUB(0)
1278     , m_tablesAppendedCount(0)
1279     , m_weight(5)
1280     , m_italic(false)
1281 {
1282
1283     float defaultHorizontalAdvance = m_fontFaceElement ? m_fontFaceElement->horizontalAdvanceX() : 0;
1284     float defaultVerticalAdvance = m_fontFaceElement ? m_fontFaceElement->verticalAdvanceY() : 0;
1285     bool initialGlyph = true;
1286
1287     if (m_fontFaceElement)
1288         m_unitsPerEm = m_fontFaceElement->unitsPerEm();
1289
1290     populateEmptyGlyphCharString(m_emptyGlyphCharString, m_unitsPerEm);
1291
1292     if (m_missingGlyphElement)
1293         processGlyphElement(*m_missingGlyphElement, nullptr, defaultHorizontalAdvance, defaultVerticalAdvance, String(), initialGlyph);
1294     else
1295         m_glyphs.append(GlyphData(Vector<char, 17>(m_emptyGlyphCharString), nullptr, m_unitsPerEm, m_unitsPerEm, FloatRect(), String()));
1296
1297     for (auto& glyphElement : childrenOfType<SVGGlyphElement>(m_fontElement)) {
1298         auto& unicodeAttribute = glyphElement.fastGetAttribute(SVGNames::unicodeAttr);
1299         if (!unicodeAttribute.isEmpty()) // If we can never actually trigger this glyph, ignore it completely
1300             processGlyphElement(glyphElement, &glyphElement, defaultHorizontalAdvance, defaultVerticalAdvance, unicodeAttribute, initialGlyph);
1301     }
1302
1303     appendLigatureGlyphs();
1304
1305     if (m_glyphs.size() > std::numeric_limits<Glyph>::max()) {
1306         m_glyphs.clear();
1307         return;
1308     }
1309
1310     std::sort(m_glyphs.begin(), m_glyphs.end(), &compareCodepointsLexicographically);
1311
1312     for (Glyph i = 0; i < m_glyphs.size(); ++i) {
1313         GlyphData& glyph = m_glyphs[i];
1314         if (glyph.glyphElement) {
1315             auto& glyphName = glyph.glyphElement->fastGetAttribute(SVGNames::glyph_nameAttr);
1316             if (!glyphName.isNull())
1317                 m_glyphNameToIndexMap.add(glyphName, i);
1318         }
1319         if (m_codepointsToIndicesMap.isValidKey(glyph.codepoints)) {
1320             auto& glyphVector = m_codepointsToIndicesMap.add(glyph.codepoints, Vector<Glyph>()).iterator->value;
1321             // Prefer isolated arabic forms
1322             if (glyph.glyphElement && equalIgnoringCase(glyph.glyphElement->fastGetAttribute(SVGNames::arabic_formAttr), "isolated"))
1323                 glyphVector.insert(0, i);
1324             else
1325                 glyphVector.append(i);
1326         }
1327     }
1328
1329     // FIXME: Handle commas.
1330     if (m_fontFaceElement) {
1331         Vector<String> segments;
1332         m_fontFaceElement->fastGetAttribute(SVGNames::font_weightAttr).string().split(' ', segments);
1333         for (auto& segment : segments) {
1334             if (equalIgnoringCase(segment, "bold")) {
1335                 m_weight = 7;
1336                 break;
1337             }
1338             bool ok;
1339             int value = segment.toInt(&ok);
1340             if (ok && value >= 0 && value < 1000) {
1341                 m_weight = (value + 50) / 100;
1342                 break;
1343             }
1344         }
1345         m_fontFaceElement->fastGetAttribute(SVGNames::font_styleAttr).string().split(' ', segments);
1346         for (auto& segment : segments) {
1347             if (equalIgnoringCase(segment, "italic") || equalIgnoringCase(segment, "oblique")) {
1348                 m_italic = true;
1349                 break;
1350             }
1351         }
1352     }
1353
1354     if (m_fontFaceElement)
1355         m_fontFamily = m_fontFaceElement->fontFamily();
1356 }
1357
1358 static inline bool isFourByteAligned(size_t x)
1359 {
1360     return !(x & 3);
1361 }
1362
1363 uint32_t SVGToOTFFontConverter::calculateChecksum(size_t startingOffset, size_t endingOffset) const
1364 {
1365     ASSERT(isFourByteAligned(endingOffset - startingOffset));
1366     uint32_t sum = 0;
1367     for (size_t offset = startingOffset; offset < endingOffset; offset += 4) {
1368         sum += (static_cast<unsigned char>(m_result[offset + 3]) << 24)
1369             | (static_cast<unsigned char>(m_result[offset + 2]) << 16)
1370             | (static_cast<unsigned char>(m_result[offset + 1]) << 8)
1371             | static_cast<unsigned char>(m_result[offset]);
1372     }
1373     return sum;
1374 }
1375
1376 void SVGToOTFFontConverter::appendTable(const char identifier[4], FontAppendingFunction appendingFunction)
1377 {
1378     size_t offset = m_result.size();
1379     ASSERT(isFourByteAligned(offset));
1380     (this->*appendingFunction)();
1381     size_t unpaddedSize = m_result.size() - offset;
1382     while (!isFourByteAligned(m_result.size()))
1383         m_result.append(0);
1384     ASSERT(isFourByteAligned(m_result.size()));
1385     size_t directoryEntryOffset = headerSize + m_tablesAppendedCount * directoryEntrySize;
1386     m_result[directoryEntryOffset] = identifier[0];
1387     m_result[directoryEntryOffset + 1] = identifier[1];
1388     m_result[directoryEntryOffset + 2] = identifier[2];
1389     m_result[directoryEntryOffset + 3] = identifier[3];
1390     overwrite32(directoryEntryOffset + 4, calculateChecksum(offset, m_result.size()));
1391     overwrite32(directoryEntryOffset + 8, offset);
1392     overwrite32(directoryEntryOffset + 12, unpaddedSize);
1393     ++m_tablesAppendedCount;
1394 }
1395
1396 void SVGToOTFFontConverter::convertSVGToOTFFont()
1397 {
1398     if (m_glyphs.isEmpty())
1399         return;
1400
1401     uint16_t numTables = 14;
1402     uint16_t roundedNumTables = roundDownToPowerOfTwo(numTables);
1403     uint16_t searchRange = roundedNumTables * 16; // searchRange: "(Maximum power of 2 <= numTables) x 16."
1404
1405     m_result.append('O');
1406     m_result.append('T');
1407     m_result.append('T');
1408     m_result.append('O');
1409     append16(numTables);
1410     append16(searchRange);
1411     append16(integralLog2(roundedNumTables)); // entrySelector: "Log2(maximum power of 2 <= numTables)."
1412     append16(numTables * 16 - searchRange); // rangeShift: "NumTables x 16-searchRange."
1413
1414     ASSERT(m_result.size() == headerSize);
1415
1416     // Leave space for the directory entries.
1417     for (size_t i = 0; i < directoryEntrySize * numTables; ++i)
1418         m_result.append(0);
1419
1420     appendTable("CFF ", &SVGToOTFFontConverter::appendCFFTable);
1421     appendTable("GSUB", &SVGToOTFFontConverter::appendGSUBTable);
1422     appendTable("OS/2", &SVGToOTFFontConverter::appendOS2Table);
1423     appendTable("VORG", &SVGToOTFFontConverter::appendVORGTable);
1424     appendTable("cmap", &SVGToOTFFontConverter::appendCMAPTable);
1425     auto headTableOffset = m_result.size();
1426     appendTable("head", &SVGToOTFFontConverter::appendHEADTable);
1427     appendTable("hhea", &SVGToOTFFontConverter::appendHHEATable);
1428     appendTable("hmtx", &SVGToOTFFontConverter::appendHMTXTable);
1429     appendTable("kern", &SVGToOTFFontConverter::appendKERNTable);
1430     appendTable("maxp", &SVGToOTFFontConverter::appendMAXPTable);
1431     appendTable("name", &SVGToOTFFontConverter::appendNAMETable);
1432     appendTable("post", &SVGToOTFFontConverter::appendPOSTTable);
1433     appendTable("vhea", &SVGToOTFFontConverter::appendVHEATable);
1434     appendTable("vmtx", &SVGToOTFFontConverter::appendVMTXTable);
1435
1436     ASSERT(numTables == m_tablesAppendedCount);
1437
1438     // checksumAdjustment: "To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory,
1439     // sum the entire font as uint32, then store B1B0AFBA - sum. The checksum for the 'head' table will now be wrong. That is OK."
1440     overwrite32(headTableOffset + 8, 0xB1B0AFBAU - calculateChecksum(0, m_result.size()));
1441 }
1442
1443 Vector<char> convertSVGToOTFFont(const SVGFontElement& element)
1444 {
1445     SVGToOTFFontConverter converter(element);
1446     converter.convertSVGToOTFFont();
1447     return converter.releaseResult();
1448 }
1449
1450 }