blob: 3c834a408854787d087334574bef29bda4049335 [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>
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070025#include <utils/GenerationCache.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>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080035
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070036#include <unicode/ubidi.h>
37#include <unicode/ushape.h>
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -080038#include <unicode/unistr.h>
39
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080040#include "HarfbuzzSkia.h"
41#include "harfbuzz-shaper.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
Fabrice Di Meglio010d5c42011-04-21 15:33:50 -070059#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.250f
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,
74 size_t contextCount, int dirFlags);
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 /**
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();
Fabrice Di Megliod313c662011-02-24 19:56:18 -080083
84 /**
85 * Get the size of the Cache key.
86 */
Jeff Brown06daa7b2011-11-11 15:14:56 -080087 size_t getSize() const;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080088
Fabrice Di Meglio717060b2011-09-27 15:53:42 -070089 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
90
Fabrice Di Megliod313c662011-02-24 19:56:18 -080091private:
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -070092 const UChar* text; // if text is NULL, use textCopy
Fabrice Di Megliod313c662011-02-24 19:56:18 -080093 String16 textCopy;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070094 size_t start;
Fabrice Di Meglio9c418db2011-09-18 12:54:38 -070095 size_t count;
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -070096 size_t contextCount;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080097 int dirFlags;
Fabrice Di Megliod313c662011-02-24 19:56:18 -080098 SkTypeface* typeface;
Fabrice Di Meglioaabe5372011-03-30 16:06:02 -070099 SkScalar textSize;
100 SkScalar textSkewX;
101 SkScalar textScaleX;
102 uint32_t flags;
103 SkPaint::Hinting hinting;
Fabrice Di Meglioe74fef32011-09-18 14:30:21 -0700104
Fabrice Di Meglio717060b2011-09-27 15:53:42 -0700105 inline const UChar* getText() const { return text ? text : textCopy.string(); }
106
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800107}; // TextLayoutCacheKey
108
Fabrice Di Meglio717060b2011-09-27 15:53:42 -0700109inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
110 return TextLayoutCacheKey::compare(lhs, rhs) < 0;
111}
112
113inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
114 return TextLayoutCacheKey::compare(lhs, rhs);
115}
116
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800117/*
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800118 * TextLayoutValue is the Cache value
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800119 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800120class TextLayoutValue : public RefBase {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800121public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800122 TextLayoutValue(size_t contextCount);
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800123
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700124 void setElapsedTime(uint32_t time);
125 uint32_t getElapsedTime();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800126
Fabrice Di Meglio5c863f72011-10-05 18:11:59 -0700127 inline const jfloat* getAdvances() const { return mAdvances.array(); }
128 inline size_t getAdvancesCount() const { return mAdvances.size(); }
129 inline jfloat getTotalAdvance() const { return mTotalAdvance; }
130 inline const jchar* getGlyphs() const { return mGlyphs.array(); }
131 inline size_t getGlyphsCount() const { return mGlyphs.size(); }
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800132
133 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700134 * Advances vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700135 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700136 Vector<jfloat> mAdvances;
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800137
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700138 /**
139 * Total number of advances
140 */
141 jfloat mTotalAdvance;
142
143 /**
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700144 * Glyphs vector
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700145 */
Fabrice Di Meglio4dd99e52011-09-19 10:47:10 -0700146 Vector<jchar> mGlyphs;
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700147
148 /**
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800149 * Get the size of the Cache entry
150 */
151 size_t getSize() const;
152
153private:
154 /**
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700155 * Time for computing the values (in milliseconds)
156 */
157 uint32_t mElapsedTime;
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800158
Fabrice Di Meglio48796a82011-04-05 15:22:41 -0700159}; // TextLayoutCacheValue
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800160
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700161/**
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800162 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
Fabrice Di Megliofcf2be12011-04-05 17:02:36 -0700163 */
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800164class TextLayoutShaper {
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800165public:
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800166 TextLayoutShaper();
167 virtual ~TextLayoutShaper();
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800168
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800169 void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800170 size_t start, size_t count, size_t contextCount, int dirFlags);
171
172private:
173 /**
174 * Harfbuzz shaper item
175 */
176 HB_ShaperItem mShaperItem;
177
178 /**
179 * Harfbuzz font
180 */
181 HB_FontRec mFontRec;
182
183 /**
184 * Skia Paint used for shaping
185 */
186 SkPaint mShapingPaint;
187
188 /**
189 * Skia typefaces cached for shaping
190 */
191 SkTypeface* mDefaultTypeface;
192 SkTypeface* mArabicTypeface;
193 SkTypeface* mHebrewRegularTypeface;
194 SkTypeface* mHebrewBoldTypeface;
Fabrice Di Meglio65194ad2011-12-13 16:26:08 -0800195 SkTypeface* mBengaliTypeface;
Fabrice Di Meglioa4d07702011-12-13 18:52:13 -0800196 SkTypeface* mThaiTypeface;
Fabrice Di Meglioff40ab72012-02-28 13:16:21 -0800197 SkTypeface* mDevanagariTypeface;
198 SkTypeface* mTamilTypeface;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800199
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800200 /**
201 * Cache of Harfbuzz faces
202 */
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800203 KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
204
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800205 /**
206 * Cache of glyph array size
207 */
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800208 size_t mShaperItemGlyphArraySize;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800209
Fabrice Di Meglio902a5b32011-12-08 18:59:14 -0800210 /**
211 * Buffer for containing the ICU normalized form of a run
212 */
213 UnicodeString mNormalizedString;
214
215 /**
216 * Buffer for normalizing a piece of a run with ICU
217 */
218 UnicodeString mBuffer;
219
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800220 size_t shapeFontRun(const SkPaint* paint, bool isRTL);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800221
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800222 void computeValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800223 size_t start, size_t count, size_t contextCount, int dirFlags,
224 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
225 Vector<jchar>* const outGlyphs);
226
Fabrice Di Megliobd901de2012-01-20 17:41:55 -0800227 void computeRunValues(const SkPaint* paint, const UChar* chars,
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800228 size_t count, bool isRTL,
229 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
230 Vector<jchar>* const outGlyphs);
231
232 SkTypeface* getCachedTypeface(SkTypeface** typeface, const char path[]);
233 HB_Face getCachedHBFace(SkTypeface* typeface);
234
235 void ensureShaperItemGlyphArrays(size_t size);
236 void createShaperItemGlyphArrays(size_t size);
237 void deleteShaperItemGlyphArrays();
238
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800239}; // TextLayoutShaper
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800240
Fabrice Di Meglioa731b082012-01-23 18:18:45 -0800241/**
242 * Cache of text layout information.
243 */
244class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
245{
246public:
247 TextLayoutCache(TextLayoutShaper* shaper);
248
249 ~TextLayoutCache();
250
251 bool isInitialized() {
252 return mInitialized;
253 }
254
255 /**
256 * Used as a callback when an entry is removed from the cache
257 * Do not invoke directly
258 */
259 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
260
261 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
262 jint count, jint contextCount, jint dirFlags);
263
264 /**
265 * Clear the cache
266 */
267 void clear();
268
269private:
270 TextLayoutShaper* mShaper;
271 Mutex mLock;
272 bool mInitialized;
273
274 GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
275
276 uint32_t mSize;
277 uint32_t mMaxSize;
278
279 uint32_t mCacheHitCount;
280 uint64_t mNanosecondsSaved;
281
282 uint64_t mCacheStartTime;
283
284 RtlDebugLevel mDebugLevel;
285 bool mDebugEnabled;
286
287 /*
288 * Class initialization
289 */
290 void init();
291
292 /**
293 * Dump Cache statistics
294 */
295 void dumpCacheStats();
296
297}; // TextLayoutCache
298
299/**
300 * The TextLayoutEngine is reponsible for computing TextLayoutValues
301 */
302class TextLayoutEngine : public Singleton<TextLayoutEngine> {
303public:
304 TextLayoutEngine();
305 virtual ~TextLayoutEngine();
306
307 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
308 jint count, jint contextCount, jint dirFlags);
309private:
310 TextLayoutCache* mTextLayoutCache;
311 TextLayoutShaper* mShaper;
312}; // TextLayoutEngine
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800313
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800314} // namespace android
315#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
316