Diff
Modified: trunk/Source/WebCore/ChangeLog (88556 => 88557)
--- trunk/Source/WebCore/ChangeLog 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/ChangeLog 2011-06-10 20:15:10 UTC (rev 88557)
@@ -1,3 +1,47 @@
+2011-06-10 Nikolas Zimmermann <[email protected]>
+
+ Reviewed by Rob Buis.
+
+ Integrate SVG Fonts within GlyphPage concept, removing the special SVG code paths from Font, making it possible to reuse the simple text code path for SVG Fonts
+ https://bugs.webkit.org/show_bug.cgi?id=59085
+
+ Add glyph table to SVGFontElement mapping between SVGGlyph <-> Glyph
+ https://bugs.webkit.org/show_bug.cgi?id=62441
+
+ Preparation patch 1: Introduce the internal glyph table in SVGGlyphMap that will be used to identify each
+ SVGGlyph identifier with a Glyph (which is just an ushort). It will be used by follow-up patches.
+
+ Doesn't affect any test so far.
+
+ * platform/graphics/SVGGlyph.h:
+ (WebCore::SVGGlyph::SVGGlyph):
+ (WebCore::SVGGlyph::operator==):
+ * rendering/svg/SVGTextRunRenderingContext.cpp:
+ (WebCore::SVGTextRunWalker::walk):
+ * svg/SVGFontData.cpp:
+ (WebCore::SVGFontData::initializeFontData):
+ * svg/SVGFontElement.cpp:
+ (WebCore::SVGFontElement::SVGFontElement):
+ (WebCore::SVGFontElement::registerLigaturesInGlyphCache):
+ (WebCore::SVGFontElement::ensureGlyphCache):
+ (WebCore::kerningForPairOfStringsAndGlyphs):
+ (WebCore::SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs):
+ (WebCore::SVGFontElement::verticalKerningForPairOfStringsAndGlyphs):
+ (WebCore::SVGFontElement::collectGlyphsForString):
+ (WebCore::SVGFontElement::collectGlyphsForGlyphName):
+ (WebCore::SVGFontElement::svgGlyphForGlyph):
+ (WebCore::SVGFontElement::missingGlyph):
+ * svg/SVGFontElement.h:
+ (WebCore::SVGKerningPair::SVGKerningPair):
+ * svg/SVGGlyphMap.h:
+ (WebCore::SVGGlyphMap::addGlyphByUnicodeString):
+ (WebCore::SVGGlyphMap::addGlyphByName):
+ (WebCore::SVGGlyphMap::appendToGlyphTable):
+ (WebCore::SVGGlyphMap::collectGlyphsForString):
+ (WebCore::SVGGlyphMap::clear):
+ (WebCore::SVGGlyphMap::svgGlyphForGlyph):
+ (WebCore::SVGGlyphMap::glyphIdentifierForGlyphName):
+
2011-06-10 Emil A Eklund <[email protected]>
Reviewed by Eric Seidel.
Modified: trunk/Source/WebCore/platform/graphics/SVGGlyph.h (88556 => 88557)
--- trunk/Source/WebCore/platform/graphics/SVGGlyph.h 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/platform/graphics/SVGGlyph.h 2011-06-10 20:15:10 UTC (rev 88557)
@@ -24,6 +24,7 @@
#define SVGGlyph_h
#if ENABLE(SVG_FONTS)
+#include "Glyph.h"
#include "Path.h"
#include <limits>
@@ -54,6 +55,7 @@
, orientation(Both)
, arabicForm(None)
, priority(0)
+ , tableEntry(0)
, unicodeStringLength(0)
, horizontalAdvanceX(0)
, verticalOriginX(0)
@@ -74,6 +76,7 @@
return isValid == other.isValid
&& orientation == other.orientation
&& arabicForm == other.arabicForm
+ && tableEntry == other.tableEntry
&& unicodeStringLength == other.unicodeStringLength
&& glyphName == other.glyphName
&& horizontalAdvanceX == other.horizontalAdvanceX
@@ -88,6 +91,7 @@
unsigned orientation : 2; // Orientation
unsigned arabicForm : 3; // ArabicForm
int priority;
+ Glyph tableEntry;
size_t unicodeStringLength;
String glyphName;
Modified: trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp (88556 => 88557)
--- trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp 2011-06-10 20:15:10 UTC (rev 88557)
@@ -152,7 +152,7 @@
if (haveAltGlyph)
glyphs.append(altGlyphIdentifier);
else
- m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);
+ m_fontElement->collectGlyphsForString(lookupString, glyphs);
Vector<SVGGlyph>::iterator it = glyphs.begin();
Vector<SVGGlyph>::iterator end = glyphs.end();
Modified: trunk/Source/WebCore/svg/SVGFontData.cpp (88556 => 88557)
--- trunk/Source/WebCore/svg/SVGFontData.cpp 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/svg/SVGFontData.cpp 2011-06-10 20:15:10 UTC (rev 88557)
@@ -59,7 +59,7 @@
if (!xHeight) {
// Fallback if x_heightAttr is not specified for the font element.
Vector<SVGGlyph> letterXGlyphs;
- associatedFontElement->getGlyphIdentifiersForString(String("x", 1), letterXGlyphs);
+ associatedFontElement->collectGlyphsForString(String("x", 1), letterXGlyphs);
xHeight = letterXGlyphs.isEmpty() ? 2 * ascent / 3 : letterXGlyphs.first().horizontalAdvanceX * scale;
}
@@ -72,15 +72,15 @@
fontMetrics.setXHeight(xHeight);
Vector<SVGGlyph> spaceGlyphs;
- associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
+ associatedFontElement->collectGlyphsForString(String(" ", 1), spaceGlyphs);
fontData->setSpaceWidth(spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale);
Vector<SVGGlyph> numeralZeroGlyphs;
- associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
+ associatedFontElement->collectGlyphsForString(String("0", 1), numeralZeroGlyphs);
fontData->setAvgCharWidth(numeralZeroGlyphs.isEmpty() ? fontData->spaceWidth() : numeralZeroGlyphs.first().horizontalAdvanceX * scale);
Vector<SVGGlyph> letterWGlyphs;
- associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs);
+ associatedFontElement->collectGlyphsForString(String("W", 1), letterWGlyphs);
fontData->setMaxCharWidth(letterWGlyphs.isEmpty() ? ascent : letterWGlyphs.first().horizontalAdvanceX * scale);
// FIXME: is there a way we can get the space glyph from the SVGGlyph above?
Modified: trunk/Source/WebCore/svg/SVGFontElement.cpp (88556 => 88557)
--- trunk/Source/WebCore/svg/SVGFontElement.cpp 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/svg/SVGFontElement.cpp 2011-06-10 20:15:10 UTC (rev 88557)
@@ -41,6 +41,7 @@
inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* document)
: SVGStyledElement(tagName, document)
+ , m_missingGlyph(0)
, m_isGlyphCacheValid(false)
{
ASSERT(hasTagName(SVGNames::fontTag));
@@ -79,26 +80,94 @@
return 0;
}
-void SVGFontElement::ensureGlyphCache() const
+void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures)
{
+ ASSERT(!ligatures.isEmpty());
+
+ // Register each character of a ligature in the map, if not present.
+ // Eg. If only a "fi" ligature is present, but not "f" and "i", the
+ // GlyphPage will not contain any entries for "f" and "i", so the
+ // SVGFont is not used to render the text "fi1234". Register an
+ // empty SVGGlyph with the character, so the SVG Font will be used
+ // to render the text. If someone tries to render "f2" the SVG Font
+ // will not be able to find a glyph for "f", but handles the fallback
+ // character substitution properly through glyphDataForCharacter().
+ Vector<SVGGlyph> glyphs;
+ size_t ligaturesSize = ligatures.size();
+ for (size_t i = 0; i < ligaturesSize; ++i) {
+ const String& unicode = ligatures[i];
+
+ unsigned unicodeLength = unicode.length();
+ ASSERT(unicodeLength > 1);
+
+ const UChar* characters = unicode.characters();
+ for (unsigned i = 0; i < unicodeLength; ++i) {
+ String lookupString(characters + i, 1);
+ m_glyphMap.collectGlyphsForString(lookupString, glyphs);
+ if (!glyphs.isEmpty()) {
+ glyphs.clear();
+ continue;
+ }
+
+ // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
+ SVGGlyph newGlyphPart;
+ /* FIXME: Enable this once with the next patch.
+ newGlyphPart.isPartOfLigature = true;
+ */
+ m_glyphMap.addGlyphByUnicodeString(lookupString, newGlyphPart);
+ }
+ }
+}
+
+void SVGFontElement::ensureGlyphCache()
+{
if (m_isGlyphCacheValid)
return;
+ SVGMissingGlyphElement* firstMissingGlyphElement = 0;
+ Vector<String> ligatures;
for (Node* child = firstChild(); child; child = child->nextSibling()) {
if (child->hasTagName(SVGNames::glyphTag)) {
SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child);
String unicode = glyph->getAttribute(SVGNames::unicodeAttr);
- if (unicode.length())
- m_glyphMap.add(unicode, glyph->buildGlyphIdentifier());
+ SVGGlyph svgGlyph = glyph->buildGlyphIdentifier();
+ unsigned unicodeLength = unicode.length();
+
+ // Register named glyphs in the glyph table as well.
+ if (!unicodeLength) {
+ m_glyphMap.addGlyphByName(glyph->getIdAttribute(), svgGlyph);
+ continue;
+ }
+
+ // Register ligatures, if needed.
+ if (unicodeLength > 1)
+ ligatures.append(unicode);
+
+ m_glyphMap.addGlyphByUnicodeString(unicode, svgGlyph);
} else if (child->hasTagName(SVGNames::hkernTag)) {
SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child);
hkern->buildHorizontalKerningPair(m_horizontalKerningPairs);
} else if (child->hasTagName(SVGNames::vkernTag)) {
SVGVKernElement* vkern = static_cast<SVGVKernElement*>(child);
vkern->buildVerticalKerningPair(m_verticalKerningPairs);
- }
+ } else if (child->hasTagName(SVGNames::missing_glyphTag) && !firstMissingGlyphElement)
+ firstMissingGlyphElement = static_cast<SVGMissingGlyphElement*>(child);
}
-
+
+ /* FIXME: Register each character of each ligature, if needed.
+ This is not needed yet, turn it on with the next patch. With the current SVG Fonts code it would break fonts-glyph-04-t.svg
+ if (!ligatures.isEmpty())
+ registerLigaturesInGlyphCache(ligatures);
+ */
+
+ // Register missing-glyph element, if present.
+ if (firstMissingGlyphElement) {
+ SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
+ m_glyphMap.appendToGlyphTable(svgGlyph);
+ m_missingGlyph = svgGlyph.tableEntry;
+ ASSERT(m_missingGlyph > 0);
+ }
+
m_isGlyphCacheValid = true;
}
@@ -132,7 +201,7 @@
return false;
}
-
+
static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGKerningPair& kerningPair)
{
if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1)
@@ -146,7 +215,7 @@
return true;
}
-static float kerningForPairOfStringsAndGlyphs(KerningPairVector& kerningPairs, const String& u1, const String& g1, const String& u2, const String& g2)
+static float kerningForPairOfStringsAndGlyphs(const KerningPairVector& kerningPairs, const String& u1, const String& g1, const String& u2, const String& g2)
{
KerningPairVector::const_iterator it = kerningPairs.end() - 1;
const KerningPairVector::const_iterator begin = kerningPairs.begin() - 1;
@@ -155,13 +224,13 @@
return it->kerning;
}
- return 0.0f;
+ return 0;
}
float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
{
if (m_horizontalKerningPairs.isEmpty())
- return 0.0f;
+ return 0;
return kerningForPairOfStringsAndGlyphs(m_horizontalKerningPairs, u1, g1, u2, g2);
}
@@ -169,17 +238,36 @@
float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
{
if (m_verticalKerningPairs.isEmpty())
- return 0.0f;
+ return 0;
return kerningForPairOfStringsAndGlyphs(m_verticalKerningPairs, u1, g1, u2, g2);
}
-void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyph>& glyphs) const
+void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
{
ensureGlyphCache();
- m_glyphMap.get(string, glyphs);
+ m_glyphMap.collectGlyphsForString(string, glyphs);
}
+void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs)
+{
+ ensureGlyphCache();
+ // FIXME: We only support glyphName -> single glyph mapping so far.
+ glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName));
+}
+
+SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
+{
+ ensureGlyphCache();
+ return m_glyphMap.svgGlyphForGlyph(glyph);
+}
+
+Glyph SVGFontElement::missingGlyph()
+{
+ ensureGlyphCache();
+ return m_missingGlyph;
+}
+
AttributeToPropertyTypeMap& SVGFontElement::attributeToPropertyTypeMap()
{
DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
Modified: trunk/Source/WebCore/svg/SVGFontElement.h (88556 => 88557)
--- trunk/Source/WebCore/svg/SVGFontElement.h 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/svg/SVGFontElement.h 2011-06-10 20:15:10 UTC (rev 88557)
@@ -43,7 +43,7 @@
HashSet<String> glyphName2;
SVGKerningPair()
- : kerning(0.0f)
+ : kerning(0)
{
}
};
@@ -58,12 +58,16 @@
static PassRefPtr<SVGFontElement> create(const QualifiedName&, Document*);
void invalidateGlyphCache();
+ void collectGlyphsForString(const String&, Vector<SVGGlyph>&);
+ void collectGlyphsForGlyphName(const String&, Vector<SVGGlyph>&);
- void getGlyphIdentifiersForString(const String&, Vector<SVGGlyph>&) const;
-
float horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const;
float verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const;
-
+
+ // Used by SimpleFontData/WidthIterator.
+ SVGGlyph svgGlyphForGlyph(Glyph);
+ Glyph missingGlyph();
+
SVGMissingGlyphElement* firstMissingGlyphElement() const;
private:
@@ -74,17 +78,19 @@
virtual void fillAttributeToPropertyTypeMap();
virtual AttributeToPropertyTypeMap& attributeToPropertyTypeMap();
- void ensureGlyphCache() const;
+ void ensureGlyphCache();
+ void registerLigaturesInGlyphCache(Vector<String>&);
// Animated property declarations
// SVGExternalResourcesRequired
DECLARE_ANIMATED_BOOLEAN(ExternalResourcesRequired, externalResourcesRequired)
- mutable KerningPairVector m_horizontalKerningPairs;
- mutable KerningPairVector m_verticalKerningPairs;
- mutable SVGGlyphMap m_glyphMap;
- mutable bool m_isGlyphCacheValid;
+ KerningPairVector m_horizontalKerningPairs;
+ KerningPairVector m_verticalKerningPairs;
+ SVGGlyphMap m_glyphMap;
+ Glyph m_missingGlyph;
+ bool m_isGlyphCacheValid;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/svg/SVGGlyphMap.h (88556 => 88557)
--- trunk/Source/WebCore/svg/SVGGlyphMap.h 2011-06-10 19:44:39 UTC (rev 88556)
+++ trunk/Source/WebCore/svg/SVGGlyphMap.h 2011-06-10 20:15:10 UTC (rev 88557)
@@ -21,11 +21,16 @@
#define SVGGlyphMap_h
#if ENABLE(SVG_FONTS)
+#include "SVGGlyph.h"
#include "SVGGlyphElement.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
namespace WebCore {
struct GlyphMapNode;
+class SVGFontData;
typedef HashMap<UChar, RefPtr<GlyphMapNode> > GlyphMapLayer;
@@ -45,7 +50,7 @@
public:
SVGGlyphMap() : m_currentPriority(0) { }
- void add(const String& string, const SVGGlyph& glyph)
+ void addGlyphByUnicodeString(const String& string, const SVGGlyph& glyph)
{
size_t len = string.length();
GlyphMapLayer* currentLayer = &m_rootLayer;
@@ -63,22 +68,44 @@
if (node) {
node->glyphs.append(glyph);
- node->glyphs.last().priority = m_currentPriority++;
- node->glyphs.last().unicodeStringLength = len;
- node->glyphs.last().isValid = true;
+
+ SVGGlyph& svgGlyph = node->glyphs.last();
+ svgGlyph.priority = m_currentPriority++;
+ svgGlyph.unicodeStringLength = len;
+ svgGlyph.isValid = true;
+ appendToGlyphTable(svgGlyph);
}
}
+ void addGlyphByName(const String& glyphName, SVGGlyph& glyph)
+ {
+ if (glyphName.isEmpty())
+ return;
+ appendToGlyphTable(glyph);
+ m_namedGlyphs.add(glyphName, glyph.tableEntry);
+ }
+
+ void appendToGlyphTable(SVGGlyph& glyph)
+ {
+ size_t tableEntry = m_glyphTable.size();
+ ASSERT(tableEntry < std::numeric_limits<unsigned short>::max());
+
+ // The first table entry starts with 1. 0 denotes an unknown glyph.
+ glyph.tableEntry = tableEntry + 1;
+ m_glyphTable.append(glyph);
+ }
+
static inline bool compareGlyphPriority(const SVGGlyph& first, const SVGGlyph& second)
{
return first.priority < second.priority;
}
- void get(const String& string, Vector<SVGGlyph>& glyphs)
+ void collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
{
GlyphMapLayer* currentLayer = &m_rootLayer;
- for (size_t i = 0; i < string.length(); ++i) {
+ size_t length = string.length();
+ for (size_t i = 0; i < length; ++i) {
UChar curChar = string[i];
RefPtr<GlyphMapNode> node = currentLayer->get(curChar);
if (!node)
@@ -88,21 +115,36 @@
}
std::sort(glyphs.begin(), glyphs.end(), compareGlyphPriority);
}
-
+
void clear()
{
- m_rootLayer.clear();
+ m_rootLayer.clear();
+ m_glyphTable.clear();
m_currentPriority = 0;
}
+ const SVGGlyph& svgGlyphForGlyph(Glyph glyph) const
+ {
+ if (!glyph || glyph > m_glyphTable.size()) {
+ DEFINE_STATIC_LOCAL(SVGGlyph, defaultGlyph, ());
+ return defaultGlyph;
+ }
+ return m_glyphTable[glyph - 1];
+ }
+
+ const SVGGlyph& glyphIdentifierForGlyphName(const String& glyphName) const
+ {
+ return svgGlyphForGlyph(m_namedGlyphs.get(glyphName));
+ }
+
private:
GlyphMapLayer m_rootLayer;
+ Vector<SVGGlyph, 256> m_glyphTable;
+ HashMap<String, Glyph> m_namedGlyphs;
int m_currentPriority;
};
}
#endif // ENABLE(SVG_FONTS)
-
-
#endif // SVGGlyphMap_h