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