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/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