Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/svg/SVGFontElement.h"
26
27 #include "core/dom/ElementTraversal.h"
28 #include "core/frame/UseCounter.h"
29 #include "core/svg/SVGGlyphElement.h"
30 #include "core/svg/SVGHKernElement.h"
31 #include "core/svg/SVGMissingGlyphElement.h"
32 #include "core/svg/SVGVKernElement.h"
33 #include "wtf/ASCIICType.h"
34
35 namespace blink {
36
37 inline SVGFontElement::SVGFontElement(Document& document)
38     : SVGElement(SVGNames::fontTag, document)
39     , m_missingGlyph(0)
40     , m_isGlyphCacheValid(false)
41 {
42     UseCounter::count(document, UseCounter::SVGFontElement);
43 }
44
45 DEFINE_NODE_FACTORY(SVGFontElement)
46
47 void SVGFontElement::invalidateGlyphCache()
48 {
49     if (m_isGlyphCacheValid) {
50         m_glyphMap.clear();
51         m_horizontalKerningTable.clear();
52         m_verticalKerningTable.clear();
53     }
54     m_isGlyphCacheValid = false;
55 }
56
57 void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures)
58 {
59     ASSERT(!ligatures.isEmpty());
60
61     // Register each character of a ligature in the map, if not present.
62     // Eg. If only a "fi" ligature is present, but not "f" and "i", the
63     // GlyphPage will not contain any entries for "f" and "i", so the
64     // SVGFont is not used to render the text "fi1234". Register an
65     // empty SVGGlyph with the character, so the SVG Font will be used
66     // to render the text. If someone tries to render "f2" the SVG Font
67     // will not be able to find a glyph for "f", but handles the fallback
68     // character substitution properly through glyphDataForCharacter().
69     Vector<SVGGlyph> glyphs;
70     size_t ligaturesSize = ligatures.size();
71     for (size_t i = 0; i < ligaturesSize; ++i) {
72         const String& unicode = ligatures[i];
73
74         unsigned unicodeLength = unicode.length();
75         ASSERT(unicodeLength > 1);
76
77         for (unsigned i = 0; i < unicodeLength; ++i) {
78             String lookupString = unicode.substring(i, 1);
79             m_glyphMap.collectGlyphsForString(lookupString, glyphs);
80             if (!glyphs.isEmpty()) {
81                 glyphs.clear();
82                 continue;
83             }
84
85             // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
86             SVGGlyph newGlyphPart;
87             newGlyphPart.isPartOfLigature = true;
88             m_glyphMap.addGlyph(String(), lookupString, newGlyphPart);
89         }
90     }
91 }
92
93 static inline KerningPairKey makeKerningPairKey(Glyph glyphId1, Glyph glyphId2)
94 {
95     return glyphId1 << 16 | glyphId2;
96 }
97
98 Vector<SVGGlyph> SVGFontElement::buildGlyphList(const UnicodeRanges& unicodeRanges, const HashSet<String>& unicodeNames, const HashSet<String>& glyphNames) const
99 {
100     Vector<SVGGlyph> glyphs;
101     if (!unicodeRanges.isEmpty()) {
102         const UnicodeRanges::const_iterator end = unicodeRanges.end();
103         for (UnicodeRanges::const_iterator it = unicodeRanges.begin(); it != end; ++it)
104             m_glyphMap.collectGlyphsForUnicodeRange(*it, glyphs);
105     }
106     if (!unicodeNames.isEmpty()) {
107         const HashSet<String>::const_iterator end = unicodeNames.end();
108         for (HashSet<String>::const_iterator it = unicodeNames.begin(); it != end; ++it)
109             m_glyphMap.collectGlyphsForStringExact(*it, glyphs);
110     }
111     if (!glyphNames.isEmpty()) {
112         const HashSet<String>::const_iterator end = glyphNames.end();
113         for (HashSet<String>::const_iterator it = glyphNames.begin(); it != end; ++it) {
114             const SVGGlyph& glyph = m_glyphMap.glyphIdentifierForGlyphName(*it);
115             if (glyph.tableEntry)
116                 glyphs.append(glyph);
117         }
118     }
119     return glyphs;
120 }
121
122 void SVGFontElement::addPairsToKerningTable(const SVGKerningPair& kerningPair, KerningTable& kerningTable)
123 {
124     Vector<SVGGlyph> glyphsLhs = buildGlyphList(kerningPair.unicodeRange1, kerningPair.unicodeName1, kerningPair.glyphName1);
125     Vector<SVGGlyph> glyphsRhs = buildGlyphList(kerningPair.unicodeRange2, kerningPair.unicodeName2, kerningPair.glyphName2);
126     if (glyphsLhs.isEmpty() || glyphsRhs.isEmpty())
127         return;
128     size_t glyphsLhsSize = glyphsLhs.size();
129     size_t glyphsRhsSize = glyphsRhs.size();
130     // Enumerate all the valid kerning pairs, and add them to the table.
131     for (size_t lhsIndex = 0; lhsIndex < glyphsLhsSize; ++lhsIndex) {
132         for (size_t rhsIndex = 0; rhsIndex < glyphsRhsSize; ++rhsIndex) {
133             Glyph glyph1 = glyphsLhs[lhsIndex].tableEntry;
134             Glyph glyph2 = glyphsRhs[rhsIndex].tableEntry;
135             ASSERT(glyph1 && glyph2);
136             kerningTable.add(makeKerningPairKey(glyph1, glyph2), kerningPair.kerning);
137         }
138     }
139 }
140
141 void SVGFontElement::buildKerningTable(const KerningPairVector& kerningPairs, KerningTable& kerningTable)
142 {
143     size_t kerningPairsSize = kerningPairs.size();
144     for (size_t i = 0; i < kerningPairsSize; ++i)
145         addPairsToKerningTable(kerningPairs[i], kerningTable);
146 }
147
148 void SVGFontElement::ensureGlyphCache()
149 {
150     if (m_isGlyphCacheValid)
151         return;
152
153     KerningPairVector horizontalKerningPairs;
154     KerningPairVector verticalKerningPairs;
155
156     SVGMissingGlyphElement* firstMissingGlyphElement = 0;
157     Vector<String> ligatures;
158     for (SVGElement* element = Traversal<SVGElement>::firstChild(*this); element; element = Traversal<SVGElement>::nextSibling(*element)) {
159         if (isSVGGlyphElement(*element)) {
160             SVGGlyphElement& glyph = toSVGGlyphElement(*element);
161             AtomicString unicode = glyph.fastGetAttribute(SVGNames::unicodeAttr);
162             AtomicString glyphId = glyph.getIdAttribute();
163             if (glyphId.isEmpty() && unicode.isEmpty())
164                 continue;
165
166             m_glyphMap.addGlyph(glyphId, unicode, glyph.buildGlyphIdentifier());
167
168             // Register ligatures, if needed, don't mix up with surrogate pairs though!
169             if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0]))
170                 ligatures.append(unicode.string());
171         } else if (isSVGHKernElement(*element)) {
172             toSVGHKernElement(*element).buildHorizontalKerningPair(horizontalKerningPairs);
173         } else if (isSVGVKernElement(*element)) {
174             toSVGVKernElement(*element).buildVerticalKerningPair(verticalKerningPairs);
175         } else if (isSVGMissingGlyphElement(*element) && !firstMissingGlyphElement) {
176             firstMissingGlyphElement = toSVGMissingGlyphElement(element);
177         }
178     }
179
180     // Build the kerning tables.
181     buildKerningTable(horizontalKerningPairs, m_horizontalKerningTable);
182     buildKerningTable(verticalKerningPairs, m_verticalKerningTable);
183
184     // The glyph-name->glyph-id map won't be needed/used after having built the kerning table(s).
185     m_glyphMap.dropNamedGlyphMap();
186
187     // Register each character of each ligature, if needed.
188     if (!ligatures.isEmpty())
189         registerLigaturesInGlyphCache(ligatures);
190
191     // Register missing-glyph element, if present.
192     if (firstMissingGlyphElement) {
193         SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
194         m_glyphMap.appendToGlyphTable(svgGlyph);
195         m_missingGlyph = svgGlyph.tableEntry;
196         ASSERT(m_missingGlyph > 0);
197     }
198
199     m_isGlyphCacheValid = true;
200 }
201
202 static float kerningForPairOfGlyphs(const KerningTable& kerningTable, Glyph glyphId1, Glyph glyphId2)
203 {
204     KerningTable::const_iterator result = kerningTable.find(makeKerningPairKey(glyphId1, glyphId2));
205     if (result != kerningTable.end())
206         return result->value;
207
208     return 0;
209 }
210
211 float SVGFontElement::horizontalKerningForPairOfGlyphs(Glyph glyphId1, Glyph glyphId2) const
212 {
213     if (m_horizontalKerningTable.isEmpty())
214         return 0;
215
216     return kerningForPairOfGlyphs(m_horizontalKerningTable, glyphId1, glyphId2);
217 }
218
219 float SVGFontElement::verticalKerningForPairOfGlyphs(Glyph glyphId1, Glyph glyphId2) const
220 {
221     if (m_verticalKerningTable.isEmpty())
222         return 0;
223
224     return kerningForPairOfGlyphs(m_verticalKerningTable, glyphId1, glyphId2);
225 }
226
227 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
228 {
229     ensureGlyphCache();
230     m_glyphMap.collectGlyphsForString(string, glyphs);
231 }
232
233 void SVGFontElement::collectGlyphsForAltGlyphReference(const String& glyphIdentifier, Vector<SVGGlyph>& glyphs)
234 {
235     ensureGlyphCache();
236     // FIXME: We only support glyphName -> single glyph mapping so far.
237     glyphs.append(m_glyphMap.glyphIdentifierForAltGlyphReference(glyphIdentifier));
238 }
239
240 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
241 {
242     ensureGlyphCache();
243     return m_glyphMap.svgGlyphForGlyph(glyph);
244 }
245
246 Glyph SVGFontElement::missingGlyph()
247 {
248     ensureGlyphCache();
249     return m_missingGlyph;
250 }
251
252 } // namespace blink
253
254 #endif // ENABLE(SVG_FONTS)