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/Compare.h>
27#include <utils/RefBase.h>
28#include <utils/Singleton.h>
29
30#include <SkPaint.h>
31#include <SkTemplates.h>
32#include <SkUtils.h>
33#include <SkScalerContext.h>
34#include <SkAutoKern.h>
35
36#include <unicode/ubidi.h>
37#include <unicode/ushape.h>
38#include "HarfbuzzSkia.h"
39#include "harfbuzz-shaper.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.250f
58
59// Define the interval in number of cache hits between two statistics dump
60#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
61
62namespace android {
63
64/**
65 * TextLayoutCacheKey is the Cache key
66 */
67class TextLayoutCacheKey {
68public:
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     * We need to copy the text when we insert the key into the cache itself.
78     * We don't need to copy the text when we are only comparing keys.
79     */
80    void internalTextCopy();
81
82    /**
83     * Get the size of the Cache key.
84     */
85    size_t getSize();
86
87    static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
88
89private:
90    const UChar* text; // if text is NULL, use textCopy
91    String16 textCopy;
92    size_t start;
93    size_t count;
94    size_t contextCount;
95    int dirFlags;
96    SkTypeface* typeface;
97    SkScalar textSize;
98    SkScalar textSkewX;
99    SkScalar textScaleX;
100    uint32_t flags;
101    SkPaint::Hinting hinting;
102
103    inline const UChar* getText() const { return text ? text : textCopy.string(); }
104
105}; // TextLayoutCacheKey
106
107inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
108    return TextLayoutCacheKey::compare(lhs, rhs) < 0;
109}
110
111inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
112    return TextLayoutCacheKey::compare(lhs, rhs);
113}
114
115/*
116 * TextLayoutCacheValue is the Cache value
117 */
118class TextLayoutCacheValue : public RefBase {
119public:
120    TextLayoutCacheValue();
121
122    void setElapsedTime(uint32_t time);
123    uint32_t getElapsedTime();
124
125    void computeValues(SkPaint* paint, const UChar* chars, size_t start, size_t count,
126            size_t contextCount, int dirFlags);
127
128    inline const jfloat* getAdvances() const { return mAdvances.array(); }
129    inline size_t getAdvancesCount() const { return mAdvances.size(); }
130    inline jfloat getTotalAdvance() const { return mTotalAdvance; }
131    inline const jchar* getGlyphs() const { return mGlyphs.array(); }
132    inline size_t getGlyphsCount() const { return mGlyphs.size(); }
133
134    /**
135     * Get the size of the Cache entry
136     */
137    size_t getSize();
138
139private:
140    /**
141     * Advances vector
142     */
143    Vector<jfloat> mAdvances;
144
145    /**
146     * Total number of advances
147     */
148    jfloat mTotalAdvance;
149
150    /**
151     * Glyphs vector
152     */
153    Vector<jchar> mGlyphs;
154
155    /**
156     * Time for computing the values (in milliseconds)
157     */
158    uint32_t mElapsedTime;
159
160    static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
161            size_t start, size_t count, size_t contextCount, int dirFlags,
162            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
163            Vector<jchar>* const outGlyphs);
164
165    static void computeRunValuesWithHarfbuzz(HB_ShaperItem& shaperItem, SkPaint* paint,
166            size_t start, size_t count, bool isRTL,
167            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
168            Vector<jchar>* const outGlyphs);
169
170    static void initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* font, FontData* fontData,
171            SkPaint* paint, const UChar* chars, size_t contextCount);
172
173    static void freeShaperItem(HB_ShaperItem& shaperItem);
174
175    static void shapeRun(HB_ShaperItem& shaperItem, size_t start, size_t count, bool isRTL);
176
177    static void deleteGlyphArrays(HB_ShaperItem& shaperItem);
178
179    static void createGlyphArrays(HB_ShaperItem& shaperItem, int size);
180
181}; // TextLayoutCacheValue
182
183/**
184 * Cache of text layout information.
185 */
186class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >,
187        public Singleton<TextLayoutCache>
188{
189public:
190    TextLayoutCache();
191
192    virtual ~TextLayoutCache();
193
194    bool isInitialized() {
195        return mInitialized;
196    }
197
198    /**
199     * Used as a callback when an entry is removed from the cache
200     * Do not invoke directly
201     */
202    void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
203
204    sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint start, jint count,
205            jint contextCount, jint dirFlags);
206
207    /**
208     * Clear the cache
209     */
210    void clear();
211
212    /**
213     * Sets the maximum size of the cache in bytes
214     */
215    void setMaxSize(uint32_t maxSize);
216
217    /**
218     * Returns the maximum size of the cache in bytes
219     */
220    uint32_t getMaxSize();
221
222    /**
223     * Returns the current size of the cache in bytes
224     */
225    uint32_t getSize();
226
227private:
228    Mutex mLock;
229    bool mInitialized;
230
231    GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache;
232
233    uint32_t mSize;
234    uint32_t mMaxSize;
235
236    uint32_t mCacheHitCount;
237    uint64_t mNanosecondsSaved;
238
239    uint64_t mCacheStartTime;
240
241    RtlDebugLevel mDebugLevel;
242    bool mDebugEnabled;
243
244    /*
245     * Class initialization
246     */
247    void init();
248
249    /**
250     * Remove oldest entries until we are having enough space
251     */
252    void removeOldests();
253
254    /**
255     * Dump Cache statistics
256     */
257    void dumpCacheStats();
258
259}; // TextLayoutCache
260
261} // namespace android
262#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
263
264