• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
64 namespace android {
65 
66 /**
67  * TextLayoutCacheKey is the Cache key
68  */
69 class TextLayoutCacheKey {
70 public:
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 
91 private:
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 
getText()105     inline const UChar* getText() const { return text ? text : textCopy.string(); }
106 
107 }; // TextLayoutCacheKey
108 
strictly_order_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)109 inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
110     return TextLayoutCacheKey::compare(lhs, rhs) < 0;
111 }
112 
compare_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)113 inline 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  */
120 class TextLayoutValue : public RefBase {
121 public:
122     TextLayoutValue(size_t contextCount);
123 
124     void setElapsedTime(uint32_t time);
125     uint32_t getElapsedTime();
126 
getAdvances()127     inline const jfloat* getAdvances() const { return mAdvances.array(); }
getAdvancesCount()128     inline size_t getAdvancesCount() const { return mAdvances.size(); }
getTotalAdvance()129     inline jfloat getTotalAdvance() const { return mTotalAdvance; }
getGlyphs()130     inline const jchar* getGlyphs() const { return mGlyphs.array(); }
getGlyphsCount()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 
153 private:
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  */
164 class TextLayoutShaper {
165 public:
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 
172     void purgeCaches();
173 
174 private:
175     /**
176      * Harfbuzz shaper item
177      */
178     HB_ShaperItem mShaperItem;
179 
180     /**
181      * Harfbuzz font
182      */
183     HB_FontRec mFontRec;
184 
185     /**
186      * Skia Paint used for shaping
187      */
188     SkPaint mShapingPaint;
189 
190     /**
191      * Skia typefaces cached for shaping
192      */
193     SkTypeface* mDefaultTypeface;
194     SkTypeface* mArabicTypeface;
195     SkTypeface* mHebrewRegularTypeface;
196     SkTypeface* mHebrewBoldTypeface;
197     SkTypeface* mBengaliTypeface;
198     SkTypeface* mThaiTypeface;
199     SkTypeface* mDevanagariRegularTypeface;
200     SkTypeface* mTamilRegularTypeface;
201     SkTypeface* mTamilBoldTypeface;
202 
203     /**
204      * Cache of Harfbuzz faces
205      */
206     KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
207 
208     /**
209      * Cache of glyph array size
210      */
211     size_t mShaperItemGlyphArraySize;
212 
213     /**
214      * Buffer for containing the ICU normalized form of a run
215      */
216     UnicodeString mNormalizedString;
217 
218     /**
219      * Buffer for normalizing a piece of a run with ICU
220      */
221     UnicodeString mBuffer;
222 
223     void init();
224     void unrefTypefaces();
225 
226     SkTypeface* typefaceForUnichar(const SkPaint* paint, SkTypeface* typeface,
227         SkUnichar unichar, HB_Script script);
228 
229     size_t shapeFontRun(const SkPaint* paint, bool isRTL);
230 
231     void computeValues(const SkPaint* paint, const UChar* chars,
232             size_t start, size_t count, size_t contextCount, int dirFlags,
233             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
234             Vector<jchar>* const outGlyphs);
235 
236     void computeRunValues(const SkPaint* paint, const UChar* chars,
237             size_t count, bool isRTL,
238             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
239             Vector<jchar>* const outGlyphs);
240 
241     SkTypeface* getCachedTypeface(SkTypeface** typeface, const char path[]);
242     HB_Face getCachedHBFace(SkTypeface* typeface);
243 
244     void ensureShaperItemGlyphArrays(size_t size);
245     void createShaperItemGlyphArrays(size_t size);
246     void deleteShaperItemGlyphArrays();
247 
248 }; // TextLayoutShaper
249 
250 /**
251  * Cache of text layout information.
252  */
253 class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
254 {
255 public:
256     TextLayoutCache(TextLayoutShaper* shaper);
257 
258     ~TextLayoutCache();
259 
isInitialized()260     bool isInitialized() {
261         return mInitialized;
262     }
263 
264     /**
265      * Used as a callback when an entry is removed from the cache
266      * Do not invoke directly
267      */
268     void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
269 
270     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
271             jint count, jint contextCount, jint dirFlags);
272 
273     /**
274      * Clear the cache
275      */
276     void clear();
277 
278 private:
279     TextLayoutShaper* mShaper;
280     Mutex mLock;
281     bool mInitialized;
282 
283     GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
284 
285     uint32_t mSize;
286     uint32_t mMaxSize;
287 
288     uint32_t mCacheHitCount;
289     uint64_t mNanosecondsSaved;
290 
291     uint64_t mCacheStartTime;
292 
293     RtlDebugLevel mDebugLevel;
294     bool mDebugEnabled;
295 
296     /*
297      * Class initialization
298      */
299     void init();
300 
301     /**
302      * Dump Cache statistics
303      */
304     void dumpCacheStats();
305 
306 }; // TextLayoutCache
307 
308 /**
309  * The TextLayoutEngine is reponsible for computing TextLayoutValues
310  */
311 class TextLayoutEngine : public Singleton<TextLayoutEngine> {
312 public:
313     TextLayoutEngine();
314     virtual ~TextLayoutEngine();
315 
316     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
317             jint count, jint contextCount, jint dirFlags);
318 
319     void purgeCaches();
320 
321 private:
322     TextLayoutCache* mTextLayoutCache;
323     TextLayoutShaper* mShaper;
324 }; // TextLayoutEngine
325 
326 } // namespace android
327 #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
328 
329