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