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)