blob: 5414a11623e8ed177e294b5089566d3b324afb7d [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 Megliofcf2be12011-04-05 17:02:36 -070027#include <utils/RefBase.h>
Fabrice Di Meglio163268b2011-09-07 18:12:11 -070028#include <utils/Singleton.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080029
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070030#include <SkAutoKern.h>
Billy Hewlettac1cbaf2012-07-18 09:51:45 -070031#include <SkLanguage.h>
Kristian Monsen2d76d4f2013-01-15 19:23:21 -080032#include <SkPaint.h>
33#include <SkTemplates.h>
34#include <SkTypeface.h>
35#include <SkUtils.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080036
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070037#include <unicode/ubidi.h>
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -080038#include <unicode/unistr.h>
39
Raph Levienaaedde52012-10-30 15:55:33 -070040#include <hb.h>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080041
42#include <android_runtime/AndroidRuntime.h>
43
44#define UNICODE_NOT_A_CHAR 0xffff
45#define UNICODE_ZWSP 0x200b
46#define UNICODE_FIRST_LOW_SURROGATE 0xdc00
47#define UNICODE_FIRST_HIGH_SURROGATE 0xd800
48#define UNICODE_FIRST_PRIVATE_USE 0xe000
49#define UNICODE_FIRST_RTL_CHAR 0x0590
50
51// Temporary buffer size
52#define CHAR_BUFFER_SIZE 80
53
54// Converts a number of mega-bytes into bytes
55#define MB(s) s * 1024 * 1024
56
57// Define the default cache size in Mb
Raph Levien161ebab2012-07-18 15:57:15 -070058#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f
Fabrice Di Megliod313c662011-02-24 19:56:18 -080059
60// Define the interval in number of cache hits between two statistics dump
61#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
62
63namespace android {
64
65/**
66 * TextLayoutCacheKey is the Cache key
67 */
68class TextLayoutCacheKey {
69public:
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070070 TextLayoutCacheKey();
Fabrice Di Megliod313c662011-02-24 19:56:18 -080071
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070072 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
Fabrice Di Meglioda12f382013-03-15 11:26:56 -070073 size_t contextCount, int dirFlags);
Fabrice Di Megliod313c662011-02-24 19:56:18 -080074
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -070075 TextLayoutCacheKey(const TextLayoutCacheKey& other);
76
Fabrice Di Meglio48796a82011-04-05 15:22:41 -070077 /**
Fabrice Di Megliod313c662011-02-24 19:56:18 -080078 * Get the size of the Cache key.
79 */
Jeff Brown06daa7b2011-11-11 15:14:56 -080080 size_t getSize() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080081
Fabrice Di Meglio717060b2011-09-27 15:53:42 -070082 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
83
Raph Levien832815c2012-10-02 10:30:41 -070084 inline const UChar* getText() const { return textCopy.string(); }
85
Raph Leviend98efca2012-10-25 23:17:33 -070086 bool operator==(const TextLayoutCacheKey& other) const {
87 return compare(*this, other) == 0;
88 }
89
90 bool operator!=(const TextLayoutCacheKey& other) const {
91 return compare(*this, other) != 0;
92 }
93
94 hash_t hash() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080095private:
Fabrice Di Megliod313c662011-02-24 19:56:18 -080096 String16 textCopy;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070097 size_t start;
Fabrice Di Meglio9c418db2011-09-18 12:54:38 -070098 size_t count;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070099 size_t contextCount;
Fabrice Di Meglioda12f382013-03-15 11:26:56 -0700100 int dirFlags;
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 Meglioda12f382013-03-15 11:26:56 -0700184 size_t start, size_t count, size_t contextCount, int dirFlags);
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 /**
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800200 * Cache of Harfbuzz faces
201 */
Raph Levienaaedde52012-10-30 15:55:33 -0700202 KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800203
Billy Hewlettd6deccb2012-06-22 10:30:55 -0700204 SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
Raph Levienaaedde52012-10-30 15:55:33 -0700205 hb_script_t script);
Raph Levien1637dcd2012-05-02 10:41:14 -0700206
Raph Levienaaedde52012-10-30 15:55:33 -0700207 size_t shapeFontRun(const SkPaint* paint);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800208
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800209 void computeValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglioda12f382013-03-15 11:26:56 -0700210 size_t start, size_t count, size_t contextCount, int dirFlags,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800211 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700212 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800213
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800214 void computeRunValues(const SkPaint* paint, const UChar* chars,
Raph Levienaaedde52012-10-30 15:55:33 -0700215 size_t start, size_t count, size_t contextCount, bool isRTL,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800216 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Raph Levien2301d322012-07-17 16:39:49 -0700217 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800218
Raph Levienaaedde52012-10-30 15:55:33 -0700219 SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
220 hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800221
Raph Levienaaedde52012-10-30 15:55:33 -0700222 bool isComplexScript(hb_script_t script);
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800223}; // TextLayoutShaper
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800224
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800225/**
226 * Cache of text layout information.
227 */
228class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
229{
230public:
231 TextLayoutCache(TextLayoutShaper* shaper);
232
233 ~TextLayoutCache();
234
235 bool isInitialized() {
236 return mInitialized;
237 }
238
239 /**
240 * Used as a callback when an entry is removed from the cache
241 * Do not invoke directly
242 */
243 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
244
245 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
Fabrice Di Meglioda12f382013-03-15 11:26:56 -0700246 jint count, jint contextCount, jint dirFlags);
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800247
248 /**
249 * Clear the cache
250 */
Raph Levien13ba4e42012-09-12 15:15:51 -0700251 void purgeCaches();
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800252
253private:
254 TextLayoutShaper* mShaper;
255 Mutex mLock;
256 bool mInitialized;
257
Raph Leviend98efca2012-10-25 23:17:33 -0700258 LruCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800259
260 uint32_t mSize;
261 uint32_t mMaxSize;
262
263 uint32_t mCacheHitCount;
264 uint64_t mNanosecondsSaved;
265
266 uint64_t mCacheStartTime;
267
268 RtlDebugLevel mDebugLevel;
269 bool mDebugEnabled;
270
271 /*
272 * Class initialization
273 */
274 void init();
275
276 /**
277 * Dump Cache statistics
278 */
279 void dumpCacheStats();
280
281}; // TextLayoutCache
282
283/**
284 * The TextLayoutEngine is reponsible for computing TextLayoutValues
285 */
286class TextLayoutEngine : public Singleton<TextLayoutEngine> {
287public:
288 TextLayoutEngine();
289 virtual ~TextLayoutEngine();
290
Raph Levien832815c2012-10-02 10:30:41 -0700291 /**
292 * Note: this method currently does a defensive copy of the text argument, in case
293 * there is concurrent mutation of it. The contract may change, and may in the
294 * future require the caller to guarantee that the contents will not change during
295 * the call. Be careful of this when doing optimization.
296 **/
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800297 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
Fabrice Di Meglioda12f382013-03-15 11:26:56 -0700298 jint count, jint contextCount, jint dirFlags);
Fabrice Di Meglio30ca5cd2012-05-07 17:45:44 -0700299
300 void purgeCaches();
301
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800302private:
303 TextLayoutCache* mTextLayoutCache;
304 TextLayoutShaper* mShaper;
305}; // TextLayoutEngine
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800306
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800307} // namespace android
308#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
309