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/CSSFontSelector.h"
32 #include "core/css/CSSStyleSheet.h"
33 #include "core/css/CSSValueList.h"
34 #include "core/css/StylePropertySet.h"
35 #include "core/css/StyleRule.h"
36 #include "core/dom/Attribute.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/StyleEngine.h"
39 #include "core/svg/SVGDocumentExtensions.h"
40 #include "core/svg/SVGFontElement.h"
41 #include "core/svg/SVGFontFaceSrcElement.h"
42 #include "core/svg/SVGGlyphElement.h"
43 #include "platform/fonts/Font.h"
47 using namespace SVGNames;
49 inline SVGFontFaceElement::SVGFontFaceElement(Document& document)
50 : SVGElement(font_faceTag, document)
51 , m_fontFaceRule(StyleRuleFontFace::create())
55 ScriptWrappable::init(this);
56 RefPtrWillBeRawPtr<MutableStylePropertySet> styleDeclaration = MutableStylePropertySet::create(HTMLStandardMode);
57 m_fontFaceRule->setProperties(styleDeclaration.release());
60 PassRefPtr<SVGFontFaceElement> SVGFontFaceElement::create(Document& document)
62 return adoptRef(new SVGFontFaceElement(document));
65 static CSSPropertyID cssPropertyIdForFontFaceAttributeName(const QualifiedName& attrName)
67 if (!attrName.namespaceURI().isNull())
68 return CSSPropertyInvalid;
70 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
71 if (!propertyNameToIdMap) {
72 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
73 // This is a list of all @font-face CSS properties which are exposed as SVG XML attributes
74 // Those commented out are not yet supported by WebCore's style system
75 // mapAttributeToCSSProperty(propertyNameToIdMap, accent_heightAttr);
76 // mapAttributeToCSSProperty(propertyNameToIdMap, alphabeticAttr);
77 // mapAttributeToCSSProperty(propertyNameToIdMap, ascentAttr);
78 // mapAttributeToCSSProperty(propertyNameToIdMap, bboxAttr);
79 // mapAttributeToCSSProperty(propertyNameToIdMap, cap_heightAttr);
80 // mapAttributeToCSSProperty(propertyNameToIdMap, descentAttr);
81 mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
82 mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
83 mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
84 mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
85 mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
86 mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
87 // mapAttributeToCSSProperty(propertyNameToIdMap, hangingAttr);
88 // mapAttributeToCSSProperty(propertyNameToIdMap, ideographicAttr);
89 // mapAttributeToCSSProperty(propertyNameToIdMap, mathematicalAttr);
90 // mapAttributeToCSSProperty(propertyNameToIdMap, overline_positionAttr);
91 // mapAttributeToCSSProperty(propertyNameToIdMap, overline_thicknessAttr);
92 // mapAttributeToCSSProperty(propertyNameToIdMap, panose_1Attr);
93 // mapAttributeToCSSProperty(propertyNameToIdMap, slopeAttr);
94 // mapAttributeToCSSProperty(propertyNameToIdMap, stemhAttr);
95 // mapAttributeToCSSProperty(propertyNameToIdMap, stemvAttr);
96 // mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_positionAttr);
97 // mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_thicknessAttr);
98 // mapAttributeToCSSProperty(propertyNameToIdMap, underline_positionAttr);
99 // mapAttributeToCSSProperty(propertyNameToIdMap, underline_thicknessAttr);
100 // mapAttributeToCSSProperty(propertyNameToIdMap, unicode_rangeAttr);
101 // mapAttributeToCSSProperty(propertyNameToIdMap, units_per_emAttr);
102 // mapAttributeToCSSProperty(propertyNameToIdMap, v_alphabeticAttr);
103 // mapAttributeToCSSProperty(propertyNameToIdMap, v_hangingAttr);
104 // mapAttributeToCSSProperty(propertyNameToIdMap, v_ideographicAttr);
105 // mapAttributeToCSSProperty(propertyNameToIdMap, v_mathematicalAttr);
106 // mapAttributeToCSSProperty(propertyNameToIdMap, widthsAttr);
107 // mapAttributeToCSSProperty(propertyNameToIdMap, x_heightAttr);
110 return propertyNameToIdMap->get(attrName.localName().impl());
113 void SVGFontFaceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
115 CSSPropertyID propId = cssPropertyIdForFontFaceAttributeName(name);
117 m_fontFaceRule->mutableProperties().setProperty(propId, value, false);
122 SVGElement::parseAttribute(name, value);
125 unsigned SVGFontFaceElement::unitsPerEm() const
127 const AtomicString& value = fastGetAttribute(units_per_emAttr);
129 return gDefaultUnitsPerEm;
131 return static_cast<unsigned>(ceilf(value.toFloat()));
134 int SVGFontFaceElement::xHeight() const
136 return static_cast<int>(ceilf(fastGetAttribute(x_heightAttr).toFloat()));
139 float SVGFontFaceElement::horizontalOriginX() const
144 // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
145 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
146 // If the attribute is not specified, the effect is as if a value of "0" were specified.
147 return m_fontElement->fastGetAttribute(horiz_origin_xAttr).toFloat();
150 float SVGFontFaceElement::horizontalOriginY() const
155 // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
156 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
157 // If the attribute is not specified, the effect is as if a value of "0" were specified.
158 return m_fontElement->fastGetAttribute(horiz_origin_yAttr).toFloat();
161 float SVGFontFaceElement::horizontalAdvanceX() const
166 // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
167 // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
168 // as in Hebrew and Arabic scripts.
169 return m_fontElement->fastGetAttribute(horiz_adv_xAttr).toFloat();
172 float SVGFontFaceElement::verticalOriginX() const
177 // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
178 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
179 // were set to half of the effective value of attribute horiz-adv-x.
180 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_xAttr);
182 return horizontalAdvanceX() / 2.0f;
184 return value.toFloat();
187 float SVGFontFaceElement::verticalOriginY() const
192 // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
193 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
194 // were set to the position specified by the font's ascent attribute.
195 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_yAttr);
199 return value.toFloat();
202 float SVGFontFaceElement::verticalAdvanceY() const
207 // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
208 // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).
209 const AtomicString& value = m_fontElement->fastGetAttribute(vert_adv_yAttr);
213 return value.toFloat();
216 int SVGFontFaceElement::ascent() const
218 // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
219 // unaccented height of the font within the font coordinate system. If the attribute is not specified,
220 // the effect is as if the attribute were set to the difference between the units-per-em value and the
221 // vert-origin-y value for the corresponding font.
222 const AtomicString& ascentValue = fastGetAttribute(ascentAttr);
223 if (!ascentValue.isEmpty())
224 return static_cast<int>(ceilf(ascentValue.toFloat()));
227 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
228 if (!vertOriginY.isEmpty())
229 return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertOriginY.toFloat()));
232 // Match Batiks default value
233 return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
236 int SVGFontFaceElement::descent() const
238 // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
239 // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
240 // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
241 const AtomicString& descentValue = fastGetAttribute(descentAttr);
242 if (!descentValue.isEmpty()) {
243 // 14 different W3C SVG 1.1 testcases use a negative descent value,
244 // where a positive was meant to be used Including:
245 // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and 11 others)
246 int descent = static_cast<int>(ceilf(descentValue.toFloat()));
247 return descent < 0 ? -descent : descent;
251 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
252 if (!vertOriginY.isEmpty())
253 return static_cast<int>(ceilf(vertOriginY.toFloat()));
256 // Match Batiks default value
257 return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
260 String SVGFontFaceElement::fontFamily() const
262 return m_fontFaceRule->properties().getPropertyValue(CSSPropertyFontFamily);
265 SVGFontElement* SVGFontFaceElement::associatedFontElement() const
267 ASSERT(parentNode() == m_fontElement);
268 ASSERT(!parentNode() || isSVGFontElement(*parentNode()));
269 return m_fontElement;
272 void SVGFontFaceElement::rebuildFontFace()
275 ASSERT(!m_fontElement);
279 bool describesParentFont = isSVGFontElement(*parentNode());
280 RefPtrWillBeRawPtr<CSSValueList> list = nullptr;
282 if (describesParentFont) {
283 m_fontElement = toSVGFontElement(parentNode());
285 list = CSSValueList::createCommaSeparated();
286 list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
289 // we currently ignore all but the last src element, alternatively we could concat them
290 if (SVGFontFaceSrcElement* element = Traversal<SVGFontFaceSrcElement>::lastChild(*this))
291 list = element->srcValue();
294 if (!list || !list->length())
297 // Parse in-memory CSS rules
298 m_fontFaceRule->mutableProperties().addParsedProperty(CSSProperty(CSSPropertySrc, list));
300 if (describesParentFont) {
301 // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
302 RefPtrWillBeRawPtr<CSSValue> src = m_fontFaceRule->properties().getPropertyCSSValue(CSSPropertySrc);
303 CSSValueList* srcList = toCSSValueList(src.get());
305 unsigned srcLength = srcList ? srcList->length() : 0;
306 for (unsigned i = 0; i < srcLength; i++) {
307 if (CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i)))
308 item->setSVGFontFaceElement(this);
312 document().styleResolverChanged(RecalcStyleDeferred);
315 Node::InsertionNotificationRequest SVGFontFaceElement::insertedInto(ContainerNode* rootParent)
317 SVGElement::insertedInto(rootParent);
318 if (!rootParent->inDocument()) {
319 ASSERT(!m_fontElement);
320 return InsertionDone;
322 document().accessSVGExtensions().registerSVGFontFaceElement(this);
325 return InsertionDone;
328 void SVGFontFaceElement::removedFrom(ContainerNode* rootParent)
330 SVGElement::removedFrom(rootParent);
332 if (rootParent->inDocument()) {
334 document().accessSVGExtensions().unregisterSVGFontFaceElement(this);
336 // FIXME: HTMLTemplateElement's document or imported document can be active?
337 // If so, we also need to check whether fontSelector() is nullptr or not.
338 // Otherwise, we will use just document().isActive() here.
339 if (document().isActive() && document().styleEngine()->fontSelector()) {
340 document().styleEngine()->fontSelector()->fontFaceCache()->remove(m_fontFaceRule.get());
341 document().accessSVGExtensions().registerPendingSVGFontFaceElementsForRemoval(this);
343 m_fontFaceRule->mutableProperties().clear();
344 document().styleResolverChanged(RecalcStyleDeferred);
346 ASSERT(!m_fontElement);
349 void SVGFontFaceElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
351 SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
355 void SVGFontFaceElement::trace(Visitor* visitor)
357 visitor->trace(m_fontFaceRule);
358 SVGElement::trace(visitor);
361 } // namespace WebCore
363 #endif // ENABLE(SVG_FONTS)