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