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/Compare.h>
27 #include <utils/RefBase.h>
28 #include <utils/Singleton.h>
29
30 #include <SkPaint.h>
31 #include <SkTemplates.h>
32 #include <SkUtils.h>
33 #include <SkScalerContext.h>
34 #include <SkAutoKern.h>
35
36 #include <unicode/ubidi.h>
37 #include <unicode/ushape.h>
38 #include "HarfbuzzSkia.h"
39 #include "harfbuzz-shaper.h"
40
41 #include <android_runtime/AndroidRuntime.h>
42
43 #define UNICODE_NOT_A_CHAR 0xffff
44 #define UNICODE_ZWSP 0x200b
45 #define UNICODE_FIRST_LOW_SURROGATE 0xdc00
46 #define UNICODE_FIRST_HIGH_SURROGATE 0xd800
47 #define UNICODE_FIRST_PRIVATE_USE 0xe000
48 #define UNICODE_FIRST_RTL_CHAR 0x0590
49
50 // Temporary buffer size
51 #define CHAR_BUFFER_SIZE 80
52
53 // Converts a number of mega-bytes into bytes
54 #define MB(s) s * 1024 * 1024
55
56 // Define the default cache size in Mb
57 #define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.250f
58
59 // Define the interval in number of cache hits between two statistics dump
60 #define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
61
62 namespace android {
63
64 /**
65 * TextLayoutCacheKey is the Cache key
66 */
67 class TextLayoutCacheKey {
68 public:
69 TextLayoutCacheKey();
70
71 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
72 size_t contextCount, int dirFlags);
73
74 TextLayoutCacheKey(const TextLayoutCacheKey& other);
75
76 /**
77 * We need to copy the text when we insert the key into the cache itself.
78 * We don't need to copy the text when we are only comparing keys.
79 */
80 void internalTextCopy();
81
82 /**
83 * Get the size of the Cache key.
84 */
85 size_t getSize();
86
87 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
88
89 private:
90 const UChar* text; // if text is NULL, use textCopy
91 String16 textCopy;
92 size_t start;
93 size_t count;
94 size_t contextCount;
95 int dirFlags;
96 SkTypeface* typeface;
97 SkScalar textSize;
98 SkScalar textSkewX;
99 SkScalar textScaleX;
100 uint32_t flags;
101 SkPaint::Hinting hinting;
102
getText()103 inline const UChar* getText() const { return text ? text : textCopy.string(); }
104
105 }; // TextLayoutCacheKey
106
strictly_order_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)107 inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
108 return TextLayoutCacheKey::compare(lhs, rhs) < 0;
109 }
110
compare_type(const TextLayoutCacheKey & lhs,const TextLayoutCacheKey & rhs)111 inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
112 return TextLayoutCacheKey::compare(lhs, rhs);
113 }
114
115 /*
116 * TextLayoutCacheValue is the Cache value
117 */
118 class TextLayoutCacheValue : public RefBase {
119 public:
120 TextLayoutCacheValue();
121
122 void setElapsedTime(uint32_t time);
123 uint32_t getElapsedTime();
124
125 void computeValues(SkPaint* paint, const UChar* chars, size_t start, size_t count,
126 size_t contextCount, int dirFlags);
127
getAdvances()128 inline const jfloat* getAdvances() const { return mAdvances.array(); }
getAdvancesCount()129 inline size_t getAdvancesCount() const { return mAdvances.size(); }
getTotalAdvance()130 inline jfloat getTotalAdvance() const { return mTotalAdvance; }
getGlyphs()131 inline const jchar* getGlyphs() const { return mGlyphs.array(); }
getGlyphsCount()132 inline size_t getGlyphsCount() const { return mGlyphs.size(); }
133
134 /**
135 * Get the size of the Cache entry
136 */
137 size_t getSize();
138
139 private:
140 /**
141 * Advances vector
142 */
143 Vector<jfloat> mAdvances;
144
145 /**
146 * Total number of advances
147 */
148 jfloat mTotalAdvance;
149
150 /**
151 * Glyphs vector
152 */
153 Vector<jchar> mGlyphs;
154
155 /**
156 * Time for computing the values (in milliseconds)
157 */
158 uint32_t mElapsedTime;
159
160 static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
161 size_t start, size_t count, size_t contextCount, int dirFlags,
162 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
163 Vector<jchar>* const outGlyphs);
164
165 static void computeRunValuesWithHarfbuzz(HB_ShaperItem& shaperItem, SkPaint* paint,
166 size_t start, size_t count, bool isRTL,
167 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
168 Vector<jchar>* const outGlyphs);
169
170 static void initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* font, FontData* fontData,
171 SkPaint* paint, const UChar* chars, size_t contextCount);
172
173 static void freeShaperItem(HB_ShaperItem& shaperItem);
174
175 static void shapeRun(HB_ShaperItem& shaperItem, size_t start, size_t count, bool isRTL);
176
177 static void deleteGlyphArrays(HB_ShaperItem& shaperItem);
178
179 static void createGlyphArrays(HB_ShaperItem& shaperItem, int size);
180
181 }; // TextLayoutCacheValue
182
183 /**
184 * Cache of text layout information.
185 */
186 class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >,
187 public Singleton<TextLayoutCache>
188 {
189 public:
190 TextLayoutCache();
191
192 virtual ~TextLayoutCache();
193
isInitialized()194 bool isInitialized() {
195 return mInitialized;
196 }
197
198 /**
199 * Used as a callback when an entry is removed from the cache
200 * Do not invoke directly
201 */
202 void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
203
204 sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint start, jint count,
205 jint contextCount, jint dirFlags);
206
207 /**
208 * Clear the cache
209 */
210 void clear();
211
212 /**
213 * Sets the maximum size of the cache in bytes
214 */
215 void setMaxSize(uint32_t maxSize);
216
217 /**
218 * Returns the maximum size of the cache in bytes
219 */
220 uint32_t getMaxSize();
221
222 /**
223 * Returns the current size of the cache in bytes
224 */
225 uint32_t getSize();
226
227 private:
228 Mutex mLock;
229 bool mInitialized;
230
231 GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache;
232
233 uint32_t mSize;
234 uint32_t mMaxSize;
235
236 uint32_t mCacheHitCount;
237 uint64_t mNanosecondsSaved;
238
239 uint64_t mCacheStartTime;
240
241 RtlDebugLevel mDebugLevel;
242 bool mDebugEnabled;
243
244 /*
245 * Class initialization
246 */
247 void init();
248
249 /**
250 * Remove oldest entries until we are having enough space
251 */
252 void removeOldests();
253
254 /**
255 * Dump Cache statistics
256 */
257 void dumpCacheStats();
258
259 }; // TextLayoutCache
260
261 } // namespace android
262 #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
263
264