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  * 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 "core/svg/SVGFontElement.h"
     26 
     27 #include "SVGNames.h"
     28 #include "core/page/UseCounter.h"
     29 #include "core/svg/SVGGlyphElement.h"
     30 #include "core/svg/SVGHKernElement.h"
     31 #include "core/svg/SVGMissingGlyphElement.h"
     32 #include "core/svg/SVGVKernElement.h"
     33 #include "wtf/ASCIICType.h"
     34 
     35 namespace WebCore {
     36 
     37 // Animated property definitions
     38 DEFINE_ANIMATED_BOOLEAN(SVGFontElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     39 
     40 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFontElement)
     41     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
     42     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
     43 END_REGISTER_ANIMATED_PROPERTIES
     44 
     45 inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* document)
     46     : SVGElement(tagName, document)
     47     , m_missingGlyph(0)
     48     , m_isGlyphCacheValid(false)
     49 {
     50     ASSERT(hasTagName(SVGNames::fontTag));
     51     ScriptWrappable::init(this);
     52     registerAnimatedPropertiesForSVGFontElement();
     53 
     54     UseCounter::count(document, UseCounter::SVGFontElement);
     55 }
     56 
     57 PassRefPtr<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document* document)
     58 {
     59     return adoptRef(new SVGFontElement(tagName, document));
     60 }
     61 
     62 void SVGFontElement::invalidateGlyphCache()
     63 {
     64     if (m_isGlyphCacheValid) {
     65         m_glyphMap.clear();
     66         m_horizontalKerningPairs.clear();
     67         m_verticalKerningPairs.clear();
     68     }
     69     m_isGlyphCacheValid = false;
     70 }
     71 
     72 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const
     73 {
     74     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     75         if (child->hasTagName(SVGNames::missing_glyphTag))
     76             return static_cast<SVGMissingGlyphElement*>(child);
     77     }
     78 
     79     return 0;
     80 }
     81 
     82 void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures)
     83 {
     84     ASSERT(!ligatures.isEmpty());
     85 
     86     // Register each character of a ligature in the map, if not present.
     87     // Eg. If only a "fi" ligature is present, but not "f" and "i", the
     88     // GlyphPage will not contain any entries for "f" and "i", so the
     89     // SVGFont is not used to render the text "fi1234". Register an
     90     // empty SVGGlyph with the character, so the SVG Font will be used
     91     // to render the text. If someone tries to render "f2" the SVG Font
     92     // will not be able to find a glyph for "f", but handles the fallback
     93     // character substitution properly through glyphDataForCharacter().
     94     Vector<SVGGlyph> glyphs;
     95     size_t ligaturesSize = ligatures.size();
     96     for (size_t i = 0; i < ligaturesSize; ++i) {
     97         const String& unicode = ligatures[i];
     98 
     99         unsigned unicodeLength = unicode.length();
    100         ASSERT(unicodeLength > 1);
    101 
    102         for (unsigned i = 0; i < unicodeLength; ++i) {
    103             String lookupString = unicode.substring(i, 1);
    104             m_glyphMap.collectGlyphsForString(lookupString, glyphs);
    105             if (!glyphs.isEmpty()) {
    106                 glyphs.clear();
    107                 continue;
    108             }
    109 
    110             // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
    111             SVGGlyph newGlyphPart;
    112             newGlyphPart.isPartOfLigature = true;
    113             m_glyphMap.addGlyph(String(), lookupString, newGlyphPart);
    114         }
    115     }
    116 }
    117 
    118 void SVGFontElement::ensureGlyphCache()
    119 {
    120     if (m_isGlyphCacheValid)
    121         return;
    122 
    123     SVGMissingGlyphElement* firstMissingGlyphElement = 0;
    124     Vector<String> ligatures;
    125     for (Node* child = firstChild(); child; child = child->nextSibling()) {
    126         if (child->hasTagName(SVGNames::glyphTag)) {
    127             SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child);
    128             AtomicString unicode = glyph->fastGetAttribute(SVGNames::unicodeAttr);
    129             AtomicString glyphId = glyph->getIdAttribute();
    130             if (glyphId.isEmpty() && unicode.isEmpty())
    131                 continue;
    132 
    133             m_glyphMap.addGlyph(glyphId, unicode, glyph->buildGlyphIdentifier());
    134 
    135             // Register ligatures, if needed, don't mix up with surrogate pairs though!
    136             if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0]))
    137                 ligatures.append(unicode.string());
    138         } else if (child->hasTagName(SVGNames::hkernTag)) {
    139             SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child);
    140             hkern->buildHorizontalKerningPair(m_horizontalKerningPairs);
    141         } else if (child->hasTagName(SVGNames::vkernTag)) {
    142             SVGVKernElement* vkern = static_cast<SVGVKernElement*>(child);
    143             vkern->buildVerticalKerningPair(m_verticalKerningPairs);
    144         } else if (child->hasTagName(SVGNames::missing_glyphTag) && !firstMissingGlyphElement)
    145             firstMissingGlyphElement = static_cast<SVGMissingGlyphElement*>(child);
    146     }
    147 
    148     // Register each character of each ligature, if needed.
    149     if (!ligatures.isEmpty())
    150         registerLigaturesInGlyphCache(ligatures);
    151 
    152     // Register missing-glyph element, if present.
    153     if (firstMissingGlyphElement) {
    154         SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
    155         m_glyphMap.appendToGlyphTable(svgGlyph);
    156         m_missingGlyph = svgGlyph.tableEntry;
    157         ASSERT(m_missingGlyph > 0);
    158     }
    159 
    160     m_isGlyphCacheValid = true;
    161 }
    162 
    163 static bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges, const HashSet<String>& unicodeValues)
    164 {
    165     if (unicodeString.isEmpty())
    166         return false;
    167 
    168     if (!ranges.isEmpty()) {
    169         UChar firstChar = unicodeString[0];
    170         const UnicodeRanges::const_iterator end = ranges.end();
    171         for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) {
    172             if (firstChar >= it->first && firstChar <= it->second)
    173                 return true;
    174         }
    175     }
    176 
    177     if (!unicodeValues.isEmpty())
    178         return unicodeValues.contains(unicodeString);
    179 
    180     return false;
    181 }
    182 
    183 static bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues)
    184 {
    185     if (glyphName.isEmpty())
    186         return false;
    187 
    188     if (!glyphValues.isEmpty())
    189         return glyphValues.contains(glyphName);
    190 
    191     return false;
    192 }
    193 
    194 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGKerningPair& kerningPair)
    195 {
    196     if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1)
    197         && !stringMatchesGlyphName(g1, kerningPair.glyphName1))
    198         return false;
    199 
    200     if (!stringMatchesUnicodeRange(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2)
    201         && !stringMatchesGlyphName(g2, kerningPair.glyphName2))
    202         return false;
    203 
    204     return true;
    205 }
    206 
    207 static float kerningForPairOfStringsAndGlyphs(const KerningPairVector& kerningPairs, const String& u1, const String& g1, const String& u2, const String& g2)
    208 {
    209     KerningPairVector::const_iterator it = kerningPairs.end() - 1;
    210     const KerningPairVector::const_iterator begin = kerningPairs.begin() - 1;
    211     for (; it != begin; --it) {
    212         if (matches(u1, g1, u2, g2, *it))
    213             return it->kerning;
    214     }
    215 
    216     return 0;
    217 }
    218 
    219 float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
    220 {
    221     if (m_horizontalKerningPairs.isEmpty())
    222         return 0;
    223 
    224     return kerningForPairOfStringsAndGlyphs(m_horizontalKerningPairs, u1, g1, u2, g2);
    225 }
    226 
    227 float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
    228 {
    229     if (m_verticalKerningPairs.isEmpty())
    230         return 0;
    231 
    232     return kerningForPairOfStringsAndGlyphs(m_verticalKerningPairs, u1, g1, u2, g2);
    233 }
    234 
    235 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
    236 {
    237     ensureGlyphCache();
    238     m_glyphMap.collectGlyphsForString(string, glyphs);
    239 }
    240 
    241 void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs)
    242 {
    243     ensureGlyphCache();
    244     // FIXME: We only support glyphName -> single glyph mapping so far.
    245     glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName));
    246 }
    247 
    248 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
    249 {
    250     ensureGlyphCache();
    251     return m_glyphMap.svgGlyphForGlyph(glyph);
    252 }
    253 
    254 Glyph SVGFontElement::missingGlyph()
    255 {
    256     ensureGlyphCache();
    257     return m_missingGlyph;
    258 }
    259 
    260 }
    261 
    262 #endif // ENABLE(SVG_FONTS)
    263