KHTML
SVGFontElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2007 Eric Seidel <eric@webkit.org> 00003 Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "config.h" 00022 #include "wtf/Platform.h" 00023 00024 #if ENABLE(SVG_FONTS) 00025 #include "SVGFontElement.h" 00026 00027 //#include "Font.h" 00028 //FIXME khtml #include "GlyphPageTreeNode.h" 00029 #include "SVGGlyphElement.h" 00030 #include "SVGMissingGlyphElement.h" 00031 #include "SVGNames.h" 00032 #include "SVGParserUtilities.h" 00033 #include <wtf/ASCIICType.h> 00034 00035 using namespace WTF; 00036 00037 namespace WebCore { 00038 00039 using namespace SVGNames; 00040 00041 SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* doc) 00042 : SVGStyledElement(tagName, doc) 00043 , m_isGlyphCacheValid(false) 00044 { 00045 } 00046 00047 SVGFontElement::~SVGFontElement() 00048 { 00049 } 00050 00051 void SVGFontElement::invalidateGlyphCache() 00052 { 00053 if (m_isGlyphCacheValid) { 00054 m_glyphMap.clear(); 00055 m_kerningPairs.clear(); 00056 } 00057 m_isGlyphCacheValid = false; 00058 } 00059 00060 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const 00061 { 00062 for (Node* child = firstChild(); child; child = child->nextSibling()) { 00063 if (child->hasTagName(missing_glyphTag)) 00064 return static_cast<SVGMissingGlyphElement*>(child); 00065 } 00066 00067 return 0; 00068 } 00069 00070 void SVGFontElement::ensureGlyphCache() const 00071 { 00072 if (m_isGlyphCacheValid) 00073 return; 00074 00075 for (Node* child = firstChild(); child; child = child->nextSibling()) { 00076 if (child->hasTagName(glyphTag)) { 00077 SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child); 00078 String unicode = glyph->getAttribute(unicodeAttr); 00079 if (unicode.length()) 00080 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier()); 00081 } else if (child->hasTagName(hkernTag)) { 00082 SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child); 00083 SVGHorizontalKerningPair kerningPair = hkern->buildHorizontalKerningPair(); 00084 m_kerningPairs.append(kerningPair); 00085 } 00086 } 00087 00088 m_isGlyphCacheValid = true; 00089 } 00090 00091 // Returns the number of characters consumed or 0 if no range was found. 00092 static unsigned parseUnicodeRange(const UChar* characters, unsigned length, pair<unsigned, unsigned>& range) 00093 { 00094 Q_UNUSED(characters); 00095 Q_UNUSED(length); 00096 Q_UNUSED(range); 00097 // FIXME khtml 00098 return 0; 00099 /*if (length < 2) 00100 return 0; 00101 if (characters[0] != 'U') 00102 return 0; 00103 if (characters[1] != '+') 00104 return 0; 00105 00106 // Parse the starting hex number (or its prefix). 00107 unsigned start = 0; 00108 unsigned startLength = 0; 00109 for (unsigned i = 2; i < length; ++i) { 00110 if (!isASCIIHexDigit(characters[i])) 00111 break; 00112 if (++startLength > 6) 00113 return 0; 00114 start = (start << 4) | toASCIIHexValue(characters[i]); 00115 } 00116 00117 // Handle the case of ranges separated by "-" sign. 00118 if (2 + startLength < length && characters[2 + startLength] == '-') { 00119 if (!startLength) 00120 return 0; 00121 00122 // Parse the ending hex number (or its prefix). 00123 unsigned end = 0; 00124 unsigned endLength = 0; 00125 for (unsigned i = 2 + startLength + 1; i < length; ++i) { 00126 if (!isASCIIHexDigit(characters[i])) 00127 break; 00128 if (++endLength > 6) 00129 return 0; 00130 end = (end << 4) | toASCIIHexValue(characters[i]); 00131 } 00132 00133 if (!endLength) 00134 return 0; 00135 00136 range.first = start; 00137 range.second = end; 00138 return 2 + startLength + 1 + endLength; 00139 } 00140 00141 // Handle the case of a number with some optional trailing question marks. 00142 unsigned end = start; 00143 for (unsigned i = 2 + startLength; i < length; ++i) { 00144 if (characters[i] != '?') 00145 break; 00146 if (++startLength > 6) 00147 return 0; 00148 start <<= 4; 00149 end = (end << 4) | 0xF; 00150 } 00151 00152 if (!startLength) 00153 return 0; 00154 00155 range.first = start; 00156 range.second = end; 00157 return 2 + startLength;*/ 00158 } 00159 00160 static bool parseUnicodeRangeList(const UChar* characters, unsigned length, Vector<pair<unsigned, unsigned> >& ranges) 00161 { 00162 ranges.clear(); 00163 if (!length) 00164 return true; 00165 00166 const UChar* remainingCharacters = characters; 00167 unsigned remainingLength = length; 00168 00169 while (1) { 00170 pair<unsigned, unsigned> range; 00171 unsigned charactersConsumed = parseUnicodeRange(remainingCharacters, remainingLength, range); 00172 if (charactersConsumed) { 00173 ranges.append(range); 00174 remainingCharacters += charactersConsumed; 00175 remainingLength -= charactersConsumed; 00176 } else { 00177 if (!remainingLength) 00178 return false; 00179 UChar character = remainingCharacters[0]; 00180 if (character == ',') 00181 return false; 00182 ranges.append(make_pair(character.unicode(), character.unicode())); 00183 ++remainingCharacters; 00184 --remainingLength; 00185 } 00186 if (!remainingLength) 00187 return true; 00188 if (remainingCharacters[0] != ',') 00189 return false; 00190 ++remainingCharacters; 00191 --remainingLength; 00192 } 00193 } 00194 00195 static bool stringMatchesUnicodeRange(const String& unicodeString, const String& unicodeRangeSpec) 00196 { 00197 Vector<pair<unsigned, unsigned> > ranges; 00198 if (!parseUnicodeRangeList(unicodeRangeSpec.characters(), unicodeRangeSpec.length(), ranges)) 00199 return false; 00200 00201 if (unicodeString.length() != ranges.size()) 00202 return false; 00203 00204 for (size_t i = 0; i < unicodeString.length(); ++i) { 00205 UChar c = unicodeString[i]; 00206 if (c < ranges[i].first || c > ranges[i].second) 00207 return false; 00208 } 00209 00210 return true; 00211 } 00212 00213 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGHorizontalKerningPair& kerningPair) 00214 { 00215 if (kerningPair.unicode1.length() && !stringMatchesUnicodeRange(u1, kerningPair.unicode1)) 00216 return false; 00217 if (kerningPair.glyphName1.length() && kerningPair.glyphName1 != g1) 00218 return false; 00219 00220 if (kerningPair.unicode2.length() && !stringMatchesUnicodeRange(u2, kerningPair.unicode2)) 00221 return false; 00222 if (kerningPair.glyphName2.length() && kerningPair.glyphName2 != g2) 00223 return false; 00224 00225 return true; 00226 } 00227 00228 bool SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2, SVGHorizontalKerningPair& kerningPair) const 00229 { 00230 for (size_t i = 0; i < m_kerningPairs.size(); ++i) { 00231 if (matches(u1, g1, u2, g2, m_kerningPairs[i])) { 00232 kerningPair = m_kerningPairs[i]; 00233 return true; 00234 } 00235 } 00236 00237 return false; 00238 } 00239 00240 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const 00241 { 00242 ensureGlyphCache(); 00243 m_glyphMap.get(string, glyphs); 00244 } 00245 00246 } 00247 00248 #endif // ENABLE(SVG_FONTS)
KDE 4.6 API Reference