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/LruCache.h> 26 #include <utils/KeyedVector.h> 27 #include <utils/RefBase.h> 28 #include <utils/Singleton.h> 29 30 #include <SkAutoKern.h> 31 #include <SkLanguage.h> 32 #include <SkPaint.h> 33 #include <SkTemplates.h> 34 #include <SkTypeface.h> 35 #include <SkUtils.h> 36 37 #include <unicode/ubidi.h> 38 #include <unicode/unistr.h> 39 40 #include <hb.h> 41 42 #include <android_runtime/AndroidRuntime.h> 43 44 #define UNICODE_NOT_A_CHAR 0xffff 45 #define UNICODE_ZWSP 0x200b 46 #define UNICODE_FIRST_LOW_SURROGATE 0xdc00 47 #define UNICODE_FIRST_HIGH_SURROGATE 0xd800 48 #define UNICODE_FIRST_PRIVATE_USE 0xe000 49 #define UNICODE_FIRST_RTL_CHAR 0x0590 50 51 // Temporary buffer size 52 #define CHAR_BUFFER_SIZE 80 53 54 // Converts a number of mega-bytes into bytes 55 #define MB(s) s * 1024 * 1024 56 57 // Define the default cache size in Mb 58 #define DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB 0.500f 59 60 // Define the interval in number of cache hits between two statistics dump 61 #define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100 62 63 namespace android { 64 65 /** 66 * TextLayoutCacheKey is the Cache key 67 */ 68 class TextLayoutCacheKey { 69 public: 70 TextLayoutCacheKey(); 71 72 TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count, 73 size_t contextCount, int dirFlags); 74 75 TextLayoutCacheKey(const TextLayoutCacheKey& other); 76 77 /** 78 * Get the size of the Cache key. 79 */ 80 size_t getSize() const; 81 82 static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs); 83 84 inline const UChar* getText() const { return textCopy.string(); } 85 86 bool operator==(const TextLayoutCacheKey& other) const { 87 return compare(*this, other) == 0; 88 } 89 90 bool operator!=(const TextLayoutCacheKey& other) const { 91 return compare(*this, other) != 0; 92 } 93 94 hash_t hash() const; 95 private: 96 String16 textCopy; 97 size_t start; 98 size_t count; 99 size_t contextCount; 100 int dirFlags; 101 SkTypeface* typeface; 102 SkScalar textSize; 103 SkScalar textSkewX; 104 SkScalar textScaleX; 105 uint32_t flags; 106 SkPaint::Hinting hinting; 107 SkPaint::FontVariant variant; 108 SkLanguage language; 109 110 }; // TextLayoutCacheKey 111 112 inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) { 113 return TextLayoutCacheKey::compare(lhs, rhs) < 0; 114 } 115 116 inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) { 117 return TextLayoutCacheKey::compare(lhs, rhs); 118 } 119 120 inline hash_t hash_type(const TextLayoutCacheKey& key) { 121 return key.hash(); 122 } 123 124 /* 125 * TextLayoutValue is the Cache value 126 */ 127 class TextLayoutValue : public RefBase { 128 public: 129 TextLayoutValue(size_t contextCount); 130 131 void setElapsedTime(uint32_t time); 132 uint32_t getElapsedTime(); 133 134 inline const jfloat* getAdvances() const { return mAdvances.array(); } 135 inline size_t getAdvancesCount() const { return mAdvances.size(); } 136 inline jfloat getTotalAdvance() const { return mTotalAdvance; } 137 inline const jchar* getGlyphs() const { return mGlyphs.array(); } 138 inline size_t getGlyphsCount() const { return mGlyphs.size(); } 139 inline const jfloat* getPos() const { return mPos.array(); } 140 inline size_t getPosCount() const { return mPos.size(); } 141 142 /** 143 * Advances vector 144 */ 145 Vector<jfloat> mAdvances; 146 147 /** 148 * Total number of advances 149 */ 150 jfloat mTotalAdvance; 151 152 /** 153 * Glyphs vector 154 */ 155 Vector<jchar> mGlyphs; 156 157 /** 158 * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText) 159 */ 160 Vector<jfloat> mPos; 161 162 /** 163 * Get the size of the Cache entry 164 */ 165 size_t getSize() const; 166 167 private: 168 /** 169 * Time for computing the values (in milliseconds) 170 */ 171 uint32_t mElapsedTime; 172 173 }; // TextLayoutCacheValue 174 175 /** 176 * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library) 177 */ 178 class TextLayoutShaper { 179 public: 180 TextLayoutShaper(); 181 virtual ~TextLayoutShaper(); 182 183 void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, 184 size_t start, size_t count, size_t contextCount, int dirFlags); 185 186 void purgeCaches(); 187 188 private: 189 /** 190 * Harfbuzz buffer for shaping 191 */ 192 hb_buffer_t* mBuffer; 193 194 /** 195 * Skia Paint used for shaping 196 */ 197 SkPaint mShapingPaint; 198 199 /** 200 * Cache of Harfbuzz faces 201 */ 202 KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces; 203 204 SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface, 205 hb_script_t script); 206 207 size_t shapeFontRun(const SkPaint* paint); 208 209 void computeValues(const SkPaint* paint, const UChar* chars, 210 size_t start, size_t count, size_t contextCount, int dirFlags, 211 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, 212 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos); 213 214 void computeRunValues(const SkPaint* paint, const UChar* chars, 215 size_t start, size_t count, size_t contextCount, bool isRTL, 216 Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, 217 Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos); 218 219 SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style); 220 hb_face_t* referenceCachedHBFace(SkTypeface* typeface); 221 222 bool isComplexScript(hb_script_t script); 223 }; // TextLayoutShaper 224 225 /** 226 * Cache of text layout information. 227 */ 228 class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> > 229 { 230 public: 231 TextLayoutCache(TextLayoutShaper* shaper); 232 233 ~TextLayoutCache(); 234 235 bool isInitialized() { 236 return mInitialized; 237 } 238 239 /** 240 * Used as a callback when an entry is removed from the cache 241 * Do not invoke directly 242 */ 243 void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc); 244 245 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, 246 jint count, jint contextCount, jint dirFlags); 247 248 /** 249 * Clear the cache 250 */ 251 void purgeCaches(); 252 253 private: 254 TextLayoutShaper* mShaper; 255 Mutex mLock; 256 bool mInitialized; 257 258 LruCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache; 259 260 uint32_t mSize; 261 uint32_t mMaxSize; 262 263 uint32_t mCacheHitCount; 264 uint64_t mNanosecondsSaved; 265 266 uint64_t mCacheStartTime; 267 268 RtlDebugLevel mDebugLevel; 269 bool mDebugEnabled; 270 271 /* 272 * Class initialization 273 */ 274 void init(); 275 276 /** 277 * Dump Cache statistics 278 */ 279 void dumpCacheStats(); 280 281 }; // TextLayoutCache 282 283 /** 284 * The TextLayoutEngine is reponsible for computing TextLayoutValues 285 */ 286 class TextLayoutEngine : public Singleton<TextLayoutEngine> { 287 public: 288 TextLayoutEngine(); 289 virtual ~TextLayoutEngine(); 290 291 /** 292 * Note: this method currently does a defensive copy of the text argument, in case 293 * there is concurrent mutation of it. The contract may change, and may in the 294 * future require the caller to guarantee that the contents will not change during 295 * the call. Be careful of this when doing optimization. 296 **/ 297 sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, 298 jint count, jint contextCount, jint dirFlags); 299 300 void purgeCaches(); 301 302 private: 303 TextLayoutCache* mTextLayoutCache; 304 TextLayoutShaper* mShaper; 305 }; // TextLayoutEngine 306 307 } // namespace android 308 #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */ 309 310