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 "core/dom/ElementTraversal.h"
     28 #include "core/frame/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 blink {
     36 
     37 inline SVGFontElement::SVGFontElement(Document& document)
     38     : SVGElement(SVGNames::fontTag, document)
     39     , m_missingGlyph(0)
     40     , m_isGlyphCacheValid(false)
     41 {
     42     UseCounter::count(document, UseCounter::SVGFontElement);
     43 }
     44 
     45 DEFINE_NODE_FACTORY(SVGFontElement)
     46 
     47 void SVGFontElement::invalidateGlyphCache()
     48 {
     49     if (m_isGlyphCacheValid) {
     50         m_glyphMap.clear();
     51         m_horizontalKerningTable.clear();
     52         m_verticalKerningTable.clear();
     53     }
     54     m_isGlyphCacheValid = false;
     55 }
     56 
     57 void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures)
     58 {
     59     ASSERT(!ligatures.isEmpty());
     60 
     61     // Register each character of a ligature in the map, if not present.
     62     // Eg. If only a "fi" ligature is present, but not "f" and "i", the
     63     // GlyphPage will not contain any entries for "f" and "i", so the
     64     // SVGFont is not used to render the text "fi1234". Register an
     65     // empty SVGGlyph with the character, so the SVG Font will be used
     66     // to render the text. If someone tries to render "f2" the SVG Font
     67     // will not be able to find a glyph for "f", but handles the fallback
     68     // character substitution properly through glyphDataForCharacter().
     69     Vector<SVGGlyph> glyphs;
     70     size_t ligaturesSize = ligatures.size();
     71     for (size_t i = 0; i < ligaturesSize; ++i) {
     72         const String& unicode = ligatures[i];
     73 
     74         unsigned unicodeLength = unicode.length();
     75         ASSERT(unicodeLength > 1);
     76 
     77         for (unsigned i = 0; i < unicodeLength; ++i) {
     78             String lookupString = unicode.substring(i, 1);
     79             m_glyphMap.collectGlyphsForString(lookupString, glyphs);
     80             if (!glyphs.isEmpty()) {
     81                 glyphs.clear();
     82                 continue;
     83             }
     84 
     85             // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature.
     86             SVGGlyph newGlyphPart;
     87             newGlyphPart.isPartOfLigature = true;
     88             m_glyphMap.addGlyph(String(), lookupString, newGlyphPart);
     89         }
     90     }
     91 }
     92 
     93 static inline KerningPairKey makeKerningPairKey(Glyph glyphId1, Glyph glyphId2)
     94 {
     95     return glyphId1 << 16 | glyphId2;
     96 }
     97 
     98 Vector<SVGGlyph> SVGFontElement::buildGlyphList(const UnicodeRanges& unicodeRanges, const HashSet<String>& unicodeNames, const HashSet<String>& glyphNames) const
     99 {
    100     Vector<SVGGlyph> glyphs;
    101     if (!unicodeRanges.isEmpty()) {
    102         const UnicodeRanges::const_iterator end = unicodeRanges.end();
    103         for (UnicodeRanges::const_iterator it = unicodeRanges.begin(); it != end; ++it)
    104             m_glyphMap.collectGlyphsForUnicodeRange(*it, glyphs);
    105     }
    106     if (!unicodeNames.isEmpty()) {
    107         const HashSet<String>::const_iterator end = unicodeNames.end();
    108         for (HashSet<String>::const_iterator it = unicodeNames.begin(); it != end; ++it)
    109             m_glyphMap.collectGlyphsForStringExact(*it, glyphs);
    110     }
    111     if (!glyphNames.isEmpty()) {
    112         const HashSet<String>::const_iterator end = glyphNames.end();
    113         for (HashSet<String>::const_iterator it = glyphNames.begin(); it != end; ++it) {
    114             const SVGGlyph& glyph = m_glyphMap.glyphIdentifierForGlyphName(*it);
    115             if (glyph.tableEntry)
    116                 glyphs.append(glyph);
    117         }
    118     }
    119     return glyphs;
    120 }
    121 
    122 void SVGFontElement::addPairsToKerningTable(const SVGKerningPair& kerningPair, KerningTable& kerningTable)
    123 {
    124     Vector<SVGGlyph> glyphsLhs = buildGlyphList(kerningPair.unicodeRange1, kerningPair.unicodeName1, kerningPair.glyphName1);
    125     Vector<SVGGlyph> glyphsRhs = buildGlyphList(kerningPair.unicodeRange2, kerningPair.unicodeName2, kerningPair.glyphName2);
    126     if (glyphsLhs.isEmpty() || glyphsRhs.isEmpty())
    127         return;
    128     size_t glyphsLhsSize = glyphsLhs.size();
    129     size_t glyphsRhsSize = glyphsRhs.size();
    130     // Enumerate all the valid kerning pairs, and add them to the table.
    131     for (size_t lhsIndex = 0; lhsIndex < glyphsLhsSize; ++lhsIndex) {
    132         for (size_t rhsIndex = 0; rhsIndex < glyphsRhsSize; ++rhsIndex) {
    133             Glyph glyph1 = glyphsLhs[lhsIndex].tableEntry;
    134             Glyph glyph2 = glyphsRhs[rhsIndex].tableEntry;
    135             ASSERT(glyph1 && glyph2);
    136             kerningTable.add(makeKerningPairKey(glyph1, glyph2), kerningPair.kerning);
    137         }
    138     }
    139 }
    140 
    141 void SVGFontElement::buildKerningTable(const KerningPairVector& kerningPairs, KerningTable& kerningTable)
    142 {
    143     size_t kerningPairsSize = kerningPairs.size();
    144     for (size_t i = 0; i < kerningPairsSize; ++i)
    145         addPairsToKerningTable(kerningPairs[i], kerningTable);
    146 }
    147 
    148 void SVGFontElement::ensureGlyphCache()
    149 {
    150     if (m_isGlyphCacheValid)
    151         return;
    152 
    153     KerningPairVector horizontalKerningPairs;
    154     KerningPairVector verticalKerningPairs;
    155 
    156     SVGMissingGlyphElement* firstMissingGlyphElement = 0;
    157     Vector<String> ligatures;
    158     for (SVGElement* element = Traversal<SVGElement>::firstChild(*this); element; element = Traversal<SVGElement>::nextSibling(*element)) {
    159         if (isSVGGlyphElement(*element)) {
    160             SVGGlyphElement& glyph = toSVGGlyphElement(*element);
    161             AtomicString unicode = glyph.fastGetAttribute(SVGNames::unicodeAttr);
    162             AtomicString glyphId = glyph.getIdAttribute();
    163             if (glyphId.isEmpty() && unicode.isEmpty())
    164                 continue;
    165 
    166             m_glyphMap.addGlyph(glyphId, unicode, glyph.buildGlyphIdentifier());
    167 
    168             // Register ligatures, if needed, don't mix up with surrogate pairs though!
    169             if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0]))
    170                 ligatures.append(unicode.string());
    171         } else if (isSVGHKernElement(*element)) {
    172             toSVGHKernElement(*element).buildHorizontalKerningPair(horizontalKerningPairs);
    173         } else if (isSVGVKernElement(*element)) {
    174             toSVGVKernElement(*element).buildVerticalKerningPair(verticalKerningPairs);
    175         } else if (isSVGMissingGlyphElement(*element) && !firstMissingGlyphElement) {
    176             firstMissingGlyphElement = toSVGMissingGlyphElement(element);
    177         }
    178     }
    179 
    180     // Build the kerning tables.
    181     buildKerningTable(horizontalKerningPairs, m_horizontalKerningTable);
    182     buildKerningTable(verticalKerningPairs, m_verticalKerningTable);
    183 
    184     // The glyph-name->glyph-id map won't be needed/used after having built the kerning table(s).
    185     m_glyphMap.dropNamedGlyphMap();
    186 
    187     // Register each character of each ligature, if needed.
    188     if (!ligatures.isEmpty())
    189         registerLigaturesInGlyphCache(ligatures);
    190 
    191     // Register missing-glyph element, if present.
    192     if (firstMissingGlyphElement) {
    193         SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement);
    194         m_glyphMap.appendToGlyphTable(svgGlyph);
    195         m_missingGlyph = svgGlyph.tableEntry;
    196         ASSERT(m_missingGlyph > 0);
    197     }
    198 
    199     m_isGlyphCacheValid = true;
    200 }
    201 
    202 static float kerningForPairOfGlyphs(const KerningTable& kerningTable, Glyph glyphId1, Glyph glyphId2)
    203 {
    204     KerningTable::const_iterator result = kerningTable.find(makeKerningPairKey(glyphId1, glyphId2));
    205     if (result != kerningTable.end())
    206         return result->value;
    207 
    208     return 0;
    209 }
    210 
    211 float SVGFontElement::horizontalKerningForPairOfGlyphs(Glyph glyphId1, Glyph glyphId2) const
    212 {
    213     if (m_horizontalKerningTable.isEmpty())
    214         return 0;
    215 
    216     return kerningForPairOfGlyphs(m_horizontalKerningTable, glyphId1, glyphId2);
    217 }
    218 
    219 float SVGFontElement::verticalKerningForPairOfGlyphs(Glyph glyphId1, Glyph glyphId2) const
    220 {
    221     if (m_verticalKerningTable.isEmpty())
    222         return 0;
    223 
    224     return kerningForPairOfGlyphs(m_verticalKerningTable, glyphId1, glyphId2);
    225 }
    226 
    227 void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
    228 {
    229     ensureGlyphCache();
    230     m_glyphMap.collectGlyphsForString(string, glyphs);
    231 }
    232 
    233 void SVGFontElement::collectGlyphsForAltGlyphReference(const String& glyphIdentifier, Vector<SVGGlyph>& glyphs)
    234 {
    235     ensureGlyphCache();
    236     // FIXME: We only support glyphName -> single glyph mapping so far.
    237     glyphs.append(m_glyphMap.glyphIdentifierForAltGlyphReference(glyphIdentifier));
    238 }
    239 
    240 SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph)
    241 {
    242     ensureGlyphCache();
    243     return m_glyphMap.svgGlyphForGlyph(glyph);
    244 }
    245 
    246 Glyph SVGFontElement::missingGlyph()
    247 {
    248     ensureGlyphCache();
    249     return m_missingGlyph;
    250 }
    251 
    252 } // namespace blink
    253 
    254 #endif // ENABLE(SVG_FONTS)
    255