Node::document() should return a reference.
[WebKit-https.git] / Source / WebCore / svg / SVGGlyphMap.h
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifndef SVGGlyphMap_h
21 #define SVGGlyphMap_h
22
23 #if ENABLE(SVG_FONTS)
24 #include "SurrogatePairAwareTextIterator.h"
25 #include "SVGGlyph.h"
26
27 #include <wtf/HashMap.h>
28 #include <wtf/Vector.h>
29
30 namespace WebCore {
31
32 struct GlyphMapNode;
33 class SVGFontData;
34
35 typedef HashMap<UChar32, RefPtr<GlyphMapNode> > GlyphMapLayer;
36
37 struct GlyphMapNode : public RefCounted<GlyphMapNode> {
38 private:
39     GlyphMapNode() { }
40 public:
41     static PassRefPtr<GlyphMapNode> create() { return adoptRef(new GlyphMapNode); }
42
43     Vector<SVGGlyph> glyphs;
44
45     GlyphMapLayer children;
46 };
47
48 class SVGGlyphMap {
49 public:
50     SVGGlyphMap() : m_currentPriority(0) { }
51
52     void addGlyph(const String& glyphName, const String& unicodeString, SVGGlyph glyph)
53     {
54         ASSERT(!glyphName.isEmpty() || !unicodeString.isEmpty());
55
56         bool hasGlyphName = !glyphName.isEmpty();
57         if (unicodeString.isEmpty()) {
58             // Register named glyph in the named glyph map and in the glyph table.
59             ASSERT(hasGlyphName);
60             appendToGlyphTable(glyph);
61             m_namedGlyphs.add(glyphName, glyph.tableEntry);
62             return;
63         }
64     
65         GlyphMapLayer* currentLayer = &m_rootLayer;
66         RefPtr<GlyphMapNode> node;
67         size_t length = unicodeString.length();
68
69         UChar32 character = 0;
70         unsigned clusterLength = 0;
71         SurrogatePairAwareTextIterator textIterator(unicodeString.characters(), 0, length, length);
72         while (textIterator.consume(character, clusterLength)) {
73             node = currentLayer->get(character);
74             if (!node) {
75                 node = GlyphMapNode::create();
76                 currentLayer->set(character, node);
77             }
78             currentLayer = &node->children;
79             textIterator.advance(clusterLength);
80         }
81
82         if (!node)
83             return;
84
85         // Register glyph associated with an unicode string into the glyph map.
86         node->glyphs.append(glyph);
87         SVGGlyph& lastGlyph = node->glyphs.last();
88         lastGlyph.priority = m_currentPriority++;
89         lastGlyph.unicodeStringLength = length;
90     
91         // If the glyph is named, also add it to the named glyph name, and to the glyph table in both cases.
92         appendToGlyphTable(lastGlyph);
93         if (hasGlyphName)  
94             m_namedGlyphs.add(glyphName, lastGlyph.tableEntry);
95     }
96
97     void appendToGlyphTable(SVGGlyph& glyph)
98     {
99         size_t tableEntry = m_glyphTable.size();
100         ASSERT(tableEntry < std::numeric_limits<unsigned short>::max());
101
102         // The first table entry starts with 1. 0 denotes an unknown glyph.
103         glyph.tableEntry = tableEntry + 1;
104         m_glyphTable.append(glyph);
105     }
106
107     static inline bool compareGlyphPriority(const SVGGlyph& first, const SVGGlyph& second)
108     {
109         return first.priority < second.priority;
110     }
111
112     void collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs)
113     {
114         GlyphMapLayer* currentLayer = &m_rootLayer;
115
116         const UChar* characters = string.characters();
117         size_t length = string.length();
118
119         UChar32 character = 0;
120         unsigned clusterLength = 0;
121         SurrogatePairAwareTextIterator textIterator(characters, 0, length, length);
122         while (textIterator.consume(character, clusterLength)) {
123             RefPtr<GlyphMapNode> node = currentLayer->get(character);
124             if (!node)
125                 break;
126             glyphs.appendVector(node->glyphs);
127             currentLayer = &node->children;
128             textIterator.advance(clusterLength);
129         }
130
131         std::sort(glyphs.begin(), glyphs.end(), compareGlyphPriority);
132     }
133     
134     void clear() 
135     { 
136         m_rootLayer.clear();
137         m_glyphTable.clear();
138         m_currentPriority = 0;
139     }
140
141     const SVGGlyph& svgGlyphForGlyph(Glyph glyph) const
142     {
143         if (!glyph || glyph > m_glyphTable.size()) {
144             DEFINE_STATIC_LOCAL(SVGGlyph, defaultGlyph, ());
145             return defaultGlyph;
146         }
147         return m_glyphTable[glyph - 1];
148     }
149
150     const SVGGlyph& glyphIdentifierForGlyphName(const String& glyphName) const
151     {
152         return svgGlyphForGlyph(m_namedGlyphs.get(glyphName));
153     }
154
155 private:
156     GlyphMapLayer m_rootLayer;
157     Vector<SVGGlyph, 256> m_glyphTable;
158     HashMap<String, Glyph> m_namedGlyphs;
159     int m_currentPriority;
160 };
161
162 }
163
164 #endif // ENABLE(SVG_FONTS)
165 #endif // SVGGlyphMap_h