r184718 and r184725 caused four tests to begin crashing
[WebKit-https.git] / Source / WebCore / svg / SVGFontElement.cpp
1 /*
2  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4  * Copyright (C) Research In Motion Limited 2010. 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 "SVGFontElement.h"
26
27 #include "Document.h"
28 #include "ElementIterator.h"
29 #include "FontCascade.h"
30 #include "SVGGlyphElement.h"
31 #include "SVGHKernElement.h"
32 #include "SVGMissingGlyphElement.h"
33 #include "SVGNames.h"
34 #include "SVGVKernElement.h"
35 #include <wtf/ASCIICType.h>
36
37 namespace WebCore {
38
39 // Animated property definitions
40 DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
41
42 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFontElement)
43     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
44     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
45 END_REGISTER_ANIMATED_PROPERTIES
46
47 inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document& document)
48     : SVGElement(tagName, document)
49     , m_missingGlyph(0)
50     , m_isGlyphCacheValid(false)
51 {
52     ASSERT(hasTagName(SVGNames::fontTag));
53     registerAnimatedPropertiesForSVGFontElement();
54 }
55
56 Ref<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document& document)
57 {
58     return adoptRef(*new SVGFontElement(tagName, document));
59 }
60
61 void SVGFontElement::invalidateGlyphCache()
62 {
63     if (m_isGlyphCacheValid) {
64         m_glyphMap.clear();
65         m_horizontalKerningMap.clear();
66         m_verticalKerningMap.clear();
67     }
68     m_isGlyphCacheValid = false;
69 }
70
71 const SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const
72 {
73     return childrenOfType<SVGMissingGlyphElement>(*this).first();
74 }
75
76 void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures)
77 {
78     ASSERT(!ligatures.isEmpty());
79
80     // Register each character of a ligature in the map, if not present.
81     // Eg. If only a "fi" ligature is present, but not "f" and "i", the
82     // GlyphPage will not contain any entries for "f" and "i", so the
83     // SVGFont is not used to render the text "fi1234". Register an
84     // empty SVGGlyph with the character, so the SVG Font will be used
85     // to render the text. If someone tries to render "f2" the SVG Font
86     // will not be able to find a glyph for "f", but handles the fallback
87     // character substitution properly through glyphDataForCharacter().
88     Vector<SVGGlyph> glyphs;
89     size_t ligaturesSize = ligatures.size();
90     for (size_t i = 0; i < ligaturesSize; ++i) {
91         const String& unicode = ligatures[i];
92
93         unsigned unicodeLength = unicode.length();
94         ASSERT(unicodeLength > 1);
95
96         for (unsigned i = 0; i < unicodeLength; ++i) {
97             UChar character = unicode[i];
98             String lookupString(&character, 1);
99             m_glyphMap.collectGlyphsForString(lookupString, glyphs);
100             if (!glyphs.isEmpty()) {
101                 glyphs.clear();
102                 continue;
103             }
104
105             // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
106             SVGGlyph newGlyphPart;
107             newGlyphPart.isPartOfLigature = true;
108             m_glyphMap.addGlyph(String(), lookupString, newGlyphPart);
109         }
110     }
111 }
112
113 void SVGFontElement::ensureGlyphCache()
114 {
115     if (m_isGlyphCacheValid)
116         return;
117
118     const SVGMissingGlyphElement* firstMissingGlyphElement = nullptr;
119     Vector<String> ligatures;
120     for (auto& child : childrenOfType<SVGElement>(*this)) {
121         if (is<SVGGlyphElement>(child)) {
122             SVGGlyphElement& glyph = downcast<SVGGlyphElement>(child);
123             AtomicString unicode = glyph.fastGetAttribute(SVGNames::unicodeAttr);
124             AtomicString glyphId = glyph.getIdAttribute();
125             if (glyphId.isEmpty() && unicode.isEmpty())
126                 continue;
127
128             m_glyphMap.addGlyph(glyphId, unicode, glyph.buildGlyphIdentifier());
129
130             // Register ligatures, if needed, don't mix up with surrogate pairs though!
131             if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0]))
132                 ligatures.append(unicode.string());
133         } else if (is<SVGHKernElement>(child)) {
134             SVGHKernElement& hkern = downcast<SVGHKernElement>(child);
135             SVGKerningPair kerningPair;
136             if (hkern.buildHorizontalKerningPair(kerningPair))
137                 m_horizontalKerningMap.insert(kerningPair);
138         } else if (is<SVGVKernElement>(child)) {
139             SVGVKernElement& vkern = downcast<SVGVKernElement>(child);
140             SVGKerningPair kerningPair;
141             if (vkern.buildVerticalKerningPair(kerningPair))
142                 m_verticalKerningMap.insert(kerningPair);
143         } else if (is<SVGMissingGlyphElement>(child) && !firstMissingGlyphElement)
144             firstMissingGlyphElement = &downcast<SVGMissingGlyphElement>(child);
145     }
146
147     // Register each character of each ligature, if needed.
148     if (!ligatures.isEmpty())
149         registerLigaturesInGlyphCache(ligatures);
150
151     // Register missing-glyph element, if present.
152     if (firstMissingGlyphElement) {
153         SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
154         m_glyphMap.appendToGlyphTable(svgGlyph);
155         m_missingGlyph = svgGlyph.tableEntry;
156         ASSERT(m_missingGlyph > 0);
157     }
158
159     m_isGlyphCacheValid = true;
160 }
161
162 void SVGKerningMap::clear()
163 {
164     unicodeMap.clear();
165     glyphMap.clear();
166     kerningUnicodeRangeMap.clear();
167 }
168
169 void SVGKerningMap::insert(const SVGKerningPair& kerningPair)
170 {
171     SVGKerning svgKerning;
172     svgKerning.kerning = kerningPair.kerning;
173     svgKerning.unicodeRange2 = kerningPair.unicodeRange2;
174     svgKerning.unicodeName2 = kerningPair.unicodeName2;
175     svgKerning.glyphName2 = kerningPair.glyphName2;
176
177     HashSet<String>::const_iterator uIt = kerningPair.unicodeName1.begin();
178     const HashSet<String>::const_iterator uEnd = kerningPair.unicodeName1.end();
179     for (; uIt != uEnd; ++uIt) {
180         if (unicodeMap.contains(*uIt))
181             unicodeMap.get(*uIt)->append(svgKerning);
182         else {
183             auto newVector = std::make_unique<SVGKerningVector>();
184             newVector->append(svgKerning);
185             unicodeMap.add(*uIt, WTF::move(newVector));
186         }
187     }
188
189     HashSet<String>::const_iterator gIt = kerningPair.glyphName1.begin();
190     const HashSet<String>::const_iterator gEnd = kerningPair.glyphName1.end();
191     for (; gIt != gEnd; ++gIt) {
192         if (glyphMap.contains(*gIt))
193             glyphMap.get(*gIt)->append(svgKerning);
194         else {
195             auto newVector = std::make_unique<SVGKerningVector>();
196             newVector->append(svgKerning);
197             glyphMap.add(*gIt, WTF::move(newVector));
198         }
199     }
200
201     if (!kerningPair.unicodeRange1.isEmpty())
202         kerningUnicodeRangeMap.append(kerningPair);
203 }
204
205 static inline bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges)
206 {
207     if (unicodeString.isEmpty())
208         return false;
209
210     if (!ranges.isEmpty()) {
211         UChar firstChar = unicodeString[0];
212         const UnicodeRanges::const_iterator end = ranges.end();
213         for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) {
214             if (firstChar >= it->first && firstChar <= it->second)
215                 return true;
216         }
217     }
218
219     return false;
220 }
221
222 static inline bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues)
223 {
224     if (glyphName.isEmpty())
225         return false;
226
227     return glyphValues.contains(glyphName);
228 }
229
230 static inline bool stringMatchesUnicodeName(const String& unicodeName, const HashSet<String>& unicodeValues)
231 {
232     if (unicodeName.isEmpty())
233         return false;
234
235     return unicodeValues.contains(unicodeName);
236 }
237
238 static inline bool matches(const String& u2, const String& g2, const SVGKerning& svgKerning)
239 {
240     return stringMatchesGlyphName(g2, svgKerning.glyphName2)
241         || stringMatchesUnicodeName(u2, svgKerning.unicodeName2)
242         || stringMatchesUnicodeRange(u2, svgKerning.unicodeRange2);
243 }
244
245 static inline bool matches(const String& u1, const String& u2, const String& g2, const SVGKerningPair& svgKerningPair)
246 {
247     return stringMatchesUnicodeRange(u1, svgKerningPair.unicodeRange1) && matches(u2, g2, svgKerningPair);
248 }
249
250 static inline float kerningForPairOfStringsAndGlyphs(const SVGKerningMap& kerningMap, const String& u1, const String& g1, const String& u2, const String& g2)
251 {
252     if (!g1.isEmpty() && kerningMap.glyphMap.contains(g1)) {
253         SVGKerningVector* kerningVector = kerningMap.glyphMap.get(g1);
254         SVGKerningVector::const_iterator it = kerningVector->end() - 1;
255         const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1;
256         for (; it != begin; --it) {
257             if (matches(u2, g2, *it))
258                 return it->kerning;
259         }
260     }
261
262     if (!u1.isEmpty()) {
263         if (kerningMap.unicodeMap.contains(u1)) {
264             SVGKerningVector* kerningVector = kerningMap.unicodeMap.get(u1);
265             SVGKerningVector::const_iterator it = kerningVector->end() - 1;
266             const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1;
267             for (; it != begin; --it) {
268                 if (matches(u2, g2, *it))
269                     return it->kerning;
270             }
271         }
272
273         if (!kerningMap.kerningUnicodeRangeMap.isEmpty()) {
274             Vector<SVGKerningPair>::const_iterator it = kerningMap.kerningUnicodeRangeMap.end() - 1;
275             const Vector<SVGKerningPair>::const_iterator begin = kerningMap.kerningUnicodeRangeMap.begin() - 1;
276             for (; it != begin; --it) {
277                 if (matches(u1, u2, g2, *it))
278                     return it->kerning;
279             }
280         }
281     }
282
283     return 0;
284 }
285
286 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
287 {
288     if (m_horizontalKerningMap.isEmpty())
289         return 0;
290
291     return kerningForPairOfStringsAndGlyphs(m_horizontalKerningMap, u1, g1, u2, g2);
292 }
293
294 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
295 {
296     if (m_verticalKerningMap.isEmpty())
297         return 0;
298
299     return kerningForPairOfStringsAndGlyphs(m_verticalKerningMap, u1, g1, u2, g2);
300 }
301
302 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
303 {
304     ensureGlyphCache();
305     m_glyphMap.collectGlyphsForString(string, glyphs);
306 }
307
308 void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs)
309 {
310     ensureGlyphCache();
311     // FIXME: We only support glyphName -> single glyph mapping so far.
312     glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName));
313 }
314
315 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
316 {
317     ensureGlyphCache();
318     return m_glyphMap.svgGlyphForGlyph(glyph);
319 }
320
321 Glyph SVGFontElement::missingGlyph()
322 {
323     ensureGlyphCache();
324     return m_missingGlyph;
325 }
326
327 }
328
329 #endif // ENABLE(SVG_FONTS)