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.
22 #include "wtf/Platform.h"
25 #include "SVGFontElement.h"
28 //FIXME khtml #include "GlyphPageTreeNode.h"
29 #include "SVGGlyphElement.h"
30 #include "SVGMissingGlyphElement.h"
32 #include "SVGParserUtilities.h"
33 #include <wtf/ASCIICType.h>
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
) {
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
);
70 void SVGFontElement::ensureGlyphCache() const
72 if (m_isGlyphCacheValid
)
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
);
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
)
98 if (characters[0] != 'U')
100 if (characters[1] != '+')
103 // Parse the starting hex number (or its prefix).
105 unsigned startLength = 0;
106 for (unsigned i = 2; i < length; ++i) {
107 if (!isASCIIHexDigit(characters[i]))
109 if (++startLength > 6)
111 start = (start << 4) | toASCIIHexValue(characters[i]);
114 // Handle the case of ranges separated by "-" sign.
115 if (2 + startLength < length && characters[2 + startLength] == '-') {
119 // Parse the ending hex number (or its prefix).
121 unsigned endLength = 0;
122 for (unsigned i = 2 + startLength + 1; i < length; ++i) {
123 if (!isASCIIHexDigit(characters[i]))
127 end = (end << 4) | toASCIIHexValue(characters[i]);
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] != '?')
143 if (++startLength > 6)
146 end = (end << 4) | 0xF;
154 return 2 + startLength;*/
157 static bool parseUnicodeRangeList(const UChar
* characters
, unsigned length
, Vector
<pair
<unsigned, unsigned> >& ranges
)
163 const UChar
* remainingCharacters
= characters
;
164 unsigned remainingLength
= length
;
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
;
174 if (!remainingLength
)
176 UChar character
= remainingCharacters
[0];
177 if (character
== ',')
179 ranges
.append(make_pair(character
.unicode(), character
.unicode()));
180 ++remainingCharacters
;
183 if (!remainingLength
)
185 if (remainingCharacters
[0] != ',')
187 ++remainingCharacters
;
192 static bool stringMatchesUnicodeRange(const String
& unicodeString
, const String
& unicodeRangeSpec
)
194 Vector
<pair
<unsigned, unsigned> > ranges
;
195 if (!parseUnicodeRangeList(unicodeRangeSpec
.characters(), unicodeRangeSpec
.length(), ranges
))
198 if (unicodeString
.length() != ranges
.size())
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
)
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
))
214 if (kerningPair
.glyphName1
.length() && kerningPair
.glyphName1
!= g1
)
217 if (kerningPair
.unicode2
.length() && !stringMatchesUnicodeRange(u2
, kerningPair
.unicode2
))
219 if (kerningPair
.glyphName2
.length() && kerningPair
.glyphName2
!= g2
)
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
];
237 void SVGFontElement::getGlyphIdentifiersForString(const String
& string
, Vector
<SVGGlyphIdentifier
>& glyphs
) const
240 m_glyphMap
.get(string
, glyphs
);
245 #endif // ENABLE(SVG_FONTS)