2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
4 * Copyright (C) 2008 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
25 #include "core/svg/SVGFontFaceElement.h"
28 #include "CSSPropertyNames.h"
29 #include "CSSValueKeywords.h"
30 #include "core/css/CSSFontFaceSrcValue.h"
31 #include "core/css/CSSStyleSheet.h"
32 #include "core/css/CSSValueList.h"
33 #include "core/css/StylePropertySet.h"
34 #include "core/css/StyleRule.h"
35 #include "core/dom/Attribute.h"
36 #include "core/dom/Document.h"
37 #include "core/svg/SVGDocumentExtensions.h"
38 #include "core/svg/SVGFontElement.h"
39 #include "core/svg/SVGFontFaceSrcElement.h"
40 #include "core/svg/SVGGlyphElement.h"
41 #include "platform/fonts/Font.h"
45 using namespace SVGNames;
47 inline SVGFontFaceElement::SVGFontFaceElement(Document& document)
48 : SVGElement(font_faceTag, document)
49 , m_fontFaceRule(StyleRuleFontFace::create())
52 ScriptWrappable::init(this);
53 RefPtr<MutableStylePropertySet> styleDeclaration = MutableStylePropertySet::create(HTMLStandardMode);
54 m_fontFaceRule->setProperties(styleDeclaration.release());
57 PassRefPtr<SVGFontFaceElement> SVGFontFaceElement::create(Document& document)
59 return adoptRef(new SVGFontFaceElement(document));
62 static CSSPropertyID cssPropertyIdForFontFaceAttributeName(const QualifiedName& attrName)
64 if (!attrName.namespaceURI().isNull())
65 return CSSPropertyInvalid;
67 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
68 if (!propertyNameToIdMap) {
69 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
70 // This is a list of all @font-face CSS properties which are exposed as SVG XML attributes
71 // Those commented out are not yet supported by WebCore's style system
72 // mapAttributeToCSSProperty(propertyNameToIdMap, accent_heightAttr);
73 // mapAttributeToCSSProperty(propertyNameToIdMap, alphabeticAttr);
74 // mapAttributeToCSSProperty(propertyNameToIdMap, ascentAttr);
75 // mapAttributeToCSSProperty(propertyNameToIdMap, bboxAttr);
76 // mapAttributeToCSSProperty(propertyNameToIdMap, cap_heightAttr);
77 // mapAttributeToCSSProperty(propertyNameToIdMap, descentAttr);
78 mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
79 mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
80 mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
81 mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
82 mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
83 mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
84 // mapAttributeToCSSProperty(propertyNameToIdMap, hangingAttr);
85 // mapAttributeToCSSProperty(propertyNameToIdMap, ideographicAttr);
86 // mapAttributeToCSSProperty(propertyNameToIdMap, mathematicalAttr);
87 // mapAttributeToCSSProperty(propertyNameToIdMap, overline_positionAttr);
88 // mapAttributeToCSSProperty(propertyNameToIdMap, overline_thicknessAttr);
89 // mapAttributeToCSSProperty(propertyNameToIdMap, panose_1Attr);
90 // mapAttributeToCSSProperty(propertyNameToIdMap, slopeAttr);
91 // mapAttributeToCSSProperty(propertyNameToIdMap, stemhAttr);
92 // mapAttributeToCSSProperty(propertyNameToIdMap, stemvAttr);
93 // mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_positionAttr);
94 // mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_thicknessAttr);
95 // mapAttributeToCSSProperty(propertyNameToIdMap, underline_positionAttr);
96 // mapAttributeToCSSProperty(propertyNameToIdMap, underline_thicknessAttr);
97 // mapAttributeToCSSProperty(propertyNameToIdMap, unicode_rangeAttr);
98 // mapAttributeToCSSProperty(propertyNameToIdMap, units_per_emAttr);
99 // mapAttributeToCSSProperty(propertyNameToIdMap, v_alphabeticAttr);
100 // mapAttributeToCSSProperty(propertyNameToIdMap, v_hangingAttr);
101 // mapAttributeToCSSProperty(propertyNameToIdMap, v_ideographicAttr);
102 // mapAttributeToCSSProperty(propertyNameToIdMap, v_mathematicalAttr);
103 // mapAttributeToCSSProperty(propertyNameToIdMap, widthsAttr);
104 // mapAttributeToCSSProperty(propertyNameToIdMap, x_heightAttr);
107 return propertyNameToIdMap->get(attrName.localName().impl());
110 void SVGFontFaceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
112 CSSPropertyID propId = cssPropertyIdForFontFaceAttributeName(name);
114 m_fontFaceRule->mutableProperties()->setProperty(propId, value, false);
119 SVGElement::parseAttribute(name, value);
122 unsigned SVGFontFaceElement::unitsPerEm() const
124 const AtomicString& value = fastGetAttribute(units_per_emAttr);
126 return gDefaultUnitsPerEm;
128 return static_cast<unsigned>(ceilf(value.toFloat()));
131 int SVGFontFaceElement::xHeight() const
133 return static_cast<int>(ceilf(fastGetAttribute(x_heightAttr).toFloat()));
136 float SVGFontFaceElement::horizontalOriginX() const
141 // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
142 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
143 // If the attribute is not specified, the effect is as if a value of "0" were specified.
144 return m_fontElement->fastGetAttribute(horiz_origin_xAttr).toFloat();
147 float SVGFontFaceElement::horizontalOriginY() const
152 // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
153 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
154 // If the attribute is not specified, the effect is as if a value of "0" were specified.
155 return m_fontElement->fastGetAttribute(horiz_origin_yAttr).toFloat();
158 float SVGFontFaceElement::horizontalAdvanceX() const
163 // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
164 // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
165 // as in Hebrew and Arabic scripts.
166 return m_fontElement->fastGetAttribute(horiz_adv_xAttr).toFloat();
169 float SVGFontFaceElement::verticalOriginX() const
174 // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
175 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
176 // were set to half of the effective value of attribute horiz-adv-x.
177 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_xAttr);
179 return horizontalAdvanceX() / 2.0f;
181 return value.toFloat();
184 float SVGFontFaceElement::verticalOriginY() const
189 // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
190 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
191 // were set to the position specified by the font's ascent attribute.
192 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_yAttr);
196 return value.toFloat();
199 float SVGFontFaceElement::verticalAdvanceY() const
204 // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
205 // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).
206 const AtomicString& value = m_fontElement->fastGetAttribute(vert_adv_yAttr);
210 return value.toFloat();
213 int SVGFontFaceElement::ascent() const
215 // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
216 // unaccented height of the font within the font coordinate system. If the attribute is not specified,
217 // the effect is as if the attribute were set to the difference between the units-per-em value and the
218 // vert-origin-y value for the corresponding font.
219 const AtomicString& ascentValue = fastGetAttribute(ascentAttr);
220 if (!ascentValue.isEmpty())
221 return static_cast<int>(ceilf(ascentValue.toFloat()));
224 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
225 if (!vertOriginY.isEmpty())
226 return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertOriginY.toFloat()));
229 // Match Batiks default value
230 return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
233 int SVGFontFaceElement::descent() const
235 // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
236 // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
237 // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
238 const AtomicString& descentValue = fastGetAttribute(descentAttr);
239 if (!descentValue.isEmpty()) {
240 // 14 different W3C SVG 1.1 testcases use a negative descent value,
241 // where a positive was meant to be used Including:
242 // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and 11 others)
243 int descent = static_cast<int>(ceilf(descentValue.toFloat()));
244 return descent < 0 ? -descent : descent;
248 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
249 if (!vertOriginY.isEmpty())
250 return static_cast<int>(ceilf(vertOriginY.toFloat()));
253 // Match Batiks default value
254 return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
257 String SVGFontFaceElement::fontFamily() const
259 return m_fontFaceRule->properties()->getPropertyValue(CSSPropertyFontFamily);
262 SVGFontElement* SVGFontFaceElement::associatedFontElement() const
264 ASSERT(parentNode() == m_fontElement);
265 ASSERT(!parentNode() || parentNode()->hasTagName(SVGNames::fontTag));
266 return m_fontElement;
269 void SVGFontFaceElement::rebuildFontFace()
272 ASSERT(!m_fontElement);
276 bool describesParentFont = parentNode()->hasTagName(SVGNames::fontTag);
277 RefPtrWillBeRawPtr<CSSValueList> list;
279 if (describesParentFont) {
280 m_fontElement = toSVGFontElement(parentNode());
282 list = CSSValueList::createCommaSeparated();
283 list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
286 // we currently ignore all but the last src element, alternatively we could concat them
287 for (Node* child = lastChild(); child && !list; child = child->previousSibling()) {
288 if (child->hasTagName(font_face_srcTag)) {
289 list = toSVGFontFaceSrcElement(child)->srcValue();
295 if (!list || !list->length())
298 // Parse in-memory CSS rules
299 m_fontFaceRule->mutableProperties()->addParsedProperty(CSSProperty(CSSPropertySrc, list));
301 if (describesParentFont) {
302 // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
303 RefPtr<CSSValue> src = m_fontFaceRule->properties()->getPropertyCSSValue(CSSPropertySrc);
304 CSSValueList* srcList = toCSSValueList(src.get());
306 unsigned srcLength = srcList ? srcList->length() : 0;
307 for (unsigned i = 0; i < srcLength; i++) {
308 if (CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i)))
309 item->setSVGFontFaceElement(this);
313 document().styleResolverChanged(RecalcStyleDeferred);
316 Node::InsertionNotificationRequest SVGFontFaceElement::insertedInto(ContainerNode* rootParent)
318 SVGElement::insertedInto(rootParent);
319 if (!rootParent->inDocument()) {
320 ASSERT(!m_fontElement);
321 return InsertionDone;
323 document().accessSVGExtensions()->registerSVGFontFaceElement(this);
326 return InsertionDone;
329 void SVGFontFaceElement::removedFrom(ContainerNode* rootParent)
331 SVGElement::removedFrom(rootParent);
333 if (rootParent->inDocument()) {
335 document().accessSVGExtensions()->unregisterSVGFontFaceElement(this);
336 m_fontFaceRule->mutableProperties()->clear();
338 document().styleResolverChanged(RecalcStyleDeferred);
340 ASSERT(!m_fontElement);
343 void SVGFontFaceElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
345 SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
349 } // namespace WebCore
351 #endif // ENABLE(SVG_FONTS)