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