<!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 < 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 "k" 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 "no weight" 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 "false" 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 < 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 "first wins" instead of "last wins" 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 <darin@apple.com>
+
+ 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 < 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 "k" 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 "no weight" 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 "false" 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 < 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 "first wins" instead of "last wins" 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 <cgarcia@igalia.com>
</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<char>& vector, unsigned location, uint32_t value)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(vector.size() >= location + 4);
</span><del>- *(vector.data() + location) = value >> 24;
- *(vector.data() + location + 1) = value >> 16;
- *(vector.data() + location + 2) = value >> 8;
- *(vector.data() + location + 3) = value;
</del><ins>+ vector[location] = value >> 24;
+ vector[location + 1] = value >> 16;
+ vector[location + 2] = value >> 8;
+ vector[location + 3] = value;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+static inline void overwrite16(Vector<char>& vector, unsigned location, uint16_t value)
+{
+ ASSERT(vector.size() >= location + 2);
+ vector[location] = value >> 8;
+ vector[location + 1] = value;
+}
+
</ins><span class="cx"> class SVGToOTFFontConverter {
</span><span class="cx"> public:
</span><span class="cx"> SVGToOTFFontConverter(const SVGFontElement&);
</span><span class="cx"> Vector<char> 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<char> charString, const SVGGlyphElement* glyphElement, float horizontalAdvance, float verticalAdvance, FloatRect boundingBox, Codepoint codepoint)
</del><ins>+ GlyphData(Vector<char>&& 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<(const KerningData& other) const
- {
- return glyph1 < other.glyph1 || (glyph1 == other.glyph1 && glyph2 < 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& glyphOrMissingGlyphElement, const SVGGlyphElement*, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint, bool& initialGlyph);
</ins><span class="cx">
</span><del>- template <typename T>
- void appendGlyphData(const Vector<char>& path, const T* element, float horizontalAdvance, float verticalAdvance, const FloatRect& boundingBox, Codepoint codepoint);
- template <typename T>
- void processGlyphElement(const T& element, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint, bool& initialGlyph);
-
</del><span class="cx"> typedef void (SVGToOTFFontConverter::*FontAppendingFunction)(Vector<char> &) const;
</span><span class="cx"> void appendTable(const char identifier[4], Vector<char>&, FontAppendingFunction);
</span><span class="cx"> void appendCMAPTable(Vector<char>&) const;
</span><span class="lines">@@ -130,20 +129,18 @@
</span><span class="cx"> void appendCFFTable(Vector<char>&) const;
</span><span class="cx"> void appendVORGTable(Vector<char>&) const;
</span><span class="cx">
</span><del>- template <typename T>
- Vector<char> transcodeGlyphPaths(float width, const T& glyphElement, FloatRect& boundingBox) const;
</del><ins>+ Vector<char> transcodeGlyphPaths(float width, const SVGElement& glyphOrMissingGlyphElement, FloatRect& boundingBox) const;
</ins><span class="cx">
</span><span class="cx"> void addCodepointRanges(const UnicodeRanges&, HashSet<uint16_t>& glyphSet) const;
</span><span class="cx"> void addCodepoints(const HashSet<String>& codepoints, HashSet<uint16_t>& glyphSet) const;
</span><span class="cx"> void addGlyphNames(const HashSet<String>& glyphNames, HashSet<uint16_t>& glyphSet) const;
</span><del>- template <typename T>
- Vector<KerningData> computeKerningData(bool (T::*buildKerningPair)(SVGKerningPair&) const) const;
- template <typename T>
- size_t appendKERNSubtable(Vector<char>& result, bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage) const;
</del><ins>+ void addKerningPair(Vector<KerningData>&, const SVGKerningPair&) const;
+ template<typename T> size_t appendKERNSubtable(Vector<char>& result, bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage) const;
+ size_t finishAppendingKERNSubtable(Vector<char>& result, Vector<KerningData>, uint16_t coverage) const;
</ins><span class="cx">
</span><span class="cx"> Vector<GlyphData> m_glyphs;
</span><span class="cx"> HashMap<String, Glyph> m_glyphNameToIndexMap; // SVG 1.1: "It is recommended that glyph names be unique within a font."
</span><del>- HashMap<Codepoint, Glyph> m_codepointToIndexMap; // FIXME: There might be many glyphs that map to a single codepoint.
</del><ins>+ HashMap<UChar32, Glyph> 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& m_fontElement;
</span><span class="cx"> const SVGFontFaceElement* m_fontFaceElement;
</span><span class="lines">@@ -167,7 +164,8 @@
</span><span class="cx"> return (x >> 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 >>= 1)
</span><span class="cx"> ++result;
</span><span class="lines">@@ -204,9 +202,9 @@
</span><span class="cx"> for (auto& 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 < m_glyphs.size(); ++i) {
</del><ins>+ for (Glyph i = 0; i < m_glyphs.size(); ++i) {
</ins><span class="cx"> // Note that this value can be "negative," but that is okay because wrapping is defined and expected here
</span><del>- write16(result, static_cast<uint16_t>(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 < 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. "Set to 0x5F0F3CF5"
- 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 << 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 <typename T1, typename T2>
-static inline T1 clampTo(T2 x)
</del><ins>+// Assumption: T2 can hold every value that a T1 can hold.
+template<typename T1, typename T2> static inline T1 clampTo(T2 x)
</ins><span class="cx"> {
</span><span class="cx"> x = std::min(x, static_cast<T2>(std::numeric_limits<T1>::max()));
</span><span class="cx"> x = std::max(x, static_cast<T2>(std::numeric_limits<T1>::min()));
</span><span class="lines">@@ -253,33 +246,34 @@
</span><span class="cx">
</span><span class="cx"> void SVGToOTFFontConverter::appendHHEATable(Vector<char>& result) const
</span><span class="cx"> {
</span><del>- int16_t ascent = std::numeric_limits<int16_t>::max();
- int16_t descent = std::numeric_limits<int16_t>::max();
- if (m_fontFaceElement) {
</del><ins>+ int16_t ascent;
+ int16_t descent;
+ if (!m_fontFaceElement) {
+ ascent = std::numeric_limits<int16_t>::max();
+ descent = std::numeric_limits<int16_t>::max();
+ } else {
</ins><span class="cx"> ascent = m_fontFaceElement->ascent();
</span><span class="cx"> descent = m_fontFaceElement->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<uint16_t>(m_advanceWidthMax));
</span><span class="cx"> write16(result, clampTo<int16_t>(m_boundingBox.x())); // Minimum left side bearing
</span><span class="cx"> write16(result, clampTo<int16_t>(m_minRightSideBearing)); // Minimum right side bearing
</span><span class="cx"> write16(result, clampTo<int16_t>(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); // "Set value to 0 for non-slanted fonts"
</span><span class="lines">@@ -336,16 +330,12 @@
</span><span class="cx"> void SVGToOTFFontConverter::appendOS2Table(Vector<char>& result) const
</span><span class="cx"> {
</span><span class="cx"> int16_t averageAdvance = m_unitsPerEm;
</span><del>- auto& attribute = m_fontElement.fastGetAttribute(SVGNames::horiz_adv_xAttr);
</del><span class="cx"> bool ok;
</span><del>- int value = attribute.toInt(&ok);
</del><ins>+ int value = m_fontElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&ok);
+ if (!ok && m_missingGlyphElement)
+ value = m_missingGlyphElement->fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&ok);
</ins><span class="cx"> if (ok)
</span><span class="cx"> averageAdvance = clampTo<int16_t>(value);
</span><del>- else if (m_missingGlyphElement) {
- int value = m_missingGlyphElement->fastGetAttribute(SVGNames::horiz_adv_xAttr).toInt(&ok);
- if (ok)
- averageAdvance = clampTo<int16_t>(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<unsigned char> specifiedPanose;
</del><ins>+ unsigned numPanoseBytes = 0;
+ const unsigned panoseSize = 10;
+ char panoseBytes[panoseSize];
</ins><span class="cx"> if (m_fontFaceElement) {
</span><del>- auto& attribute = m_fontFaceElement->fastGetAttribute(SVGNames::panose_1Attr);
- Vector<String> split;
- String(attribute).split(" ", split);
- if (split.size() == 10) {
- for (auto& s : split) {
- bool ok = true;
- int value = s.toInt(&ok);
- if (!ok || value < 0 || value > 0xFF) {
- specifiedPanose.clear();
- break;
- }
- specifiedPanose.append(static_cast<unsigned char>(value));
</del><ins>+ Vector<String> segments;
+ m_fontFaceElement->fastGetAttribute(SVGNames::panose_1Attr).string().split(' ', segments);
+ if (segments.size() == panoseSize) {
+ for (auto& segment : segments) {
+ bool ok;
+ int value = segment.toInt(&ok);
+ if (ok && value >= 0 && value <= 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 < 10; ++i)
- result.append(0); // PANOSE: Any
- }
-
</del><span class="cx"> for (int i = 0; i < 4; ++i)
</span><span class="cx"> write32(result, 0); // "Bit assignments are pending. Set to 0"
</span><span class="cx"> write32(result, 0x544B4257); // Font Vendor. "WBKT"
</span><span class="cx"> write16(result, (m_weight >= 7 ? 1 << 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<char>& 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<char>& output, const String& string)
</del><ins>+static void appendValidCFFString(Vector<char>& output, const String& string)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(isValidStringForCFF(string));
</span><span class="cx"> for (unsigned i = 0; i < string.length(); ++i)
</span><span class="lines">@@ -431,6 +414,7 @@
</span><span class="cx"> void SVGToOTFFontConverter::appendCFFTable(Vector<char>& 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 < m_glyphs.size(); ++i)
</del><ins>+ for (Glyph i = 1; i < 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<int16_t>(m_missingGlyphElement->fastGetAttribute(SVGNames::vert_origin_yAttr).toInt());
</span><span class="cx"> write16(result, defaultVerticalOriginY);
</span><span class="cx">
</span><del>- Vector<std::pair<uint16_t, int16_t>> origins;
- for (uint16_t i = 0; i < m_glyphs.size(); ++i) {
- if (m_glyphs[i].glyphElement) {
- auto& attribute = m_glyphs[i].glyphElement->fastGetAttribute(SVGNames::vert_origin_yAttr);
- if (attribute != nullAtom && attribute.is8Bit()) {
- bool ok;
- int16_t verticalOriginY = attribute.toInt(&ok);
- if (ok && 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 < m_glyphs.size(); ++i) {
+ if (auto* glyph = m_glyphs[i].glyphElement) {
+ if (int16_t verticalOriginY = clampTo<int16_t>(glyph->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& 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<char>& result) const
</span><span class="lines">@@ -585,7 +565,7 @@
</span><span class="cx"> write16(result, clampTo<int16_t>(m_unitsPerEm - m_boundingBox.maxY())); // Minimum top side bearing
</span><span class="cx"> write16(result, clampTo<int16_t>(m_boundingBox.y())); // Minimum bottom side bearing
</span><span class="cx"> write16(result, clampTo<int16_t>(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); // "Set value to 0 for non-slanted fonts"
</span><span class="lines">@@ -607,11 +587,10 @@
</span><span class="cx"> {
</span><span class="cx"> for (auto& unicodeRange : unicodeRanges) {
</span><span class="cx"> for (auto codepoint = unicodeRange.first; codepoint <= unicodeRange.second; ++codepoint) {
</span><del>- if (!codepoint || codepoint >= std::numeric_limits<Codepoint>::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->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 >= std::numeric_limits<Codepoint>::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->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<String>& glyphNames, HashSet<uint16_t>& glyphSet) const
</span><span class="cx"> {
</span><span class="cx"> for (auto& glyphName : glyphNames) {
</span><del>- auto indexIter = m_glyphNameToIndexMap.find(glyphName);
- if (indexIter != m_glyphNameToIndexMap.end())
- glyphSet.add(indexIter->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 <typename T>
-auto SVGToOTFFontConverter::computeKerningData(bool (T::*buildKerningPair)(SVGKerningPair&) const) const -> Vector<KerningData>
</del><ins>+void SVGToOTFFontConverter::addKerningPair(Vector<KerningData>& data, const SVGKerningPair& kerningPair) const
</ins><span class="cx"> {
</span><del>- Vector<KerningData> result;
</del><ins>+ HashSet<Glyph> glyphSet1;
+ HashSet<Glyph> glyphSet2;
</ins><span class="cx">
</span><del>- for (auto& kernElement : childrenOfType<T>(m_fontElement)) {
- SVGKerningPair kerningPair;
- if ((kernElement.*buildKerningPair)(kerningPair)) {
- HashSet<Glyph> glyphSet1;
- HashSet<Glyph> 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& glyph1 : glyphSet1) {
- for (auto& glyph2 : glyphSet2)
- result.append(KerningData(glyph1, glyph2, clampTo<int16_t>(-kerningPair.kerning)));
- }
- }
</del><ins>+ // FIXME: Use table format 2 so we don't have to append each of these one by one.
+ for (auto& glyph1 : glyphSet1) {
+ for (auto& glyph2 : glyphSet2)
+ data.append(KerningData(glyph1, glyph2, clampTo<int16_t>(-kerningPair.kerning)));
</ins><span class="cx"> }
</span><ins>+}
</ins><span class="cx">
</span><del>- return result;
</del><ins>+template<typename T> inline size_t SVGToOTFFontConverter::appendKERNSubtable(Vector<char>& result, bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage) const
+{
+ Vector<KerningData> kerningData;
+ for (auto& element : childrenOfType<T>(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 <typename T>
-size_t SVGToOTFFontConverter::appendKERNSubtable(Vector<char>& result, bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage) const
</del><ins>+size_t SVGToOTFFontConverter::finishAppendingKERNSubtable(Vector<char>& result, Vector<KerningData> kerningData, uint16_t coverage) const
</ins><span class="cx"> {
</span><del>- Vector<KerningData> kerningData = computeKerningData<T>(buildKerningPair);
- std::sort(kerningData.begin(), kerningData.end());
</del><ins>+ std::sort(kerningData.begin(), kerningData.end(), [](const KerningData& a, const KerningData& b) {
+ return a.glyph1 < b.glyph1 || (a.glyph1 == b.glyph1 && a.glyph2 < b.glyph2);
+ });
+
</ins><span class="cx"> size_t sizeOfKerningDataTable = 14 + 6 * kerningData.size();
</span><span class="cx"> if (sizeOfKerningDataTable > std::numeric_limits<uint16_t>::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<char>& 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<char>& 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& 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& targetPoint, bool closed, PathCoordinateMode mode) override
+ {
</ins><span class="cx"> if (closed && 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& targetPoint, PathCoordinateMode mode) override
</del><ins>+ virtual void lineTo(const FloatPoint& 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& point1, const FloatPoint& point2, const FloatPoint& targetPoint, PathCoordinateMode mode) override
</del><ins>+ virtual void curveToCubic(const FloatPoint& point1, const FloatPoint& point2, const FloatPoint& 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<char>& 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 <typename T>
-Vector<char> SVGToOTFFontConverter::transcodeGlyphPaths(float width, const T& glyphElement, FloatRect& boundingBox) const
</del><ins>+Vector<char> SVGToOTFFontConverter::transcodeGlyphPaths(float width, const SVGElement& glyphOrMissingGlyphElement, FloatRect& boundingBox) const
</ins><span class="cx"> {
</span><span class="cx"> Vector<char> result;
</span><del>- auto& dAttribute = glyphElement.fastGetAttribute(SVGNames::dAttr);
- if (dAttribute.isEmpty()) {
</del><ins>+
+ auto& 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(&ok);
</del><ins>+ float horizontalOriginX = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_xAttr).toFloat(&ok);
+ if (!ok)
+ horizontalOriginX = m_fontFaceElement ? m_fontFaceElement->horizontalOriginX() : 0;
+ float horizontalOriginY = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_origin_yAttr).toFloat(&ok);
</ins><span class="cx"> if (!ok && m_fontFaceElement)
</span><del>- horizontalOriginX = m_fontFaceElement->horizontalOriginX();
- float horizontalOriginY = glyphElement.fastGetAttribute(SVGNames::horiz_origin_yAttr).toFloat(&ok);
- if (!ok && m_fontFaceElement)
- horizontalOriginY = m_fontFaceElement->horizontalOriginY();
</del><ins>+ horizontalOriginY = m_fontFaceElement ? m_fontFaceElement->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(&source);
</span><span class="cx"> parser.setCurrentConsumer(&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 <typename T>
-void SVGToOTFFontConverter::appendGlyphData(const Vector<char>& path, const T*, float horizontalAdvance, float verticalAdvance, const FloatRect& boundingBox, Codepoint codepoint)
</del><ins>+void SVGToOTFFontConverter::processGlyphElement(const SVGElement& glyphOrMissingGlyphElement, const SVGGlyphElement* glyphElement, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint codepoint, bool& initialGlyph)
</ins><span class="cx"> {
</span><del>- m_glyphs.append(GlyphData(path, nullptr, horizontalAdvance, verticalAdvance, boundingBox, codepoint));
-}
-
-template <>
-void SVGToOTFFontConverter::appendGlyphData(const Vector<char>& path, const SVGGlyphElement* element, float horizontalAdvance, float verticalAdvance, const FloatRect& boundingBox, Codepoint codepoint)
-{
- m_glyphs.append(GlyphData(path, element, horizontalAdvance, verticalAdvance, boundingBox, codepoint));
-}
-
-template <typename T>
-void SVGToOTFFontConverter::processGlyphElement(const T& element, float defaultHorizontalAdvance, float defaultVerticalAdvance, Codepoint codepoint, bool& initialGlyph)
-{
</del><span class="cx"> bool ok;
</span><del>- float horizontalAdvance = element.fastGetAttribute(SVGNames::horiz_adv_xAttr).toFloat(&ok);
</del><ins>+ float horizontalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::horiz_adv_xAttr).toFloat(&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(&ok);
</del><ins>+ float verticalAdvance = glyphOrMissingGlyphElement.fastGetAttribute(SVGNames::vert_adv_yAttr).toFloat(&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, &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& fontElement)
</span><span class="lines">@@ -935,7 +891,7 @@
</span><span class="cx"> m_unitsPerEm = m_fontFaceElement->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<char> 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& glyphElement : childrenOfType<SVGGlyphElement>(m_fontElement)) {
</span><span class="cx"> auto& 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, &glyphElement, defaultHorizontalAdvance, defaultVerticalAdvance, unicodeAttribute[0], initialGlyph);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (m_glyphs.size() > std::numeric_limits<Glyph>::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& glyph = m_glyphs[i];
</span><span class="cx"> if (glyph.glyphElement) {
</span><span class="cx"> auto& glyphName = glyph.glyphElement->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& fontWeightAttribute = m_fontFaceElement->fastGetAttribute(SVGNames::font_weightAttr);
- Vector<String> split;
- fontWeightAttribute.string().split(" ", split);
- for (auto& segment : split) {
- if (segment == "bold")
</del><ins>+ Vector<String> segments;
+ m_fontFaceElement->fastGetAttribute(SVGNames::font_weightAttr).string().split(' ', segments);
+ for (auto& segment : segments) {
+ if (equalIgnoringCase(segment, "bold")) {
</ins><span class="cx"> m_weight = 7;
</span><ins>+ break;
+ }
</ins><span class="cx"> bool ok;
</span><span class="cx"> int value = segment.toInt(&ok);
</span><del>- if (ok && value >= 0 && value < 1000)
- m_weight = value / 100;
</del><ins>+ if (ok && value >= 0 && value < 1000) {
+ m_weight = (value + 50) / 100;
+ break;
+ }
</ins><span class="cx"> }
</span><del>- auto& fontStyleAttribute = m_fontFaceElement->fastGetAttribute(SVGNames::font_weightAttr);
- split.clear();
- String(fontStyleAttribute).split(" ", split);
- for (auto& s : split) {
- if (s == "italic" || s == "oblique")
</del><ins>+ m_fontFaceElement->fastGetAttribute(SVGNames::font_styleAttr).string().split(' ', segments);
+ for (auto& segment : segments) {
+ if (equalIgnoringCase(segment, "italic") || equalIgnoringCase(segment, "oblique")) {
</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->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 & sizeof(uint32_t)-1);
</del><ins>+ return !(x & 3);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static uint32_t calculateChecksum(const Vector<char>& 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 < 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<unsigned char>(table[startingOffset + 3]) << 24)
- | (static_cast<unsigned char>(table[startingOffset + 2]) << 16)
- | (static_cast<unsigned char>(table[startingOffset + 1]) << 8)
- | static_cast<unsigned char>(table[startingOffset]);
</del><ins>+ for (size_t offset = startingOffset; offset < endingOffset; offset += 4) {
+ sum += (static_cast<unsigned char>(table[offset + 3]) << 24)
+ | (static_cast<unsigned char>(table[offset + 2]) << 16)
+ | (static_cast<unsigned char>(table[offset + 1]) << 8)
+ | static_cast<unsigned char>(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<char> SVGToOTFFontConverter::convertSVGToOTFFont()
</span><span class="cx"> {
</span><span class="cx"> Vector<char> 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: "Log2(maximum power of 2 <= numTables)."
</span><span class="cx"> write16(result, numTables * 16 - searchRange); // rangeShift: "NumTables x 16-searchRange."
</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 < kDirectoryEntrySize * numTables; ++i)
</del><ins>+ // Leave space for the directory entries.
+ for (size_t i = 0; i < directoryEntrySize * numTables; ++i)
</ins><span class="cx"> result.append(0);
</span><span class="cx">
</span><span class="cx"> appendTable("CFF ", result, &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: "To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory,
</del><ins>+ // checksumAdjustment: "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."
</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 <darin@apple.com>
+
+ 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 <pnormand@igalia.com>
</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(&ok));
+ EXPECT_EQ(false, ok);
+
+ EXPECT_EQ(0, emptyString().toInt());
+ EXPECT_EQ(0, emptyString().toInt(&ok));
+ EXPECT_EQ(false, ok);
+
+ EXPECT_EQ(0, String("0").toInt());
+ EXPECT_EQ(0, String("0").toInt(&ok));
+ EXPECT_EQ(true, ok);
+
+ EXPECT_EQ(1, String("1").toInt());
+ EXPECT_EQ(1, String("1").toInt(&ok));
+ EXPECT_EQ(true, ok);
+
+ EXPECT_EQ(2147483647, String("2147483647").toInt());
+ EXPECT_EQ(2147483647, String("2147483647").toInt(&ok));
+ EXPECT_EQ(true, ok);
+
+ EXPECT_EQ(0, String("2147483648").toInt());
+ EXPECT_EQ(0, String("2147483648").toInt(&ok));
+ EXPECT_EQ(false, ok);
+
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt());
+ EXPECT_EQ(-2147483648, String("-2147483648").toInt(&ok));
+ EXPECT_EQ(true, ok);
+
+ EXPECT_EQ(0, String("-2147483649").toInt());
+ EXPECT_EQ(0, String("-2147483649").toInt(&ok));
+ EXPECT_EQ(false, ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0, String("x1").toInt());
+ EXPECT_EQ(0, String("x1").toInt(&ok));
+ EXPECT_EQ(false, ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1, String(" 1").toInt());
+ EXPECT_EQ(1, String(" 1").toInt(&ok));
+ EXPECT_EQ(true, ok);
+
+ // silently ignore trailing junk
+ EXPECT_EQ(1, String("1x").toInt());
+ EXPECT_EQ(1, String("1x").toInt(&ok));
+ EXPECT_EQ(true, ok);
+}
+
+TEST(WTF, StringToDouble)
+{
+ bool ok;
+
+ EXPECT_EQ(0.0, String().toDouble());
+ EXPECT_EQ(0.0, String().toDouble(&ok));
+ EXPECT_EQ(false, ok);
+
+ EXPECT_EQ(0.0, emptyString().toDouble());
+ EXPECT_EQ(0.0, emptyString().toDouble(&ok));
+ EXPECT_EQ(false, ok);
+
+ EXPECT_EQ(0.0, String("0").toDouble());
+ EXPECT_EQ(0.0, String("0").toDouble(&ok));
+ EXPECT_EQ(true, ok);
+
+ EXPECT_EQ(1.0, String("1").toDouble());
+ EXPECT_EQ(1.0, String("1").toDouble(&ok));
+ EXPECT_EQ(true, ok);
+
+ // fail if we see leading junk
+ EXPECT_EQ(0.0, String("x1").toDouble());
+ EXPECT_EQ(0.0, String("x1").toDouble(&ok));
+ EXPECT_EQ(false, ok);
+
+ // succeed if we see leading spaces
+ EXPECT_EQ(1.0, String(" 1").toDouble());
+ EXPECT_EQ(1.0, String(" 1").toDouble(&ok));
+ EXPECT_EQ(true, ok);
+
+ // ignore trailing junk, but return false for "ok"
+ // 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("1x").toDouble());
+ EXPECT_EQ(1.0, String("1x").toDouble(&ok));
+ EXPECT_EQ(false, ok);
+
+ // parse only numbers, not special values such as "infinity"
+ EXPECT_EQ(0.0, String("infinity").toDouble());
+ EXPECT_EQ(0.0, String("infinity").toDouble(&ok));
+ EXPECT_EQ(false, ok);
+
+ // parse only numbers, not special values such as "nan"
+ EXPECT_EQ(0.0, String("nan").toDouble());
+ EXPECT_EQ(0.0, String("nan").toDouble(&ok));
+ EXPECT_EQ(false, ok);
+}
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>
</body>
</html>