TextLayoutCache.h revision 30ca5cd11a23f06f2f8eeaa587685450826f800f
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
64namespace android {
65
66/**
67 * TextLayoutCacheKey is the Cache key
68 */
69class TextLayoutCacheKey {
70public:
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
91private:
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
105    inline const UChar* getText() const { return text ? text : textCopy.string(); }
106
107}; // TextLayoutCacheKey
108
109inline 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
117/*
118 * TextLayoutValue is the Cache value
119 */
120class TextLayoutValue : public RefBase {
121public:
122    TextLayoutValue(size_t contextCount);
123
124    void setElapsedTime(uint32_t time);
125    uint32_t getElapsedTime();
126
127    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(); }
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
153private:
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 */
164class TextLayoutShaper {
165public:
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
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;
195    SkTypeface* mBengaliTypeface;
196    SkTypeface* mThaiTypeface;
197    SkTypeface* mDevanagariTypeface;
198    SkTypeface* mTamilTypeface;
199
200    /**
201     * Cache of Harfbuzz faces
202     */
203    KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
204
205    /**
206     * Cache of glyph array size
207     */
208    size_t mShaperItemGlyphArraySize;
209
210    /**
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
220    SkTypeface* typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface,
221        SkUnichar unichar, HB_Script script);
222
223    size_t shapeFontRun(const SkPaint* paint, bool isRTL);
224
225    void computeValues(const SkPaint* paint, const UChar* chars,
226            size_t start, size_t count, size_t contextCount, int dirFlags,
227            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
228            Vector<jchar>* const outGlyphs);
229
230    void computeRunValues(const SkPaint* paint, const UChar* chars,
231            size_t count, bool isRTL,
232            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
233            Vector<jchar>* const outGlyphs);
234
235    SkTypeface* getCachedTypeface(SkTypeface** typeface, const char path[]);
236    HB_Face getCachedHBFace(SkTypeface* typeface);
237
238    void ensureShaperItemGlyphArrays(size_t size);
239    void createShaperItemGlyphArrays(size_t size);
240    void deleteShaperItemGlyphArrays();
241
242}; // TextLayoutShaper
243
244/**
245 * Cache of text layout information.
246 */
247class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
248{
249public:
250    TextLayoutCache(TextLayoutShaper* shaper);
251
252    ~TextLayoutCache();
253
254    bool isInitialized() {
255        return mInitialized;
256    }
257
258    /**
259     * Used as a callback when an entry is removed from the cache
260     * Do not invoke directly
261     */
262    void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
263
264    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
265            jint count, jint contextCount, jint dirFlags);
266
267    /**
268     * Clear the cache
269     */
270    void clear();
271
272private:
273    TextLayoutShaper* mShaper;
274    Mutex mLock;
275    bool mInitialized;
276
277    GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
278
279    uint32_t mSize;
280    uint32_t mMaxSize;
281
282    uint32_t mCacheHitCount;
283    uint64_t mNanosecondsSaved;
284
285    uint64_t mCacheStartTime;
286
287    RtlDebugLevel mDebugLevel;
288    bool mDebugEnabled;
289
290    /*
291     * Class initialization
292     */
293    void init();
294
295    /**
296     * Dump Cache statistics
297     */
298    void dumpCacheStats();
299
300}; // TextLayoutCache
301
302/**
303 * The TextLayoutEngine is reponsible for computing TextLayoutValues
304 */
305class TextLayoutEngine : public Singleton<TextLayoutEngine> {
306public:
307    TextLayoutEngine();
308    virtual ~TextLayoutEngine();
309
310    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
311            jint count, jint contextCount, jint dirFlags);
312
313    void purgeCaches();
314
315private:
316    TextLayoutCache* mTextLayoutCache;
317    TextLayoutShaper* mShaper;
318}; // TextLayoutEngine
319
320} // namespace android
321#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
322
323