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