Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2007 Eric Seidel <eric (at) webkit.org>
      3     Copyright (C) 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public License
     16     along with this library; see the file COPYING.LIB.  If not, write to
     17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18     Boston, MA 02110-1301, USA.
     19 */
     20 
     21 #include "config.h"
     22 
     23 #if ENABLE(SVG_FONTS)
     24 #include "SVGFontElement.h"
     25 
     26 #include "Document.h"
     27 #include "Font.h"
     28 #include "GlyphPageTreeNode.h"
     29 #include "SVGGlyphElement.h"
     30 #include "SVGMissingGlyphElement.h"
     31 #include "SVGNames.h"
     32 #include "SVGParserUtilities.h"
     33 #include <wtf/ASCIICType.h>
     34 
     35 using namespace WTF;
     36 
     37 namespace WebCore {
     38 
     39 using namespace SVGNames;
     40 
     41 SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* doc)
     42     : SVGStyledElement(tagName, doc)
     43     , m_isGlyphCacheValid(false)
     44 {
     45 }
     46 
     47 SVGFontElement::~SVGFontElement()
     48 {
     49 }
     50 
     51 void SVGFontElement::synchronizeProperty(const QualifiedName& attrName)
     52 {
     53     SVGStyledElement::synchronizeProperty(attrName);
     54 
     55     if (attrName == anyQName() || SVGExternalResourcesRequired::isKnownAttribute(attrName))
     56         synchronizeExternalResourcesRequired();
     57 }
     58 
     59 void SVGFontElement::invalidateGlyphCache()
     60 {
     61     if (m_isGlyphCacheValid) {
     62         m_glyphMap.clear();
     63         m_kerningPairs.clear();
     64     }
     65     m_isGlyphCacheValid = false;
     66 }
     67 
     68 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const
     69 {
     70     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     71         if (child->hasTagName(missing_glyphTag))
     72             return static_cast<SVGMissingGlyphElement*>(child);
     73     }
     74 
     75     return 0;
     76 }
     77 
     78 void SVGFontElement::ensureGlyphCache() const
     79 {
     80     if (m_isGlyphCacheValid)
     81         return;
     82 
     83     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     84         if (child->hasTagName(glyphTag)) {
     85             SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child);
     86             String unicode = glyph->getAttribute(unicodeAttr);
     87             if (unicode.length())
     88                 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier());
     89         } else if (child->hasTagName(hkernTag)) {
     90             SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child);
     91             SVGHorizontalKerningPair kerningPair = hkern->buildHorizontalKerningPair();
     92             m_kerningPairs.append(kerningPair);
     93         }
     94     }
     95 
     96     m_isGlyphCacheValid = true;
     97 }
     98 
     99 // Returns the number of characters consumed or 0 if no range was found.
    100 static unsigned parseUnicodeRange(const UChar* characters, unsigned length, pair<unsigned, unsigned>& range)
    101 {
    102     if (length < 2)
    103         return 0;
    104     if (characters[0] != 'U')
    105         return 0;
    106     if (characters[1] != '+')
    107         return 0;
    108 
    109     // Parse the starting hex number (or its prefix).
    110     unsigned start = 0;
    111     unsigned startLength = 0;
    112     for (unsigned i = 2; i < length; ++i) {
    113         if (!isASCIIHexDigit(characters[i]))
    114             break;
    115         if (++startLength > 6)
    116             return 0;
    117         start = (start << 4) | toASCIIHexValue(characters[i]);
    118     }
    119 
    120     // Handle the case of ranges separated by "-" sign.
    121     if (2 + startLength < length && characters[2 + startLength] == '-') {
    122         if (!startLength)
    123             return 0;
    124 
    125         // Parse the ending hex number (or its prefix).
    126         unsigned end = 0;
    127         unsigned endLength = 0;
    128         for (unsigned i = 2 + startLength + 1; i < length; ++i) {
    129             if (!isASCIIHexDigit(characters[i]))
    130                 break;
    131             if (++endLength > 6)
    132                 return 0;
    133             end = (end << 4) | toASCIIHexValue(characters[i]);
    134         }
    135 
    136         if (!endLength)
    137             return 0;
    138 
    139         range.first = start;
    140         range.second = end;
    141         return 2 + startLength + 1 + endLength;
    142     }
    143 
    144     // Handle the case of a number with some optional trailing question marks.
    145     unsigned end = start;
    146     for (unsigned i = 2 + startLength; i < length; ++i) {
    147         if (characters[i] != '?')
    148             break;
    149         if (++startLength > 6)
    150             return 0;
    151         start <<= 4;
    152         end = (end << 4) | 0xF;
    153     }
    154 
    155     if (!startLength)
    156         return 0;
    157 
    158     range.first = start;
    159     range.second = end;
    160     return 2 + startLength;
    161 }
    162 
    163 static bool parseUnicodeRangeList(const UChar* characters, unsigned length, Vector<pair<unsigned, unsigned> >& ranges)
    164 {
    165     ranges.clear();
    166     if (!length)
    167         return true;
    168 
    169     const UChar* remainingCharacters = characters;
    170     unsigned remainingLength = length;
    171 
    172     while (1) {
    173         pair<unsigned, unsigned> range;
    174         unsigned charactersConsumed = parseUnicodeRange(remainingCharacters, remainingLength, range);
    175         if (charactersConsumed) {
    176             ranges.append(range);
    177             remainingCharacters += charactersConsumed;
    178             remainingLength -= charactersConsumed;
    179         } else {
    180             if (!remainingLength)
    181                 return false;
    182             UChar character = remainingCharacters[0];
    183             if (character == ',')
    184                 return false;
    185             ranges.append(make_pair(character, character));
    186             ++remainingCharacters;
    187             --remainingLength;
    188         }
    189         if (!remainingLength)
    190             return true;
    191         if (remainingCharacters[0] != ',')
    192             return false;
    193         ++remainingCharacters;
    194         --remainingLength;
    195     }
    196 }
    197 
    198 static bool stringMatchesUnicodeRange(const String& unicodeString, const String& unicodeRangeSpec)
    199 {
    200     Vector<pair<unsigned, unsigned> > ranges;
    201     if (!parseUnicodeRangeList(unicodeRangeSpec.characters(), unicodeRangeSpec.length(), ranges))
    202         return false;
    203 
    204     if (unicodeString.length() != ranges.size())
    205         return false;
    206 
    207     for (size_t i = 0; i < unicodeString.length(); ++i) {
    208         UChar c = unicodeString[i];
    209         if (c < ranges[i].first || c > ranges[i].second)
    210             return false;
    211     }
    212 
    213     return true;
    214 }
    215 
    216 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGHorizontalKerningPair& kerningPair)
    217 {
    218     if (kerningPair.unicode1.length() && !stringMatchesUnicodeRange(u1, kerningPair.unicode1))
    219         return false;
    220     if (kerningPair.glyphName1.length() && kerningPair.glyphName1 != g1)
    221         return false;
    222 
    223     if (kerningPair.unicode2.length() && !stringMatchesUnicodeRange(u2, kerningPair.unicode2))
    224         return false;
    225     if (kerningPair.glyphName2.length() && kerningPair.glyphName2 != g2)
    226         return false;
    227 
    228     return true;
    229 }
    230 
    231 bool SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2, SVGHorizontalKerningPair& kerningPair) const
    232 {
    233     for (size_t i = 0; i < m_kerningPairs.size(); ++i) {
    234         if (matches(u1, g1, u2, g2, m_kerningPairs[i])) {
    235             kerningPair = m_kerningPairs[i];
    236             return true;
    237         }
    238     }
    239 
    240     return false;
    241 }
    242 
    243 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const
    244 {
    245     ensureGlyphCache();
    246     m_glyphMap.get(string, glyphs);
    247 }
    248 
    249 }
    250 
    251 #endif // ENABLE(SVG_FONTS)
    252