| 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 |