TextLayoutCache.h revision 13ba4e478d19001ddb6828bd1fd8fbc1e0cb208f
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#include <SkLanguage.h>
36
37#include <unicode/ubidi.h>
38#include <unicode/ushape.h>
39#include <unicode/unistr.h>
40
41#include "HarfbuzzSkia.h"
42#include "harfbuzz-shaper.h"
43
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
60#define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f
61
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:
72    TextLayoutCacheKey();
73
74    TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
75            size_t contextCount, int dirFlags);
76
77    TextLayoutCacheKey(const TextLayoutCacheKey& other);
78
79    /**
80     * We need to copy the text when we insert the key into the cache itself.
81     * We don't need to copy the text when we are only comparing keys.
82     */
83    void internalTextCopy();
84
85    /**
86     * Get the size of the Cache key.
87     */
88    size_t getSize() const;
89
90    static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
91
92private:
93    const UChar* text; // if text is NULL, use textCopy
94    String16 textCopy;
95    size_t start;
96    size_t count;
97    size_t contextCount;
98    int dirFlags;
99    SkTypeface* typeface;
100    SkScalar textSize;
101    SkScalar textSkewX;
102    SkScalar textScaleX;
103    uint32_t flags;
104    SkPaint::Hinting hinting;
105    SkPaint::FontVariant variant;
106    SkLanguage language;
107
108    inline const UChar* getText() const { return text ? text : textCopy.string(); }
109
110}; // TextLayoutCacheKey
111
112inline 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
120/*
121 * TextLayoutValue is the Cache value
122 */
123class TextLayoutValue : public RefBase {
124public:
125    TextLayoutValue(size_t contextCount);
126
127    void setElapsedTime(uint32_t time);
128    uint32_t getElapsedTime();
129
130    inline const jfloat* getAdvances() const { return mAdvances.array(); }
131    inline size_t getAdvancesCount() const { return mAdvances.size(); }
132    inline jfloat getTotalAdvance() const { return mTotalAdvance; }
133    inline const jchar* getGlyphs() const { return mGlyphs.array(); }
134    inline size_t getGlyphsCount() const { return mGlyphs.size(); }
135    inline const jfloat* getPos() const { return mPos.array(); }
136    inline size_t getPosCount() const { return mPos.size(); }
137
138    /**
139     * Advances vector
140     */
141    Vector<jfloat> mAdvances;
142
143    /**
144     * Total number of advances
145     */
146    jfloat mTotalAdvance;
147
148    /**
149     * Glyphs vector
150     */
151    Vector<jchar> mGlyphs;
152
153    /**
154     * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText)
155     */
156    Vector<jfloat> mPos;
157
158    /**
159     * Get the size of the Cache entry
160     */
161    size_t getSize() const;
162
163private:
164    /**
165     * Time for computing the values (in milliseconds)
166     */
167    uint32_t mElapsedTime;
168
169}; // TextLayoutCacheValue
170
171/**
172 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
173 */
174class TextLayoutShaper {
175public:
176    TextLayoutShaper();
177    virtual ~TextLayoutShaper();
178
179    void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
180            size_t start, size_t count, size_t contextCount, int dirFlags);
181
182    void purgeCaches();
183
184private:
185    /**
186     * Harfbuzz shaper item
187     */
188    HB_ShaperItem mShaperItem;
189
190    /**
191     * Harfbuzz font
192     */
193    HB_FontRec mFontRec;
194
195    /**
196     * Skia Paint used for shaping
197     */
198    SkPaint mShapingPaint;
199
200    /**
201     * Skia default typeface to be returned if we cannot resolve script
202     */
203    SkTypeface* mDefaultTypeface;
204
205    /**
206     * Cache of Harfbuzz faces
207     */
208    KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
209
210    /**
211     * Cache of glyph array size
212     */
213    size_t mShaperItemGlyphArraySize;
214
215    /**
216     * Buffer for containing the ICU normalized form of a run
217     */
218    UnicodeString mNormalizedString;
219
220    /**
221     * Buffer for normalizing a piece of a run with ICU
222     */
223    UnicodeString mBuffer;
224
225    void init();
226    void unrefTypefaces();
227
228    SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
229        HB_Script script);
230
231    size_t shapeFontRun(const SkPaint* paint, bool isRTL);
232
233    void computeValues(const SkPaint* paint, const UChar* chars,
234            size_t start, size_t count, size_t contextCount, int dirFlags,
235            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
236            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
237
238    void computeRunValues(const SkPaint* paint, const UChar* chars,
239            size_t count, bool isRTL,
240            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
241            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
242
243    SkTypeface* getCachedTypeface(SkTypeface** typeface, HB_Script script, SkTypeface::Style style);
244    HB_Face getCachedHBFace(SkTypeface* typeface);
245
246    bool doShaping(size_t size);
247    void createShaperItemGlyphArrays(size_t size);
248    void deleteShaperItemGlyphArrays();
249    bool isComplexScript(HB_Script script);
250
251}; // TextLayoutShaper
252
253/**
254 * Cache of text layout information.
255 */
256class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
257{
258public:
259    TextLayoutCache(TextLayoutShaper* shaper);
260
261    ~TextLayoutCache();
262
263    bool isInitialized() {
264        return mInitialized;
265    }
266
267    /**
268     * Used as a callback when an entry is removed from the cache
269     * Do not invoke directly
270     */
271    void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
272
273    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
274            jint count, jint contextCount, jint dirFlags);
275
276    /**
277     * Clear the cache
278     */
279    void purgeCaches();
280
281private:
282    TextLayoutShaper* mShaper;
283    Mutex mLock;
284    bool mInitialized;
285
286    GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
287
288    uint32_t mSize;
289    uint32_t mMaxSize;
290
291    uint32_t mCacheHitCount;
292    uint64_t mNanosecondsSaved;
293
294    uint64_t mCacheStartTime;
295
296    RtlDebugLevel mDebugLevel;
297    bool mDebugEnabled;
298
299    /*
300     * Class initialization
301     */
302    void init();
303
304    /**
305     * Dump Cache statistics
306     */
307    void dumpCacheStats();
308
309}; // TextLayoutCache
310
311/**
312 * The TextLayoutEngine is reponsible for computing TextLayoutValues
313 */
314class TextLayoutEngine : public Singleton<TextLayoutEngine> {
315public:
316    TextLayoutEngine();
317    virtual ~TextLayoutEngine();
318
319    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
320            jint count, jint contextCount, jint dirFlags);
321
322    void purgeCaches();
323
324private:
325    TextLayoutCache* mTextLayoutCache;
326    TextLayoutShaper* mShaper;
327}; // TextLayoutEngine
328
329} // namespace android
330#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
331
332