Add an argument indicating the type of insertion to Node::insertedInto
[WebKit-https.git] / Source / WebCore / svg / SVGFontFaceElement.cpp
1 /*
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.
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(SVG_FONTS)
25 #include "SVGFontFaceElement.h"
26
27 #include "CSSFontFaceSrcValue.h"
28 #include "CSSParser.h"
29 #include "CSSPropertyNames.h"
30 #include "CSSStyleSheet.h"
31 #include "CSSValueKeywords.h"
32 #include "CSSValueList.h"
33 #include "Document.h"
34 #include "ElementIterator.h"
35 #include "FontCascade.h"
36 #include "SVGDocumentExtensions.h"
37 #include "SVGFontElement.h"
38 #include "SVGFontFaceSrcElement.h"
39 #include "SVGGlyphElement.h"
40 #include "SVGNames.h"
41 #include "StyleProperties.h"
42 #include "StyleResolver.h"
43 #include "StyleRule.h"
44 #include "StyleScope.h"
45 #include <math.h>
46
47 namespace WebCore {
48
49 using namespace SVGNames;
50
51 inline SVGFontFaceElement::SVGFontFaceElement(const QualifiedName& tagName, Document& document)
52     : SVGElement(tagName, document)
53     , m_fontFaceRule(StyleRuleFontFace::create(MutableStyleProperties::create(HTMLStandardMode)))
54     , m_fontElement(nullptr)
55 {
56     ASSERT(hasTagName(font_faceTag));
57 }
58
59 Ref<SVGFontFaceElement> SVGFontFaceElement::create(const QualifiedName& tagName, Document& document)
60 {
61     return adoptRef(*new SVGFontFaceElement(tagName, document));
62 }
63
64 void SVGFontFaceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
65 {    
66     CSSPropertyID propId = cssPropertyIdForSVGAttributeName(name);
67     if (propId > 0) {
68         // FIXME: Parse using the @font-face descriptor grammars, not the property grammars.
69         m_fontFaceRule->mutableProperties().setProperty(propId, value, false);
70         rebuildFontFace();
71         return;
72     }
73     
74     SVGElement::parseAttribute(name, value);
75 }
76
77 unsigned SVGFontFaceElement::unitsPerEm() const
78 {
79     const AtomicString& value = attributeWithoutSynchronization(units_per_emAttr);
80     if (value.isEmpty())
81         return FontMetrics::defaultUnitsPerEm;
82
83     return static_cast<unsigned>(ceilf(value.toFloat()));
84 }
85
86 int SVGFontFaceElement::xHeight() const
87 {
88     return static_cast<int>(ceilf(attributeWithoutSynchronization(x_heightAttr).toFloat()));
89 }
90
91 int SVGFontFaceElement::capHeight() const
92 {
93     return static_cast<int>(ceilf(attributeWithoutSynchronization(cap_heightAttr).toFloat()));
94 }
95
96 float SVGFontFaceElement::horizontalOriginX() const
97 {
98     if (!m_fontElement)
99         return 0.0f;
100
101     // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
102     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
103     // If the attribute is not specified, the effect is as if a value of "0" were specified.
104     return m_fontElement->attributeWithoutSynchronization(horiz_origin_xAttr).toFloat();
105 }
106
107 float SVGFontFaceElement::horizontalOriginY() const
108 {
109     if (!m_fontElement)
110         return 0.0f;
111
112     // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
113     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
114     // If the attribute is not specified, the effect is as if a value of "0" were specified.
115     return m_fontElement->attributeWithoutSynchronization(horiz_origin_yAttr).toFloat();
116 }
117
118 float SVGFontFaceElement::horizontalAdvanceX() const
119 {
120     if (!m_fontElement)
121         return 0.0f;
122
123     // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
124     // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
125     // as in Hebrew and Arabic scripts.
126     return m_fontElement->attributeWithoutSynchronization(horiz_adv_xAttr).toFloat();
127 }
128
129 float SVGFontFaceElement::verticalOriginX() const
130 {
131     if (!m_fontElement)
132         return 0.0f;
133
134     // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
135     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
136     // were set to half of the effective value of attribute horiz-adv-x.
137     const AtomicString& value = m_fontElement->attributeWithoutSynchronization(vert_origin_xAttr);
138     if (value.isEmpty())
139         return horizontalAdvanceX() / 2.0f;
140
141     return value.toFloat();
142 }
143
144 float SVGFontFaceElement::verticalOriginY() const
145 {
146     if (!m_fontElement)
147         return 0.0f;
148
149     // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
150     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
151     // were set to the position specified by the font's ascent attribute.             
152     const AtomicString& value = m_fontElement->attributeWithoutSynchronization(vert_origin_yAttr);
153     if (value.isEmpty())
154         return ascent();
155
156     return value.toFloat();
157 }
158
159 float SVGFontFaceElement::verticalAdvanceY() const
160 {
161     if (!m_fontElement)
162         return 0.0f;
163
164     // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
165     // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).                    
166     const AtomicString& value = m_fontElement->attributeWithoutSynchronization(vert_adv_yAttr);
167        if (value.isEmpty())
168         return 1.0f;
169
170     return value.toFloat();
171 }
172
173 int SVGFontFaceElement::ascent() const
174 {
175     // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
176     // unaccented height of the font within the font coordinate system. If the attribute is not specified,
177     // the effect is as if the attribute were set to the difference between the units-per-em value and the
178     // vert-origin-y value for the corresponding font.
179     const AtomicString& ascentValue = attributeWithoutSynchronization(ascentAttr);
180     if (!ascentValue.isEmpty())
181         return static_cast<int>(ceilf(ascentValue.toFloat()));
182
183     if (m_fontElement) {
184         const AtomicString& vertOriginY = m_fontElement->attributeWithoutSynchronization(vert_origin_yAttr);
185         if (!vertOriginY.isEmpty())
186             return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertOriginY.toFloat()));
187     }
188
189     // Match Batiks default value
190     return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
191 }
192
193 int SVGFontFaceElement::descent() const
194 {
195     // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
196     // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
197     // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
198     const AtomicString& descentValue = attributeWithoutSynchronization(descentAttr);
199     if (!descentValue.isEmpty()) {
200         // 14 different W3C SVG 1.1 testcases use a negative descent value,
201         // where a positive was meant to be used  Including:
202         // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and 11 others)
203         int descent = static_cast<int>(ceilf(descentValue.toFloat()));
204         return descent < 0 ? -descent : descent;
205     }
206
207     if (m_fontElement) {
208         const AtomicString& vertOriginY = m_fontElement->attributeWithoutSynchronization(vert_origin_yAttr);
209         if (!vertOriginY.isEmpty())
210             return static_cast<int>(ceilf(vertOriginY.toFloat()));
211     }
212
213     // Match Batiks default value
214     return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
215 }
216
217 String SVGFontFaceElement::fontFamily() const
218 {
219     return m_fontFaceRule->properties().getPropertyValue(CSSPropertyFontFamily);
220 }
221
222 SVGFontElement* SVGFontFaceElement::associatedFontElement() const
223 {
224     ASSERT(parentNode() == m_fontElement);
225     ASSERT(!parentNode() || is<SVGFontElement>(*parentNode()));
226     return m_fontElement;
227 }
228
229 void SVGFontFaceElement::rebuildFontFace()
230 {
231     if (!isConnected()) {
232         ASSERT(!m_fontElement);
233         return;
234     }
235
236     // we currently ignore all but the first src element, alternatively we could concat them
237     auto srcElement = childrenOfType<SVGFontFaceSrcElement>(*this).first();
238
239     bool describesParentFont = is<SVGFontElement>(*parentNode());
240     RefPtr<CSSValueList> list;
241
242     if (describesParentFont) {
243         m_fontElement = downcast<SVGFontElement>(parentNode());
244
245         list = CSSValueList::createCommaSeparated();
246         list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
247     } else {
248         m_fontElement = nullptr;
249         if (srcElement)
250             list = srcElement->srcValue();
251     }
252
253     if (!list || !list->length())
254         return;
255
256     // Parse in-memory CSS rules
257     m_fontFaceRule->mutableProperties().addParsedProperty(CSSProperty(CSSPropertySrc, list));
258
259     if (describesParentFont) {    
260         // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
261         RefPtr<CSSValue> src = m_fontFaceRule->properties().getPropertyCSSValue(CSSPropertySrc);
262         CSSValueList* srcList = downcast<CSSValueList>(src.get());
263
264         unsigned srcLength = srcList ? srcList->length() : 0;
265         for (unsigned i = 0; i < srcLength; ++i) {
266             if (CSSFontFaceSrcValue* item = downcast<CSSFontFaceSrcValue>(srcList->itemWithoutBoundsCheck(i)))
267                 item->setSVGFontFaceElement(this);
268         }
269     }
270
271     document().styleScope().didChangeStyleSheetEnvironment();
272 }
273
274 Node::InsertedIntoResult SVGFontFaceElement::insertedInto(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
275 {
276     SVGElement::insertedInto(insertionType, parentOfInsertedTree);
277     if (!insertionType.connectedToDocument) {
278         ASSERT(!m_fontElement);
279         return InsertedIntoResult::Done;
280     }
281     document().accessSVGExtensions().registerSVGFontFaceElement(this);
282
283     rebuildFontFace();
284     return InsertedIntoResult::Done;
285 }
286
287 void SVGFontFaceElement::removedFrom(ContainerNode& rootParent)
288 {
289     SVGElement::removedFrom(rootParent);
290
291     if (rootParent.isConnected()) {
292         m_fontElement = nullptr;
293         document().accessSVGExtensions().unregisterSVGFontFaceElement(this);
294         m_fontFaceRule->mutableProperties().clear();
295
296         document().styleScope().didChangeStyleSheetEnvironment();
297     } else
298         ASSERT(!m_fontElement);
299 }
300
301 void SVGFontFaceElement::childrenChanged(const ChildChange& change)
302 {
303     SVGElement::childrenChanged(change);
304     rebuildFontFace();
305 }
306
307 } // namespace WebCore
308
309 #endif // ENABLE(SVG_FONTS)