<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174063] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174063">174063</a></dd>
<dt>Author</dt> <dd>darin@apple.com</dd>
<dt>Date</dt> <dd>2014-09-29 09:26:59 -0700 (Mon, 29 Sep 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Tweak and tighten SVG font converter
https://bugs.webkit.org/show_bug.cgi?id=136956

Reviewed by Myles Maxfield.

Source/WebCore:

* svg/SVGToOTFFontConversion.cpp: Fixed copyright date.
(WebCore::overwrite32): Changed to use normal subscripting for clarity.
(WebCore::overwrite16): Added.
(WebCore::SVGToOTFFontConverter::GlyphData::GlyphData): Added a move
to make constructing each GlyphData less expensive.
(WebCore::SVGToOTFFontConverter::KerningData): Removed the &lt; operator
since it the struct contains more than what we want to sort it by, so it's
not elegant to build the sorting rule into the struct.
(WebCore::SVGToOTFFontConverter): Removed &quot;k&quot; prefix from some constants.
Replaced many function templates with non-template functions. Changed
key type for m_codepointToIndexMap to UChar32.
(WebCore::integralLog2): Tweaked formatting.
(WebCore::SVGToOTFFontConverter::appendCMAPTable): Removed a stray
cast that doesn't have any effect. Use the Glyph type to index m_glyphs.
(WebCore::SVGToOTFFontConverter::appendHEADTable): Append the magic
number in a more straightforward way.
(WebCore::clampTo): Tweak formatting of the template function.
(WebCore::SVGToOTFFontConverter::appendHHEATable): Made some minor
style changes and improved some comments.
(WebCore::SVGToOTFFontConverter::appendOS2Table): Made some minor
style changes and tightened up code that did parsing a bit, removing the
dynamically allocated array for the fixed length Panose number.
Also use first and last instead of hand-coded versions of those.
(WebCore::appendValidCFFString): Renamed.
(WebCore::SVGToOTFFontConverter::appendCFFTable): Made various tweaks,
including more specific of null for the &quot;no weight&quot; value instead of
either empty or null.
(WebCore::SVGToOTFFontConverter::appendVORGTable): Simplified some of
the numeric parsing, since toInt is guaranteed to return 0 when it also
would return &quot;false&quot; for ok. Also got rid of a local vector and instead
just fixed up the size of the table afterward.
(WebCore::SVGToOTFFontConverter::appendVHEATable): Tweaked comment.
(WebCore::SVGToOTFFontConverter::addCodepointRanges): Use isValidKey
instead of a local hardcoded rule to check hash table key validity.
Check for zero in the result of get rather than using find on the HashMap.
(WebCore::SVGToOTFFontConverter::addCodepointRanges): Ditto.
(WebCore::SVGToOTFFontConverter::addGlyphNames): Ditto.
(WebCore::SVGToOTFFontConverter::addKerningPair): Added. Factored out from
appendKERNSubtable to reduce template bloat and improve clarity.
(WebCore::SVGToOTFFontConverter::appendKERNSubtable): Tweaked formatting.
Moved the bulk of the function into non-template function.
(WebCore::SVGToOTFFontConverter::finishAppendingKERNSubtable): Added.
Non-template part of appendKERNSubtable. Also changed std::sort to supply
custom comparison function rather than trying to use the &lt; operator directly
on KerningData.
(WebCore::writeCFFEncodedNumber): Don't use powf just to multiply by
2^16. It's pretty easy to do that with plain old multiplication.
(WebCore::CFFBuilder::CFFBuilder): Renamed m_firstPoint to
m_hasBoundingBox.
(WebCore::CFFBuilder::boundingBox): Made this public and const and made
the rest of the class private.
(WebCore::CFFBuilder::updateBoundingBox): Used early return and revised
to use m_hasBoundingBox.
(WebCore::CFFBuilder::writePoint): Added. Used to keep the other
functions below smaller.
(WebCore::CFFBuilder::moveTo): Marked virtual and simplified using writePoint.
Might find a way to simplify even further by teaching writePoint about
the PathCoordinateMode.
(WebCore::CFFBuilder::lineTo): Ditto.
(WebCore::CFFBuilder::curveToCubic): Ditto. Also removed comment that said
the function could be faster. Not sure that's important to state like this.
(WebCore::SVGToOTFFontConverter::transcodeGlyphPaths): Changed into a
non-template function. Tweaked logic and formatting a bit.
(WebCore::SVGToOTFFontConverter::processGlyphElement): Changed into a
non-template function. Moved the code from appendGlyphData in here.
Use WTF::move so we don't copy the glyph paths when creating a GlyphData.
(WebCore::SVGToOTFFontConverter::SVGToOTFFontConverter): Updated a bit for
function changes above. Changed code to use isValidKey to check if we can
add to m_codepointToIndexMap. Parse font-style rather than parsing
font-weight twice. Round weights instead of truncating them. Change rule
to &quot;first wins&quot; instead of &quot;last wins&quot; when there are multiple segments.
Removed one vague and non-helpful comment.
(WebCore::isFourByteAligned): Fixed minor formatting issue by making the
function non-abstract. No reason not to hard-code the number 3 when the
number four appears in the function name.
(WebCore::calculateChecksum): Removed unneeded comment about why the
checksum is little-endian; since this came from Windows documentation there
is no doubt that little-endian is correct, so we don't need a comment creating
fear, uncertainty, and doubt. If the checksum computation is wrong, it should
become obvious that we have a bad checksum. Also changed the for loop to use
its own loop variable instead of changing startingOffset, which is not logical.
(WebCore::SVGToOTFFontConverter::appendTable): Updated for name changes.
(WebCore::SVGToOTFFontConverter::convertSVGToOTFFont): Ditto. Also streamlined
the checksum code a little. The comment still is a little peculiar; I was
tempted to take it out.

Tools:

I was investigating behavior of String::toInt, String::toDouble, and
String::toFloat for various failure cases, and decided to start some
unit tests for those functions here.

* TestWebKitAPI/Tests/WTF/WTFString.cpp:
(TestWebKitAPI::TEST): Addded a first small bit of StringToInt and
StringToDouble testing.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoresvgSVGToOTFFontConversioncpp">trunk/Source/WebCore/svg/SVGToOTFFontConversion.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWTFWTFStringcpp">trunk/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (174062 => 174063)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-09-29 15:37:17 UTC (rev 174062)
+++ trunk/Source/WebCore/ChangeLog        2014-09-29 16:26:59 UTC (rev 174063)
</span><span class="lines">@@ -1,3 +1,96 @@
</span><ins>+2014-09-29  Darin Adler  &lt;darin@apple.com&gt;
+
+        Tweak and tighten SVG font converter
+        https://bugs.webkit.org/show_bug.cgi?id=136956
+
+        Reviewed by Myles Maxfield.
+
+        * svg/SVGToOTFFontConversion.cpp: Fixed copyright date.
+        (WebCore::overwrite32): Changed to use normal subscripting for clarity.
+        (WebCore::overwrite16): Added.
+        (WebCore::SVGToOTFFontConverter::GlyphData::GlyphData): Added a move
+        to make constructing each GlyphData less expensive.
+        (WebCore::SVGToOTFFontConverter::KerningData): Removed the &lt; operator
+        since it the struct contains more than what we want to sort it by, so it's
+        not elegant to build the sorting rule into the struct.
+        (WebCore::SVGToOTFFontConverter): Removed &quot;k&quot; prefix from some constants.
+        Replaced many function templates with non-template functions. Changed
+        key type for m_codepointToIndexMap to UChar32.
+        (WebCore::integralLog2): Tweaked formatting.
+        (WebCore::SVGToOTFFontConverter::appendCMAPTable): Removed a stray
+        cast that doesn't have any effect. Use the Glyph type to index m_glyphs.
+        (WebCore::SVGToOTFFontConverter::appendHEADTable): Append the magic
+        number in a more straightforward way.
+        (WebCore::clampTo): Tweak formatting of the template function.
+        (WebCore::SVGToOTFFontConverter::appendHHEATable): Made some minor
+        style changes and improved some comments.
+        (WebCore::SVGToOTFFontConverter::appendOS2Table): Made some minor
+        style changes and tightened up code that did parsing a bit, removing the
+        dynamically allocated array for the fixed length Panose number.
+        Also use first and last instead of hand-coded versions of those.
+        (WebCore::appendValidCFFString): Renamed.
+        (WebCore::SVGToOTFFontConverter::appendCFFTable): Made various tweaks,
+        including more specific of null for the &quot;no weight&quot; value instead of
+        either empty or null.
+        (WebCore::SVGToOTFFontConverter::appendVORGTable): Simplified some of
+        the numeric parsing, since toInt is guaranteed to return 0 when it also
+        would return &quot;false&quot; for ok. Also got rid of a local vector and instead
+        just fixed up the size of the table afterward.
+        (WebCore::SVGToOTFFontConverter::appendVHEATable): Tweaked comment.
+        (WebCore::SVGToOTFFontConverter::addCodepointRanges): Use isValidKey
+        instead of a local hardcoded rule to check hash table key validity.
+        Check for zero in the result of get rather than using find on the HashMap.
+        (WebCore::SVGToOTFFontConverter::addCodepointRanges): Ditto.
+        (WebCore::SVGToOTFFontConverter::addGlyphNames): Ditto.
+        (WebCore::SVGToOTFFontConverter::addKerningPair): Added. Factored out from
+        appendKERNSubtable to reduce template bloat and improve clarity.
+        (WebCore::SVGToOTFFontConverter::appendKERNSubtable): Tweaked formatting.
+        Moved the bulk of the function into non-template function.
+        (WebCore::SVGToOTFFontConverter::finishAppendingKERNSubtable): Added.
+        Non-template part of appendKERNSubtable. Also changed std::sort to supply
+        custom comparison function rather than trying to use the &lt; operator directly
+        on KerningData.
+        (WebCore::writeCFFEncodedNumber): Don't use powf just to multiply by
+        2^16. It's pretty easy to do that with plain old multiplication.
+        (WebCore::CFFBuilder::CFFBuilder): Renamed m_firstPoint to
+        m_hasBoundingBox.
+        (WebCore::CFFBuilder::boundingBox): Made this public and const and made
+        the rest of the class private.
+        (WebCore::CFFBuilder::updateBoundingBox): Used early return and revised
+        to use m_hasBoundingBox.
+        (WebCore::CFFBuilder::writePoint): Added. Used to keep the other
+        functions below smaller.
+        (WebCore::CFFBuilder::moveTo): Marked virtual and simplified using writePoint.
+        Might find a way to simplify even further by teaching writePoint about
+        the PathCoordinateMode.
+        (WebCore::CFFBuilder::lineTo): Ditto.
+        (WebCore::CFFBuilder::curveToCubic): Ditto. Also removed comment that said
+        the function could be faster. Not sure that's important to state like this.
+        (WebCore::SVGToOTFFontConverter::transcodeGlyphPaths): Changed into a
+        non-template function. Tweaked logic and formatting a bit.
+        (WebCore::SVGToOTFFontConverter::processGlyphElement): Changed into a
+        non-template function. Moved the code from appendGlyphData in here.
+        Use WTF::move so we don't copy the glyph paths when creating a GlyphData.
+        (WebCore::SVGToOTFFontConverter::SVGToOTFFontConverter): Updated a bit for
+        function changes above. Changed code to use isValidKey to check if we can
+        add to m_codepointToIndexMap. Parse font-style rather than parsing
+        font-weight twice. Round weights instead of truncating them. Change rule
+        to &quot;first wins&quot; instead of &quot;last wins&quot; when there are multiple segments.
+        Removed one vague and non-helpful comment.
+        (WebCore::isFourByteAligned): Fixed minor formatting issue by making the
+        function non-abstract. No reason not to hard-code the number 3 when the
+        number four appears in the function name.
+        (WebCore::calculateChecksum): Removed unneeded comment about why the
+        checksum is little-endian; since this came from Windows documentation there
+        is no doubt that little-endian is correct, so we don't need a comment creating
+        fear, uncertainty, and doubt. If the checksum computation is wrong, it should
+        become obvious that we have a bad checksum. Also changed the for loop to use
+        its own loop variable instead of changing startingOffset, which is not logical.
+        (WebCore::SVGToOTFFontConverter::appendTable): Updated for name changes.
+        (WebCore::SVGToOTFFontConverter::convertSVGToOTFFont): Ditto. Also streamlined
+        the checksum code a little. The comment still is a little peculiar; I was
+        tempted to take it out.
+
</ins><span class="cx"> 2014-09-29  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Remove MainFrameScrollbarGtk.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGToOTFFontConversioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGToOTFFontConversion.cpp (174062 => 174063)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGToOTFFontConversion.cpp        2014-09-29 15:37:17 UTC (rev 174062)
+++ trunk/Source/WebCore/svg/SVGToOTFFontConversion.cpp        2014-09-29 16:26:59 UTC (rev 174063)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2010 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -57,22 +57,29 @@
</span><span class="cx"> static inline void overwrite32(Vector&lt;char&gt;&amp; vector, unsigned location, uint32_t value)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(vector.size() &gt;= location + 4);
</span><del>-    *(vector.data() + location) = value &gt;&gt; 24;
-    *(vector.data() + location + 1) = value &gt;&gt; 16;
-    *(vector.data() + location + 2) = value &gt;&gt; 8;
-    *(vector.data() + location + 3) = value;
</del><ins>+    vector[location] = value &gt;&gt; 24;
+    vector[location + 1] = value &gt;&gt; 16;
+    vector[location + 2] = value &gt;&gt; 8;
+    vector[location + 3] = value;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline void overwrite16(Vector&lt;char&gt;&amp; vector, unsigned location, uint16_t value)
+{
+    ASSERT(vector.size() &gt;= location + 2);
+    vector[location] = value &gt;&gt; 8;
+    vector[location + 1] = value;
+}
+
</ins><span class="cx"> class SVGToOTFFontConverter {
</span><span class="cx"> public:
</span><span class="cx">     SVGToOTFFontConverter(const SVGFontElement&amp;);
</span><span class="cx">     Vector&lt;char&gt; convertSVGToOTFFont();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    typedef uint16_t SID; // String ID
</del><span class="cx">     typedef UChar Codepoint; // FIXME: Only support BMP for now
</span><ins>+
</ins><span class="cx">     struct GlyphData {
</span><del>-        GlyphData(Vector&lt;char&gt; charString, const SVGGlyphElement* glyphElement, float horizontalAdvance, float verticalAdvance, FloatRect boundingBox, Codepoint codepoint)
</del><ins>+        GlyphData(Vector&lt;char&gt;&amp;&amp; charString, const SVGGlyphElement* glyphElement, float horizontalAdvance, float verticalAdvance, FloatRect boundingBox, Codepoint codepoint)
</ins><span class="cx">             : boundingBox(boundingBox)
</span><span class="cx">             , charString(charString)
</span><span class="cx">             , glyphElement(glyphElement)
</span><span class="lines">@@ -96,24 +103,16 @@
</span><span class="cx">             , adjustment(adjustment)
</span><span class="cx">         {
</span><span class="cx">         }
</span><del>-        bool operator&lt;(const KerningData&amp; other) const
-        {
-            return glyph1 &lt; other.glyph1 || (glyph1 == other.glyph1 &amp;&amp; glyph2 &lt; other.glyph2);
-        }
</del><span class="cx">         uint16_t glyph1;
</span><span class="cx">         uint16_t glyph2;
</span><span class="cx">         int16_t adjustment;
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    static const size_t kSNFTHeaderSize = 12;
-    static const size_t kDirectoryEntrySize = 16;
</del><ins>+    static const size_t headerSize = 12;
+    static const size_t directoryEntrySize = 16;
</ins><span class="cx"> 
</span><ins>+    void processGlyphElement(const SVGElement&amp; glyphOrMissingGlyphElement, const SVGGlyphElement*, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint, bool&amp; initialGlyph);
</ins><span class="cx"> 
</span><del>-    template &lt;typename T&gt;
-    void appendGlyphData(const Vector&lt;char&gt;&amp; path, const T* element, float horizontalAdvance, float verticalAdvance, const FloatRect&amp; boundingBox, Codepoint codepoint);
-    template &lt;typename T&gt;
-    void processGlyphElement(const T&amp; element, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint, bool&amp; initialGlyph);
-
</del><span class="cx">     typedef void (SVGToOTFFontConverter::*FontAppendingFunction)(Vector&lt;char&gt; &amp;) const;
</span><span class="cx">     void appendTable(const char identifier[4], Vector&lt;char&gt;&amp;, FontAppendingFunction);
</span><span class="cx">     void appendCMAPTable(Vector&lt;char&gt;&amp;) const;
</span><span class="lines">@@ -130,20 +129,18 @@
</span><span class="cx">     void appendCFFTable(Vector&lt;char&gt;&amp;) const;
</span><span class="cx">     void appendVORGTable(Vector&lt;char&gt;&amp;) const;
</span><span class="cx"> 
</span><del>-    template &lt;typename T&gt;
-    Vector&lt;char&gt; transcodeGlyphPaths(float width, const T&amp; glyphElement, FloatRect&amp; boundingBox) const;
</del><ins>+    Vector&lt;char&gt; transcodeGlyphPaths(float width, const SVGElement&amp; glyphOrMissingGlyphElement, FloatRect&amp; boundingBox) const;
</ins><span class="cx"> 
</span><span class="cx">     void addCodepointRanges(const UnicodeRanges&amp;, HashSet&lt;uint16_t&gt;&amp; glyphSet) const;
</span><span class="cx">     void addCodepoints(const HashSet&lt;String&gt;&amp; codepoints, HashSet&lt;uint16_t&gt;&amp; glyphSet) const;
</span><span class="cx">     void addGlyphNames(const HashSet&lt;String&gt;&amp; glyphNames, HashSet&lt;uint16_t&gt;&amp; glyphSet) const;
</span><del>-    template &lt;typename T&gt;
-    Vector&lt;KerningData&gt; computeKerningData(bool (T::*buildKerningPair)(SVGKerningPair&amp;) const) const;
-    template &lt;typename T&gt;
-    size_t appendKERNSubtable(Vector&lt;char&gt;&amp; result, bool (T::*buildKerningPair)(SVGKerningPair&amp;) const, uint16_t coverage) const;
</del><ins>+    void addKerningPair(Vector&lt;KerningData&gt;&amp;, const SVGKerningPair&amp;) const;
+    template&lt;typename T&gt; size_t appendKERNSubtable(Vector&lt;char&gt;&amp; result, bool (T::*buildKerningPair)(SVGKerningPair&amp;) const, uint16_t coverage) const;
+    size_t finishAppendingKERNSubtable(Vector&lt;char&gt;&amp; result, Vector&lt;KerningData&gt;, uint16_t coverage) const;
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;GlyphData&gt; m_glyphs;
</span><span class="cx">     HashMap&lt;String, Glyph&gt; m_glyphNameToIndexMap; // SVG 1.1: &quot;It is recommended that glyph names be unique within a font.&quot;
</span><del>-    HashMap&lt;Codepoint, Glyph&gt; m_codepointToIndexMap; // FIXME: There might be many glyphs that map to a single codepoint.
</del><ins>+    HashMap&lt;UChar32, Glyph&gt; m_codepointToIndexMap; // FIXME: There might be many glyphs that map to a single codepoint.
</ins><span class="cx">     FloatRect m_boundingBox;
</span><span class="cx">     const SVGFontElement&amp; m_fontElement;
</span><span class="cx">     const SVGFontFaceElement* m_fontFaceElement;
</span><span class="lines">@@ -167,7 +164,8 @@
</span><span class="cx">     return (x &gt;&gt; 1) + 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static uint16_t integralLog2(uint16_t x) {
</del><ins>+static uint16_t integralLog2(uint16_t x)
+{
</ins><span class="cx">     uint16_t result = 0;
</span><span class="cx">     while (x &gt;&gt;= 1)
</span><span class="cx">         ++result;
</span><span class="lines">@@ -204,9 +202,9 @@
</span><span class="cx">     for (auto&amp; glyph : m_glyphs)
</span><span class="cx">         write16(result, glyph.codepoint); // startCode
</span><span class="cx">     write16(result, 0xFFFF);
</span><del>-    for (unsigned i = 0; i &lt; m_glyphs.size(); ++i) {
</del><ins>+    for (Glyph i = 0; i &lt; m_glyphs.size(); ++i) {
</ins><span class="cx">         // Note that this value can be &quot;negative,&quot; but that is okay because wrapping is defined and expected here
</span><del>-        write16(result, static_cast&lt;uint16_t&gt;(i) - m_glyphs[i].codepoint); // idDelta
</del><ins>+        write16(result, i - m_glyphs[i].codepoint); // idDelta
</ins><span class="cx">     }
</span><span class="cx">     write16(result, 1);
</span><span class="cx">     for (unsigned i = 0; i &lt; m_glyphs.size(); ++i)
</span><span class="lines">@@ -218,12 +216,8 @@
</span><span class="cx"> {
</span><span class="cx">     write32(result, 0x00010000); // Version
</span><span class="cx">     write32(result, 0x00010000); // Revision
</span><del>-    write32(result, 0); // Checksum adjustment
-    // Magic number. &quot;Set to 0x5F0F3CF5&quot;
-    result.append(0x5F);
-    result.append(0x0F);
-    result.append(0x3C);
-    result.append(-0x0B); // Wraparound
</del><ins>+    write32(result, 0); // Checksum placeholder; to be overwritten by the caller.
+    write32(result, 0x5F0F3CF5); // Magic number.
</ins><span class="cx">     write16(result, (1 &lt;&lt; 9) | 1);
</span><span class="cx"> 
</span><span class="cx">     write16(result, m_unitsPerEm);
</span><span class="lines">@@ -242,9 +236,8 @@
</span><span class="cx">     write16(result, 0); // Glyph data format
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Assumption: T2 can hold every value that a T1 can hold
-template &lt;typename T1, typename T2&gt;
-static inline T1 clampTo(T2 x)
</del><ins>+// Assumption: T2 can hold every value that a T1 can hold.
+template&lt;typename T1, typename T2&gt; static inline T1 clampTo(T2 x)
</ins><span class="cx"> {
</span><span class="cx">     x = std::min(x, static_cast&lt;T2&gt;(std::numeric_limits&lt;T1&gt;::max()));
</span><span class="cx">     x = std::max(x, static_cast&lt;T2&gt;(std::numeric_limits&lt;T1&gt;::min()));
</span><span class="lines">@@ -253,33 +246,34 @@
</span><span class="cx"> 
</span><span class="cx"> void SVGToOTFFontConverter::appendHHEATable(Vector&lt;char&gt;&amp; result) const
</span><span class="cx"> {
</span><del>-    int16_t ascent = std::numeric_limits&lt;int16_t&gt;::max();
-    int16_t descent = std::numeric_limits&lt;int16_t&gt;::max();
-    if (m_fontFaceElement) {
</del><ins>+    int16_t ascent;
+    int16_t descent;
+    if (!m_fontFaceElement) {
+        ascent = std::numeric_limits&lt;int16_t&gt;::max();
+        descent = std::numeric_limits&lt;int16_t&gt;::max();
+    } else {
</ins><span class="cx">         ascent = m_fontFaceElement-&gt;ascent();
</span><span class="cx">         descent = m_fontFaceElement-&gt;descent();
</span><ins>+
+        // Some platforms, including OS X, use 0 ascent and descent to mean that the platform should synthesize
+        // a value based on a heuristic. However, SVG fonts can legitimately have 0 for ascent or descent.
+        // Specifing a single FUnit gets us as close to 0 as we can without triggering the synthesis.
+        if (!ascent)
+            ascent = 1;
+        if (!descent)
+            descent = 1;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Many platforms will assume that a 0 ascent or descent means that the platform should synthesize a font
-    // based on a heuristic. However, many SVG fonts legitimitely have a 0 ascent or descent. Therefore,
-    // we should specify a single FUnit instead, which is as close as we can get to 0 without actually being
-    // it.
-    if (!ascent)
-        ascent = 1;
-    if (!descent)
-        descent = 1;
-
</del><span class="cx">     write32(result, 0x00010000); // Version
</span><span class="cx">     write16(result, ascent);
</span><span class="cx">     write16(result, descent);
</span><del>-    // WebKit's SVG codepath hardcodes the line gap to be 1/10th of the font size (see r29719). Matching that
-    // allows us to have consistent renderings between the two paths.
</del><ins>+    // WebKit SVG font rendering has hard coded the line gap to be 1/10th of the font size since 2008 (see r29719).
</ins><span class="cx">     write16(result, m_unitsPerEm / 10); // Line gap
</span><span class="cx">     write16(result, clampTo&lt;uint16_t&gt;(m_advanceWidthMax));
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_boundingBox.x())); // Minimum left side bearing
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_minRightSideBearing)); // Minimum right side bearing
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_boundingBox.maxX())); // X maximum extent
</span><del>-    // WebKit draws the caret
</del><ins>+    // Since WebKit draws the caret and ignores the following values, it doesn't matter what we set them to.
</ins><span class="cx">     write16(result, 1); // Vertical caret
</span><span class="cx">     write16(result, 0); // Vertical caret
</span><span class="cx">     write16(result, 0); // &quot;Set value to 0 for non-slanted fonts&quot;
</span><span class="lines">@@ -336,16 +330,12 @@
</span><span class="cx"> void SVGToOTFFontConverter::appendOS2Table(Vector&lt;char&gt;&amp; result) const
</span><span class="cx"> {
</span><span class="cx">     int16_t averageAdvance = m_unitsPerEm;
</span><del>-    auto&amp; attribute = m_fontElement.fastGetAttribute(SVGNames::horiz_adv_xAttr);
</del><span class="cx">     bool ok;
</span><del>-    int value = attribute.toInt(&amp;ok);
</del><ins>+    int value = m_fontElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&amp;ok);
+    if (!ok &amp;&amp; m_missingGlyphElement)
+        value = m_missingGlyphElement-&gt;fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&amp;ok);
</ins><span class="cx">     if (ok)
</span><span class="cx">         averageAdvance = clampTo&lt;int16_t&gt;(value);
</span><del>-    else if (m_missingGlyphElement) {
-        int value = m_missingGlyphElement-&gt;fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&amp;ok);
-        if (ok)
-            averageAdvance = clampTo&lt;int16_t&gt;(value);
-    }
</del><span class="cx"> 
</span><span class="cx">     write16(result, 0); // Version
</span><span class="cx">     write16(result, averageAdvance);
</span><span class="lines">@@ -365,38 +355,31 @@
</span><span class="cx">     write16(result, 0); // Strikeout Position
</span><span class="cx">     write16(result, 0); // No classification
</span><span class="cx"> 
</span><del>-    Vector&lt;unsigned char&gt; specifiedPanose;
</del><ins>+    unsigned numPanoseBytes = 0;
+    const unsigned panoseSize = 10;
+    char panoseBytes[panoseSize];
</ins><span class="cx">     if (m_fontFaceElement) {
</span><del>-        auto&amp; attribute = m_fontFaceElement-&gt;fastGetAttribute(SVGNames::panose_1Attr);
-        Vector&lt;String&gt; split;
-        String(attribute).split(&quot; &quot;, split);
-        if (split.size() == 10) {
-            for (auto&amp; s : split) {
-                bool ok = true;
-                int value = s.toInt(&amp;ok);
-                if (!ok || value &lt; 0 || value &gt; 0xFF) {
-                    specifiedPanose.clear();
-                    break;
-                }
-                specifiedPanose.append(static_cast&lt;unsigned char&gt;(value));
</del><ins>+        Vector&lt;String&gt; segments;
+        m_fontFaceElement-&gt;fastGetAttribute(SVGNames::panose_1Attr).string().split(' ', segments);
+        if (segments.size() == panoseSize) {
+            for (auto&amp; segment : segments) {
+                bool ok;
+                int value = segment.toInt(&amp;ok);
+                if (ok &amp;&amp; value &gt;= 0 &amp;&amp; value &lt;= 0xFF)
+                    panoseBytes[numPanoseBytes++] = value;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    if (numPanoseBytes != panoseSize)
+        memset(panoseBytes, 0, panoseSize);
+    result.append(panoseBytes, panoseSize);
</ins><span class="cx"> 
</span><del>-    if (specifiedPanose.size() == 10) {
-        for (char c : specifiedPanose)
-            result.append(c);
-    } else {
-        for (int i = 0; i &lt; 10; ++i)
-            result.append(0); // PANOSE: Any
-    }
-
</del><span class="cx">     for (int i = 0; i &lt; 4; ++i)
</span><span class="cx">         write32(result, 0); // &quot;Bit assignments are pending. Set to 0&quot;
</span><span class="cx">     write32(result, 0x544B4257); // Font Vendor. &quot;WBKT&quot;
</span><span class="cx">     write16(result, (m_weight &gt;= 7 ? 1 &lt;&lt; 5 : 0) | (m_italic ? 1 : 0)); // Font Patterns.
</span><del>-    write16(result, m_glyphs[0].codepoint); // First unicode index
-    write16(result, m_glyphs[m_glyphs.size() - 1].codepoint); // Last unicode index
</del><ins>+    write16(result, m_glyphs.first().codepoint); // First unicode index
+    write16(result, m_glyphs.last().codepoint); // Last unicode index
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SVGToOTFFontConverter::appendPOSTTable(Vector&lt;char&gt;&amp; result) const
</span><span class="lines">@@ -421,7 +404,7 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void appendCFFValidString(Vector&lt;char&gt;&amp; output, const String&amp; string)
</del><ins>+static void appendValidCFFString(Vector&lt;char&gt;&amp; output, const String&amp; string)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isValidStringForCFF(string));
</span><span class="cx">     for (unsigned i = 0; i &lt; string.length(); ++i)
</span><span class="lines">@@ -431,6 +414,7 @@
</span><span class="cx"> void SVGToOTFFontConverter::appendCFFTable(Vector&lt;char&gt;&amp; result) const
</span><span class="cx"> {
</span><span class="cx">     auto startingOffset = result.size();
</span><ins>+
</ins><span class="cx">     // Header
</span><span class="cx">     result.append(1); // Major version
</span><span class="cx">     result.append(0); // Minor version
</span><span class="lines">@@ -440,7 +424,7 @@
</span><span class="cx">     // Name INDEX
</span><span class="cx">     String fontName;
</span><span class="cx">     if (m_fontFaceElement) {
</span><del>-        // FIXME: fontFamily() here might not be quite what I want
</del><ins>+        // FIXME: fontFamily() here might not be quite what we want.
</ins><span class="cx">         String potentialFontName = m_fontFamily;
</span><span class="cx">         if (isValidStringForCFF(potentialFontName))
</span><span class="cx">             fontName = potentialFontName;
</span><span class="lines">@@ -449,7 +433,7 @@
</span><span class="cx">     result.append(4); // Offsets in this INDEX are 4 bytes long
</span><span class="cx">     write32(result, 1); // 1-index offset of name data
</span><span class="cx">     write32(result, fontName.length() + 1); // 1-index offset just past end of name data
</span><del>-    appendCFFValidString(result, fontName);
</del><ins>+    appendValidCFFString(result, fontName);
</ins><span class="cx"> 
</span><span class="cx">     String weight;
</span><span class="cx">     if (m_fontFaceElement) {
</span><span class="lines">@@ -458,6 +442,8 @@
</span><span class="cx">             weight = potentialWeight;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool hasWeight = !weight.isNull();
+
</ins><span class="cx">     const char operand32Bit = 29;
</span><span class="cx">     const char fullNameKey = 2;
</span><span class="cx">     const char familyNameKey = 3;
</span><span class="lines">@@ -466,7 +452,7 @@
</span><span class="cx">     const char charsetIndexKey = 15;
</span><span class="cx">     const char charstringsIndexKey = 17;
</span><span class="cx">     const uint32_t userDefinedStringStartIndex = 391;
</span><del>-    const unsigned sizeOfTopIndex = 45 + (weight.isEmpty() ? 0 : 6);
</del><ins>+    const unsigned sizeOfTopIndex = 45 + (hasWeight ? 6 : 0);
</ins><span class="cx"> 
</span><span class="cx">     // Top DICT INDEX.
</span><span class="cx">     write16(result, 1); // INDEX contains 1 element
</span><span class="lines">@@ -484,7 +470,7 @@
</span><span class="cx">     result.append(operand32Bit);
</span><span class="cx">     write32(result, userDefinedStringStartIndex);
</span><span class="cx">     result.append(familyNameKey);
</span><del>-    if (!weight.isEmpty()) {
</del><ins>+    if (hasWeight) {
</ins><span class="cx">         result.append(operand32Bit);
</span><span class="cx">         write32(result, userDefinedStringStartIndex + 1);
</span><span class="cx">         result.append(weightKey);
</span><span class="lines">@@ -509,25 +495,25 @@
</span><span class="cx">     ASSERT(result.size() == topDictStart + sizeOfTopIndex);
</span><span class="cx"> 
</span><span class="cx">     // String INDEX
</span><del>-    write16(result, 1 + (weight.isEmpty() ? 0 : 1)); // Number of elements in INDEX
</del><ins>+    write16(result, 1 + (hasWeight ? 1 : 0)); // Number of elements in INDEX
</ins><span class="cx">     result.append(4); // Offsets in this INDEX are 4 bytes long
</span><span class="cx">     uint32_t offset = 1;
</span><span class="cx">     write32(result, offset);
</span><span class="cx">     offset += fontName.length();
</span><span class="cx">     write32(result, offset);
</span><del>-    if (!weight.isEmpty()) {
</del><ins>+    if (hasWeight) {
</ins><span class="cx">         offset += weight.length();
</span><span class="cx">         write32(result, offset);
</span><span class="cx">     }
</span><del>-    appendCFFValidString(result, fontName);
-    appendCFFValidString(result, weight);
</del><ins>+    appendValidCFFString(result, fontName);
+    appendValidCFFString(result, weight);
</ins><span class="cx"> 
</span><span class="cx">     write16(result, 0); // Empty subroutine INDEX
</span><span class="cx"> 
</span><span class="cx">     // Charset info
</span><span class="cx">     overwrite32(result, charsetOffsetLocation, result.size() - startingOffset);
</span><span class="cx">     result.append(0);
</span><del>-    for (unsigned i = 1; i &lt; m_glyphs.size(); ++i)
</del><ins>+    for (Glyph i = 1; i &lt; m_glyphs.size(); ++i)
</ins><span class="cx">         write16(result, i);
</span><span class="cx"> 
</span><span class="cx">     // CharStrings INDEX
</span><span class="lines">@@ -555,24 +541,18 @@
</span><span class="cx">         defaultVerticalOriginY = clampTo&lt;int16_t&gt;(m_missingGlyphElement-&gt;fastGetAttribute(SVGNames::vert_origin_yAttr).toInt());
</span><span class="cx">     write16(result, defaultVerticalOriginY);
</span><span class="cx"> 
</span><del>-    Vector&lt;std::pair&lt;uint16_t, int16_t&gt;&gt; origins;
-    for (uint16_t i = 0; i &lt; m_glyphs.size(); ++i) {
-        if (m_glyphs[i].glyphElement) {
-            auto&amp; attribute = m_glyphs[i].glyphElement-&gt;fastGetAttribute(SVGNames::vert_origin_yAttr);
-            if (attribute != nullAtom &amp;&amp; attribute.is8Bit()) {
-                bool ok;
-                int16_t verticalOriginY = attribute.toInt(&amp;ok);
-                if (ok &amp;&amp; verticalOriginY)
-                    origins.append(std::make_pair(i, verticalOriginY));
</del><ins>+    auto tableSizeOffset = result.size();
+    write16(result, 0); // Place to write table size.
+    for (Glyph i = 0; i &lt; m_glyphs.size(); ++i) {
+        if (auto* glyph = m_glyphs[i].glyphElement) {
+            if (int16_t verticalOriginY = clampTo&lt;int16_t&gt;(glyph-&gt;fastGetAttribute(SVGNames::vert_origin_yAttr).toInt())) {
+                write16(result, i);
+                write16(result, verticalOriginY);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    write16(result, origins.size());
-
-    for (auto&amp; p : origins) {
-        write16(result, p.first);
-        write16(result, p.second);
-    }
</del><ins>+    ASSERT(!((result.size() - tableSizeOffset - 2) % 4));
+    overwrite16(result, tableSizeOffset, (result.size() - tableSizeOffset - 2) / 4);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SVGToOTFFontConverter::appendVHEATable(Vector&lt;char&gt;&amp; result) const
</span><span class="lines">@@ -585,7 +565,7 @@
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_unitsPerEm - m_boundingBox.maxY())); // Minimum top side bearing
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_boundingBox.y())); // Minimum bottom side bearing
</span><span class="cx">     write16(result, clampTo&lt;int16_t&gt;(m_unitsPerEm - m_boundingBox.y())); // Y maximum extent
</span><del>-    // WebKit draws the caret
</del><ins>+    // Since WebKit draws the caret and ignores the following values, it doesn't matter what we set them to.
</ins><span class="cx">     write16(result, 1); // Vertical caret
</span><span class="cx">     write16(result, 0); // Vertical caret
</span><span class="cx">     write16(result, 0); // &quot;Set value to 0 for non-slanted fonts&quot;
</span><span class="lines">@@ -607,11 +587,10 @@
</span><span class="cx"> {
</span><span class="cx">     for (auto&amp; unicodeRange : unicodeRanges) {
</span><span class="cx">         for (auto codepoint = unicodeRange.first; codepoint &lt;= unicodeRange.second; ++codepoint) {
</span><del>-            if (!codepoint || codepoint &gt;= std::numeric_limits&lt;Codepoint&gt;::max())
</del><ins>+            if (!m_codepointToIndexMap.isValidKey(codepoint))
</ins><span class="cx">                 continue;
</span><del>-            auto iterator = m_codepointToIndexMap.find(codepoint);
-            if (iterator != m_codepointToIndexMap.end())
-                glyphSet.add(iterator-&gt;value);
</del><ins>+            if (Glyph glyph = m_codepointToIndexMap.get(codepoint))
+                glyphSet.add(glyph);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -628,12 +607,10 @@
</span><span class="cx">                 codepoint = codepointString.characters8()[i++];
</span><span class="cx">             else
</span><span class="cx">                 U16_NEXT(codepointString.characters16(), i, codepointStringLength, codepoint);
</span><del>-
-            if (!codepoint || codepoint &gt;= std::numeric_limits&lt;Codepoint&gt;::max())
</del><ins>+            if (!m_codepointToIndexMap.isValidKey(codepoint))
</ins><span class="cx">                 continue;
</span><del>-            auto indexIter = m_codepointToIndexMap.find(codepoint);
-            if (indexIter != m_codepointToIndexMap.end())
-                glyphSet.add(indexIter-&gt;value);
</del><ins>+            if (Glyph glyph = m_codepointToIndexMap.get(codepoint))
+                glyphSet.add(glyph);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -641,46 +618,47 @@
</span><span class="cx"> void SVGToOTFFontConverter::addGlyphNames(const HashSet&lt;String&gt;&amp; glyphNames, HashSet&lt;uint16_t&gt;&amp; glyphSet) const
</span><span class="cx"> {
</span><span class="cx">     for (auto&amp; glyphName : glyphNames) {
</span><del>-        auto indexIter = m_glyphNameToIndexMap.find(glyphName);
-        if (indexIter != m_glyphNameToIndexMap.end())
-            glyphSet.add(indexIter-&gt;value);
</del><ins>+        if (Glyph glyph = m_glyphNameToIndexMap.get(glyphName))
+            glyphSet.add(glyph);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template &lt;typename T&gt;
-auto SVGToOTFFontConverter::computeKerningData(bool (T::*buildKerningPair)(SVGKerningPair&amp;) const) const -&gt; Vector&lt;KerningData&gt;
</del><ins>+void SVGToOTFFontConverter::addKerningPair(Vector&lt;KerningData&gt;&amp; data, const SVGKerningPair&amp; kerningPair) const
</ins><span class="cx"> {
</span><del>-    Vector&lt;KerningData&gt; result;
</del><ins>+    HashSet&lt;Glyph&gt; glyphSet1;
+    HashSet&lt;Glyph&gt; glyphSet2;
</ins><span class="cx"> 
</span><del>-    for (auto&amp; kernElement : childrenOfType&lt;T&gt;(m_fontElement)) {
-        SVGKerningPair kerningPair;
-        if ((kernElement.*buildKerningPair)(kerningPair)) {
-            HashSet&lt;Glyph&gt; glyphSet1;
-            HashSet&lt;Glyph&gt; glyphSet2;
</del><ins>+    addCodepointRanges(kerningPair.unicodeRange1, glyphSet1);
+    addCodepointRanges(kerningPair.unicodeRange2, glyphSet2);
+    addGlyphNames(kerningPair.glyphName1, glyphSet1);
+    addGlyphNames(kerningPair.glyphName2, glyphSet2);
+    addCodepoints(kerningPair.unicodeName1, glyphSet1);
+    addCodepoints(kerningPair.unicodeName2, glyphSet2);
</ins><span class="cx"> 
</span><del>-            addCodepointRanges(kerningPair.unicodeRange1, glyphSet1);
-            addCodepointRanges(kerningPair.unicodeRange2, glyphSet2);
-            addGlyphNames(kerningPair.glyphName1, glyphSet1);
-            addGlyphNames(kerningPair.glyphName2, glyphSet2);
-            addCodepoints(kerningPair.unicodeName1, glyphSet1);
-            addCodepoints(kerningPair.unicodeName2, glyphSet2);
-
-            // FIXME: Use table format 2 so we don't have to append each of these one by one
-            for (auto&amp; glyph1 : glyphSet1) {
-                for (auto&amp; glyph2 : glyphSet2)
-                    result.append(KerningData(glyph1, glyph2, clampTo&lt;int16_t&gt;(-kerningPair.kerning)));
-            }
-        }
</del><ins>+    // FIXME: Use table format 2 so we don't have to append each of these one by one.
+    for (auto&amp; glyph1 : glyphSet1) {
+        for (auto&amp; glyph2 : glyphSet2)
+            data.append(KerningData(glyph1, glyph2, clampTo&lt;int16_t&gt;(-kerningPair.kerning)));
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    return result;
</del><ins>+template&lt;typename T&gt; inline size_t SVGToOTFFontConverter::appendKERNSubtable(Vector&lt;char&gt;&amp; result, bool (T::*buildKerningPair)(SVGKerningPair&amp;) const, uint16_t coverage) const
+{
+    Vector&lt;KerningData&gt; kerningData;
+    for (auto&amp; element : childrenOfType&lt;T&gt;(m_fontElement)) {
+        SVGKerningPair kerningPair;
+        if ((element.*buildKerningPair)(kerningPair))
+            addKerningPair(kerningData, kerningPair);
+    }
+    return finishAppendingKERNSubtable(result, WTF::move(kerningData), coverage);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-template &lt;typename T&gt;
-size_t SVGToOTFFontConverter::appendKERNSubtable(Vector&lt;char&gt;&amp; result, bool (T::*buildKerningPair)(SVGKerningPair&amp;) const, uint16_t coverage) const
</del><ins>+size_t SVGToOTFFontConverter::finishAppendingKERNSubtable(Vector&lt;char&gt;&amp; result, Vector&lt;KerningData&gt; kerningData, uint16_t coverage) const
</ins><span class="cx"> {
</span><del>-    Vector&lt;KerningData&gt; kerningData = computeKerningData&lt;T&gt;(buildKerningPair);
-    std::sort(kerningData.begin(), kerningData.end());
</del><ins>+    std::sort(kerningData.begin(), kerningData.end(), [](const KerningData&amp; a, const KerningData&amp; b) {
+        return a.glyph1 &lt; b.glyph1 || (a.glyph1 == b.glyph1 &amp;&amp; a.glyph2 &lt; b.glyph2);
+    });
+
</ins><span class="cx">     size_t sizeOfKerningDataTable = 14 + 6 * kerningData.size();
</span><span class="cx">     if (sizeOfKerningDataTable &gt; std::numeric_limits&lt;uint16_t&gt;::max()) {
</span><span class="cx">         kerningData.clear();
</span><span class="lines">@@ -729,9 +707,8 @@
</span><span class="cx"> 
</span><span class="cx"> static void writeCFFEncodedNumber(Vector&lt;char&gt;&amp; vector, float number)
</span><span class="cx"> {
</span><del>-    int raw = number * powf(2, 16);
-    vector.append(-1); // 0xFF
-    write32(vector, raw);
</del><ins>+    vector.append(0xFF);
+    write32(vector, number * 0x10000);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static const char rLineTo = 0x05;
</span><span class="lines">@@ -743,7 +720,7 @@
</span><span class="cx"> public:
</span><span class="cx">     CFFBuilder(Vector&lt;char&gt;&amp; cffData, float width, FloatPoint origin)
</span><span class="cx">         : m_cffData(cffData)
</span><del>-        , m_firstPoint(true)
</del><ins>+        , m_hasBoundingBox(false)
</ins><span class="cx">     {
</span><span class="cx">         writeCFFEncodedNumber(m_cffData, width);
</span><span class="cx">         writeCFFEncodedNumber(m_cffData, origin.x());
</span><span class="lines">@@ -751,48 +728,56 @@
</span><span class="cx">         m_cffData.append(rMoveTo);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void updateForConstituentPoint(FloatPoint x)
</del><ins>+    FloatRect boundingBox() const
</ins><span class="cx">     {
</span><del>-        if (m_firstPoint)
-            m_boundingBox = FloatRect(x, FloatSize());
-        else
-            m_boundingBox.extend(x);
-        m_firstPoint = false;
</del><ins>+        return m_boundingBox;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void moveTo(const FloatPoint&amp; targetPoint, bool closed, PathCoordinateMode mode) override
</del><ins>+private:
+    void updateBoundingBox(FloatPoint point)
</ins><span class="cx">     {
</span><del>-        FloatPoint destination = mode == AbsoluteCoordinates ? targetPoint : m_current + targetPoint;
-        updateForConstituentPoint(destination);
</del><ins>+        if (!m_hasBoundingBox) {
+            m_boundingBox = FloatRect(point, FloatSize());
+            m_hasBoundingBox = true;
+            return;
+        }
+        m_boundingBox.extend(point);
+    }
+
+    void writePoint(FloatPoint destination)
+    {
+        updateBoundingBox(destination);
+
</ins><span class="cx">         FloatSize delta = destination - m_current;
</span><ins>+        writeCFFEncodedNumber(m_cffData, delta.width());
+        writeCFFEncodedNumber(m_cffData, delta.height());
</ins><span class="cx"> 
</span><ins>+        m_current = destination;
+    }
+
+    virtual void moveTo(const FloatPoint&amp; targetPoint, bool closed, PathCoordinateMode mode) override
+    {
</ins><span class="cx">         if (closed &amp;&amp; m_cffData.size())
</span><span class="cx">             closePath();
</span><span class="cx"> 
</span><del>-        writeCFFEncodedNumber(m_cffData, delta.width());
-        writeCFFEncodedNumber(m_cffData, delta.height());
</del><ins>+        FloatPoint destination = mode == AbsoluteCoordinates ? targetPoint : m_current + targetPoint;
+
+        writePoint(destination);
</ins><span class="cx">         m_cffData.append(rMoveTo);
</span><span class="cx"> 
</span><del>-        m_current = destination;
</del><span class="cx">         m_startingPoint = m_current;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void lineTo(const FloatPoint&amp; targetPoint, PathCoordinateMode mode) override
</del><ins>+    virtual void lineTo(const FloatPoint&amp; targetPoint, PathCoordinateMode mode) override
</ins><span class="cx">     {
</span><span class="cx">         FloatPoint destination = mode == AbsoluteCoordinates ? targetPoint : m_current + targetPoint;
</span><del>-        updateForConstituentPoint(destination);
-        FloatSize delta = destination - m_current;
</del><span class="cx"> 
</span><del>-        writeCFFEncodedNumber(m_cffData, delta.width());
-        writeCFFEncodedNumber(m_cffData, delta.height());
</del><ins>+        writePoint(destination);
</ins><span class="cx">         m_cffData.append(rLineTo);
</span><del>-
-        m_current = destination;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void curveToCubic(const FloatPoint&amp; point1, const FloatPoint&amp; point2, const FloatPoint&amp; targetPoint, PathCoordinateMode mode) override
</del><ins>+    virtual void curveToCubic(const FloatPoint&amp; point1, const FloatPoint&amp; point2, const FloatPoint&amp; targetPoint, PathCoordinateMode mode) override
</ins><span class="cx">     {
</span><del>-        // FIXME: This can be made way faster
</del><span class="cx">         FloatPoint destination1 = point1;
</span><span class="cx">         FloatPoint destination2 = point2;
</span><span class="cx">         FloatPoint destination3 = targetPoint;
</span><span class="lines">@@ -801,48 +786,31 @@
</span><span class="cx">             destination2 += m_current;
</span><span class="cx">             destination3 += m_current;
</span><span class="cx">         }
</span><del>-        updateForConstituentPoint(destination1);
-        updateForConstituentPoint(destination2);
-        updateForConstituentPoint(destination3);
-        FloatSize delta3 = destination3 - destination2;
-        FloatSize delta2 = destination2 - destination1;
-        FloatSize delta1 = destination1 - m_current;
</del><span class="cx"> 
</span><del>-        writeCFFEncodedNumber(m_cffData, delta1.width());
-        writeCFFEncodedNumber(m_cffData, delta1.height());
-        writeCFFEncodedNumber(m_cffData, delta2.width());
-        writeCFFEncodedNumber(m_cffData, delta2.height());
-        writeCFFEncodedNumber(m_cffData, delta3.width());
-        writeCFFEncodedNumber(m_cffData, delta3.height());
</del><ins>+        writePoint(destination1);
+        writePoint(destination2);
+        writePoint(destination3);
</ins><span class="cx">         m_cffData.append(rrCurveTo);
</span><del>-
-        m_current = destination3;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void closePath() override
</del><ins>+    virtual void closePath() override
</ins><span class="cx">     {
</span><span class="cx">         if (m_current != m_startingPoint)
</span><span class="cx">             lineTo(m_startingPoint, AbsoluteCoordinates);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    FloatRect boundingBox()
-    {
-        return m_boundingBox;
-    }
-
-private:
</del><span class="cx">     Vector&lt;char&gt;&amp; m_cffData;
</span><span class="cx">     FloatPoint m_startingPoint;
</span><span class="cx">     FloatRect m_boundingBox;
</span><del>-    bool m_firstPoint;
</del><ins>+    bool m_hasBoundingBox;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-template &lt;typename T&gt;
-Vector&lt;char&gt; SVGToOTFFontConverter::transcodeGlyphPaths(float width, const T&amp; glyphElement, FloatRect&amp; boundingBox) const
</del><ins>+Vector&lt;char&gt; SVGToOTFFontConverter::transcodeGlyphPaths(float width, const SVGElement&amp; glyphOrMissingGlyphElement, FloatRect&amp; boundingBox) const
</ins><span class="cx"> {
</span><span class="cx">     Vector&lt;char&gt; result;
</span><del>-    auto&amp; dAttribute = glyphElement.fastGetAttribute(SVGNames::dAttr);
-    if (dAttribute.isEmpty()) {
</del><ins>+
+    auto&amp; dAttribute = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::dAttr);
+    if (dAttribute.isNull()) {
</ins><span class="cx">         writeCFFEncodedNumber(result, width);
</span><span class="cx">         writeCFFEncodedNumber(result, 0);
</span><span class="cx">         writeCFFEncodedNumber(result, 0);
</span><span class="lines">@@ -853,15 +821,16 @@
</span><span class="cx"> 
</span><span class="cx">     // FIXME: If we are vertical, use vert_origin_x and vert_origin_y
</span><span class="cx">     bool ok;
</span><del>-    float horizontalOriginX = glyphElement.fastGetAttribute(SVGNames::horiz_origin_xAttr).toFloat(&amp;ok);
</del><ins>+    float horizontalOriginX = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_xAttr).toFloat(&amp;ok);
+    if (!ok)
+        horizontalOriginX = m_fontFaceElement ? m_fontFaceElement-&gt;horizontalOriginX() : 0;
+    float horizontalOriginY = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_yAttr).toFloat(&amp;ok);
</ins><span class="cx">     if (!ok &amp;&amp; m_fontFaceElement)
</span><del>-        horizontalOriginX = m_fontFaceElement-&gt;horizontalOriginX();
-    float horizontalOriginY = glyphElement.fastGetAttribute(SVGNames::horiz_origin_yAttr).toFloat(&amp;ok);
-    if (!ok &amp;&amp; m_fontFaceElement)
-        horizontalOriginY = m_fontFaceElement-&gt;horizontalOriginY();
</del><ins>+        horizontalOriginY = m_fontFaceElement ? m_fontFaceElement-&gt;horizontalOriginY() : 0;
</ins><span class="cx"> 
</span><span class="cx">     CFFBuilder builder(result, width, FloatPoint(horizontalOriginX, horizontalOriginY));
</span><span class="cx">     SVGPathStringSource source(dAttribute);
</span><ins>+
</ins><span class="cx">     SVGPathParser parser;
</span><span class="cx">     parser.setCurrentSource(&amp;source);
</span><span class="cx">     parser.setCurrentConsumer(&amp;builder);
</span><span class="lines">@@ -878,33 +847,20 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template &lt;typename T&gt;
-void SVGToOTFFontConverter::appendGlyphData(const Vector&lt;char&gt;&amp; path, const T*, float horizontalAdvance, float verticalAdvance, const FloatRect&amp; boundingBox, Codepoint codepoint)
</del><ins>+void SVGToOTFFontConverter::processGlyphElement(const SVGElement&amp; glyphOrMissingGlyphElement, const SVGGlyphElement* glyphElement, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint codepoint, bool&amp; initialGlyph)
</ins><span class="cx"> {
</span><del>-    m_glyphs.append(GlyphData(path, nullptr, horizontalAdvance, verticalAdvance, boundingBox, codepoint));
-}
-
-template &lt;&gt;
-void SVGToOTFFontConverter::appendGlyphData(const Vector&lt;char&gt;&amp; path, const SVGGlyphElement* element, float horizontalAdvance, float verticalAdvance, const FloatRect&amp; boundingBox, Codepoint codepoint)
-{
-    m_glyphs.append(GlyphData(path, element, horizontalAdvance, verticalAdvance, boundingBox, codepoint));
-}
-
-template &lt;typename T&gt;
-void SVGToOTFFontConverter::processGlyphElement(const T&amp; element, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint codepoint, bool&amp; initialGlyph)
-{
</del><span class="cx">     bool ok;
</span><del>-    float horizontalAdvance = element.fastGetAttribute(SVGNames::horiz_adv_xAttr).toFloat(&amp;ok);
</del><ins>+    float horizontalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toFloat(&amp;ok);
</ins><span class="cx">     if (!ok)
</span><span class="cx">         horizontalAdvance = defaultHorizontalAdvance;
</span><span class="cx">     m_advanceWidthMax = std::max(m_advanceWidthMax, horizontalAdvance);
</span><del>-    float verticalAdvance = element.fastGetAttribute(SVGNames::vert_adv_yAttr).toFloat(&amp;ok);
</del><ins>+    float verticalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::vert_adv_yAttr).toFloat(&amp;ok);
</ins><span class="cx">     if (!ok)
</span><span class="cx">         verticalAdvance = defaultVerticalAdvance;
</span><span class="cx">     m_advanceHeightMax = std::max(m_advanceHeightMax, verticalAdvance);
</span><span class="cx"> 
</span><span class="cx">     FloatRect glyphBoundingBox;
</span><del>-    auto path = transcodeGlyphPaths(horizontalAdvance, element, glyphBoundingBox);
</del><ins>+    auto path = transcodeGlyphPaths(horizontalAdvance, glyphOrMissingGlyphElement, glyphBoundingBox);
</ins><span class="cx">     if (initialGlyph)
</span><span class="cx">         m_boundingBox = glyphBoundingBox;
</span><span class="cx">     else
</span><span class="lines">@@ -912,7 +868,7 @@
</span><span class="cx">     m_minRightSideBearing = std::min(m_minRightSideBearing, horizontalAdvance - glyphBoundingBox.maxX());
</span><span class="cx">     initialGlyph = false;
</span><span class="cx"> 
</span><del>-    appendGlyphData(path, &amp;element, horizontalAdvance, verticalAdvance, glyphBoundingBox, codepoint);
</del><ins>+    m_glyphs.append(GlyphData(WTF::move(path), glyphElement, horizontalAdvance, verticalAdvance, m_boundingBox, codepoint));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SVGToOTFFontConverter::SVGToOTFFontConverter(const SVGFontElement&amp; fontElement)
</span><span class="lines">@@ -935,7 +891,7 @@
</span><span class="cx">         m_unitsPerEm = m_fontFaceElement-&gt;unitsPerEm();
</span><span class="cx"> 
</span><span class="cx">     if (m_missingGlyphElement)
</span><del>-        processGlyphElement(*m_missingGlyphElement, defaultHorizontalAdvance, defaultVerticalAdvance, 0, initialGlyph);
</del><ins>+        processGlyphElement(*m_missingGlyphElement, nullptr, defaultHorizontalAdvance, defaultVerticalAdvance, 0, initialGlyph);
</ins><span class="cx">     else {
</span><span class="cx">         Vector&lt;char&gt; notdefCharString;
</span><span class="cx">         writeCFFEncodedNumber(notdefCharString, m_unitsPerEm);
</span><span class="lines">@@ -943,18 +899,17 @@
</span><span class="cx">         writeCFFEncodedNumber(notdefCharString, 0);
</span><span class="cx">         notdefCharString.append(rMoveTo);
</span><span class="cx">         notdefCharString.append(endChar);
</span><del>-        m_glyphs.append(GlyphData(notdefCharString, nullptr, m_unitsPerEm, m_unitsPerEm, FloatRect(), 0));
</del><ins>+        m_glyphs.append(GlyphData(WTF::move(notdefCharString), nullptr, m_unitsPerEm, m_unitsPerEm, FloatRect(), 0));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     for (auto&amp; glyphElement : childrenOfType&lt;SVGGlyphElement&gt;(m_fontElement)) {
</span><span class="cx">         auto&amp; unicodeAttribute = glyphElement.fastGetAttribute(SVGNames::unicodeAttr);
</span><span class="cx">         // Only support Basic Multilingual Plane w/o ligatures for now
</span><span class="cx">         if (unicodeAttribute.length() == 1)
</span><del>-            processGlyphElement(glyphElement, defaultHorizontalAdvance, defaultVerticalAdvance, unicodeAttribute[0], initialGlyph);
</del><ins>+            processGlyphElement(glyphElement, &amp;glyphElement, defaultHorizontalAdvance, defaultVerticalAdvance, unicodeAttribute[0], initialGlyph);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_glyphs.size() &gt; std::numeric_limits&lt;Glyph&gt;::max()) {
</span><del>-        // This will break all sorts of things. Bail early instead.
</del><span class="cx">         m_glyphs.clear();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -967,55 +922,56 @@
</span><span class="cx">         GlyphData&amp; glyph = m_glyphs[i];
</span><span class="cx">         if (glyph.glyphElement) {
</span><span class="cx">             auto&amp; glyphName = glyph.glyphElement-&gt;fastGetAttribute(SVGNames::glyph_nameAttr);
</span><del>-            if (!glyphName.isEmpty())
</del><ins>+            if (!glyphName.isNull())
</ins><span class="cx">                 m_glyphNameToIndexMap.add(glyphName, i);
</span><span class="cx">         }
</span><del>-        if (glyph.codepoint)
</del><ins>+        if (m_codepointToIndexMap.isValidKey(glyph.codepoint))
</ins><span class="cx">             m_codepointToIndexMap.add(glyph.codepoint, i);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // FIXME: Handle commas
</del><ins>+    // FIXME: Handle commas.
</ins><span class="cx">     if (m_fontFaceElement) {
</span><del>-        auto&amp; fontWeightAttribute = m_fontFaceElement-&gt;fastGetAttribute(SVGNames::font_weightAttr);
-        Vector&lt;String&gt; split;
-        fontWeightAttribute.string().split(&quot; &quot;, split);
-        for (auto&amp; segment : split) {
-            if (segment == &quot;bold&quot;)
</del><ins>+        Vector&lt;String&gt; segments;
+        m_fontFaceElement-&gt;fastGetAttribute(SVGNames::font_weightAttr).string().split(' ', segments);
+        for (auto&amp; segment : segments) {
+            if (equalIgnoringCase(segment, &quot;bold&quot;)) {
</ins><span class="cx">                 m_weight = 7;
</span><ins>+                break;
+            }
</ins><span class="cx">             bool ok;
</span><span class="cx">             int value = segment.toInt(&amp;ok);
</span><del>-            if (ok &amp;&amp; value &gt;= 0 &amp;&amp; value &lt; 1000)
-                m_weight = value / 100;
</del><ins>+            if (ok &amp;&amp; value &gt;= 0 &amp;&amp; value &lt; 1000) {
+                m_weight = (value + 50) / 100;
+                break;
+            }
</ins><span class="cx">         }
</span><del>-        auto&amp; fontStyleAttribute = m_fontFaceElement-&gt;fastGetAttribute(SVGNames::font_weightAttr);
-        split.clear();
-        String(fontStyleAttribute).split(&quot; &quot;, split);
-        for (auto&amp; s : split) {
-            if (s == &quot;italic&quot; || s == &quot;oblique&quot;)
</del><ins>+        m_fontFaceElement-&gt;fastGetAttribute(SVGNames::font_styleAttr).string().split(' ', segments);
+        for (auto&amp; segment : segments) {
+            if (equalIgnoringCase(segment, &quot;italic&quot;) || equalIgnoringCase(segment, &quot;oblique&quot;)) {
</ins><span class="cx">                 m_italic = true;
</span><ins>+                break;
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Might not be quite what I want
</del><span class="cx">     if (m_fontFaceElement)
</span><span class="cx">         m_fontFamily = m_fontFaceElement-&gt;fontFamily();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static inline bool isFourByteAligned(size_t x)
</span><span class="cx"> {
</span><del>-    return !(x &amp; sizeof(uint32_t)-1);
</del><ins>+    return !(x &amp; 3);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static uint32_t calculateChecksum(const Vector&lt;char&gt;&amp; table, size_t startingOffset, size_t endingOffset)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isFourByteAligned(endingOffset - startingOffset));
</span><span class="cx">     uint32_t sum = 0;
</span><del>-    for (; startingOffset &lt; endingOffset; startingOffset += 4) {
-        // The spec is unclear whether this is a little-endian sum or a big-endian sum. Choose little endian.
-        sum += (static_cast&lt;unsigned char&gt;(table[startingOffset + 3]) &lt;&lt; 24)
-            | (static_cast&lt;unsigned char&gt;(table[startingOffset + 2]) &lt;&lt; 16)
-            | (static_cast&lt;unsigned char&gt;(table[startingOffset + 1]) &lt;&lt; 8)
-            | static_cast&lt;unsigned char&gt;(table[startingOffset]);
</del><ins>+    for (size_t offset = startingOffset; offset &lt; endingOffset; offset += 4) {
+        sum += (static_cast&lt;unsigned char&gt;(table[offset + 3]) &lt;&lt; 24)
+            | (static_cast&lt;unsigned char&gt;(table[offset + 2]) &lt;&lt; 16)
+            | (static_cast&lt;unsigned char&gt;(table[offset + 1]) &lt;&lt; 8)
+            | static_cast&lt;unsigned char&gt;(table[offset]);
</ins><span class="cx">     }
</span><span class="cx">     return sum;
</span><span class="cx"> }
</span><span class="lines">@@ -1029,7 +985,7 @@
</span><span class="cx">     while (!isFourByteAligned(output.size()))
</span><span class="cx">         output.append(0);
</span><span class="cx">     ASSERT(isFourByteAligned(output.size()));
</span><del>-    size_t directoryEntryOffset = kSNFTHeaderSize + m_tablesAppendedCount * kDirectoryEntrySize;
</del><ins>+    size_t directoryEntryOffset = headerSize + m_tablesAppendedCount * directoryEntrySize;
</ins><span class="cx">     output[directoryEntryOffset] = identifier[0];
</span><span class="cx">     output[directoryEntryOffset + 1] = identifier[1];
</span><span class="cx">     output[directoryEntryOffset + 2] = identifier[2];
</span><span class="lines">@@ -1043,7 +999,8 @@
</span><span class="cx"> Vector&lt;char&gt; SVGToOTFFontConverter::convertSVGToOTFFont()
</span><span class="cx"> {
</span><span class="cx">     Vector&lt;char&gt; result;
</span><del>-    if (!m_glyphs.size())
</del><ins>+
+    if (m_glyphs.isEmpty())
</ins><span class="cx">         return result;
</span><span class="cx"> 
</span><span class="cx">     uint16_t numTables = 13;
</span><span class="lines">@@ -1059,10 +1016,10 @@
</span><span class="cx">     write16(result, integralLog2(roundedNumTables)); // entrySelector: &quot;Log2(maximum power of 2 &lt;= numTables).&quot;
</span><span class="cx">     write16(result, numTables * 16 - searchRange); // rangeShift: &quot;NumTables x 16-searchRange.&quot;
</span><span class="cx"> 
</span><del>-    ASSERT(result.size() == kSNFTHeaderSize);
</del><ins>+    ASSERT(result.size() == headerSize);
</ins><span class="cx"> 
</span><del>-    // Leave space for the Directory Entries
-    for (size_t i = 0; i &lt; kDirectoryEntrySize * numTables; ++i)
</del><ins>+    // Leave space for the directory entries.
+    for (size_t i = 0; i &lt; directoryEntrySize * numTables; ++i)
</ins><span class="cx">         result.append(0);
</span><span class="cx"> 
</span><span class="cx">     appendTable(&quot;CFF &quot;, result, &amp;SVGToOTFFontConverter::appendCFFTable);
</span><span class="lines">@@ -1082,10 +1039,9 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(numTables == m_tablesAppendedCount);
</span><span class="cx"> 
</span><del>-    // checkSumAdjustment: &quot;To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory,
</del><ins>+    // checksumAdjustment: &quot;To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory,
</ins><span class="cx">     // sum the entire font as uint32, then store B1B0AFBA - sum. The checksum for the 'head' table will now be wrong. That is OK.&quot;
</span><del>-    uint32_t checksumAdjustment = 0xB1B0AFBAU - calculateChecksum(result, 0, result.size());
-    overwrite32(result, headTableOffset + 8, checksumAdjustment);
</del><ins>+    overwrite32(result, headTableOffset + 8, 0xB1B0AFBAU - calculateChecksum(result, 0, result.size()));
</ins><span class="cx"> 
</span><span class="cx">     return result;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (174062 => 174063)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2014-09-29 15:37:17 UTC (rev 174062)
+++ trunk/Tools/ChangeLog        2014-09-29 16:26:59 UTC (rev 174063)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2014-09-29  Darin Adler  &lt;darin@apple.com&gt;
+
+        Tweak and tighten SVG font converter
+        https://bugs.webkit.org/show_bug.cgi?id=136956
+
+        Reviewed by Myles Maxfield.
+
+        I was investigating behavior of String::toInt, String::toDouble, and
+        String::toFloat for various failure cases, and decided to start some
+        unit tests for those functions here.
+
+        * TestWebKitAPI/Tests/WTF/WTFString.cpp:
+        (TestWebKitAPI::TEST): Addded a first small bit of StringToInt and
+        StringToDouble testing.
+
</ins><span class="cx"> 2014-09-29  Philippe Normand  &lt;pnormand@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK][CMake] TestWebCore target build sometimes fail
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFWTFStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp (174062 => 174063)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp        2014-09-29 15:37:17 UTC (rev 174062)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/WTFString.cpp        2014-09-29 16:26:59 UTC (rev 174063)
</span><span class="lines">@@ -160,4 +160,104 @@
</span><span class="cx">     ASSERT_FALSE(original.impl() == copy.impl());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST(WTF, StringToInt)
+{
+    bool ok;
+
+    EXPECT_EQ(0, String().toInt());
+    EXPECT_EQ(0, String().toInt(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    EXPECT_EQ(0, emptyString().toInt());
+    EXPECT_EQ(0, emptyString().toInt(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    EXPECT_EQ(0, String(&quot;0&quot;).toInt());
+    EXPECT_EQ(0, String(&quot;0&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    EXPECT_EQ(1, String(&quot;1&quot;).toInt());
+    EXPECT_EQ(1, String(&quot;1&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    EXPECT_EQ(2147483647, String(&quot;2147483647&quot;).toInt());
+    EXPECT_EQ(2147483647, String(&quot;2147483647&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    EXPECT_EQ(0, String(&quot;2147483648&quot;).toInt());
+    EXPECT_EQ(0, String(&quot;2147483648&quot;).toInt(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    EXPECT_EQ(-2147483648, String(&quot;-2147483648&quot;).toInt());
+    EXPECT_EQ(-2147483648, String(&quot;-2147483648&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    EXPECT_EQ(0, String(&quot;-2147483649&quot;).toInt());
+    EXPECT_EQ(0, String(&quot;-2147483649&quot;).toInt(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    // fail if we see leading junk
+    EXPECT_EQ(0, String(&quot;x1&quot;).toInt());
+    EXPECT_EQ(0, String(&quot;x1&quot;).toInt(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    // succeed if we see leading spaces
+    EXPECT_EQ(1, String(&quot; 1&quot;).toInt());
+    EXPECT_EQ(1, String(&quot; 1&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    // silently ignore trailing junk
+    EXPECT_EQ(1, String(&quot;1x&quot;).toInt());
+    EXPECT_EQ(1, String(&quot;1x&quot;).toInt(&amp;ok));
+    EXPECT_EQ(true, ok);
+}
+
+TEST(WTF, StringToDouble)
+{
+    bool ok;
+
+    EXPECT_EQ(0.0, String().toDouble());
+    EXPECT_EQ(0.0, String().toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    EXPECT_EQ(0.0, emptyString().toDouble());
+    EXPECT_EQ(0.0, emptyString().toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    EXPECT_EQ(0.0, String(&quot;0&quot;).toDouble());
+    EXPECT_EQ(0.0, String(&quot;0&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    EXPECT_EQ(1.0, String(&quot;1&quot;).toDouble());
+    EXPECT_EQ(1.0, String(&quot;1&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    // fail if we see leading junk
+    EXPECT_EQ(0.0, String(&quot;x1&quot;).toDouble());
+    EXPECT_EQ(0.0, String(&quot;x1&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    // succeed if we see leading spaces
+    EXPECT_EQ(1.0, String(&quot; 1&quot;).toDouble());
+    EXPECT_EQ(1.0, String(&quot; 1&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(true, ok);
+
+    // ignore trailing junk, but return false for &quot;ok&quot;
+    // FIXME: This is an inconsistency with toInt, which always guarantees
+    // it will return 0 if it's also going to return false for ok.
+    EXPECT_EQ(1.0, String(&quot;1x&quot;).toDouble());
+    EXPECT_EQ(1.0, String(&quot;1x&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    // parse only numbers, not special values such as &quot;infinity&quot;
+    EXPECT_EQ(0.0, String(&quot;infinity&quot;).toDouble());
+    EXPECT_EQ(0.0, String(&quot;infinity&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+
+    // parse only numbers, not special values such as &quot;nan&quot;
+    EXPECT_EQ(0.0, String(&quot;nan&quot;).toDouble());
+    EXPECT_EQ(0.0, String(&quot;nan&quot;).toDouble(&amp;ok));
+    EXPECT_EQ(false, ok);
+}
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>

</body>
</html>