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 "SVGFontElement.h" 26 27#include "Document.h" 28#include "Font.h" 29#include "GlyphPageTreeNode.h" 30#include "SVGGlyphElement.h" 31#include "SVGHKernElement.h" 32#include "SVGMissingGlyphElement.h" 33#include "SVGNames.h" 34#include "SVGVKernElement.h" 35#include <wtf/ASCIICType.h> 36 37namespace WebCore { 38 39// Animated property definitions 40DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 41 42BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFontElement) 43 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 44 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGStyledElement) 45END_REGISTER_ANIMATED_PROPERTIES 46 47inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* document) 48 : SVGStyledElement(tagName, document) 49 , m_missingGlyph(0) 50 , m_isGlyphCacheValid(false) 51{ 52 ASSERT(hasTagName(SVGNames::fontTag)); 53 registerAnimatedPropertiesForSVGFontElement(); 54} 55 56PassRefPtr<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document* document) 57{ 58 return adoptRef(new SVGFontElement(tagName, document)); 59} 60 61void SVGFontElement::invalidateGlyphCache() 62{ 63 if (m_isGlyphCacheValid) { 64 m_glyphMap.clear(); 65 m_horizontalKerningPairs.clear(); 66 m_verticalKerningPairs.clear(); 67 } 68 m_isGlyphCacheValid = false; 69} 70 71SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const 72{ 73 for (Node* child = firstChild(); child; child = child->nextSibling()) { 74 if (child->hasTagName(SVGNames::missing_glyphTag)) 75 return static_cast<SVGMissingGlyphElement*>(child); 76 } 77 78 return 0; 79} 80 81void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures) 82{ 83 ASSERT(!ligatures.isEmpty()); 84 85 // Register each character of a ligature in the map, if not present. 86 // Eg. If only a "fi" ligature is present, but not "f" and "i", the 87 // GlyphPage will not contain any entries for "f" and "i", so the 88 // SVGFont is not used to render the text "fi1234". Register an 89 // empty SVGGlyph with the character, so the SVG Font will be used 90 // to render the text. If someone tries to render "f2" the SVG Font 91 // will not be able to find a glyph for "f", but handles the fallback 92 // character substitution properly through glyphDataForCharacter(). 93 Vector<SVGGlyph> glyphs; 94 size_t ligaturesSize = ligatures.size(); 95 for (size_t i = 0; i < ligaturesSize; ++i) { 96 const String& unicode = ligatures[i]; 97 98 unsigned unicodeLength = unicode.length(); 99 ASSERT(unicodeLength > 1); 100 101 const UChar* characters = unicode.characters(); 102 for (unsigned i = 0; i < unicodeLength; ++i) { 103 String lookupString(characters + 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 118void 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 163static 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 183static 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 194static 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 207static 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 219float 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 227float 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 235void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs) 236{ 237 ensureGlyphCache(); 238 m_glyphMap.collectGlyphsForString(string, glyphs); 239} 240 241void 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 248SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph) 249{ 250 ensureGlyphCache(); 251 return m_glyphMap.svgGlyphForGlyph(glyph); 252} 253 254Glyph SVGFontElement::missingGlyph() 255{ 256 ensureGlyphCache(); 257 return m_missingGlyph; 258} 259 260} 261 262#endif // ENABLE(SVG_FONTS) 263