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 63namespace android { 64 65/** 66 * TextLayoutCacheKey is the Cache key 67 */ 68class TextLayoutCacheKey { 69public: 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; 95private: 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 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 120inline hash_t hash_type(const TextLayoutCacheKey& key) { 121 return key.hash(); 122} 123 124/* 125 * TextLayoutValue is the Cache value 126 */ 127class TextLayoutValue : public RefBase { 128public: 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 167private: 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 */ 178class TextLayoutShaper { 179public: 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 188private: 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 */ 228class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> > 229{ 230public: 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 253private: 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 */ 286class TextLayoutEngine : public Singleton<TextLayoutEngine> { 287public: 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 302private: 303 TextLayoutCache* mTextLayoutCache; 304 TextLayoutShaper* mShaper; 305}; // TextLayoutEngine 306 307} // namespace android 308#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */ 309 310