a5733506fc18f88859562e3cf36afae8c29b8ded
[WebKit-https.git] / WebCore / svg / SVGFontElement.cpp
1 /*
2     Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3     Copyright (C) 2007 Nikolas Zimmermann <zimmermann@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 static bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges, const HashSet<String>& unicodeValues)
100 {
101     if (unicodeString.isEmpty())
102         return false;
103
104     if (!ranges.isEmpty()) {
105         UChar firstChar = unicodeString[0];
106         const UnicodeRanges::const_iterator end = ranges.end();
107         for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) {
108             if (firstChar >= it->first && firstChar <= it->second)
109                 return true;
110         }
111     }
112
113     if (!unicodeValues.isEmpty())
114         return unicodeValues.contains(unicodeString);
115     
116     return false;
117 }
118
119 static bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues)
120 {
121     if (glyphName.isEmpty())
122         return false;
123
124     if (!glyphValues.isEmpty())
125         return glyphValues.contains(glyphName);
126     
127     return false;
128 }
129     
130 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGHorizontalKerningPair& kerningPair)
131 {
132     if (!stringMatchesUnicodeRange(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1)
133         && !stringMatchesGlyphName(g1, kerningPair.glyphName1))
134         return false;
135
136     if (!stringMatchesUnicodeRange(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2)
137         && !stringMatchesGlyphName(g2, kerningPair.glyphName2))
138         return false;
139
140     return true;
141 }
142     
143 float SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const
144 {
145     if (m_kerningPairs.isEmpty())
146         return 0.0f;
147
148     KerningPairVector::const_iterator it = m_kerningPairs.end() - 1;
149     const KerningPairVector::const_iterator begin = m_kerningPairs.begin() - 1;
150     for (; it != begin; --it) {
151         if (matches(u1, g1, u2, g2, *it))
152             return it->kerning;
153     }
154
155     return 0.0f;
156 }
157
158 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const
159 {
160     ensureGlyphCache();
161     m_glyphMap.get(string, glyphs);
162 }
163
164 }
165
166 #endif // ENABLE(SVG_FONTS)