[Win] [SVG -> OTF Converter] Support the SVG -> OTF Font Converter
https://bugs.webkit.org/show_bug.cgi?id=143402
Patch by Myles C. Maxfield <mmaxfield@apple.com> on 2015-04-06
Reviewed by Darin Adler.
Source/WebCore:
There are a few pieces to the converter that Windows requires that we haven't already
implemented:
1. Checksums were being calculated with the wrong endianness
2. Windows requires a format 4 'cmap' subtable in addition to the format 12 one we already
were using
3. Windows requires a reference to a Private DICT inside the CFF table, even if the DICT
is of 0 length.
Covered by all our existing SVG font tests.
* svg/SVGFontFaceElement.h: Add capHeight accessor.
* svg/SVGFontFaceElement.cpp:
(WebCore::SVGFontFaceElement::capHeight): Ditto.
* svg/SVGToOTFConversion.cpp: Update the conversion process according to the above
requirements.
(WebCore::SVGToOTFFontConverter::appendFormat12CMAPTable):
(WebCore::SVGToOTFFontConverter::appendFormat4CMAPTable):
(WebCore::SVGToOTFFontConverter::appendCMAPTable): Use helpers.
(WebCore::SVGToOTFFontConverter::appendHHEATable): Use member variables.
(WebCore::SVGToOTFFontConverter::appendOS2Table): Update to version 2.
(WebCore::SVGToOTFFontConverter::appendCFFTable): Create a reference to a
zero-sized Private DICT
(WebCore::SVGToOTFFontConverter::SVGToOTFFontConverter): Populate member
variables.
(WebCore::SVGToOTFFontConverter::calculateChecksum): Flip endianness
WebKitLibraries:
* win/tools/vsprops/FeatureDefines.props: Enable the define.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@182423 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 8a123bd..8795c39 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,36 @@
+2015-04-06 Myles C. Maxfield <mmaxfield@apple.com>
+
+ [Win] [SVG -> OTF Converter] Support the SVG -> OTF Font Converter
+ https://bugs.webkit.org/show_bug.cgi?id=143402
+
+ Reviewed by Darin Adler.
+
+ There are a few pieces to the converter that Windows requires that we haven't already
+ implemented:
+ 1. Checksums were being calculated with the wrong endianness
+ 2. Windows requires a format 4 'cmap' subtable in addition to the format 12 one we already
+ were using
+ 3. Windows requires a reference to a Private DICT inside the CFF table, even if the DICT
+ is of 0 length.
+
+ Covered by all our existing SVG font tests.
+
+ * svg/SVGFontFaceElement.h: Add capHeight accessor.
+ * svg/SVGFontFaceElement.cpp:
+ (WebCore::SVGFontFaceElement::capHeight): Ditto.
+ * svg/SVGToOTFConversion.cpp: Update the conversion process according to the above
+ requirements.
+ (WebCore::SVGToOTFFontConverter::appendFormat12CMAPTable):
+ (WebCore::SVGToOTFFontConverter::appendFormat4CMAPTable):
+ (WebCore::SVGToOTFFontConverter::appendCMAPTable): Use helpers.
+ (WebCore::SVGToOTFFontConverter::appendHHEATable): Use member variables.
+ (WebCore::SVGToOTFFontConverter::appendOS2Table): Update to version 2.
+ (WebCore::SVGToOTFFontConverter::appendCFFTable): Create a reference to a
+ zero-sized Private DICT
+ (WebCore::SVGToOTFFontConverter::SVGToOTFFontConverter): Populate member
+ variables.
+ (WebCore::SVGToOTFFontConverter::calculateChecksum): Flip endianness
+
2015-04-06 Yusuke Suzuki <utatane.tea@gmail.com>
Return Optional<uint32_t> from PropertyName::asIndex
diff --git a/Source/WebCore/svg/SVGFontFaceElement.cpp b/Source/WebCore/svg/SVGFontFaceElement.cpp
index 10d2a68..069bf19 100644
--- a/Source/WebCore/svg/SVGFontFaceElement.cpp
+++ b/Source/WebCore/svg/SVGFontFaceElement.cpp
@@ -86,6 +86,11 @@
return static_cast<int>(ceilf(fastGetAttribute(x_heightAttr).toFloat()));
}
+int SVGFontFaceElement::capHeight() const
+{
+ return static_cast<int>(ceilf(fastGetAttribute(cap_heightAttr).toFloat()));
+}
+
float SVGFontFaceElement::horizontalOriginX() const
{
if (!m_fontElement)
diff --git a/Source/WebCore/svg/SVGFontFaceElement.h b/Source/WebCore/svg/SVGFontFaceElement.h
index c96f81b..50044f5 100644
--- a/Source/WebCore/svg/SVGFontFaceElement.h
+++ b/Source/WebCore/svg/SVGFontFaceElement.h
@@ -36,6 +36,7 @@
unsigned unitsPerEm() const;
int xHeight() const;
+ int capHeight() const;
float horizontalOriginX() const;
float horizontalOriginY() const;
float horizontalAdvanceX() const;
diff --git a/Source/WebCore/svg/SVGToOTFFontConversion.cpp b/Source/WebCore/svg/SVGToOTFFontConversion.cpp
index 955e504..a4ffd28 100644
--- a/Source/WebCore/svg/SVGToOTFFontConversion.cpp
+++ b/Source/WebCore/svg/SVGToOTFFontConversion.cpp
@@ -192,6 +192,8 @@
typedef void (SVGToOTFFontConverter::*FontAppendingFunction)();
void appendTable(const char identifier[4], FontAppendingFunction);
+ void appendFormat12CMAPTable(const Vector<std::pair<UChar32, Glyph>>& codepointToGlyphMappings);
+ void appendFormat4CMAPTable(const Vector<std::pair<UChar32, Glyph>>& codepointToGlyphMappings);
void appendCMAPTable();
void appendGSUBTable();
void appendHEADTable();
@@ -241,8 +243,13 @@
float m_advanceHeightMax;
float m_minRightSideBearing;
unsigned m_unitsPerEm;
+ int m_lineGap;
+ int m_xHeight;
+ int m_capHeight;
+ int m_ascent;
+ int m_descent;
unsigned m_featureCountGSUB;
- int m_tablesAppendedCount;
+ unsigned m_tablesAppendedCount;
char m_weight;
bool m_italic;
};
@@ -264,16 +271,8 @@
return result;
}
-void SVGToOTFFontConverter::appendCMAPTable()
+void SVGToOTFFontConverter::appendFormat12CMAPTable(const Vector<std::pair<UChar32, Glyph>>& mappings)
{
- auto startingOffset = m_result.size();
- append16(0);
- append16(1); // Number subtables
-
- append16(0); // Unicode
- append16(3); // Unicode version 2.2+
- append32(m_result.size() - startingOffset + sizeof(uint32_t)); // Byte offset of subtable
-
// Braindead scheme: One segment for each character
ASSERT(m_glyphs.size() < 0xFFFF);
auto subtableLocation = m_result.size();
@@ -281,8 +280,77 @@
append32(0); // Placeholder for byte length
append32(0); // Language independent
append32(0); // Placeholder for nGroups
+ for (auto& mapping : mappings) {
+ append32(mapping.first); // startCharCode
+ append32(mapping.first); // endCharCode
+ append32(mapping.second); // startGlyphCode
+ }
+ overwrite32(subtableLocation + 4, m_result.size() - subtableLocation);
+ overwrite32(subtableLocation + 12, mappings.size());
+}
- uint16_t nGroups = 0;
+void SVGToOTFFontConverter::appendFormat4CMAPTable(const Vector<std::pair<UChar32, Glyph>>& bmpMappings)
+{
+ auto subtableLocation = m_result.size();
+ append16(4); // Format 4
+ append16(0); // Placeholder for length in bytes
+ append16(0); // Language independent
+ uint16_t segCount = bmpMappings.size() + 1;
+ append16(clampTo<uint16_t>(2 * segCount)); // segCountX2: "2 x segCount"
+ uint16_t originalSearchRange = roundDownToPowerOfTwo(segCount);
+ uint16_t searchRange = clampTo<uint16_t>(2 * originalSearchRange); // searchRange: "2 x (2**floor(log2(segCount)))"
+ append16(searchRange);
+ append16(integralLog2(originalSearchRange)); // entrySelector: "log2(searchRange/2)"
+ append16(clampTo<uint16_t>((2 * segCount) - searchRange)); // rangeShift: "2 x segCount - searchRange"
+
+ // Ending character codes
+ for (auto& mapping : bmpMappings)
+ append16(mapping.first); // startCharCode
+ append16(0xFFFF);
+
+ append16(0); // reserved
+
+ // Starting character codes
+ for (auto& mapping : bmpMappings)
+ append16(mapping.first); // startCharCode
+ append16(0xFFFF);
+
+ // idDelta
+ for (auto& mapping : bmpMappings)
+ append16(static_cast<uint16_t>(mapping.second) - static_cast<uint16_t>(mapping.first)); // startCharCode
+ append16(0x0001);
+
+ // idRangeOffset
+ for (size_t i = 0; i < bmpMappings.size(); ++i)
+ append16(0); // startCharCode
+ append16(0);
+
+ // Fonts strive to hold 2^16 glyphs, but with the current encoding scheme, we write 8 bytes per codepoint into this subtable.
+ // Because the size of this subtable must be represented as a 16-bit number, we are limiting the number of glyphs we support to 2^13.
+ // FIXME: If we hit this limit in the wild, use a more compact encoding scheme for this subtable.
+ overwrite16(subtableLocation + 2, clampTo<uint16_t>(m_result.size() - subtableLocation));
+}
+
+void SVGToOTFFontConverter::appendCMAPTable()
+{
+ auto startingOffset = m_result.size();
+ append16(0);
+ append16(3); // Number of subtables
+
+ append16(0); // Unicode
+ append16(3); // Unicode version 2.2+
+ append32(28); // Byte offset of subtable
+
+ append16(3); // Microsoft
+ append16(1); // Unicode BMP
+ auto format4OffsetLocation = m_result.size();
+ append32(0); // Byte offset of subtable
+
+ append16(3); // Microsoft
+ append16(10); // Unicode
+ append32(28); // Byte offset of subtable
+
+ Vector<std::pair<UChar32, Glyph>> mappings;
UChar32 previousCodepoint = std::numeric_limits<UChar32>::max();
for (size_t i = 0; i < m_glyphs.size(); ++i) {
auto& glyph = m_glyphs[i];
@@ -299,14 +367,19 @@
continue;
}
- append32(codepoint); // startCharCode
- append32(codepoint); // endCharCode
- append32(i); // startGlyphCode
- ++nGroups;
+ mappings.append(std::make_pair(codepoint, Glyph(i)));
previousCodepoint = codepoint;
}
- overwrite32(subtableLocation + 4, m_result.size() - subtableLocation);
- overwrite32(subtableLocation + 12, nGroups);
+
+ appendFormat12CMAPTable(mappings);
+
+ Vector<std::pair<UChar32, Glyph>> bmpMappings;
+ for (auto& mapping : mappings) {
+ if (mapping.first < 0x10000)
+ bmpMappings.append(mapping);
+ }
+ overwrite32(format4OffsetLocation, m_result.size() - startingOffset);
+ appendFormat4CMAPTable(bmpMappings);
}
void SVGToOTFFontConverter::appendHEADTable()
@@ -343,29 +416,11 @@
void SVGToOTFFontConverter::appendHHEATable()
{
- int16_t ascent;
- int16_t descent;
- if (!m_fontFaceElement) {
- ascent = m_unitsPerEm;
- descent = 1;
- } else {
- ascent = m_fontFaceElement->ascent();
- descent = m_fontFaceElement->descent();
-
- // 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;
- }
-
append32(0x00010000); // Version
- append16(ascent);
- append16(descent);
+ append16(clampTo<int16_t>(m_ascent));
+ append16(clampTo<int16_t>(m_descent));
// WebKit SVG font rendering has hard coded the line gap to be 1/10th of the font size since 2008 (see r29719).
- append16(m_unitsPerEm / 10); // Line gap
+ append16(clampTo<int16_t>(m_lineGap));
append16(clampTo<uint16_t>(m_advanceWidthMax));
append16(clampTo<int16_t>(m_boundingBox.x())); // Minimum left side bearing
append16(clampTo<int16_t>(m_minRightSideBearing)); // Minimum right side bearing
@@ -434,9 +489,9 @@
if (ok)
averageAdvance = clampTo<int16_t>(value);
- append16(0); // Version
- append16(averageAdvance);
- append16(m_weight); // Weight class
+ append16(2); // Version
+ append16(clampTo<int16_t>(averageAdvance));
+ append16(clampTo<uint16_t>(m_weight)); // Weight class
append16(5); // Width class
append16(0); // Protected font
// WebKit handles these superscripts and subscripts
@@ -477,6 +532,20 @@
append16((m_weight >= 7 ? 1 << 5 : 0) | (m_italic ? 1 : 0)); // Font Patterns.
append16(0); // First unicode index
append16(0xFFFF); // Last unicode index
+ append16(clampTo<int16_t>(m_ascent)); // Typographical ascender
+ append16(clampTo<int16_t>(m_descent)); // Typographical descender
+ append16(clampTo<int16_t>(m_lineGap)); // Typographical line gap
+ append16(clampTo<uint16_t>(m_ascent)); // Windows-specific ascent
+ append16(clampTo<uint16_t>(m_descent)); // Windows-specific descent
+ append32(0xFF10FC07); // Bitmask for supported codepages (Part 1). Report all pages as supported.
+ append32(0x0000FFFF); // Bitmask for supported codepages (Part 2). Report all pages as supported.
+ append16(clampTo<int16_t>(m_xHeight)); // x-height
+ append16(clampTo<int16_t>(m_capHeight)); // Cap-height
+ append16(0); // Default char
+ append16(' '); // Break character
+ append16(3); // Maximum context needed to perform font features
+ append16(3); // Smallest optical point size
+ append16(0xFFFF); // Largest optical point size
}
void SVGToOTFFontConverter::appendPOSTTable()
@@ -548,8 +617,9 @@
const char fontBBoxKey = 5;
const char charsetIndexKey = 15;
const char charstringsIndexKey = 17;
+ const char privateDictIndexKey = 18;
const uint32_t userDefinedStringStartIndex = 391;
- const unsigned sizeOfTopIndex = 45 + (hasWeight ? 6 : 0);
+ const unsigned sizeOfTopIndex = 56 + (hasWeight ? 6 : 0);
// Top DICT INDEX.
append16(1); // INDEX contains 1 element
@@ -589,6 +659,11 @@
unsigned charstringsOffsetLocation = m_result.size();
append32(0); // Offset of CharStrings INDEX. Will be overwritten later.
m_result.append(charstringsIndexKey);
+ m_result.append(operand32Bit);
+ append32(0); // 0-sized private dict
+ m_result.append(operand32Bit);
+ append32(0); // no location for private dict
+ m_result.append(privateDictIndexKey); // Private dict size and offset
ASSERT(m_result.size() == topDictStart + sizeOfTopIndex);
// String INDEX
@@ -1273,7 +1348,6 @@
, m_advanceWidthMax(0)
, m_advanceHeightMax(0)
, m_minRightSideBearing(std::numeric_limits<float>::max())
- , m_unitsPerEm(0)
, m_featureCountGSUB(0)
, m_tablesAppendedCount(0)
, m_weight(5)
@@ -1287,6 +1361,30 @@
if (m_fontFaceElement)
m_unitsPerEm = m_fontFaceElement->unitsPerEm();
+ if (!m_fontFaceElement) {
+ m_unitsPerEm = 1;
+ m_ascent = m_unitsPerEm;
+ m_descent = 1;
+ m_xHeight = m_unitsPerEm;
+ m_capHeight = m_ascent;
+ } else {
+ m_unitsPerEm = m_fontFaceElement->unitsPerEm();
+ m_ascent = m_fontFaceElement->ascent();
+ m_descent = m_fontFaceElement->descent();
+ m_xHeight = m_fontFaceElement->xHeight();
+ m_capHeight = m_fontFaceElement->capHeight();
+
+ // 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 (!m_ascent)
+ m_ascent = 1;
+ if (!m_descent)
+ m_descent = 1;
+ }
+
+ m_lineGap = m_unitsPerEm / 10;
+
populateEmptyGlyphCharString(m_emptyGlyphCharString, m_unitsPerEm);
if (m_missingGlyphElement)
@@ -1369,10 +1467,10 @@
ASSERT(isFourByteAligned(endingOffset - startingOffset));
uint32_t sum = 0;
for (size_t offset = startingOffset; offset < endingOffset; offset += 4) {
- sum += (static_cast<unsigned char>(m_result[offset + 3]) << 24)
- | (static_cast<unsigned char>(m_result[offset + 2]) << 16)
- | (static_cast<unsigned char>(m_result[offset + 1]) << 8)
- | static_cast<unsigned char>(m_result[offset]);
+ sum += static_cast<unsigned char>(m_result[offset + 3])
+ | (static_cast<unsigned char>(m_result[offset + 2]) << 8)
+ | (static_cast<unsigned char>(m_result[offset + 1]) << 16)
+ | (static_cast<unsigned char>(m_result[offset]) << 24);
}
return sum;
}
diff --git a/WebKitLibraries/ChangeLog b/WebKitLibraries/ChangeLog
index c2870e1..1e7c191 100644
--- a/WebKitLibraries/ChangeLog
+++ b/WebKitLibraries/ChangeLog
@@ -1,3 +1,12 @@
+2015-04-06 Myles C. Maxfield <mmaxfield@apple.com>
+
+ [Win] [SVG -> OTF Converter] Support the SVG -> OTF Font Converter
+ https://bugs.webkit.org/show_bug.cgi?id=143402
+
+ Reviewed by Darin Adler.
+
+ * win/tools/vsprops/FeatureDefines.props: Enable the define.
+
2015-03-09 Daniel Bates <dabates@apple.com>
[iOS] Add WebKitSystemInterface for iOS 8.2
diff --git a/WebKitLibraries/win/tools/vsprops/FeatureDefines.props b/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
index 61e253f..73934b7 100644
--- a/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
+++ b/WebKitLibraries/win/tools/vsprops/FeatureDefines.props
@@ -74,7 +74,7 @@
<ENABLE_SVG>ENABLE_SVG</ENABLE_SVG>
<ENABLE_SVG_DOM_OBJC_BINDINGS />
<ENABLE_SVG_FONTS>ENABLE_SVG_FONTS</ENABLE_SVG_FONTS>
- <ENABLE_SVG_OTF_CONVERTER />
+ <ENABLE_SVG_OTF_CONVERTER>ENABLE_SVG_OTF_CONVERTER</ENABLE_SVG_OTF_CONVERTER>
<ENABLE_TEMPLATE_ELEMENT>ENABLE_TEMPLATE_ELEMENT</ENABLE_TEMPLATE_ELEMENT>
<ENABLE_TEXT_AUTOSIZING />
<ENABLE_VIDEO>ENABLE_VIDEO</ENABLE_VIDEO>