1 /* 2 * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org> 3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann (at) 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/frame/UseCounter.h" 28 #include "core/svg/SVGGlyphElement.h" 29 #include "core/svg/SVGHKernElement.h" 30 #include "core/svg/SVGMissingGlyphElement.h" 31 #include "core/svg/SVGVKernElement.h" 32 #include "wtf/ASCIICType.h" 33 34 namespace WebCore { 35 36 // Animated property definitions 37 DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 38 39 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFontElement) 40 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 41 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement) 42 END_REGISTER_ANIMATED_PROPERTIES 43 44 inline SVGFontElement::SVGFontElement(Document& document) 45 : SVGElement(SVGNames::fontTag, document) 46 , m_missingGlyph(0) 47 , m_isGlyphCacheValid(false) 48 { 49 ScriptWrappable::init(this); 50 registerAnimatedPropertiesForSVGFontElement(); 51 52 UseCounter::count(document, UseCounter::SVGFontElement); 53 } 54 55 PassRefPtr<SVGFontElement> SVGFontElement::create(Document& document) 56 { 57 return adoptRef(new SVGFontElement(document)); 58 } 59 60 void SVGFontElement::invalidateGlyphCache() 61 { 62 if (m_isGlyphCacheValid) { 63 m_glyphMap.clear(); 64 m_horizontalKerningPairs.clear(); 65 m_verticalKerningPairs.clear(); 66 } 67 m_isGlyphCacheValid = false; 68 } 69 70 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const 71 { 72 for (Node* child = firstChild(); child; child = child->nextSibling()) { 73 if (child->hasTagName(SVGNames::missing_glyphTag)) 74 return toSVGMissingGlyphElement(child); 75 } 76 77 return 0; 78 } 79 80 void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures) 81 { 82 ASSERT(!ligatures.isEmpty()); 83 84 // Register each character of a ligature in the map, if not present. 85 // Eg. If only a "fi" ligature is present, but not "f" and "i", the 86 // GlyphPage will not contain any entries for "f" and "i", so the 87 // SVGFont is not used to render the text "fi1234". Register an 88 // empty SVGGlyph with the character, so the SVG Font will be used 89 // to render the text. If someone tries to render "f2" the SVG Font 90 // will not be able to find a glyph for "f", but handles the fallback 91 // character substitution properly through glyphDataForCharacter(). 92 Vector<SVGGlyph> glyphs; 93 size_t ligaturesSize = ligatures.size(); 94 for (size_t i = 0; i < ligaturesSize; ++i) { 95 const String& unicode = ligatures[i]; 96 97 unsigned unicodeLength = unicode.length(); 98 ASSERT(unicodeLength > 1); 99 100 for (unsigned i = 0; i < unicodeLength; ++i) { 101 String lookupString = unicode.substring(i, 1); 102 m_glyphMap.collectGlyphsForString(lookupString, glyphs); 103 if (!glyphs.isEmpty()) { 104 glyphs.clear(); 105 continue; 106 } 107 108 // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature. 109 SVGGlyph newGlyphPart; 110 newGlyphPart.isPartOfLigature = true; 111 m_glyphMap.addGlyph(String(), lookupString, newGlyphPart); 112 } 113 } 114 } 115 116 void SVGFontElement::ensureGlyphCache() 117 { 118 if (m_isGlyphCacheValid) 119 return; 120 121 SVGMissingGlyphElement* firstMissingGlyphElement = 0; 122 Vector<String> ligatures; 123 for (Node* child = firstChild(); child; child = child->nextSibling()) { 124 if (child->hasTagName(SVGNames::glyphTag)) { 125 SVGGlyphElement* glyph = toSVGGlyphElement(child); 126 AtomicString unicode = glyph->fastGetAttribute(SVGNames::unicodeAttr); 127 AtomicString glyphId = glyph->getIdAttribute(); 128 if (glyphId.isEmpty() && unicode.isEmpty()) 129 continue; 130 131 m_glyphMap.addGlyph(glyphId, unicode, glyph->buildGlyphIdentifier()); 132 133 // Register ligatures, if needed, don't mix up with surrogate pairs though! 134 if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0])) 135 ligatures.append(unicode.string()); 136 } else if (child->hasTagName(SVGNames::hkernTag)) { 137 toSVGHKernElement(child)->buildHorizontalKerningPair(m_horizontalKerningPairs); 138 } else if (child->hasTagName(SVGNames::vkernTag)) { 139 toSVGVKernElement(child)->buildVerticalKerningPair(m_verticalKerningPairs); 140 } else if (child->hasTagName(SVGNames::missing_glyphTag) && !firstMissingGlyphElement) { 141 firstMissingGlyphElement = toSVGMissingGlyphElement(child); 142 } 143 } 144 145 // Register each character of each ligature, if needed. 146 if (!ligatures.isEmpty()) 147 registerLigaturesInGlyphCache(ligatures); 148 149 // Register missing-glyph element, if present. 150 if (firstMissingGlyphElement) { 151 SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement); 152 m_glyphMap.appendToGlyphTable(svgGlyph); 153 m_missingGlyph = svgGlyph.tableEntry; 154 ASSERT(m_missingGlyph > 0); 155 } 156 157 m_isGlyphCacheValid = true; 158 } 159 160 static bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges, const HashSet<String>& unicodeValues) 161 { 162 if (unicodeString.isEmpty()) 163 return false; 164 165 if (!ranges.isEmpty()) { 166 UChar firstChar = unicodeString[0]; 167 const UnicodeRanges::const_iterator end = ranges.end(); 168 for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) { 169 if (firstChar >= it->first && firstChar <= it->second) 170 return true; 171 } 172 } 173 174 if (!unicodeValues.isEmpty()) 175 return unicodeValues.contains(unicodeString); 176 177 return false; 178 } 179 180 static bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues) 181 { 182 if (glyphName.isEmpty()) 183 return false; 184 185 if (!glyphValues.isEmpty()) 186 return glyphValues.contains(glyphName); 187 188 return false; 189 } 190 191 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGKerningPair& kerningPair) 192 { 193 if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1) 194 && !stringMatchesGlyphName(g1, kerningPair.glyphName1)) 195 return false; 196 197 if (!stringMatchesUnicodeRange(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2) 198 && !stringMatchesGlyphName(g2, kerningPair.glyphName2)) 199 return false; 200 201 return true; 202 } 203 204 static float kerningForPairOfStringsAndGlyphs(const KerningPairVector& kerningPairs, const String& u1, const String& g1, const String& u2, const String& g2) 205 { 206 KerningPairVector::const_iterator it = kerningPairs.end() - 1; 207 const KerningPairVector::const_iterator begin = kerningPairs.begin() - 1; 208 for (; it != begin; --it) { 209 if (matches(u1, g1, u2, g2, *it)) 210 return it->kerning; 211 } 212 213 return 0; 214 } 215 216 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const 217 { 218 if (m_horizontalKerningPairs.isEmpty()) 219 return 0; 220 221 return kerningForPairOfStringsAndGlyphs(m_horizontalKerningPairs, u1, g1, u2, g2); 222 } 223 224 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const 225 { 226 if (m_verticalKerningPairs.isEmpty()) 227 return 0; 228 229 return kerningForPairOfStringsAndGlyphs(m_verticalKerningPairs, u1, g1, u2, g2); 230 } 231 232 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs) 233 { 234 ensureGlyphCache(); 235 m_glyphMap.collectGlyphsForString(string, glyphs); 236 } 237 238 void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs) 239 { 240 ensureGlyphCache(); 241 // FIXME: We only support glyphName -> single glyph mapping so far. 242 glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName)); 243 } 244 245 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph) 246 { 247 ensureGlyphCache(); 248 return m_glyphMap.svgGlyphForGlyph(glyph); 249 } 250 251 Glyph SVGFontElement::missingGlyph() 252 { 253 ensureGlyphCache(); 254 return m_missingGlyph; 255 } 256 257 } 258 259 #endif // ENABLE(SVG_FONTS) 260