Replace WTF::move with WTFMove
[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     for (auto& unicode : ligatures) {
90         unsigned unicodeLength = unicode.length();
91         ASSERT(unicodeLength > 1);
92
93         for (unsigned i = 0; i < unicodeLength; ++i) {
94             UChar character = unicode[i];
95             String lookupString(&character, 1);
96             m_glyphMap.collectGlyphsForString(lookupString, glyphs);
97             if (!glyphs.isEmpty()) {
98                 glyphs.clear();
99                 continue;
100             }
101
102             // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
103             SVGGlyph newGlyphPart;
104             newGlyphPart.isPartOfLigature = true;
105             m_glyphMap.addGlyph(String(), lookupString, newGlyphPart);
106         }
107     }
108 }
109
110 void SVGFontElement::ensureGlyphCache()
111 {
112     if (m_isGlyphCacheValid)
113         return;
114
115     const SVGMissingGlyphElement* firstMissingGlyphElement = nullptr;
116     Vector<String> ligatures;
117     for (auto& child : childrenOfType<SVGElement>(*this)) {
118         if (is<SVGGlyphElement>(child)) {
119             SVGGlyphElement& glyph = downcast<SVGGlyphElement>(child);
120             AtomicString unicode = glyph.fastGetAttribute(SVGNames::unicodeAttr);
121             AtomicString glyphId = glyph.getIdAttribute();
122             if (glyphId.isEmpty() && unicode.isEmpty())
123                 continue;
124
125             m_glyphMap.addGlyph(glyphId, unicode, glyph.buildGlyphIdentifier());
126
127             // Register ligatures, if needed, don't mix up with surrogate pairs though!
128             if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0]))
129                 ligatures.append(unicode.string());
130         } else if (is<SVGHKernElement>(child)) {
131             SVGHKernElement& hkern = downcast<SVGHKernElement>(child);
132             SVGKerningPair kerningPair;
133             if (hkern.buildHorizontalKerningPair(kerningPair))
134                 m_horizontalKerningMap.insert(kerningPair);
135         } else if (is<SVGVKernElement>(child)) {
136             SVGVKernElement& vkern = downcast<SVGVKernElement>(child);
137             SVGKerningPair kerningPair;
138             if (vkern.buildVerticalKerningPair(kerningPair))
139                 m_verticalKerningMap.insert(kerningPair);
140         } else if (is<SVGMissingGlyphElement>(child) && !firstMissingGlyphElement)
141             firstMissingGlyphElement = &downcast<SVGMissingGlyphElement>(child);
142     }
143
144     // Register each character of each ligature, if needed.
145     if (!ligatures.isEmpty())
146         registerLigaturesInGlyphCache(ligatures);
147
148     // Register missing-glyph element, if present.
149     if (firstMissingGlyphElement) {
150         SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
151         m_glyphMap.appendToGlyphTable(svgGlyph);
152         m_missingGlyph = svgGlyph.tableEntry;
153         ASSERT(m_missingGlyph > 0);
154     }
155
156     m_isGlyphCacheValid = true;
157 }
158
159 void SVGKerningMap::clear()
160 {
161     unicodeMap.clear();
162     glyphMap.clear();
163     kerningUnicodeRangeMap.clear();
164 }
165
166 void SVGKerningMap::insert(const SVGKerningPair& kerningPair)
167 {
168     SVGKerning svgKerning;
169     svgKerning.kerning = kerningPair.kerning;
170     svgKerning.unicodeRange2 = kerningPair.unicodeRange2;
171     svgKerning.unicodeName2 = kerningPair.unicodeName2;
172     svgKerning.glyphName2 = kerningPair.glyphName2;
173
174     for (auto& name : kerningPair.unicodeName1) {
175         if (unicodeMap.contains(name))
176             unicodeMap.get(name)->append(svgKerning);
177         else {
178             auto newVector = std::make_unique<SVGKerningVector>();
179             newVector->append(svgKerning);
180             unicodeMap.add(name, WTFMove(newVector));
181         }
182     }
183
184     for (auto& name : kerningPair.glyphName1) {
185         if (glyphMap.contains(name))
186             glyphMap.get(name)->append(svgKerning);
187         else {
188             auto newVector = std::make_unique<SVGKerningVector>();
189             newVector->append(svgKerning);
190             glyphMap.add(name, WTFMove(newVector));
191         }
192     }
193
194     if (!kerningPair.unicodeRange1.isEmpty())
195         kerningUnicodeRangeMap.append(kerningPair);
196 }
197
198 static inline bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges)
199 {
200     if (unicodeString.isEmpty())
201         return false;
202
203     if (!ranges.isEmpty()) {
204         UChar firstChar = unicodeString[0];
205         for (auto& range : ranges) {
206             if (firstChar >= range.first && firstChar <= range.second)
207                 return true;
208         }
209     }
210
211     return false;
212 }
213
214 static inline bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues)
215 {
216     if (glyphName.isEmpty())
217         return false;
218
219     return glyphValues.contains(glyphName);
220 }
221
222 static inline bool stringMatchesUnicodeName(const String& unicodeName, const HashSet<String>& unicodeValues)
223 {
224     if (unicodeName.isEmpty())
225         return false;
226
227     return unicodeValues.contains(unicodeName);
228 }
229
230 static inline bool matches(const String& u2, const String& g2, const SVGKerning& svgKerning)
231 {
232     return stringMatchesGlyphName(g2, svgKerning.glyphName2)
233         || stringMatchesUnicodeName(u2, svgKerning.unicodeName2)
234         || stringMatchesUnicodeRange(u2, svgKerning.unicodeRange2);
235 }
236
237 static inline bool matches(const String& u1, const String& u2, const String& g2, const SVGKerningPair& svgKerningPair)
238 {
239     return stringMatchesUnicodeRange(u1, svgKerningPair.unicodeRange1) && matches(u2, g2, svgKerningPair);
240 }
241
242 static inline float kerningForPairOfStringsAndGlyphs(const SVGKerningMap& kerningMap, const String& u1, const String& g1, const String& u2, const String& g2)
243 {
244     if (!g1.isEmpty() && kerningMap.glyphMap.contains(g1)) {
245         SVGKerningVector* kerningVector = kerningMap.glyphMap.get(g1);
246         SVGKerningVector::const_iterator it = kerningVector->end() - 1;
247         const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1;
248         for (; it != begin; --it) {
249             if (matches(u2, g2, *it))
250                 return it->kerning;
251         }
252     }
253
254     if (!u1.isEmpty()) {
255         if (kerningMap.unicodeMap.contains(u1)) {
256             SVGKerningVector* kerningVector = kerningMap.unicodeMap.get(u1);
257             SVGKerningVector::const_iterator it = kerningVector->end() - 1;
258             const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1;
259             for (; it != begin; --it) {
260                 if (matches(u2, g2, *it))
261                     return it->kerning;
262             }
263         }
264
265         if (!kerningMap.kerningUnicodeRangeMap.isEmpty()) {
266             Vector<SVGKerningPair>::const_iterator it = kerningMap.kerningUnicodeRangeMap.end() - 1;
267             const Vector<SVGKerningPair>::const_iterator begin = kerningMap.kerningUnicodeRangeMap.begin() - 1;
268             for (; it != begin; --it) {
269                 if (matches(u1, u2, g2, *it))
270                     return it->kerning;
271             }
272         }
273     }
274
275     return 0;
276 }
277
278 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
279 {
280     if (m_horizontalKerningMap.isEmpty())
281         return 0;
282
283     return kerningForPairOfStringsAndGlyphs(m_horizontalKerningMap, u1, g1, u2, g2);
284 }
285
286 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
287 {
288     if (m_verticalKerningMap.isEmpty())
289         return 0;
290
291     return kerningForPairOfStringsAndGlyphs(m_verticalKerningMap, u1, g1, u2, g2);
292 }
293
294 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
295 {
296     ensureGlyphCache();
297     m_glyphMap.collectGlyphsForString(string, glyphs);
298 }
299
300 void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs)
301 {
302     ensureGlyphCache();
303     // FIXME: We only support glyphName -> single glyph mapping so far.
304     glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName));
305 }
306
307 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
308 {
309     ensureGlyphCache();
310     return m_glyphMap.svgGlyphForGlyph(glyph);
311 }
312
313 Glyph SVGFontElement::missingGlyph()
314 {
315     ensureGlyphCache();
316     return m_missingGlyph;
317 }
318
319 }
320
321 #endif // ENABLE(SVG_FONTS)