KHTML
SVGFontElement.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "wtf/Platform.h"
00023
00024 #if ENABLE(SVG_FONTS)
00025 #include "SVGFontElement.h"
00026
00027
00028
00029 #include "SVGGlyphElement.h"
00030 #include "SVGMissingGlyphElement.h"
00031 #include "SVGNames.h"
00032 #include "SVGParserUtilities.h"
00033 #include <wtf/ASCIICType.h>
00034
00035 using namespace WTF;
00036
00037 namespace WebCore {
00038
00039 using namespace SVGNames;
00040
00041 SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document* doc)
00042 : SVGStyledElement(tagName, doc)
00043 , m_isGlyphCacheValid(false)
00044 {
00045 }
00046
00047 SVGFontElement::~SVGFontElement()
00048 {
00049 }
00050
00051 void SVGFontElement::invalidateGlyphCache()
00052 {
00053 if (m_isGlyphCacheValid) {
00054 m_glyphMap.clear();
00055 m_kerningPairs.clear();
00056 }
00057 m_isGlyphCacheValid = false;
00058 }
00059
00060 SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const
00061 {
00062 for (Node* child = firstChild(); child; child = child->nextSibling()) {
00063 if (child->hasTagName(missing_glyphTag))
00064 return static_cast<SVGMissingGlyphElement*>(child);
00065 }
00066
00067 return 0;
00068 }
00069
00070 void SVGFontElement::ensureGlyphCache() const
00071 {
00072 if (m_isGlyphCacheValid)
00073 return;
00074
00075 for (Node* child = firstChild(); child; child = child->nextSibling()) {
00076 if (child->hasTagName(glyphTag)) {
00077 SVGGlyphElement* glyph = static_cast<SVGGlyphElement*>(child);
00078 String unicode = glyph->getAttribute(unicodeAttr);
00079 if (unicode.length())
00080 m_glyphMap.add(unicode, glyph->buildGlyphIdentifier());
00081 } else if (child->hasTagName(hkernTag)) {
00082 SVGHKernElement* hkern = static_cast<SVGHKernElement*>(child);
00083 SVGHorizontalKerningPair kerningPair = hkern->buildHorizontalKerningPair();
00084 m_kerningPairs.append(kerningPair);
00085 }
00086 }
00087
00088 m_isGlyphCacheValid = true;
00089 }
00090
00091
00092 static unsigned parseUnicodeRange(const UChar* characters, unsigned length, pair<unsigned, unsigned>& range)
00093 {
00094
00095 return 0;
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 }
00156
00157 static bool parseUnicodeRangeList(const UChar* characters, unsigned length, Vector<pair<unsigned, unsigned> >& ranges)
00158 {
00159 ranges.clear();
00160 if (!length)
00161 return true;
00162
00163 const UChar* remainingCharacters = characters;
00164 unsigned remainingLength = length;
00165
00166 while (1) {
00167 pair<unsigned, unsigned> range;
00168 unsigned charactersConsumed = parseUnicodeRange(remainingCharacters, remainingLength, range);
00169 if (charactersConsumed) {
00170 ranges.append(range);
00171 remainingCharacters += charactersConsumed;
00172 remainingLength -= charactersConsumed;
00173 } else {
00174 if (!remainingLength)
00175 return false;
00176 UChar character = remainingCharacters[0];
00177 if (character == ',')
00178 return false;
00179 ranges.append(make_pair(character.unicode(), character.unicode()));
00180 ++remainingCharacters;
00181 --remainingLength;
00182 }
00183 if (!remainingLength)
00184 return true;
00185 if (remainingCharacters[0] != ',')
00186 return false;
00187 ++remainingCharacters;
00188 --remainingLength;
00189 }
00190 }
00191
00192 static bool stringMatchesUnicodeRange(const String& unicodeString, const String& unicodeRangeSpec)
00193 {
00194 Vector<pair<unsigned, unsigned> > ranges;
00195 if (!parseUnicodeRangeList(unicodeRangeSpec.characters(), unicodeRangeSpec.length(), ranges))
00196 return false;
00197
00198 if (unicodeString.length() != ranges.size())
00199 return false;
00200
00201 for (size_t i = 0; i < unicodeString.length(); ++i) {
00202 UChar c = unicodeString[i];
00203 if (c < ranges[i].first || c > ranges[i].second)
00204 return false;
00205 }
00206
00207 return true;
00208 }
00209
00210 static bool matches(const String& u1, const String& g1, const String& u2, const String& g2, const SVGHorizontalKerningPair& kerningPair)
00211 {
00212 if (kerningPair.unicode1.length() && !stringMatchesUnicodeRange(u1, kerningPair.unicode1))
00213 return false;
00214 if (kerningPair.glyphName1.length() && kerningPair.glyphName1 != g1)
00215 return false;
00216
00217 if (kerningPair.unicode2.length() && !stringMatchesUnicodeRange(u2, kerningPair.unicode2))
00218 return false;
00219 if (kerningPair.glyphName2.length() && kerningPair.glyphName2 != g2)
00220 return false;
00221
00222 return true;
00223 }
00224
00225 bool SVGFontElement::getHorizontalKerningPairForStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2, SVGHorizontalKerningPair& kerningPair) const
00226 {
00227 for (size_t i = 0; i < m_kerningPairs.size(); ++i) {
00228 if (matches(u1, g1, u2, g2, m_kerningPairs[i])) {
00229 kerningPair = m_kerningPairs[i];
00230 return true;
00231 }
00232 }
00233
00234 return false;
00235 }
00236
00237 void SVGFontElement::getGlyphIdentifiersForString(const String& string, Vector<SVGGlyphIdentifier>& glyphs) const
00238 {
00239 ensureGlyphCache();
00240 m_glyphMap.get(string, glyphs);
00241 }
00242
00243 }
00244
00245 #endif // ENABLE(SVG_FONTS)