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