OLD | NEW |
| (Empty) |
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 ident
ifier 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& unicodeRang
es, const HashSet<String>& unicodeNames, const HashSet<String>& glyphNames) cons
t | |
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 != en
d; ++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, K
erningTable& kerningTable) | |
123 { | |
124 Vector<SVGGlyph> glyphsLhs = buildGlyphList(kerningPair.unicodeRange1, kerni
ngPair.unicodeName1, kerningPair.glyphName1); | |
125 Vector<SVGGlyph> glyphsRhs = buildGlyphList(kerningPair.unicodeRange2, kerni
ngPair.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.ker
ning); | |
137 } | |
138 } | |
139 } | |
140 | |
141 void SVGFontElement::buildKerningTable(const KerningPairVector& kerningPairs, Ke
rningTable& 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(horizontalKer
ningPairs); | |
173 } else if (isSVGVKernElement(*element)) { | |
174 toSVGVKernElement(*element).buildVerticalKerningPair(verticalKerning
Pairs); | |
175 } else if (isSVGMissingGlyphElement(*element) && !firstMissingGlyphEleme
nt) { | |
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(firstMi
ssingGlyphElement); | |
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 glyp
hId1, Glyph glyphId2) | |
203 { | |
204 KerningTable::const_iterator result = kerningTable.find(makeKerningPairKey(g
lyphId1, glyphId2)); | |
205 if (result != kerningTable.end()) | |
206 return result->value; | |
207 | |
208 return 0; | |
209 } | |
210 | |
211 float SVGFontElement::horizontalKerningForPairOfGlyphs(Glyph glyphId1, Glyph gly
phId2) 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 glyph
Id2) 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<SVGGlyp
h>& glyphs) | |
228 { | |
229 ensureGlyphCache(); | |
230 m_glyphMap.collectGlyphsForString(string, glyphs); | |
231 } | |
232 | |
233 void SVGFontElement::collectGlyphsForAltGlyphReference(const String& glyphIdenti
fier, 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) | |
OLD | NEW |