Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: Source/platform/fonts/WidthCache.h

Issue 1192223002: Optimize Complex Text Shaping and Caching (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Addressing review comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef WidthCache_h
27 #define WidthCache_h
28
29 #include "platform/geometry/FloatRectOutsets.h"
30 #include "platform/text/TextRun.h"
31 #include "wtf/Forward.h"
32 #include "wtf/HashFunctions.h"
33 #include "wtf/HashSet.h"
34 #include "wtf/HashTableDeletedValueType.h"
35 #include "wtf/StringHasher.h"
36
37 namespace blink {
38
39 struct WidthCacheEntry {
40 WidthCacheEntry()
41 {
42 width = std::numeric_limits<float>::quiet_NaN();
43 }
44 bool isValid() const { return !std::isnan(width); }
45 float width;
46 FloatRect glyphBounds;
47 };
48
49 class WidthCache {
50 private:
51 // Used to optimize small strings as hash table keys. Avoids malloc'ing an o ut-of-line StringImpl.
52 class SmallStringKey {
53 public:
54 static unsigned capacity() { return s_capacity; }
55
56 SmallStringKey()
57 : m_length(s_emptyValueLength)
58 {
59 }
60
61 SmallStringKey(WTF::HashTableDeletedValueType)
62 : m_length(s_deletedValueLength)
63 {
64 }
65
66 template<typename CharacterType> SmallStringKey(CharacterType* character s, unsigned short length)
67 : m_length(length)
68 {
69 ASSERT(length <= s_capacity);
70
71 StringHasher hasher;
72
73 bool remainder = length & 1;
74 length >>= 1;
75
76 unsigned i = 0;
77 while (length--) {
78 m_characters[i] = characters[i];
79 m_characters[i + 1] = characters[i + 1];
80 hasher.addCharactersAssumingAligned(characters[i], characters[i + 1]);
81 i += 2;
82 }
83
84 if (remainder) {
85 m_characters[i] = characters[i];
86 hasher.addCharacter(characters[i]);
87 }
88
89 m_hash = hasher.hash();
90 }
91
92 const UChar* characters() const { return m_characters; }
93 unsigned short length() const { return m_length; }
94 unsigned hash() const { return m_hash; }
95
96 bool isHashTableDeletedValue() const { return m_length == s_deletedValue Length; }
97 bool isHashTableEmptyValue() const { return m_length == s_emptyValueLeng th; }
98
99 private:
100 static const unsigned s_capacity = 15;
101 static const unsigned s_emptyValueLength = s_capacity + 1;
102 static const unsigned s_deletedValueLength = s_capacity + 2;
103
104 unsigned m_hash;
105 unsigned short m_length;
106 UChar m_characters[s_capacity];
107 };
108
109 struct SmallStringKeyHash {
110 static unsigned hash(const SmallStringKey& key) { return key.hash(); }
111 static bool equal(const SmallStringKey& a, const SmallStringKey& b) { re turn a == b; }
112 static const bool safeToCompareToEmptyOrDeleted = true; // Empty and del eted values have lengths that are not equal to any valid length.
113 };
114
115 struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> {
116 static const bool hasIsEmptyValueFunction = true;
117 static bool isEmptyValue(const SmallStringKey& key) { return key.isHashT ableEmptyValue(); }
118 static const unsigned minimumTableSize = 16;
119 };
120
121 friend bool operator==(const SmallStringKey&, const SmallStringKey&);
122
123 public:
124 WidthCache()
125 : m_interval(s_maxInterval)
126 , m_countdown(m_interval)
127 {
128 }
129
130 WidthCacheEntry* add(const TextRun& run, WidthCacheEntry entry)
131 {
132 if (static_cast<unsigned>(run.length()) > SmallStringKey::capacity())
133 return 0;
134
135 if (m_countdown > 0) {
136 --m_countdown;
137 return 0;
138 }
139
140 return addSlowCase(run, entry);
141 }
142
143 void clear()
144 {
145 m_singleCharMap.clear();
146 m_map.clear();
147 }
148
149 private:
150 WidthCacheEntry* addSlowCase(const TextRun& run, WidthCacheEntry entry)
151 {
152 int length = run.length();
153 bool isNewEntry;
154 WidthCacheEntry *value;
155 if (length == 1) {
156 SingleCharMap::AddResult addResult = m_singleCharMap.add(run[0], ent ry);
157 isNewEntry = addResult.isNewEntry;
158 value = &addResult.storedValue->value;
159 } else {
160 SmallStringKey smallStringKey;
161 if (run.is8Bit())
162 smallStringKey = SmallStringKey(run.characters8(), length);
163 else
164 smallStringKey = SmallStringKey(run.characters16(), length);
165
166 Map::AddResult addResult = m_map.add(smallStringKey, entry);
167 isNewEntry = addResult.isNewEntry;
168 value = &addResult.storedValue->value;
169 }
170
171 // Cache hit: ramp up by sampling the next few words.
172 if (!isNewEntry) {
173 m_interval = s_minInterval;
174 return value;
175 }
176
177 // Cache miss: ramp down by increasing our sampling interval.
178 if (m_interval < s_maxInterval)
179 ++m_interval;
180 m_countdown = m_interval;
181
182 if ((m_singleCharMap.size() + m_map.size()) < s_maxSize)
183 return value;
184
185 // No need to be fancy: we're just trying to avoid pathological growth.
186 m_singleCharMap.clear();
187 m_map.clear();
188 return 0;
189 }
190
191 typedef HashMap<SmallStringKey, WidthCacheEntry, SmallStringKeyHash, SmallSt ringKeyHashTraits> Map;
192 typedef HashMap<uint32_t, WidthCacheEntry, DefaultHash<uint32_t>::Hash, WTF: :UnsignedWithZeroKeyHashTraits<uint32_t>> SingleCharMap;
193 static const int s_minInterval = -3; // A cache hit pays for about 3 cache m isses.
194 static const int s_maxInterval = 20; // Sampling at this interval has almost no overhead.
195 static const unsigned s_maxSize = 500000; // Just enough to guard against pa thological growth.
196
197 int m_interval;
198 int m_countdown;
199 SingleCharMap m_singleCharMap;
200 Map m_map;
201 };
202
203 inline bool operator==(const WidthCache::SmallStringKey& a, const WidthCache::Sm allStringKey& b)
204 {
205 if (a.length() != b.length())
206 return false;
207 return WTF::equal(a.characters(), b.characters(), a.length());
208 }
209
210 } // namespace blink
211
212 #endif // WidthCache_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698