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 declarations 40DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 41 42inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* document) 43 : SVGStyledElement(tagName, document) 44 , m_isGlyphCacheValid(false) 45{ 46} 47 48PassRefPtr<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document* document) 49{ 50 return adoptRef(new SVGFontElement(tagName, document)); 51} 52 53void SVGFontElement::synchronizeProperty(const QualifiedName& attrName) 54{ 55 SVGStyledElement::synchronizeProperty(attrName); 56 57 if (attrName == anyQName() || SVGExternalResourcesRequired::isKnownAttribute(attrName)) 58 synchronizeExternalResourcesRequired(); 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::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 104static 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 124static 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 135static 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 148static 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 160float 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 168float 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 176void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const 177{ 178 ensureGlyphCache(); 179 m_glyphMap.get(string, glyphs); 180} 181 182AttributeToPropertyTypeMap& SVGFontElement::attributeToPropertyTypeMap() 183{ 184 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 185 return s_attributeToPropertyTypeMap; 186} 187 188void SVGFontElement::fillAttributeToPropertyTypeMap() 189{ 190 SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap()); 191} 192 193} 194 195#endif // ENABLE(SVG_FONTS) 196