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 "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 37 namespace WebCore { 38 39 // Animated property declarations 40 DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 41 42 inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* document) 43 : SVGStyledElement(tagName, document) 44 , m_isGlyphCacheValid(false) 45 { 46 } 47 48 PassRefPtr<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document* document) 49 { 50 return adoptRef(new SVGFontElement(tagName, document)); 51 } 52 53 void SVGFontElement::synchronizeProperty(const QualifiedName& attrName) 54 { 55 SVGStyledElement::synchronizeProperty(attrName); 56 57 if (attrName == anyQName() || SVGExternalResourcesRequired::isKnownAttribute(attrName)) 58 synchronizeExternalResourcesRequired(); 59 } 60 61 void 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 71 SVGMissingGlyphElement* 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 81 void SVGFontElement::ensureGlyphCache() const 82 { 83 if (m_isGlyphCacheValid) 84 return; 85 86 for (Node* child = firstChild(); child; child = child->nextSibling()) { 87 if (child->hasTagName(SVGNames::glyphTag)) { 88 SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child); 89 String unicode = glyph->getAttribute(SVGNames::unicodeAttr); 90 if (unicode.length()) 91 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier()); 92 } else if (child->hasTagName(SVGNames::hkernTag)) { 93 SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child); 94 hkern->buildHorizontalKerningPair(m_horizontalKerningPairs); 95 } else if (child->hasTagName(SVGNames::vkernTag)) { 96 SVGVKernElement* vkern = static_cast<SVGVKernElement*>(child); 97 vkern->buildVerticalKerningPair(m_verticalKerningPairs); 98 } 99 } 100 101 m_isGlyphCacheValid = true; 102 } 103 104 static bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges, const HashSet<String>& unicodeValues) 105 { 106 if (unicodeString.isEmpty()) 107 return false; 108 109 if (!ranges.isEmpty()) { 110 UChar firstChar = unicodeString[0]; 111 const UnicodeRanges::const_iterator end = ranges.end(); 112 for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) { 113 if (firstChar >= it->first && firstChar <= it->second) 114 return true; 115 } 116 } 117 118 if (!unicodeValues.isEmpty()) 119 return unicodeValues.contains(unicodeString); 120 121 return false; 122 } 123 124 static bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues) 125 { 126 if (glyphName.isEmpty()) 127 return false; 128 129 if (!glyphValues.isEmpty()) 130 return glyphValues.contains(glyphName); 131 132 return false; 133 } 134 135 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGKerningPair& kerningPair) 136 { 137 if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1) 138 && !stringMatchesGlyphName(g1, kerningPair.glyphName1)) 139 return false; 140 141 if (!stringMatchesUnicodeRange(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2) 142 && !stringMatchesGlyphName(g2, kerningPair.glyphName2)) 143 return false; 144 145 return true; 146 } 147 148 static float kerningForPairOfStringsAndGlyphs(KerningPairVector& kerningPairs, const String& u1, const String& g1, const String& u2, const String& g2) 149 { 150 KerningPairVector::const_iterator it = kerningPairs.end() - 1; 151 const KerningPairVector::const_iterator begin = kerningPairs.begin() - 1; 152 for (; it != begin; --it) { 153 if (matches(u1, g1, u2, g2, *it)) 154 return it->kerning; 155 } 156 157 return 0.0f; 158 } 159 160 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const 161 { 162 if (m_horizontalKerningPairs.isEmpty()) 163 return 0.0f; 164 165 return kerningForPairOfStringsAndGlyphs(m_horizontalKerningPairs, u1, g1, u2, g2); 166 } 167 168 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const 169 { 170 if (m_verticalKerningPairs.isEmpty()) 171 return 0.0f; 172 173 return kerningForPairOfStringsAndGlyphs(m_verticalKerningPairs, u1, g1, u2, g2); 174 } 175 176 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const 177 { 178 ensureGlyphCache(); 179 m_glyphMap.get(string, glyphs); 180 } 181 182 AttributeToPropertyTypeMap& SVGFontElement::attributeToPropertyTypeMap() 183 { 184 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 185 return s_attributeToPropertyTypeMap; 186 } 187 188 void SVGFontElement::fillAttributeToPropertyTypeMap() 189 { 190 SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap()); 191 } 192 193 } 194 195 #endif // ENABLE(SVG_FONTS) 196