blob: 22de523270132e59220badca462168360e32c063 [file] [log] [blame]
Fabrice Di Megliod313c662011-02-24 19:56:18 -08001/*
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
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070022#include <stddef.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080023#include <utils/threads.h>
24#include <utils/String16.h>
Raph Leviend98efca2012-10-25 23:17:33 -070025#include <utils/LruCache.h>
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080026#include <utils/KeyedVector.h>
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070027#include <utils/Compare.h>
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -070028#include <utils/RefBase.h>
Fabrice Di Meglio163268b2011-09-07 18:12:11 -070029#include <utils/Singleton.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080030
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070031#include <SkPaint.h>
32#include <SkTemplates.h>
33#include <SkUtils.h>
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070034#include <SkAutoKern.h>
Billy Hewlettac1cbaf2012-07-18 09:51:45 -070035#include <SkLanguage.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080036
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070037#include <unicode/ubidi.h>
38#include <unicode/ushape.h>
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -080039#include <unicode/unistr.h>
40
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080041#include "HarfbuzzSkia.h"
42#include "harfbuzz-shaper.h"
Fabrice Di Megliod313c662011-02-24 19:56:18 -080043
44#include <android_runtime/AndroidRuntime.h>
45
46#define UNICODE_NOT_A_CHAR 0xffff
47#define UNICODE_ZWSP 0x200b
48#define UNICODE_FIRST_LOW_SURROGATE 0xdc00
49#define UNICODE_FIRST_HIGH_SURROGATE 0xd800
50#define UNICODE_FIRST_PRIVATE_USE 0xe000
51#define UNICODE_FIRST_RTL_CHAR 0x0590
52
53// Temporary buffer size
54#define CHAR_BUFFER_SIZE 80
55
56// Converts a number of mega-bytes into bytes
57#define MB(s) s * 1024 * 1024
58
59// Define the default cache size in Mb
Raph Levien161ebab2012-07-18 15:57:15 -070060#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f
Fabrice Di Megliod313c662011-02-24 19:56:18 -080061
62// Define the interval in number of cache hits between two statistics dump
63#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
64
65namespace android {
66
67/**
68 * TextLayoutCacheKey is the Cache key
69 */
70class TextLayoutCacheKey {
71public:
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070072 TextLayoutCacheKey();
Fabrice Di Megliod313c662011-02-24 19:56:18 -080073
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070074 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
75 size_t contextCount, int dirFlags);
Fabrice Di Megliod313c662011-02-24 19:56:18 -080076
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -070077 TextLayoutCacheKey(const TextLayoutCacheKey& other);
78
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070079 /**
Fabrice Di Megliod313c662011-02-24 19:56:18 -080080 * Get the size of the Cache key.
81 */
Jeff Brown06daa7b2011-11-11 15:14:56 -080082 size_t getSize() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080083
Fabrice Di Meglio717060b2011-09-27 15:53:42 -070084 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
85
Raph Levien832815c2012-10-02 10:30:41 -070086 inline const UChar* getText() const { return textCopy.string(); }
87
Raph Leviend98efca2012-10-25 23:17:33 -070088 bool operator==(const TextLayoutCacheKey& other) const {
89 return compare(*this, other) == 0;
90 }
91
92 bool operator!=(const TextLayoutCacheKey& other) const {
93 return compare(*this, other) != 0;
94 }
95
96 hash_t hash() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080097private:
Fabrice Di Megliod313c662011-02-24 19:56:18 -080098 String16 textCopy;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070099 size_t start;
Fabrice Di Meglio9c418db2011-09-18 12:54:38 -0700100 size_t count;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -0700101 size_t contextCount;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800102 int dirFlags;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800103 SkTypeface* typeface;
Fabrice Di Meglioaabe5372011-03-30 16:06:02 -0700104 SkScalar textSize;
105 SkScalar textSkewX;
106 SkScalar textScaleX;
107 uint32_t flags;
108 SkPaint::Hinting hinting;
Billy Hewlettac1cbaf2012-07-18 09:51:45 -0700109 SkPaint::FontVariant variant;
110 SkLanguage language;
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -0700111
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800112}; // TextLayoutCacheKey
113
Fabrice Di Meglio717060b2011-09-27 15:53:42 -0700114inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
115 return TextLayoutCacheKey::compare(lhs, rhs) < 0;
116}
117
118inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
119 return TextLayoutCacheKey::compare(lhs, rhs);
120}
121
Raph Leviend98efca2012-10-25 23:17:33 -0700122inline hash_t hash_type(const TextLayoutCacheKey& key) {
123 return key.hash();
124}
125
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800126/*
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800127 * TextLayoutValue is the Cache value
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800128 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800129class TextLayoutValue : public RefBase {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800130public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800131 TextLayoutValue(size_t contextCount);
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800132
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700133 void setElapsedTime(uint32_t time);
134 uint32_t getElapsedTime();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800135
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -0700136 inline const jfloat* getAdvances() const { return mAdvances.array(); }
137 inline size_t getAdvancesCount() const { return mAdvances.size(); }
138 inline jfloat getTotalAdvance() const { return mTotalAdvance; }
139 inline const jchar* getGlyphs() const { return mGlyphs.array(); }
140 inline size_t getGlyphsCount() const { return mGlyphs.size(); }
Raph Levien2301d322012-07-17 16:39:49 -0700141 inline const jfloat* getPos() const { return mPos.array(); }
142 inline size_t getPosCount() const { return mPos.size(); }
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800143
144 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700145 * Advances vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700146 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700147 Vector<jfloat> mAdvances;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800148
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700149 /**
150 * Total number of advances
151 */
152 jfloat mTotalAdvance;
153
154 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700155 * Glyphs vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700156 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700157 Vector<jchar> mGlyphs;
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700158
159 /**
Raph Levien2301d322012-07-17 16:39:49 -0700160 * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText)
161 */
162 Vector<jfloat> mPos;
163
164 /**
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800165 * Get the size of the Cache entry
166 */
167 size_t getSize() const;
168
169private:
170 /**
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700171 * Time for computing the values (in milliseconds)
172 */
173 uint32_t mElapsedTime;
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800174
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700175}; // TextLayoutCacheValue
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800176
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700177/**
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800178 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700179 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800180class TextLayoutShaper {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800181public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800182 TextLayoutShaper();
183 virtual ~TextLayoutShaper();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800184
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800185 void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800186 size_t start, size_t count, size_t contextCount, int dirFlags);
187
Fabrice Di Meglio15cc68c2012-05-15 14:47:03 -0700188 void purgeCaches();
189
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800190private:
191 /**
192 * Harfbuzz shaper item
193 */
194 HB_ShaperItem mShaperItem;
195
196 /**
197 * Harfbuzz font
198 */
199 HB_FontRec mFontRec;
200
201 /**
202 * Skia Paint used for shaping
203 */
204 SkPaint mShapingPaint;
205
206 /**
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700207 * Skia default typeface to be returned if we cannot resolve script
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800208 */
209 SkTypeface* mDefaultTypeface;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800210
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800211 /**
212 * Cache of Harfbuzz faces
213 */
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800214 KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
215
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800216 /**
217 * Cache of glyph array size
218 */
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800219 size_t mShaperItemGlyphArraySize;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800220
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800221 /**
222 * Buffer for containing the ICU normalized form of a run
223 */
224 UnicodeString mNormalizedString;
225
226 /**
227 * Buffer for normalizing a piece of a run with ICU
228 */
229 UnicodeString mBuffer;
230
Fabrice Di Meglio15cc68c2012-05-15 14:47:03 -0700231 void init();
232 void unrefTypefaces();
233
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700234 SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
235 HB_Script script);
Raph Levien1637dcd2012-05-02 10:41:14 -0700236
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800237 size_t shapeFontRun(const SkPaint* paint, bool isRTL);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800238
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800239 void computeValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800240 size_t start, size_t count, size_t contextCount, int dirFlags,
241 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700242 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800243
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800244 void computeRunValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800245 size_t count, bool isRTL,
246 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700247 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800248
Billy Hewlett96051182012-06-21 09:58:42 -0700249 SkTypeface* getCachedTypeface(SkTypeface** typeface, HB_Script script, SkTypeface::Style style);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800250 HB_Face getCachedHBFace(SkTypeface* typeface);
251
Raph Levienf62034d2012-06-25 16:05:57 -0700252 bool doShaping(size_t size);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800253 void createShaperItemGlyphArrays(size_t size);
254 void deleteShaperItemGlyphArrays();
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700255 bool isComplexScript(HB_Script script);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800256
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800257}; // TextLayoutShaper
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800258
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800259/**
260 * Cache of text layout information.
261 */
262class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
263{
264public:
265 TextLayoutCache(TextLayoutShaper* shaper);
266
267 ~TextLayoutCache();
268
269 bool isInitialized() {
270 return mInitialized;
271 }
272
273 /**
274 * Used as a callback when an entry is removed from the cache
275 * Do not invoke directly
276 */
277 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
278
279 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
280 jint count, jint contextCount, jint dirFlags);
281
282 /**
283 * Clear the cache
284 */
Raph Levien13ba4e42012-09-12 15:15:51 -0700285 void purgeCaches();
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800286
287private:
288 TextLayoutShaper* mShaper;
289 Mutex mLock;
290 bool mInitialized;
291
Raph Leviend98efca2012-10-25 23:17:33 -0700292 LruCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800293
294 uint32_t mSize;
295 uint32_t mMaxSize;
296
297 uint32_t mCacheHitCount;
298 uint64_t mNanosecondsSaved;
299
300 uint64_t mCacheStartTime;
301
302 RtlDebugLevel mDebugLevel;
303 bool mDebugEnabled;
304
305 /*
306 * Class initialization
307 */
308 void init();
309
310 /**
311 * Dump Cache statistics
312 */
313 void dumpCacheStats();
314
315}; // TextLayoutCache
316
317/**
318 * The TextLayoutEngine is reponsible for computing TextLayoutValues
319 */
320class TextLayoutEngine : public Singleton<TextLayoutEngine> {
321public:
322 TextLayoutEngine();
323 virtual ~TextLayoutEngine();
324
Raph Levien832815c2012-10-02 10:30:41 -0700325 /**
326 * Note: this method currently does a defensive copy of the text argument, in case
327 * there is concurrent mutation of it. The contract may change, and may in the
328 * future require the caller to guarantee that the contents will not change during
329 * the call. Be careful of this when doing optimization.
330 **/
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800331 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
332 jint count, jint contextCount, jint dirFlags);
Fabrice Di Meglio30ca5cd2012-05-07 17:45:44 -0700333
334 void purgeCaches();
335
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800336private:
337 TextLayoutCache* mTextLayoutCache;
338 TextLayoutShaper* mShaper;
339}; // TextLayoutEngine
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800340
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800341} // namespace android
342#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
343