File indexing completed on 2024-04-28 15:24:33
0001 /* 0002 Copyright (C) 2007 Eric Seidel <eric@webkit.org> 0003 Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "wtf/Platform.h" 0022 0023 #if ENABLE(SVG_FONTS) 0024 #include "SVGFontElement.h" 0025 0026 //#include "Font.h" 0027 //FIXME khtml #include "GlyphPageTreeNode.h" 0028 #include "SVGMissingGlyphElement.h" 0029 #include "SVGNames.h" 0030 #include "SVGParserUtilities.h" 0031 #include <wtf/ASCIICType.h> 0032 0033 using namespace WTF; 0034 0035 namespace WebCore 0036 { 0037 0038 using namespace SVGNames; 0039 0040 SVGFontElement::SVGFontElement(const QualifiedName &tagName, Document *doc) 0041 : SVGStyledElement(tagName, doc) 0042 , m_isGlyphCacheValid(false) 0043 { 0044 } 0045 0046 SVGFontElement::~SVGFontElement() 0047 { 0048 } 0049 0050 void SVGFontElement::invalidateGlyphCache() 0051 { 0052 if (m_isGlyphCacheValid) { 0053 m_glyphMap.clear(); 0054 m_kerningPairs.clear(); 0055 } 0056 m_isGlyphCacheValid = false; 0057 } 0058 0059 SVGMissingGlyphElement *SVGFontElement::firstMissingGlyphElement() const 0060 { 0061 for (Node *child = firstChild(); child; child = child->nextSibling()) { 0062 if (child->hasTagName(missing_glyphTag)) { 0063 return static_cast<SVGMissingGlyphElement *>(child); 0064 } 0065 } 0066 0067 return nullptr; 0068 } 0069 0070 void SVGFontElement::ensureGlyphCache() const 0071 { 0072 if (m_isGlyphCacheValid) { 0073 return; 0074 } 0075 0076 for (Node *child = firstChild(); child; child = child->nextSibling()) { 0077 if (child->hasTagName(glyphTag)) { 0078 SVGGlyphElement *glyph = static_cast<SVGGlyphElement *>(child); 0079 String unicode = glyph->getAttribute(unicodeAttr); 0080 if (unicode.length()) { 0081 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier()); 0082 } 0083 } else if (child->hasTagName(hkernTag)) { 0084 SVGHKernElement *hkern = static_cast<SVGHKernElement *>(child); 0085 SVGHorizontalKerningPair kerningPair = hkern->buildHorizontalKerningPair(); 0086 m_kerningPairs.append(kerningPair); 0087 } 0088 } 0089 0090 m_isGlyphCacheValid = true; 0091 } 0092 0093 // Returns the number of characters consumed or 0 if no range was found. 0094 static unsigned parseUnicodeRange(const UChar *characters, unsigned length, pair<unsigned, unsigned> &range) 0095 { 0096 Q_UNUSED(characters); 0097 Q_UNUSED(length); 0098 Q_UNUSED(range); 0099 // FIXME khtml 0100 return 0; 0101 /*if (length < 2) 0102 return 0; 0103 if (characters[0] != 'U') 0104 return 0; 0105 if (characters[1] != '+') 0106 return 0; 0107 0108 // Parse the starting hex number (or its prefix). 0109 unsigned start = 0; 0110 unsigned startLength = 0; 0111 for (unsigned i = 2; i < length; ++i) { 0112 if (!isASCIIHexDigit(characters[i])) 0113 break; 0114 if (++startLength > 6) 0115 return 0; 0116 start = (start << 4) | toASCIIHexValue(characters[i]); 0117 } 0118 0119 // Handle the case of ranges separated by "-" sign. 0120 if (2 + startLength < length && characters[2 + startLength] == '-') { 0121 if (!startLength) 0122 return 0; 0123 0124 // Parse the ending hex number (or its prefix). 0125 unsigned end = 0; 0126 unsigned endLength = 0; 0127 for (unsigned i = 2 + startLength + 1; i < length; ++i) { 0128 if (!isASCIIHexDigit(characters[i])) 0129 break; 0130 if (++endLength > 6) 0131 return 0; 0132 end = (end << 4) | toASCIIHexValue(characters[i]); 0133 } 0134 0135 if (!endLength) 0136 return 0; 0137 0138 range.first = start; 0139 range.second = end; 0140 return 2 + startLength + 1 + endLength; 0141 } 0142 0143 // Handle the case of a number with some optional trailing question marks. 0144 unsigned end = start; 0145 for (unsigned i = 2 + startLength; i < length; ++i) { 0146 if (characters[i] != '?') 0147 break; 0148 if (++startLength > 6) 0149 return 0; 0150 start <<= 4; 0151 end = (end << 4) | 0xF; 0152 } 0153 0154 if (!startLength) 0155 return 0; 0156 0157 range.first = start; 0158 range.second = end; 0159 return 2 + startLength;*/ 0160 } 0161 0162 static bool parseUnicodeRangeList(const UChar *characters, unsigned length, Vector<pair<unsigned, unsigned> > &ranges) 0163 { 0164 ranges.clear(); 0165 if (!length) { 0166 return true; 0167 } 0168 0169 const UChar *remainingCharacters = characters; 0170 unsigned remainingLength = length; 0171 0172 while (1) { 0173 pair<unsigned, unsigned> range; 0174 unsigned charactersConsumed = parseUnicodeRange(remainingCharacters, remainingLength, range); 0175 if (charactersConsumed) { 0176 ranges.append(range); 0177 remainingCharacters += charactersConsumed; 0178 remainingLength -= charactersConsumed; 0179 } else { 0180 if (!remainingLength) { 0181 return false; 0182 } 0183 UChar character = remainingCharacters[0]; 0184 if (character == ',') { 0185 return false; 0186 } 0187 ranges.append(make_pair(character.unicode(), character.unicode())); 0188 ++remainingCharacters; 0189 --remainingLength; 0190 } 0191 if (!remainingLength) { 0192 return true; 0193 } 0194 if (remainingCharacters[0] != ',') { 0195 return false; 0196 } 0197 ++remainingCharacters; 0198 --remainingLength; 0199 } 0200 } 0201 0202 static bool stringMatchesUnicodeRange(const String &unicodeString, const String &unicodeRangeSpec) 0203 { 0204 Vector<pair<unsigned, unsigned> > ranges; 0205 if (!parseUnicodeRangeList(unicodeRangeSpec.characters(), unicodeRangeSpec.length(), ranges)) { 0206 return false; 0207 } 0208 0209 if (unicodeString.length() != ranges.size()) { 0210 return false; 0211 } 0212 0213 for (size_t i = 0; i < unicodeString.length(); ++i) { 0214 UChar c = unicodeString[i]; 0215 if (c < ranges[i].first || c > ranges[i].second) { 0216 return false; 0217 } 0218 } 0219 0220 return true; 0221 } 0222 0223 static bool matches(const String &u1, const String &g1, const String &u2, const String &g2, const SVGHorizontalKerningPair &kerningPair) 0224 { 0225 if (kerningPair.unicode1.length() && !stringMatchesUnicodeRange(u1, kerningPair.unicode1)) { 0226 return false; 0227 } 0228 if (kerningPair.glyphName1.length() && kerningPair.glyphName1 != g1) { 0229 return false; 0230 } 0231 0232 if (kerningPair.unicode2.length() && !stringMatchesUnicodeRange(u2, kerningPair.unicode2)) { 0233 return false; 0234 } 0235 if (kerningPair.glyphName2.length() && kerningPair.glyphName2 != g2) { 0236 return false; 0237 } 0238 0239 return true; 0240 } 0241 0242 bool SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String &u1, const String &g1, const String &u2, const String &g2, SVGHorizontalKerningPair &kerningPair) const 0243 { 0244 for (size_t i = 0; i < m_kerningPairs.size(); ++i) { 0245 if (matches(u1, g1, u2, g2, m_kerningPairs[i])) { 0246 kerningPair = m_kerningPairs[i]; 0247 return true; 0248 } 0249 } 0250 0251 return false; 0252 } 0253 0254 void SVGFontElement::getGlyphIdentifiersForString(const String &string, Vector<SVGGlyphIdentifier> &glyphs) const 0255 { 0256 ensureGlyphCache(); 0257 m_glyphMap.get(string, glyphs); 0258 } 0259 0260 } 0261 0262 #endif // ENABLE(SVG_FONTS)