OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | 2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> | 3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> |
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 4 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 | 52 |
53 PassRefPtr<SVGFontElement> SVGFontElement::create(Document& document) | 53 PassRefPtr<SVGFontElement> SVGFontElement::create(Document& document) |
54 { | 54 { |
55 return adoptRef(new SVGFontElement(document)); | 55 return adoptRef(new SVGFontElement(document)); |
56 } | 56 } |
57 | 57 |
58 void SVGFontElement::invalidateGlyphCache() | 58 void SVGFontElement::invalidateGlyphCache() |
59 { | 59 { |
60 if (m_isGlyphCacheValid) { | 60 if (m_isGlyphCacheValid) { |
61 m_glyphMap.clear(); | 61 m_glyphMap.clear(); |
62 m_horizontalKerningPairs.clear(); | 62 m_horizontalKerningTable.clear(); |
63 m_verticalKerningPairs.clear(); | 63 m_verticalKerningTable.clear(); |
64 } | 64 } |
65 m_isGlyphCacheValid = false; | 65 m_isGlyphCacheValid = false; |
66 } | 66 } |
67 | 67 |
68 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const | 68 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const |
69 { | 69 { |
70 for (Node* child = firstChild(); child; child = child->nextSibling()) { | 70 for (Node* child = firstChild(); child; child = child->nextSibling()) { |
71 if (child->hasTagName(SVGNames::missing_glyphTag)) | 71 if (child->hasTagName(SVGNames::missing_glyphTag)) |
72 return toSVGMissingGlyphElement(child); | 72 return toSVGMissingGlyphElement(child); |
73 } | 73 } |
(...skipping 30 matching lines...) Expand all Loading... |
104 } | 104 } |
105 | 105 |
106 // This glyph is never meant to be used for rendering, only as ident
ifier as a part of a ligature. | 106 // This glyph is never meant to be used for rendering, only as ident
ifier as a part of a ligature. |
107 SVGGlyph newGlyphPart; | 107 SVGGlyph newGlyphPart; |
108 newGlyphPart.isPartOfLigature = true; | 108 newGlyphPart.isPartOfLigature = true; |
109 m_glyphMap.addGlyph(String(), lookupString, newGlyphPart); | 109 m_glyphMap.addGlyph(String(), lookupString, newGlyphPart); |
110 } | 110 } |
111 } | 111 } |
112 } | 112 } |
113 | 113 |
| 114 static inline KerningPairKey makeKerningPairKey(Glyph glyphId1, Glyph glyphId2) |
| 115 { |
| 116 return glyphId1 << 16 | glyphId2; |
| 117 } |
| 118 |
| 119 Vector<SVGGlyph> SVGFontElement::buildGlyphList(const UnicodeRanges& unicodeRang
es, const HashSet<String>& unicodeNames, const HashSet<String>& glyphNames) cons
t |
| 120 { |
| 121 Vector<SVGGlyph> glyphs; |
| 122 if (!unicodeRanges.isEmpty()) { |
| 123 const UnicodeRanges::const_iterator end = unicodeRanges.end(); |
| 124 for (UnicodeRanges::const_iterator it = unicodeRanges.begin(); it != end
; ++it) |
| 125 m_glyphMap.collectGlyphsForUnicodeRange(*it, glyphs); |
| 126 } |
| 127 if (!unicodeNames.isEmpty()) { |
| 128 const HashSet<String>::const_iterator end = unicodeNames.end(); |
| 129 for (HashSet<String>::const_iterator it = unicodeNames.begin(); it != en
d; ++it) |
| 130 m_glyphMap.collectGlyphsForStringExact(*it, glyphs); |
| 131 } |
| 132 if (!glyphNames.isEmpty()) { |
| 133 const HashSet<String>::const_iterator end = glyphNames.end(); |
| 134 for (HashSet<String>::const_iterator it = glyphNames.begin(); it != end;
++it) { |
| 135 const SVGGlyph& glyph = m_glyphMap.glyphIdentifierForGlyphName(*it); |
| 136 if (glyph.tableEntry) |
| 137 glyphs.append(glyph); |
| 138 } |
| 139 } |
| 140 return glyphs; |
| 141 } |
| 142 |
| 143 void SVGFontElement::addPairsToKerningTable(const SVGKerningPair& kerningPair, K
erningTable& kerningTable) |
| 144 { |
| 145 Vector<SVGGlyph> glyphsLhs = buildGlyphList(kerningPair.unicodeRange1, kerni
ngPair.unicodeName1, kerningPair.glyphName1); |
| 146 Vector<SVGGlyph> glyphsRhs = buildGlyphList(kerningPair.unicodeRange2, kerni
ngPair.unicodeName2, kerningPair.glyphName2); |
| 147 if (glyphsLhs.isEmpty() || glyphsRhs.isEmpty()) |
| 148 return; |
| 149 size_t glyphsLhsSize = glyphsLhs.size(); |
| 150 size_t glyphsRhsSize = glyphsRhs.size(); |
| 151 // Enumerate all the valid kerning pairs, and add them to the table. |
| 152 for (size_t lhsIndex = 0; lhsIndex < glyphsLhsSize; ++lhsIndex) { |
| 153 for (size_t rhsIndex = 0; rhsIndex < glyphsRhsSize; ++rhsIndex) { |
| 154 Glyph glyph1 = glyphsLhs[lhsIndex].tableEntry; |
| 155 Glyph glyph2 = glyphsRhs[rhsIndex].tableEntry; |
| 156 ASSERT(glyph1 && glyph2); |
| 157 kerningTable.add(makeKerningPairKey(glyph1, glyph2), kerningPair.ker
ning); |
| 158 } |
| 159 } |
| 160 } |
| 161 |
| 162 void SVGFontElement::buildKerningTable(const KerningPairVector& kerningPairs, Ke
rningTable& kerningTable) |
| 163 { |
| 164 size_t kerningPairsSize = kerningPairs.size(); |
| 165 for (size_t i = 0; i < kerningPairsSize; ++i) |
| 166 addPairsToKerningTable(kerningPairs[i], kerningTable); |
| 167 } |
| 168 |
114 void SVGFontElement::ensureGlyphCache() | 169 void SVGFontElement::ensureGlyphCache() |
115 { | 170 { |
116 if (m_isGlyphCacheValid) | 171 if (m_isGlyphCacheValid) |
117 return; | 172 return; |
118 | 173 |
| 174 KerningPairVector horizontalKerningPairs; |
| 175 KerningPairVector verticalKerningPairs; |
| 176 |
119 SVGMissingGlyphElement* firstMissingGlyphElement = 0; | 177 SVGMissingGlyphElement* firstMissingGlyphElement = 0; |
120 Vector<String> ligatures; | 178 Vector<String> ligatures; |
121 for (Node* child = firstChild(); child; child = child->nextSibling()) { | 179 for (Node* child = firstChild(); child; child = child->nextSibling()) { |
122 if (child->hasTagName(SVGNames::glyphTag)) { | 180 if (child->hasTagName(SVGNames::glyphTag)) { |
123 SVGGlyphElement* glyph = toSVGGlyphElement(child); | 181 SVGGlyphElement* glyph = toSVGGlyphElement(child); |
124 AtomicString unicode = glyph->fastGetAttribute(SVGNames::unicodeAttr
); | 182 AtomicString unicode = glyph->fastGetAttribute(SVGNames::unicodeAttr
); |
125 AtomicString glyphId = glyph->getIdAttribute(); | 183 AtomicString glyphId = glyph->getIdAttribute(); |
126 if (glyphId.isEmpty() && unicode.isEmpty()) | 184 if (glyphId.isEmpty() && unicode.isEmpty()) |
127 continue; | 185 continue; |
128 | 186 |
129 m_glyphMap.addGlyph(glyphId, unicode, glyph->buildGlyphIdentifier())
; | 187 m_glyphMap.addGlyph(glyphId, unicode, glyph->buildGlyphIdentifier())
; |
130 | 188 |
131 // Register ligatures, if needed, don't mix up with surrogate pairs
though! | 189 // Register ligatures, if needed, don't mix up with surrogate pairs
though! |
132 if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0])) | 190 if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0])) |
133 ligatures.append(unicode.string()); | 191 ligatures.append(unicode.string()); |
134 } else if (child->hasTagName(SVGNames::hkernTag)) { | 192 } else if (child->hasTagName(SVGNames::hkernTag)) { |
135 toSVGHKernElement(child)->buildHorizontalKerningPair(m_horizontalKer
ningPairs); | 193 toSVGHKernElement(child)->buildHorizontalKerningPair(horizontalKerni
ngPairs); |
136 } else if (child->hasTagName(SVGNames::vkernTag)) { | 194 } else if (child->hasTagName(SVGNames::vkernTag)) { |
137 toSVGVKernElement(child)->buildVerticalKerningPair(m_verticalKerning
Pairs); | 195 toSVGVKernElement(child)->buildVerticalKerningPair(verticalKerningPa
irs); |
138 } else if (child->hasTagName(SVGNames::missing_glyphTag) && !firstMissin
gGlyphElement) { | 196 } else if (child->hasTagName(SVGNames::missing_glyphTag) && !firstMissin
gGlyphElement) { |
139 firstMissingGlyphElement = toSVGMissingGlyphElement(child); | 197 firstMissingGlyphElement = toSVGMissingGlyphElement(child); |
140 } | 198 } |
141 } | 199 } |
142 | 200 |
| 201 // Build the kerning tables. |
| 202 buildKerningTable(horizontalKerningPairs, m_horizontalKerningTable); |
| 203 buildKerningTable(verticalKerningPairs, m_verticalKerningTable); |
| 204 |
| 205 // The glyph-name->glyph-id map won't be needed/used after having built the
kerning table(s). |
| 206 m_glyphMap.dropNamedGlyphMap(); |
| 207 |
143 // Register each character of each ligature, if needed. | 208 // Register each character of each ligature, if needed. |
144 if (!ligatures.isEmpty()) | 209 if (!ligatures.isEmpty()) |
145 registerLigaturesInGlyphCache(ligatures); | 210 registerLigaturesInGlyphCache(ligatures); |
146 | 211 |
147 // Register missing-glyph element, if present. | 212 // Register missing-glyph element, if present. |
148 if (firstMissingGlyphElement) { | 213 if (firstMissingGlyphElement) { |
149 SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMi
ssingGlyphElement); | 214 SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMi
ssingGlyphElement); |
150 m_glyphMap.appendToGlyphTable(svgGlyph); | 215 m_glyphMap.appendToGlyphTable(svgGlyph); |
151 m_missingGlyph = svgGlyph.tableEntry; | 216 m_missingGlyph = svgGlyph.tableEntry; |
152 ASSERT(m_missingGlyph > 0); | 217 ASSERT(m_missingGlyph > 0); |
153 } | 218 } |
154 | 219 |
155 m_isGlyphCacheValid = true; | 220 m_isGlyphCacheValid = true; |
156 } | 221 } |
157 | 222 |
158 static bool stringMatchesUnicodeRange(const String& unicodeString, const Unicode
Ranges& ranges, const HashSet<String>& unicodeValues) | 223 static float kerningForPairOfGlyphs(const KerningTable& kerningTable, Glyph glyp
hId1, Glyph glyphId2) |
159 { | 224 { |
160 if (unicodeString.isEmpty()) | 225 KerningTable::const_iterator result = kerningTable.find(makeKerningPairKey(g
lyphId1, glyphId2)); |
161 return false; | 226 if (result != kerningTable.end()) |
162 | 227 return result->value; |
163 if (!ranges.isEmpty()) { | |
164 UChar firstChar = unicodeString[0]; | |
165 const UnicodeRanges::const_iterator end = ranges.end(); | |
166 for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it)
{ | |
167 if (firstChar >= it->first && firstChar <= it->second) | |
168 return true; | |
169 } | |
170 } | |
171 | |
172 if (!unicodeValues.isEmpty()) | |
173 return unicodeValues.contains(unicodeString); | |
174 | |
175 return false; | |
176 } | |
177 | |
178 static bool stringMatchesGlyphName(const String& glyphName, const HashSet<String
>& glyphValues) | |
179 { | |
180 if (glyphName.isEmpty()) | |
181 return false; | |
182 | |
183 if (!glyphValues.isEmpty()) | |
184 return glyphValues.contains(glyphName); | |
185 | |
186 return false; | |
187 } | |
188 | |
189 static bool matches(const String& u1, const String& g1, const String& u2, const
String& g2, const SVGKerningPair& kerningPair) | |
190 { | |
191 if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.un
icodeName1) | |
192 && !stringMatchesGlyphName(g1, kerningPair.glyphName1)) | |
193 return false; | |
194 | |
195 if (!stringMatchesUnicodeRange(u2, kerningPair.unicodeRange2, kerningPair.un
icodeName2) | |
196 && !stringMatchesGlyphName(g2, kerningPair.glyphName2)) | |
197 return false; | |
198 | |
199 return true; | |
200 } | |
201 | |
202 static float kerningForPairOfStringsAndGlyphs(const KerningPairVector& kerningPa
irs, const String& u1, const String& g1, const String& u2, const String& g2) | |
203 { | |
204 KerningPairVector::const_iterator it = kerningPairs.end() - 1; | |
205 const KerningPairVector::const_iterator begin = kerningPairs.begin() - 1; | |
206 for (; it != begin; --it) { | |
207 if (matches(u1, g1, u2, g2, *it)) | |
208 return it->kerning; | |
209 } | |
210 | 228 |
211 return 0; | 229 return 0; |
212 } | 230 } |
213 | 231 |
214 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u
1, const String& g1, const String& u2, const String& g2) const | 232 float SVGFontElement::horizontalKerningForPairOfGlyphs(Glyph glyphId1, Glyph gly
phId2) const |
215 { | 233 { |
216 if (m_horizontalKerningPairs.isEmpty()) | 234 if (m_horizontalKerningTable.isEmpty()) |
217 return 0; | 235 return 0; |
218 | 236 |
219 return kerningForPairOfStringsAndGlyphs(m_horizontalKerningPairs, u1, g1, u2
, g2); | 237 return kerningForPairOfGlyphs(m_horizontalKerningTable, glyphId1, glyphId2); |
220 } | 238 } |
221 | 239 |
222 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1,
const String& g1, const String& u2, const String& g2) const | 240 float SVGFontElement::verticalKerningForPairOfGlyphs(Glyph glyphId1, Glyph glyph
Id2) const |
223 { | 241 { |
224 if (m_verticalKerningPairs.isEmpty()) | 242 if (m_verticalKerningTable.isEmpty()) |
225 return 0; | 243 return 0; |
226 | 244 |
227 return kerningForPairOfStringsAndGlyphs(m_verticalKerningPairs, u1, g1, u2,
g2); | 245 return kerningForPairOfGlyphs(m_verticalKerningTable, glyphId1, glyphId2); |
228 } | 246 } |
229 | 247 |
230 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyp
h>& glyphs) | 248 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyp
h>& glyphs) |
231 { | 249 { |
232 ensureGlyphCache(); | 250 ensureGlyphCache(); |
233 m_glyphMap.collectGlyphsForString(string, glyphs); | 251 m_glyphMap.collectGlyphsForString(string, glyphs); |
234 } | 252 } |
235 | 253 |
236 void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<S
VGGlyph>& glyphs) | 254 void SVGFontElement::collectGlyphsForAltGlyphReference(const String& glyphIdenti
fier, Vector<SVGGlyph>& glyphs) |
237 { | 255 { |
238 ensureGlyphCache(); | 256 ensureGlyphCache(); |
239 // FIXME: We only support glyphName -> single glyph mapping so far. | 257 // FIXME: We only support glyphName -> single glyph mapping so far. |
240 glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName)); | 258 glyphs.append(m_glyphMap.glyphIdentifierForAltGlyphReference(glyphIdentifier
)); |
241 } | 259 } |
242 | 260 |
243 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph) | 261 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph) |
244 { | 262 { |
245 ensureGlyphCache(); | 263 ensureGlyphCache(); |
246 return m_glyphMap.svgGlyphForGlyph(glyph); | 264 return m_glyphMap.svgGlyphForGlyph(glyph); |
247 } | 265 } |
248 | 266 |
249 Glyph SVGFontElement::missingGlyph() | 267 Glyph SVGFontElement::missingGlyph() |
250 { | 268 { |
251 ensureGlyphCache(); | 269 ensureGlyphCache(); |
252 return m_missingGlyph; | 270 return m_missingGlyph; |
253 } | 271 } |
254 | 272 |
255 } | 273 } |
256 | 274 |
257 #endif // ENABLE(SVG_FONTS) | 275 #endif // ENABLE(SVG_FONTS) |
OLD | NEW |