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