Reviewed by Oliver.
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Dec 2007 13:50:15 +0000 (13:50 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Dec 2007 13:50:15 +0000 (13:50 +0000)
Further SVG Font work. Parse all <glyph> attributes, using SVGGlyphElement::buildGlyphIdentifier.
SVGFontElement::collectGlyphs() now uses this method. Per character advance values work well now.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29029 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/platform/graphics/FontData.cpp
WebCore/platform/graphics/FontData.h
WebCore/svg/SVGFont.cpp
WebCore/svg/SVGFontElement.cpp
WebCore/svg/SVGGlyphElement.cpp
WebCore/svg/SVGGlyphElement.h

index b19fccca79f34b8ff90010c73c101d292ca8c1b2..e73cb8cadfecccc9237fbb81f9715c0a09035950 100644 (file)
@@ -1,3 +1,28 @@
+2007-12-29  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Oliver.
+
+        Further SVG Font work. Parse all <glyph> attributes, using SVGGlyphElement::buildGlyphIdentifier.
+        SVGFontElement::collectGlyphs() now uses this method. Per character advance values work well now.
+
+        * platform/graphics/FontData.cpp:
+        (WebCore::SVGFontData::convertEmUnitToPixel): Add helper function.
+        (WebCore::FontData::ascent):
+        (WebCore::FontData::descent):
+        * platform/graphics/FontData.h:
+        * svg/SVGFont.cpp:
+        (WebCore::isVerticalWritingMode): Add helper function.
+        (WebCore::Font::drawGlyphsWithSVGFont):
+        * svg/SVGFontElement.cpp:
+        (WebCore::SVGFontElement::collectGlyphs): Simplified implementation - SVGGlyphIdentifier now build by SVGGlyphElement.
+        * svg/SVGGlyphElement.cpp:
+        (WebCore::parseArabicForm): Helper function.
+        (WebCore::parseOrientation): Ditto.
+        (WebCore::parsePathData): Ditto.
+        (WebCore::SVGGlyphElement::buildGlyphIdentifier):
+        * svg/SVGGlyphElement.h:
+        (WebCore::SVGGlyphElement::rendererIsNeeded):
+
 2007-12-29  Nikolas Zimmermann  <zimmermann@kde.org>
 
         Reviewed by Oliver.
index ec2b29638f901ed0e717197c07e0a4b6991b0e33..a6a157c9d403e01d838cebff4b4830f955de592c 100644 (file)
@@ -50,6 +50,12 @@ SVGFontData::SVGFontData(SVGFontFaceElement* element)
     , verticalAdvanceY(0.0f)
 {
 }
+
+float SVGFontData::convertEmUnitToPixel(float fontSize, float unitsPerEm, float value)
+{
+    ASSERT(unitsPerEm > 0.0f);
+    return value * fontSize / unitsPerEm;
+}
 #endif
 
 FontData::FontData(const FontPlatformData& f, bool customFont, bool loading)
@@ -113,10 +119,8 @@ FontData::~FontData()
 int FontData::ascent(float fontSize) const
 {
 #if ENABLE(SVG_FONTS)
-    if (m_svgFontData) {
-        ASSERT(m_unitsPerEm > 0);
-        return m_ascent * fontSize / m_unitsPerEm;
-    }
+    if (m_svgFontData)
+        return SVGFontData::convertEmUnitToPixel(fontSize, m_unitsPerEm, m_ascent);
 #endif
 
     return m_ascent;
@@ -125,10 +129,8 @@ int FontData::ascent(float fontSize) const
 int FontData::descent(float fontSize) const
 {
 #if ENABLE(SVG_FONTS)
-    if (m_svgFontData) {
-        ASSERT(m_unitsPerEm > 0);
-        return m_descent * fontSize / m_unitsPerEm;
-    }
+    if (m_svgFontData)
+        return SVGFontData::convertEmUnitToPixel(fontSize, m_unitsPerEm, m_descent);
 #endif
 
     return m_descent;
index 6d269c7fe23d55a503bd54d936f0d31eb0468b69..66a2c773c603eb6886318214c1090661e8637a54 100644 (file)
@@ -51,6 +51,9 @@ class SVGFontFaceElement;
 struct SVGFontData {
     SVGFontData(SVGFontFaceElement*);
 
+    // Helper function
+    static float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value);
+
     // Hold pointer to our creator
     RefPtr<SVGFontFaceElement> fontFaceElement;
 
index 8a54aea06a8cef6dd1f762c33283b874925bc3c8..fba7bad66136a3a809ae9b877fdd94b1718bf3f0 100644 (file)
 
 namespace WebCore {
 
+static inline bool isVerticalWritingMode(const SVGRenderStyle* style)
+{
+    return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB; 
+}
+
 void Font::drawGlyphsWithSVGFont(GraphicsContext* context, RenderObject* renderObject,
                                  const FontData* fontData, const GlyphBuffer& glyphBuffer,
                                  int from, int to, const FloatPoint& point) const
@@ -58,16 +63,20 @@ void Font::drawGlyphsWithSVGFont(GraphicsContext* context, RenderObject* renderO
     if (fontFace->parentNode() && fontFace->parentNode()->hasTagName(SVGNames::fontTag))
         static_cast<SVGFontElement*>(fontFace->parentNode())->collectGlyphs(*this);
 
-    FloatPoint startPoint = point;
+    float fontSize = size();
+    unsigned unitsPerEm = fontFace->unitsPerEm();
+    bool isVerticalText = isVerticalWritingMode(style->svgStyle());
 
     SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, renderObject);
     SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, renderObject);
 
+    FloatPoint startPoint = point;
     for (int i = from; i < to; ++i) {
         SVGGlyphIdentifier identifier = fontFace->glyphIdentifierForGlyphCode(glyphBuffer.glyphAt(i));
 
+        // TODO: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations)
         if (!identifier.pathData.isEmpty()) {
-            float scale = size() / fontFace->unitsPerEm();
+            float scale = SVGFontData::convertEmUnitToPixel(size(), fontFace->unitsPerEm(), 1.0f); 
 
             AffineTransform ctm;
             ctm.translate(startPoint.x(), startPoint.y());
@@ -89,7 +98,11 @@ void Font::drawGlyphsWithSVGFont(GraphicsContext* context, RenderObject* renderO
             }
 
             context->restore();
-            startPoint.move(glyphBuffer.advanceAt(i), 0);
+
+            if (isVerticalText)
+                startPoint.move(0, SVGFontData::convertEmUnitToPixel(fontSize, unitsPerEm, identifier.verticalAdvanceY));
+            else
+                startPoint.move(SVGFontData::convertEmUnitToPixel(fontSize, unitsPerEm, identifier.horizontalAdvanceX), 0);
         }
     }
 }
index 454e39200f880aaf70b16817b1183904cd63d40a..1c422ebcb6801515b548a056e1124d6bdf840b0e 100644 (file)
@@ -24,6 +24,7 @@
 #include "SVGFontElement.h"
 
 #include "Font.h"
+#include "FontData.h"
 #include "GlyphPageTreeNode.h"
 #include "SVGGlyphElement.h"
 #include "SVGMissingGlyphElement.h"
@@ -45,6 +46,8 @@ SVGFontElement::~SVGFontElement()
 
 void SVGFontElement::collectGlyphs(const Font& font)
 {
+    m_glyphMap.clear();
+
     Vector<SVGGlyphElement*> glyphElements;
     SVGMissingGlyphElement* missingGlyphElement = 0;
 
@@ -58,26 +61,32 @@ void SVGFontElement::collectGlyphs(const Font& font)
     Vector<SVGGlyphElement*>::iterator it = glyphElements.begin();
     Vector<SVGGlyphElement*>::iterator end = glyphElements.end();
 
-    m_glyphMap.clear();
+    SVGFontData* svgFontData = 0;
+
+#if !PLATFORM(QT)
+    // Why doesn't Qt have primaryFont()? The Qt guys will see an assertion, if buildGlyphIdentifier() is called :(
+    const FontData* fontData = font.primaryFont();
+    ASSERT(fontData);
 
+    svgFontData = fontData->svgFontData();
+#endif
+
+    String glyphString;
     SVGGlyphIdentifier identifier;
 
-    // Only supports single glyph <-> single character situations & glyphs rendered by paths.
     for (; it != end; ++it) {
-        String pathDataString = (*it)->getAttribute(dAttr);
-        String glyphString = (*it)->getAttribute(unicodeAttr);
+        identifier = (*it)->buildGlyphIdentifier(svgFontData);
+        glyphString = (*it)->getAttribute(unicodeAttr);
+
+        // TODO: To support glyph strings consisting of more than one character (ie. 'ffl' ligatures)
+        // we need another hashing scheme. Glyph <-> SVGGlyphIdentifier is not enough.
 
-        // To support glyph strings consisting of more than one character (ie. 'ffl' ligatures) we need another hashing scheme.
-        // Glyph <-> SVGGlyphIdentifier is not enough.
-        if (glyphString.length() != 1 || pathDataString.isEmpty())
+        // TODO: We skip glyphs with empty paths, this is not correct if the <glyph> has no d="" but children!
+        
+        if (glyphString.length() != 1 || identifier.pathData.isEmpty())
             continue;
 
         const GlyphData& glyphData = font.glyphDataForCharacter(glyphString[0], false /* TODO: no rtl, is this correct in all cases? */);
-
-        identifier.pathData = Path();
-        pathFromSVGData(identifier.pathData, pathDataString);
-
-        //fprintf(stderr, "FOUND NEW GLYPH! pathDataString: '%s' glyphString: '%s'  code: '%u'\n", pathDataString.latin1().data(), glyphString.latin1().data(), glyphData.glyph);
         m_glyphMap.add(glyphData.glyph, identifier);
     }
 }
index 16ba1ca2a8c4afa1448a5ad9851c830dd86d1003..1a794ff9e25c88b891b0d7f46c9f89b9665bb4cc 100644 (file)
 #if ENABLE(SVG_FONTS)
 #include "SVGGlyphElement.h"
 
-#include "SVGNames.h""
+#include "FontData.h"
+#include "SVGNames.h"
+#include "SVGParserUtilities.h"
+#include "XMLNames.h"
 
 namespace WebCore {
 
@@ -34,6 +37,83 @@ SVGGlyphElement::SVGGlyphElement(const QualifiedName& tagName, Document* doc)
 {
 }
 
+static inline SVGGlyphIdentifier::ArabicForm parseArabicForm(const AtomicString& value)
+{
+    if (value == "medial")
+        return SVGGlyphIdentifier::Medial;
+    else if (value == "terminal")
+        return SVGGlyphIdentifier::Terminal;
+    else if (value == "isolated")
+        return SVGGlyphIdentifier::Isolated;
+
+    return SVGGlyphIdentifier::Initial;
+}
+
+static inline SVGGlyphIdentifier::Orientation parseOrientation(const AtomicString& value)
+{
+    if (value == "h")
+        return SVGGlyphIdentifier::Horizontal;
+    else if (value == "v")
+        return SVGGlyphIdentifier::Vertical;
+
+    return SVGGlyphIdentifier::Both;
+}
+
+static inline Path parsePathData(const AtomicString& value)
+{
+    Path result;
+    pathFromSVGData(result, value);
+
+    return result;
+}
+
+SVGGlyphIdentifier SVGGlyphElement::buildGlyphIdentifier(SVGFontData* svgFontData) const
+{
+    ASSERT(svgFontData);
+
+    SVGGlyphIdentifier identifier;
+    identifier.glyphName = getAttribute(glyph_nameAttr);
+    identifier.orientation = parseOrientation(getAttribute(orientationAttr));
+    identifier.arabicForm = parseArabicForm(getAttribute(arabic_formAttr));
+    identifier.pathData = parsePathData(getAttribute(dAttr));
+    identifier.languages = parseDelimitedString(getAttribute(XMLNames::langAttr), ',');
+
+    // Spec: The horizontal advance after rendering the glyph in horizontal orientation.
+    // If the attribute is not specified, the effect is as if the attribute were set to the
+    // value of the font's horiz-adv-x attribute. Glyph widths are required to be non-negative,
+    // even if the glyph is typically rendered right-to-left, as in Hebrew and Arabic scripts.
+    if (hasAttribute(horiz_adv_xAttr))
+        identifier.horizontalAdvanceX = getAttribute(horiz_adv_xAttr).toFloat();
+    else
+        identifier.horizontalAdvanceX = svgFontData->horizontalAdvanceX;
+
+    // Spec: The X-coordinate in the font coordinate system of the origin of the glyph to be
+    // used when drawing vertically oriented text. If the attribute is not specified, the effect
+    // is as if the attribute were set to the value of the font's vert-origin-x attribute.
+    if (hasAttribute(vert_origin_xAttr))
+        identifier.verticalOriginX = getAttribute(vert_origin_xAttr).toFloat();
+    else
+        identifier.verticalOriginX = svgFontData->verticalOriginX;
+
+    // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be
+    // used when drawing vertically oriented text. If the attribute is not specified, the effect
+    // is as if the attribute were set to the value of the font's vert-origin-y attribute.
+    if (hasAttribute(vert_origin_yAttr))
+        identifier.verticalOriginY = getAttribute(vert_origin_yAttr).toFloat();
+    else
+        identifier.verticalOriginY = svgFontData->verticalOriginY;
+
+    // Spec: The vertical advance after rendering a glyph in vertical orientation.
+    // If the attribute is not specified, the effect is as if the attribute were set to the
+    // value of the font's vert-adv-y attribute.
+    if (hasAttribute(vert_adv_yAttr))
+        identifier.verticalAdvanceY = getAttribute(vert_adv_yAttr).toFloat();
+    else
+        identifier.verticalAdvanceY = svgFontData->verticalAdvanceY;
+
+    return identifier;
+}
+
 }
 
 #endif // ENABLE(SVG_FONTS)
index 296a6d948e62cf27783c9878db705f9a180005e3..0813acdf2b60850d37d9f69b67e6e5a768911ebd 100644 (file)
 #include "Path.h"
 
 namespace WebCore {
-    
-    class SVGGlyphElement : public SVGStyledElement {
-    public:
-        SVGGlyphElement(const QualifiedName&, Document*);
 
-        virtual bool rendererIsNeeded(RenderStyle*) { return false; }
-    };
+    struct SVGFontData;
 
     // Describe a SVG <glyph> element
     struct SVGGlyphIdentifier {
@@ -50,7 +45,10 @@ namespace WebCore {
         {
         }
 
-        // 'orientation' property;
+        // 'glyph-name' property
+        String glyphName;
+
+        // 'orientation' property
         Orientation orientation;
 
         // 'arabic-form' property
@@ -75,9 +73,17 @@ namespace WebCore {
         Vector<String> languages;
     };
 
+    class SVGGlyphElement : public SVGStyledElement {
+    public:
+        SVGGlyphElement(const QualifiedName&, Document*);
+
+        virtual bool rendererIsNeeded(RenderStyle*) { return false; }
+
+        SVGGlyphIdentifier buildGlyphIdentifier(SVGFontData*) const;
+    };
+
+
 } // namespace WebCore
 
 #endif // ENABLE(SVG_FONTS)
 #endif
-
-// vim:ts=4:noet