blob: 29805ee708f9e8a019751950281b9b10fe20b101 [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 <SkAutoKern.h>
Billy Hewlettac1cbaf2012-07-18 09:51:45 -070032#include <SkLanguage.h>
Kristian Monsen2d76d4f2013-01-15 19:23:21 -080033#include <SkPaint.h>
34#include <SkTemplates.h>
35#include <SkTypeface.h>
36#include <SkUtils.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080037
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070038#include <unicode/ubidi.h>
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -080039#include <unicode/unistr.h>
40
Raph Levienaaedde52012-10-30 15:55:33 -070041#include <hb.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080042
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
Raph Levien161ebab2012-07-18 15:57:15 -070059#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f
Fabrice Di Megliod313c662011-02-24 19:56:18 -080060
61// Define the interval in number of cache hits between two statistics dump
62#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
63
64namespace android {
65
66/**
67 * TextLayoutCacheKey is the Cache key
68 */
69class TextLayoutCacheKey {
70public:
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070071 TextLayoutCacheKey();
Fabrice Di Megliod313c662011-02-24 19:56:18 -080072
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070073 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
Fabrice Di Meglio6d9fe5b2013-02-11 18:27:34 -080074 size_t contextCount);
Fabrice Di Megliod313c662011-02-24 19:56:18 -080075
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -070076 TextLayoutCacheKey(const TextLayoutCacheKey& other);
77
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070078 /**
Fabrice Di Megliod313c662011-02-24 19:56:18 -080079 * Get the size of the Cache key.
80 */
Jeff Brown06daa7b2011-11-11 15:14:56 -080081 size_t getSize() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080082
Fabrice Di Meglio717060b2011-09-27 15:53:42 -070083 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
84
Raph Levien832815c2012-10-02 10:30:41 -070085 inline const UChar* getText() const { return textCopy.string(); }
86
Raph Leviend98efca2012-10-25 23:17:33 -070087 bool operator==(const TextLayoutCacheKey& other) const {
88 return compare(*this, other) == 0;
89 }
90
91 bool operator!=(const TextLayoutCacheKey& other) const {
92 return compare(*this, other) != 0;
93 }
94
95 hash_t hash() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080096private:
Fabrice Di Megliod313c662011-02-24 19:56:18 -080097 String16 textCopy;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070098 size_t start;
Fabrice Di Meglio9c418db2011-09-18 12:54:38 -070099 size_t count;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -0700100 size_t contextCount;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800101 SkTypeface* typeface;
Fabrice Di Meglioaabe5372011-03-30 16:06:02 -0700102 SkScalar textSize;
103 SkScalar textSkewX;
104 SkScalar textScaleX;
105 uint32_t flags;
106 SkPaint::Hinting hinting;
Billy Hewlettac1cbaf2012-07-18 09:51:45 -0700107 SkPaint::FontVariant variant;
108 SkLanguage language;
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -0700109
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800110}; // TextLayoutCacheKey
111
Fabrice Di Meglio717060b2011-09-27 15:53:42 -0700112inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
113 return TextLayoutCacheKey::compare(lhs, rhs) < 0;
114}
115
116inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
117 return TextLayoutCacheKey::compare(lhs, rhs);
118}
119
Raph Leviend98efca2012-10-25 23:17:33 -0700120inline hash_t hash_type(const TextLayoutCacheKey& key) {
121 return key.hash();
122}
123
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800124/*
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800125 * TextLayoutValue is the Cache value
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800126 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800127class TextLayoutValue : public RefBase {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800128public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800129 TextLayoutValue(size_t contextCount);
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800130
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700131 void setElapsedTime(uint32_t time);
132 uint32_t getElapsedTime();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800133
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -0700134 inline const jfloat* getAdvances() const { return mAdvances.array(); }
135 inline size_t getAdvancesCount() const { return mAdvances.size(); }
136 inline jfloat getTotalAdvance() const { return mTotalAdvance; }
137 inline const jchar* getGlyphs() const { return mGlyphs.array(); }
138 inline size_t getGlyphsCount() const { return mGlyphs.size(); }
Raph Levien2301d322012-07-17 16:39:49 -0700139 inline const jfloat* getPos() const { return mPos.array(); }
140 inline size_t getPosCount() const { return mPos.size(); }
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800141
142 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700143 * Advances vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700144 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700145 Vector<jfloat> mAdvances;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800146
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700147 /**
148 * Total number of advances
149 */
150 jfloat mTotalAdvance;
151
152 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700153 * Glyphs vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700154 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700155 Vector<jchar> mGlyphs;
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700156
157 /**
Raph Levien2301d322012-07-17 16:39:49 -0700158 * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText)
159 */
160 Vector<jfloat> mPos;
161
162 /**
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800163 * Get the size of the Cache entry
164 */
165 size_t getSize() const;
166
167private:
168 /**
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700169 * Time for computing the values (in milliseconds)
170 */
171 uint32_t mElapsedTime;
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800172
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700173}; // TextLayoutCacheValue
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800174
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700175/**
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800176 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700177 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800178class TextLayoutShaper {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800179public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800180 TextLayoutShaper();
181 virtual ~TextLayoutShaper();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800182
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800183 void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio6d9fe5b2013-02-11 18:27:34 -0800184 size_t start, size_t count, size_t contextCount);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800185
Fabrice Di Meglio15cc68c2012-05-15 14:47:03 -0700186 void purgeCaches();
187
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800188private:
189 /**
Raph Levienaaedde52012-10-30 15:55:33 -0700190 * Harfbuzz buffer for shaping
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800191 */
Raph Levienaaedde52012-10-30 15:55:33 -0700192 hb_buffer_t* mBuffer;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800193
194 /**
195 * Skia Paint used for shaping
196 */
197 SkPaint mShapingPaint;
198
199 /**
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700200 * Skia default typeface to be returned if we cannot resolve script
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800201 */
202 SkTypeface* mDefaultTypeface;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800203
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800204 /**
205 * Cache of Harfbuzz faces
206 */
Raph Levienaaedde52012-10-30 15:55:33 -0700207 KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800208
Fabrice Di Meglio15cc68c2012-05-15 14:47:03 -0700209 void init();
210 void unrefTypefaces();
211
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700212 SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
Raph Levienaaedde52012-10-30 15:55:33 -0700213 hb_script_t script);
Raph Levien1637dcd2012-05-02 10:41:14 -0700214
Raph Levienaaedde52012-10-30 15:55:33 -0700215 size_t shapeFontRun(const SkPaint* paint);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800216
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800217 void computeValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio6d9fe5b2013-02-11 18:27:34 -0800218 size_t start, size_t count, size_t contextCount,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800219 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700220 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800221
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800222 void computeRunValues(const SkPaint* paint, const UChar* chars,
Raph Levienaaedde52012-10-30 15:55:33 -0700223 size_t start, size_t count, size_t contextCount, bool isRTL,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800224 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700225 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800226
Raph Levienaaedde52012-10-30 15:55:33 -0700227 SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
228 hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800229
Raph Levienaaedde52012-10-30 15:55:33 -0700230 bool isComplexScript(hb_script_t script);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800231
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800232}; // TextLayoutShaper
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800233
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800234/**
235 * Cache of text layout information.
236 */
237class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
238{
239public:
240 TextLayoutCache(TextLayoutShaper* shaper);
241
242 ~TextLayoutCache();
243
244 bool isInitialized() {
245 return mInitialized;
246 }
247
248 /**
249 * Used as a callback when an entry is removed from the cache
250 * Do not invoke directly
251 */
252 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
253
254 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
Fabrice Di Meglio6d9fe5b2013-02-11 18:27:34 -0800255 jint count, jint contextCount);
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800256
257 /**
258 * Clear the cache
259 */
Raph Levien13ba4e42012-09-12 15:15:51 -0700260 void purgeCaches();
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800261
262private:
263 TextLayoutShaper* mShaper;
264 Mutex mLock;
265 bool mInitialized;
266
Raph Leviend98efca2012-10-25 23:17:33 -0700267 LruCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800268
269 uint32_t mSize;
270 uint32_t mMaxSize;
271
272 uint32_t mCacheHitCount;
273 uint64_t mNanosecondsSaved;
274
275 uint64_t mCacheStartTime;
276
277 RtlDebugLevel mDebugLevel;
278 bool mDebugEnabled;
279
280 /*
281 * Class initialization
282 */
283 void init();
284
285 /**
286 * Dump Cache statistics
287 */
288 void dumpCacheStats();
289
290}; // TextLayoutCache
291
292/**
293 * The TextLayoutEngine is reponsible for computing TextLayoutValues
294 */
295class TextLayoutEngine : public Singleton<TextLayoutEngine> {
296public:
297 TextLayoutEngine();
298 virtual ~TextLayoutEngine();
299
Raph Levien832815c2012-10-02 10:30:41 -0700300 /**
301 * Note: this method currently does a defensive copy of the text argument, in case
302 * there is concurrent mutation of it. The contract may change, and may in the
303 * future require the caller to guarantee that the contents will not change during
304 * the call. Be careful of this when doing optimization.
305 **/
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800306 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
Fabrice Di Meglio6d9fe5b2013-02-11 18:27:34 -0800307 jint count, jint contextCount);
Fabrice Di Meglio30ca5cd2012-05-07 17:45:44 -0700308
309 void purgeCaches();
310
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800311private:
312 TextLayoutCache* mTextLayoutCache;
313 TextLayoutShaper* mShaper;
314}; // TextLayoutEngine
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800315
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800316} // namespace android
317#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
318