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 "SVGFontFaceElement.h"
27 #include "Attribute.h"
28 #include "CSSFontFaceSrcValue.h"
29 #include "CSSParser.h"
30 #include "CSSPropertyNames.h"
31 #include "CSSStyleSheet.h"
32 #include "CSSValueKeywords.h"
33 #include "CSSValueList.h"
35 #include "ElementIterator.h"
37 #include "SVGDocumentExtensions.h"
38 #include "SVGFontElement.h"
39 #include "SVGFontFaceSrcElement.h"
40 #include "SVGGlyphElement.h"
42 #include "StyleProperties.h"
43 #include "StyleResolver.h"
44 #include "StyleRule.h"
49 using namespace SVGNames;
51 inline SVGFontFaceElement::SVGFontFaceElement(const QualifiedName& tagName, Document& document)
52 : SVGElement(tagName, document)
53 , m_fontFaceRule(StyleRuleFontFace::create(MutableStyleProperties::create(CSSStrictMode)))
56 ASSERT(hasTagName(font_faceTag));
59 PassRefPtr<SVGFontFaceElement> SVGFontFaceElement::create(const QualifiedName& tagName, Document& document)
61 return adoptRef(new SVGFontFaceElement(tagName, document));
64 void SVGFontFaceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
66 CSSPropertyID propId = cssPropertyIdForSVGAttributeName(name);
68 m_fontFaceRule->mutableProperties().setProperty(propId, value, false);
73 SVGElement::parseAttribute(name, value);
76 unsigned SVGFontFaceElement::unitsPerEm() const
78 const AtomicString& value = fastGetAttribute(units_per_emAttr);
80 return gDefaultUnitsPerEm;
82 return static_cast<unsigned>(ceilf(value.toFloat()));
85 int SVGFontFaceElement::xHeight() const
87 return static_cast<int>(ceilf(fastGetAttribute(x_heightAttr).toFloat()));
90 float SVGFontFaceElement::horizontalOriginX() const
95 // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
96 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
97 // If the attribute is not specified, the effect is as if a value of "0" were specified.
98 return m_fontElement->fastGetAttribute(horiz_origin_xAttr).toFloat();
101 float SVGFontFaceElement::horizontalOriginY() const
106 // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
107 // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
108 // If the attribute is not specified, the effect is as if a value of "0" were specified.
109 return m_fontElement->fastGetAttribute(horiz_origin_yAttr).toFloat();
112 float SVGFontFaceElement::horizontalAdvanceX() const
117 // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
118 // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
119 // as in Hebrew and Arabic scripts.
120 return m_fontElement->fastGetAttribute(horiz_adv_xAttr).toFloat();
123 float SVGFontFaceElement::verticalOriginX() const
128 // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
129 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
130 // were set to half of the effective value of attribute horiz-adv-x.
131 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_xAttr);
133 return horizontalAdvanceX() / 2.0f;
135 return value.toFloat();
138 float SVGFontFaceElement::verticalOriginY() const
143 // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
144 // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
145 // were set to the position specified by the font's ascent attribute.
146 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_yAttr);
150 return value.toFloat();
153 float SVGFontFaceElement::verticalAdvanceY() const
158 // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
159 // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).
160 const AtomicString& value = m_fontElement->fastGetAttribute(vert_adv_yAttr);
164 return value.toFloat();
167 int SVGFontFaceElement::ascent() const
169 // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
170 // unaccented height of the font within the font coordinate system. If the attribute is not specified,
171 // the effect is as if the attribute were set to the difference between the units-per-em value and the
172 // vert-origin-y value for the corresponding font.
173 const AtomicString& ascentValue = fastGetAttribute(ascentAttr);
174 if (!ascentValue.isEmpty())
175 return static_cast<int>(ceilf(ascentValue.toFloat()));
178 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
179 if (!vertOriginY.isEmpty())
180 return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertOriginY.toFloat()));
183 // Match Batiks default value
184 return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
187 int SVGFontFaceElement::descent() const
189 // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
190 // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
191 // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
192 const AtomicString& descentValue = fastGetAttribute(descentAttr);
193 if (!descentValue.isEmpty()) {
194 // 14 different W3C SVG 1.1 testcases use a negative descent value,
195 // where a positive was meant to be used Including:
196 // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and 11 others)
197 int descent = static_cast<int>(ceilf(descentValue.toFloat()));
198 return descent < 0 ? -descent : descent;
202 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_origin_yAttr);
203 if (!vertOriginY.isEmpty())
204 return static_cast<int>(ceilf(vertOriginY.toFloat()));
207 // Match Batiks default value
208 return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
211 String SVGFontFaceElement::fontFamily() const
213 return m_fontFaceRule->properties().getPropertyValue(CSSPropertyFontFamily);
216 SVGFontElement* SVGFontFaceElement::associatedFontElement() const
218 ASSERT(parentNode() == m_fontElement);
219 ASSERT(!parentNode() || isSVGFontElement(parentNode()));
220 return m_fontElement;
223 void SVGFontFaceElement::rebuildFontFace()
226 ASSERT(!m_fontElement);
230 // we currently ignore all but the first src element, alternatively we could concat them
231 auto srcElement = childrenOfType<SVGFontFaceSrcElement>(*this).first();
233 bool describesParentFont = isSVGFontElement(parentNode());
234 RefPtr<CSSValueList> list;
236 if (describesParentFont) {
237 m_fontElement = downcast<SVGFontElement>(parentNode());
239 list = CSSValueList::createCommaSeparated();
240 list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
242 m_fontElement = nullptr;
244 list = srcElement->srcValue();
247 if (!list || !list->length())
250 // Parse in-memory CSS rules
251 m_fontFaceRule->mutableProperties().addParsedProperty(CSSProperty(CSSPropertySrc, list));
253 if (describesParentFont) {
254 // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
255 RefPtr<CSSValue> src = m_fontFaceRule->properties().getPropertyCSSValue(CSSPropertySrc);
256 CSSValueList* srcList = toCSSValueList(src.get());
258 unsigned srcLength = srcList ? srcList->length() : 0;
259 for (unsigned i = 0; i < srcLength; i++) {
260 if (CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i)))
261 item->setSVGFontFaceElement(this);
265 document().styleResolverChanged(DeferRecalcStyle);
268 Node::InsertionNotificationRequest SVGFontFaceElement::insertedInto(ContainerNode& rootParent)
270 SVGElement::insertedInto(rootParent);
271 if (!rootParent.inDocument()) {
272 ASSERT(!m_fontElement);
273 return InsertionDone;
275 document().accessSVGExtensions().registerSVGFontFaceElement(this);
278 return InsertionDone;
281 void SVGFontFaceElement::removedFrom(ContainerNode& rootParent)
283 SVGElement::removedFrom(rootParent);
285 if (rootParent.inDocument()) {
287 document().accessSVGExtensions().unregisterSVGFontFaceElement(this);
288 m_fontFaceRule->mutableProperties().clear();
290 document().styleResolverChanged(DeferRecalcStyle);
292 ASSERT(!m_fontElement);
295 void SVGFontFaceElement::childrenChanged(const ChildChange& change)
297 SVGElement::childrenChanged(change);
301 } // namespace WebCore
303 #endif // ENABLE(SVG_FONTS)