don't discard iframe children.
[kdelibs.git] / khtml / svg / SVGFontElement.cpp
blobdfd22c83ceb9a1baa7a6ecf8352d83f9c7ebc451
1 /*
2 Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
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.
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.
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.
21 #include "config.h"
22 #include "wtf/Platform.h"
24 #if ENABLE(SVG_FONTS)
25 #include "SVGFontElement.h"
27 //#include "Font.h"
28 //FIXME khtml #include "GlyphPageTreeNode.h"
29 #include "SVGGlyphElement.h"
30 #include "SVGMissingGlyphElement.h"
31 #include "SVGNames.h"
32 #include "SVGParserUtilities.h"
33 #include <wtf/ASCIICType.h>
35 using namespace WTF;
37 namespace WebCore {
39 using namespace SVGNames;
41 SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* doc)
42 : SVGStyledElement(tagName, doc)
43 , m_isGlyphCacheValid(false)
47 SVGFontElement::~SVGFontElement()
51 void SVGFontElement::invalidateGlyphCache()
53 if (m_isGlyphCacheValid) {
54 m_glyphMap.clear();
55 m_kerningPairs.clear();
57 m_isGlyphCacheValid = false;
60 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const
62 for (Node* child = firstChild(); child; child = child->nextSibling()) {
63 if (child->hasTagName(missing_glyphTag))
64 return static_cast<SVGMissingGlyphElement*>(child);
67 return 0;
70 void SVGFontElement::ensureGlyphCache() const
72 if (m_isGlyphCacheValid)
73 return;
75 for (Node* child = firstChild(); child; child = child->nextSibling()) {
76 if (child->hasTagName(glyphTag)) {
77 SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child);
78 String unicode = glyph->getAttribute(unicodeAttr);
79 if (unicode.length())
80 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier());
81 } else if (child->hasTagName(hkernTag)) {
82 SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child);
83 SVGHorizontalKerningPair kerningPair = hkern->buildHorizontalKerningPair();
84 m_kerningPairs.append(kerningPair);
88 m_isGlyphCacheValid = true;
91 // Returns the number of characters consumed or 0 if no range was found.
92 static unsigned parseUnicodeRange(const UChar* characters, unsigned length, pair<unsigned, unsigned>& range)
94 // FIXME khtml
95 return 0;
96 /*if (length < 2)
97 return 0;
98 if (characters[0] != 'U')
99 return 0;
100 if (characters[1] != '+')
101 return 0;
103 // Parse the starting hex number (or its prefix).
104 unsigned start = 0;
105 unsigned startLength = 0;
106 for (unsigned i = 2; i < length; ++i) {
107 if (!isASCIIHexDigit(characters[i]))
108 break;
109 if (++startLength > 6)
110 return 0;
111 start = (start << 4) | toASCIIHexValue(characters[i]);
114 // Handle the case of ranges separated by "-" sign.
115 if (2 + startLength < length && characters[2 + startLength] == '-') {
116 if (!startLength)
117 return 0;
119 // Parse the ending hex number (or its prefix).
120 unsigned end = 0;
121 unsigned endLength = 0;
122 for (unsigned i = 2 + startLength + 1; i < length; ++i) {
123 if (!isASCIIHexDigit(characters[i]))
124 break;
125 if (++endLength > 6)
126 return 0;
127 end = (end << 4) | toASCIIHexValue(characters[i]);
130 if (!endLength)
131 return 0;
133 range.first = start;
134 range.second = end;
135 return 2 + startLength + 1 + endLength;
138 // Handle the case of a number with some optional trailing question marks.
139 unsigned end = start;
140 for (unsigned i = 2 + startLength; i < length; ++i) {
141 if (characters[i] != '?')
142 break;
143 if (++startLength > 6)
144 return 0;
145 start <<= 4;
146 end = (end << 4) | 0xF;
149 if (!startLength)
150 return 0;
152 range.first = start;
153 range.second = end;
154 return 2 + startLength;*/
157 static bool parseUnicodeRangeList(const UChar* characters, unsigned length, Vector<pair<unsigned, unsigned> >& ranges)
159 ranges.clear();
160 if (!length)
161 return true;
163 const UChar* remainingCharacters = characters;
164 unsigned remainingLength = length;
166 while (1) {
167 pair<unsigned, unsigned> range;
168 unsigned charactersConsumed = parseUnicodeRange(remainingCharacters, remainingLength, range);
169 if (charactersConsumed) {
170 ranges.append(range);
171 remainingCharacters += charactersConsumed;
172 remainingLength -= charactersConsumed;
173 } else {
174 if (!remainingLength)
175 return false;
176 UChar character = remainingCharacters[0];
177 if (character == ',')
178 return false;
179 ranges.append(make_pair(character.unicode(), character.unicode()));
180 ++remainingCharacters;
181 --remainingLength;
183 if (!remainingLength)
184 return true;
185 if (remainingCharacters[0] != ',')
186 return false;
187 ++remainingCharacters;
188 --remainingLength;
192 static bool stringMatchesUnicodeRange(const String& unicodeString, const String& unicodeRangeSpec)
194 Vector<pair<unsigned, unsigned> > ranges;
195 if (!parseUnicodeRangeList(unicodeRangeSpec.characters(), unicodeRangeSpec.length(), ranges))
196 return false;
198 if (unicodeString.length() != ranges.size())
199 return false;
201 for (size_t i = 0; i < unicodeString.length(); ++i) {
202 UChar c = unicodeString[i];
203 if (c < ranges[i].first || c > ranges[i].second)
204 return false;
207 return true;
210 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGHorizontalKerningPair& kerningPair)
212 if (kerningPair.unicode1.length() && !stringMatchesUnicodeRange(u1, kerningPair.unicode1))
213 return false;
214 if (kerningPair.glyphName1.length() && kerningPair.glyphName1 != g1)
215 return false;
217 if (kerningPair.unicode2.length() && !stringMatchesUnicodeRange(u2, kerningPair.unicode2))
218 return false;
219 if (kerningPair.glyphName2.length() && kerningPair.glyphName2 != g2)
220 return false;
222 return true;
225 bool SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2, SVGHorizontalKerningPair& kerningPair) const
227 for (size_t i = 0; i < m_kerningPairs.size(); ++i) {
228 if (matches(u1, g1, u2, g2, m_kerningPairs[i])) {
229 kerningPair = m_kerningPairs[i];
230 return true;
234 return false;
237 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const
239 ensureGlyphCache();
240 m_glyphMap.get(string, glyphs);
245 #endif // ENABLE(SVG_FONTS)