1 /*
2    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3    Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20 
21 #include "wtf/Platform.h"
22 
23 #if ENABLE(SVG_FONTS)
24 #include "SVGGlyphElement.h"
25 
26 #include "SVGFontElement.h"
27 //FIXME khtml #include "SVGFontFaceElement.h"
28 #include "SVGFontData.h"
29 #include "SVGNames.h"
30 #include "SVGParserUtilities.h"
31 //FIXME khtml #include "SimpleFontData.h"
32 
33 namespace WebCore
34 {
35 
36 using namespace SVGNames;
37 
SVGGlyphElement(const QualifiedName & tagName,Document * doc)38 SVGGlyphElement::SVGGlyphElement(const QualifiedName &tagName, Document *doc)
39     : SVGStyledElement(tagName, doc)
40 {
41 }
42 
~SVGGlyphElement()43 SVGGlyphElement::~SVGGlyphElement()
44 {
45 }
46 
insertedIntoDocument()47 void SVGGlyphElement::insertedIntoDocument()
48 {
49     Node *fontNode = parentNode();
50     if (fontNode && fontNode->hasTagName(fontTag)) {
51         if (SVGFontElement *element = static_cast<SVGFontElement *>(fontNode)) {
52             element->invalidateGlyphCache();
53         }
54     }
55     SVGStyledElement::insertedIntoDocument();
56 }
57 
removedFromDocument()58 void SVGGlyphElement::removedFromDocument()
59 {
60     Node *fontNode = parentNode();
61     if (fontNode && fontNode->hasTagName(fontTag)) {
62         if (SVGFontElement *element = static_cast<SVGFontElement *>(fontNode)) {
63             element->invalidateGlyphCache();
64         }
65     }
66     SVGStyledElement::removedFromDocument();
67 }
68 
parseArabicForm(const AtomicString & value)69 static inline SVGGlyphIdentifier::ArabicForm parseArabicForm(const AtomicString &value)
70 {
71     if (value == "medial") {
72         return SVGGlyphIdentifier::Medial;
73     } else if (value == "terminal") {
74         return SVGGlyphIdentifier::Terminal;
75     } else if (value == "isolated") {
76         return SVGGlyphIdentifier::Isolated;
77     } else if (value == "initial") {
78         return SVGGlyphIdentifier::Initial;
79     }
80 
81     return SVGGlyphIdentifier::None;
82 }
83 
parseOrientation(const AtomicString & value)84 static inline SVGGlyphIdentifier::Orientation parseOrientation(const AtomicString &value)
85 {
86     if (value == "h") {
87         return SVGGlyphIdentifier::Horizontal;
88     } else if (value == "v") {
89         return SVGGlyphIdentifier::Vertical;
90     }
91 
92     return SVGGlyphIdentifier::Both;
93 }
94 
parsePathData(const AtomicString & value)95 static inline Path parsePathData(const AtomicString &value)
96 {
97     Path result;
98     pathFromSVGData(result, value);
99 
100     return result;
101 }
102 
inheritUnspecifiedAttributes(SVGGlyphIdentifier & identifier,const SVGFontData * svgFontData)103 void SVGGlyphElement::inheritUnspecifiedAttributes(SVGGlyphIdentifier &identifier, const SVGFontData *svgFontData)
104 {
105     if (identifier.horizontalAdvanceX == SVGGlyphIdentifier::inheritedValue()) {
106         identifier.horizontalAdvanceX = svgFontData->horizontalAdvanceX();
107     }
108 
109     if (identifier.verticalOriginX == SVGGlyphIdentifier::inheritedValue()) {
110         identifier.verticalOriginX = svgFontData->verticalOriginX();
111     }
112 
113     if (identifier.verticalOriginY == SVGGlyphIdentifier::inheritedValue()) {
114         identifier.verticalOriginY = svgFontData->verticalOriginY();
115     }
116 
117     if (identifier.verticalAdvanceY == SVGGlyphIdentifier::inheritedValue()) {
118         identifier.verticalAdvanceY = svgFontData->verticalAdvanceY();
119     }
120 }
121 
parseSVGGlyphAttribute(const SVGElement * element,const WebCore::QualifiedName & name)122 static inline float parseSVGGlyphAttribute(const SVGElement *element, const WebCore::QualifiedName &name)
123 {
124     AtomicString value(element->getAttribute(name));
125     if (value.isEmpty()) {
126         return SVGGlyphIdentifier::inheritedValue();
127     }
128 
129     return value.string().string().toFloat();
130 }
131 
buildGenericGlyphIdentifier(const SVGElement * element)132 SVGGlyphIdentifier SVGGlyphElement::buildGenericGlyphIdentifier(const SVGElement *element)
133 {
134     SVGGlyphIdentifier identifier;
135     identifier.pathData = parsePathData(element->getAttribute(dAttr));
136 
137     // Spec: The horizontal advance after rendering the glyph in horizontal orientation.
138     // If the attribute is not specified, the effect is as if the attribute were set to the
139     // value of the font's horiz-adv-x attribute. Glyph widths are required to be non-negative,
140     // even if the glyph is typically rendered right-to-left, as in Hebrew and Arabic scripts.
141     identifier.horizontalAdvanceX = parseSVGGlyphAttribute(element, horiz_adv_xAttr);
142 
143     // Spec: The X-coordinate in the font coordinate system of the origin of the glyph to be
144     // used when drawing vertically oriented text. If the attribute is not specified, the effect
145     // is as if the attribute were set to the value of the font's vert-origin-x attribute.
146     identifier.verticalOriginX = parseSVGGlyphAttribute(element, vert_origin_xAttr);
147 
148     // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be
149     // used when drawing vertically oriented text. If the attribute is not specified, the effect
150     // is as if the attribute were set to the value of the font's vert-origin-y attribute.
151     identifier.verticalOriginY = parseSVGGlyphAttribute(element, vert_origin_yAttr);
152 
153     // Spec: The vertical advance after rendering a glyph in vertical orientation.
154     // If the attribute is not specified, the effect is as if the attribute were set to the
155     // value of the font's vert-adv-y attribute.
156     identifier.verticalAdvanceY = parseSVGGlyphAttribute(element, vert_adv_yAttr);
157 
158     return identifier;
159 }
160 
buildGlyphIdentifier() const161 SVGGlyphIdentifier SVGGlyphElement::buildGlyphIdentifier() const
162 {
163     SVGGlyphIdentifier identifier(buildGenericGlyphIdentifier(this));
164     identifier.glyphName = getAttribute(glyph_nameAttr);
165     identifier.orientation = parseOrientation(getAttribute(orientationAttr));
166     identifier.arabicForm = parseArabicForm(getAttribute(arabic_formAttr));
167 
168     String language = getAttribute(langAttr);
169     if (!language.isEmpty()) {
170         identifier.languages = parseDelimitedString(language, ',');
171     }
172 
173     return identifier;
174 }
175 
176 }
177 
178 #endif // ENABLE(SVG_FONTS)
179