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