1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ANDROID_TEXT_LAYOUT_CACHE_H
18 #define ANDROID_TEXT_LAYOUT_CACHE_H
19
20 #include "RtlProperties.h"
21
22 #include <stddef.h>
23 #include <utils/threads.h>
24 #include <utils/String16.h>
25 #include <utils/GenerationCache.h>
26 #include <utils/KeyedVector.h>
27 #include <utils/Compare.h>
28 #include <utils/RefBase.h>
29 #include <utils/Singleton.h>
30
31 #include <SkPaint.h>
32 #include <SkTemplates.h>
33 #include <SkUtils.h>
34 #include <SkAutoKern.h>
35
36 #include <unicode/ubidi.h>
37 #include <unicode/ushape.h>
38 #include <unicode/unistr.h>
39
40 #include "HarfbuzzSkia.h"
41 #include "harfbuzz-shaper.h"
42
43 #include <android_runtime/AndroidRuntime.h>
44
45 #define UNICODE_NOT_A_CHAR 0xffff
46 #define UNICODE_ZWSP 0x200b
47 #define UNICODE_FIRST_LOW_SURROGATE 0xdc00
48 #define UNICODE_FIRST_HIGH_SURROGATE 0xd800
49 #define UNICODE_FIRST_PRIVATE_USE 0xe000
50 #define UNICODE_FIRST_RTL_CHAR 0x0590
51
52 // Temporary buffer size
53 #define CHAR_BUFFER_SIZE 80
54
55 // Converts a number of mega-bytes into bytes
56 #define MB(s) s * 1024 * 1024
57
58 // Define the default cache size in Mb
59 #define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.250f
60
61 // Define the interval in number of cache hits between two statistics dump
62 #define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
63
64 namespace android {
65
66 /**
67 * TextLayoutCacheKey is the Cache key
68 */
69 class TextLayoutCacheKey {
70 public:
71 TextLayoutCacheKey();
72
73 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
74 size_t contextCount, int dirFlags);
75
76 TextLayoutCacheKey(const TextLayoutCacheKey& other);
77
78 /**
79 * We need to copy the text when we insert the key into the cache itself.
80 * We don't need to copy the text when we are only comparing keys.
81 */
82 void internalTextCopy();
83
84 /**
85 * Get the size of the Cache key.
86 */
87 size_t getSize() const;
88
89 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
90
91 private:
92 const UChar* text; // if text is NULL, use textCopy
93 String16 textCopy;
94 size_t start;
95 size_t count;
96 size_t contextCount;
97 int dirFlags;
98 SkTypeface* typeface;
99 SkScalar textSize;
100 SkScalar textSkewX;
101 SkScalar textScaleX;
102 uint32_t flags;
103 SkPaint::Hinting hinting;
104
getText()105 inline const UChar* getText() const { return text ? text : textCopy.string(); }
106
107 }; // TextLayoutCacheKey
108
strictly_order_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)109 inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
110 return TextLayoutCacheKey::compare(lhs, rhs) < 0;
111 }
112
compare_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)113 inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
114 return TextLayoutCacheKey::compare(lhs, rhs);
115 }
116
117 /*
118 * TextLayoutValue is the Cache value
119 */
120 class TextLayoutValue : public RefBase {
121 public:
122 TextLayoutValue(size_t contextCount);
123
124 void setElapsedTime(uint32_t time);
125 uint32_t getElapsedTime();
126
getAdvances()127 inline const jfloat* getAdvances() const { return mAdvances.array(); }
getAdvancesCount()128 inline size_t getAdvancesCount() const { return mAdvances.size(); }
getTotalAdvance()129 inline jfloat getTotalAdvance() const { return mTotalAdvance; }
getGlyphs()130 inline const jchar* getGlyphs() const { return mGlyphs.array(); }
getGlyphsCount()131 inline size_t getGlyphsCount() const { return mGlyphs.size(); }
132
133 /**
134 * Advances vector
135 */
136 Vector<jfloat> mAdvances;
137
138 /**
139 * Total number of advances
140 */
141 jfloat mTotalAdvance;
142
143 /**
144 * Glyphs vector
145 */
146 Vector<jchar> mGlyphs;
147
148 /**
149 * Get the size of the Cache entry
150 */
151 size_t getSize() const;
152
153 private:
154 /**
155 * Time for computing the values (in milliseconds)
156 */
157 uint32_t mElapsedTime;
158
159 }; // TextLayoutCacheValue
160
161 /**
162 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
163 */
164 class TextLayoutShaper {
165 public:
166 TextLayoutShaper();
167 virtual ~TextLayoutShaper();
168
169 void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
170 size_t start, size_t count, size_t contextCount, int dirFlags);
171
172 void purgeCaches();
173
174 private:
175 /**
176 * Harfbuzz shaper item
177 */
178 HB_ShaperItem mShaperItem;
179
180 /**
181 * Harfbuzz font
182 */
183 HB_FontRec mFontRec;
184
185 /**
186 * Skia Paint used for shaping
187 */
188 SkPaint mShapingPaint;
189
190 /**
191 * Skia typefaces cached for shaping
192 */
193 SkTypeface* mDefaultTypeface;
194 SkTypeface* mArabicTypeface;
195 SkTypeface* mHebrewRegularTypeface;
196 SkTypeface* mHebrewBoldTypeface;
197 SkTypeface* mBengaliTypeface;
198 SkTypeface* mThaiTypeface;
199 SkTypeface* mDevanagariRegularTypeface;
200 SkTypeface* mTamilRegularTypeface;
201 SkTypeface* mTamilBoldTypeface;
202
203 /**
204 * Cache of Harfbuzz faces
205 */
206 KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
207
208 /**
209 * Cache of glyph array size
210 */
211 size_t mShaperItemGlyphArraySize;
212
213 /**
214 * Buffer for containing the ICU normalized form of a run
215 */
216 UnicodeString mNormalizedString;
217
218 /**
219 * Buffer for normalizing a piece of a run with ICU
220 */
221 UnicodeString mBuffer;
222
223 void init();
224 void unrefTypefaces();
225
226 SkTypeface* typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface,
227 SkUnichar unichar, HB_Script script);
228
229 size_t shapeFontRun(const SkPaint* paint, bool isRTL);
230
231 void computeValues(const SkPaint* paint, const UChar* chars,
232 size_t start, size_t count, size_t contextCount, int dirFlags,
233 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
234 Vector<jchar>* const outGlyphs);
235
236 void computeRunValues(const SkPaint* paint, const UChar* chars,
237 size_t count, bool isRTL,
238 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
239 Vector<jchar>* const outGlyphs);
240
241 SkTypeface* getCachedTypeface(SkTypeface** typeface, const char path[]);
242 HB_Face getCachedHBFace(SkTypeface* typeface);
243
244 void ensureShaperItemGlyphArrays(size_t size);
245 void createShaperItemGlyphArrays(size_t size);
246 void deleteShaperItemGlyphArrays();
247
248 }; // TextLayoutShaper
249
250 /**
251 * Cache of text layout information.
252 */
253 class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
254 {
255 public:
256 TextLayoutCache(TextLayoutShaper* shaper);
257
258 ~TextLayoutCache();
259
isInitialized()260 bool isInitialized() {
261 return mInitialized;
262 }
263
264 /**
265 * Used as a callback when an entry is removed from the cache
266 * Do not invoke directly
267 */
268 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
269
270 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
271 jint count, jint contextCount, jint dirFlags);
272
273 /**
274 * Clear the cache
275 */
276 void clear();
277
278 private:
279 TextLayoutShaper* mShaper;
280 Mutex mLock;
281 bool mInitialized;
282
283 GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
284
285 uint32_t mSize;
286 uint32_t mMaxSize;
287
288 uint32_t mCacheHitCount;
289 uint64_t mNanosecondsSaved;
290
291 uint64_t mCacheStartTime;
292
293 RtlDebugLevel mDebugLevel;
294 bool mDebugEnabled;
295
296 /*
297 * Class initialization
298 */
299 void init();
300
301 /**
302 * Dump Cache statistics
303 */
304 void dumpCacheStats();
305
306 }; // TextLayoutCache
307
308 /**
309 * The TextLayoutEngine is reponsible for computing TextLayoutValues
310 */
311 class TextLayoutEngine : public Singleton<TextLayoutEngine> {
312 public:
313 TextLayoutEngine();
314 virtual ~TextLayoutEngine();
315
316 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
317 jint count, jint contextCount, jint dirFlags);
318
319 void purgeCaches();
320
321 private:
322 TextLayoutCache* mTextLayoutCache;
323 TextLayoutShaper* mShaper;
324 }; // TextLayoutEngine
325
326 } // namespace android
327 #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
328
329