1d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/*
2d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Copyright (C) 2011 The Android Open Source Project
3d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *
4d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License");
5d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * you may not use this file except in compliance with the License.
6d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * You may obtain a copy of the License at
7d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *
8d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *      http://www.apache.org/licenses/LICENSE-2.0
9d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *
10d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software
11d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS,
12d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * See the License for the specific language governing permissions and
14d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * limitations under the License.
15d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
16d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
17163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio#define LOG_TAG "TextLayoutCache"
18163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio
19d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio#include "TextLayoutCache.h"
20689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#include "TextLayout.h"
21ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#include "SkFontHost.h"
22ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett#include "SkTypeface_android.h"
23902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#include <unicode/unistr.h>
24902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#include <unicode/normlzr.h>
253632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio#include <unicode/uchar.h>
26d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
275de5b1a91e25ef4931661fdd089d7e0e2b7da035Fabrice Di Meglioextern "C" {
285de5b1a91e25ef4931661fdd089d7e0e2b7da035Fabrice Di Meglio  #include "harfbuzz-unicode.h"
295de5b1a91e25ef4931661fdd089d7e0e2b7da035Fabrice Di Meglio}
305de5b1a91e25ef4931661fdd089d7e0e2b7da035Fabrice Di Meglio
31d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglionamespace android {
32d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
33163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio//--------------------------------------------------------------------------------------------------
34ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
35a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
36b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio
37163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio//--------------------------------------------------------------------------------------------------
38163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio
39a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) :
40a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        mShaper(shaper),
41a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity),
42d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
43d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        mCacheHitCount(0), mNanosecondsSaved(0) {
44d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    init();
45d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
46d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
47d313c665e618af3194f504064bcd284fe5368682Fabrice Di MeglioTextLayoutCache::~TextLayoutCache() {
48d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.clear();
49d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
50d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
51d313c665e618af3194f504064bcd284fe5368682Fabrice Di Megliovoid TextLayoutCache::init() {
52d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.setOnEntryRemovedListener(this);
53d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
54d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mDebugLevel = readRtlDebugLevel();
55d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mDebugEnabled = mDebugLevel & kRtlDebugCaches;
565baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Using debug level = %d - Debug Enabled = %d", mDebugLevel, mDebugEnabled);
57d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
58d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCacheStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
599f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio
609f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio    if (mDebugEnabled) {
615baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Initialization is done - Start time = %lld", mCacheStartTime);
629f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio    }
639f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio
64163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio    mInitialized = true;
65d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
66d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
67d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/**
68d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *  Callbacks
69d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
70a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) {
7106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    size_t totalSizeToDelete = text.getSize() + desc->getSize();
7206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    mSize -= totalSizeToDelete;
7306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    if (mDebugEnabled) {
745baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Cache value %p deleted, size = %d", desc.get(), totalSizeToDelete);
75d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
76d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
77d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
78d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/*
79d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Cache clearing
80d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
8113ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levienvoid TextLayoutCache::purgeCaches() {
8213ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    AutoMutex _l(mLock);
83d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.clear();
8413ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    mShaper->purgeCaches();
85d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
86d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
87d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/*
88d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Caching
89d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
90a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
915c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
92d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    AutoMutex _l(mLock);
93d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    nsecs_t startTime = 0;
94d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    if (mDebugEnabled) {
95d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        startTime = systemTime(SYSTEM_TIME_MONOTONIC);
96d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
97d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
98fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Create the key
995c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
100d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
101fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Get value from cache if possible
102a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value = mCache.get(key);
103d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
104fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Value not found for the key, we need to add a new value in the cache
105fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    if (value == NULL) {
106010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio        if (mDebugEnabled) {
107010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio            startTime = systemTime(SYSTEM_TIME_MONOTONIC);
108010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio        }
109010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio
110a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        value = new TextLayoutValue(contextCount);
111d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
112d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        // Compute advances and store them
113a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        mShaper->computeValues(value.get(), paint,
114832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                reinterpret_cast<const UChar*>(key.getText()), start, count,
1150af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio                size_t(contextCount), int(dirFlags));
116d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
11706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown        if (mDebugEnabled) {
11806daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
11906daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown        }
120010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio
121d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        // Don't bother to add in the cache if the entry is too big
1221de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio        size_t size = key.getSize() + value->getSize();
123d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        if (size <= mMaxSize) {
124d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            // Cleanup to make some room if needed
125d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mSize + size > mMaxSize) {
126d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                if (mDebugEnabled) {
1275baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("Need to clean some entries for making some room for a new entry");
128d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                }
129d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                while (mSize + size > mMaxSize) {
130d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                    // This will call the callback
131d9e688cab3015d858110fb8240cf7378c6befd82Jeff Brown                    bool removedOne = mCache.removeOldest();
13206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    LOG_ALWAYS_FATAL_IF(!removedOne, "The cache is non-empty but we "
13306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                            "failed to remove the oldest entry.  "
13456e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                            "mSize = %u, size = %u, mMaxSize = %u, mCache.size() = %u",
13506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                            mSize, size, mMaxSize, mCache.size());
136d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                }
137d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
138d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
139d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            // Update current cache size
140d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            mSize += size;
141d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
14206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            bool putOne = mCache.put(key, value);
14306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            LOG_ALWAYS_FATAL_IF(!putOne, "Failed to put an entry into the cache.  "
14406daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    "This indicates that the cache already has an entry with the "
14506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    "same key but it should not since we checked earlier!"
14656e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                    " - start = %d, count = %d, contextCount = %d - Text = '%s'",
147832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                    start, count, contextCount, String8(key.getText() + start, count).string());
148d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
14906daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            if (mDebugEnabled) {
15006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                nsecs_t totalTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
1515baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE MISS: Added entry %p "
15256e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "with start = %d, count = %d, contextCount = %d, "
15306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        "entry size %d bytes, remaining space %d bytes"
15456e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        " - Compute time %0.6f ms - Put time %0.6f ms - Text = '%s'",
15506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value.get(), start, count, contextCount, size, mMaxSize - mSize,
15606daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
15706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        (totalTime - value->getElapsedTime()) * 0.000001f,
158832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
159d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
160d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        } else {
161d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mDebugEnabled) {
1625baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE MISS: Calculated but not storing entry because it is too big "
16356e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "with start = %d, count = %d, contextCount = %d, "
164d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                        "entry size %d bytes, remaining space %d bytes"
16556e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        " - Compute time %0.6f ms - Text = '%s'",
16606daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        start, count, contextCount, size, mMaxSize - mSize,
16706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
168832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
169d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
170d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        }
171d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    } else {
172fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio        // This is a cache hit, just log timestamp and user infos
173d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        if (mDebugEnabled) {
174d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            nsecs_t elapsedTimeThruCacheGet = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
1751de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio            mNanosecondsSaved += (value->getElapsedTime() - elapsedTimeThruCacheGet);
176d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            ++mCacheHitCount;
177d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
1781de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio            if (value->getElapsedTime() > 0) {
1791de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio                float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet)
1801de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio                        / ((float)value->getElapsedTime()));
1815baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE HIT #%d with start = %d, count = %d, contextCount = %d"
18206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        "- Compute time %0.6f ms - "
18356e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "Cache get time %0.6f ms - Gain in percent: %2.2f - Text = '%s'",
1845c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                        mCacheHitCount, start, count, contextCount,
18506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
18606daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        elapsedTimeThruCacheGet * 0.000001f,
18706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        deltaPercent,
188832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
189d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
190d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) {
191d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                dumpCacheStats();
192d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
193d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        }
194d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
195fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    return value;
196d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
197d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
198d313c665e618af3194f504064bcd284fe5368682Fabrice Di Megliovoid TextLayoutCache::dumpCacheStats() {
199d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));
200d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / 1000000000;
20106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown
20206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    size_t bytes = 0;
20306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    size_t cacheSize = mCache.size();
20406daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    for (size_t i = 0; i < cacheSize; i++) {
20506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown        bytes += mCache.getKeyAt(i).getSize() + mCache.getValueAt(i)->getSize();
20606daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    }
20706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown
2085baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
2095baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Cache stats");
2105baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
2115baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("pid       : %d", getpid());
2125baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("running   : %.0f seconds", timeRunningInSec);
2135baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("entries   : %d", cacheSize);
2145baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("max size  : %d bytes", mMaxSize);
2155baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("used      : %d bytes according to mSize, %d bytes actual", mSize, bytes);
2165baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("remaining : %d bytes or %2.2f percent", mMaxSize - mSize, remainingPercent);
2175baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("hits      : %d", mCacheHitCount);
2185baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("saved     : %0.6f ms", mNanosecondsSaved * 0.000001f);
2195baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
220d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
221d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
22248796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio/**
22348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio * TextLayoutCacheKey
22448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio */
225832815cb53e951485ff5a0e6c705446d0bfb5883Raph LevienTextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
22648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
227ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett        hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
22848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
22948796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
2305c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di MeglioTextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
2315c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags) :
232832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien            start(start), count(count), contextCount(contextCount),
23348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio            dirFlags(dirFlags) {
234832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien    textCopy.setTo(text, contextCount);
23548796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    typeface = paint->getTypeface();
23648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textSize = paint->getTextSize();
23748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textSkewX = paint->getTextSkewX();
23848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textScaleX = paint->getTextScaleX();
23948796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    flags = paint->getFlags();
24048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    hinting = paint->getHinting();
241ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    variant = paint->getFontVariant();
242ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    language = paint->getLanguage();
24348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
24448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
245e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di MeglioTextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
246e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textCopy(other.textCopy),
2475c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        start(other.start),
2487aac2979605f4811cf096f7c62d363381c68f6b2Jeff Brown        count(other.count),
2495c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        contextCount(other.contextCount),
250e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        dirFlags(other.dirFlags),
251e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        typeface(other.typeface),
252e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textSize(other.textSize),
253e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textSkewX(other.textSkewX),
254e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textScaleX(other.textScaleX),
255e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        flags(other.flags),
256ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett        hinting(other.hinting),
257ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett        variant(other.variant),
258ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett        language(other.language) {
259e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio}
260e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio
261717060b076350ea811153290281075396a554fedFabrice Di Meglioint TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
2625c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    int deltaInt = lhs.start - rhs.start;
2635c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
2645c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
2655c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    deltaInt = lhs.count - rhs.count;
2665c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
2675c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
2685c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    deltaInt = lhs.contextCount - rhs.contextCount;
269717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
270717060b076350ea811153290281075396a554fedFabrice Di Meglio
271717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.typeface < rhs.typeface) return -1;
272717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.typeface > rhs.typeface) return +1;
273717060b076350ea811153290281075396a554fedFabrice Di Meglio
274717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSize < rhs.textSize) return -1;
275717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSize > rhs.textSize) return +1;
276717060b076350ea811153290281075396a554fedFabrice Di Meglio
277717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSkewX < rhs.textSkewX) return -1;
278717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSkewX > rhs.textSkewX) return +1;
279717060b076350ea811153290281075396a554fedFabrice Di Meglio
280717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textScaleX < rhs.textScaleX) return -1;
281717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textScaleX > rhs.textScaleX) return +1;
282717060b076350ea811153290281075396a554fedFabrice Di Meglio
283717060b076350ea811153290281075396a554fedFabrice Di Meglio    deltaInt = lhs.flags - rhs.flags;
284717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
285717060b076350ea811153290281075396a554fedFabrice Di Meglio
286717060b076350ea811153290281075396a554fedFabrice Di Meglio    deltaInt = lhs.hinting - rhs.hinting;
287717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
288717060b076350ea811153290281075396a554fedFabrice Di Meglio
289717060b076350ea811153290281075396a554fedFabrice Di Meglio    deltaInt = lhs.dirFlags - rhs.dirFlags;
290717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt) return (deltaInt);
291717060b076350ea811153290281075396a554fedFabrice Di Meglio
292ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    deltaInt = lhs.variant - rhs.variant;
293ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    if (deltaInt) return (deltaInt);
294ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett
295ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    if (lhs.language < rhs.language) return -1;
296ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    if (lhs.language > rhs.language) return +1;
297ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett
2985c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
29948796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
30048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
30106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brownsize_t TextLayoutCacheKey::getSize() const {
3025c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount;
30348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
30448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
30548796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio/**
30648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio * TextLayoutCacheValue
30748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio */
308a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutValue::TextLayoutValue(size_t contextCount) :
3094dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio        mTotalAdvance(0), mElapsedTime(0) {
3100af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Give a hint for advances and glyphs vectors size
3110af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mAdvances.setCapacity(contextCount);
3120af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mGlyphs.setCapacity(contextCount);
3132301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mPos.setCapacity(contextCount * 2);
3140af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
3150af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
316a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosize_t TextLayoutValue::getSize() const {
317a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
3182301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            sizeof(jchar) * mGlyphs.capacity() + sizeof(jfloat) * mPos.capacity();
31948796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
32048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
321a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutValue::setElapsedTime(uint32_t time) {
322fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    mElapsedTime = time;
32348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
32448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
325a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliouint32_t TextLayoutValue::getElapsedTime() {
326fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    return mElapsedTime;
32748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
32848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
329a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) {
33015cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    init();
33148796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
3320af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mFontRec.klass = &harfbuzzSkiaClass;
3330af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mFontRec.userData = 0;
3345c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
3352301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    // Note that the scaling values (x_ and y_ppem, x_ and y_scale) will be set
3362301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    // below, when the paint transform and em unit of the actual shaping font
3372301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    // are known.
3385c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
3390af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    memset(&mShaperItem, 0, sizeof(mShaperItem));
34048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
3410af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.font = &mFontRec;
3420af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.font->userData = &mShapingPaint;
3435c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio}
34448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
34515cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Megliovoid TextLayoutShaper::init() {
34615cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
34715cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio}
34815cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio
34915cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Megliovoid TextLayoutShaper::unrefTypefaces() {
350a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    SkSafeUnref(mDefaultTypeface);
35115cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio}
35215cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio
35315cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di MeglioTextLayoutShaper::~TextLayoutShaper() {
35415cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    unrefTypefaces();
355a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    deleteShaperItemGlyphArrays();
35648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
35748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
358a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
3590af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags) {
360ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
36156e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio    computeValues(paint, chars, start, count, contextCount, dirFlags,
3622301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
3630af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#if DEBUG_ADVANCES
3645baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
3655448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio            contextCount, value->mTotalAdvance);
366a4f5aa87c73de7a2581dc4dd72e0f90ccea79a18Fabrice Di Meglio#endif
367208d4592f6e8db90eab30cfca3dc294731258d1cFabrice Di Meglio}
368208d4592f6e8db90eab30cfca3dc294731258d1cFabrice Di Meglio
369a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
3705c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags,
3714dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
3722301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
3732301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        *outTotalAdvance = 0;
374a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        if (!count) {
375a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown            return;
376a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        }
377689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
378689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        UBiDiLevel bidiReq = 0;
379689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        bool forceLTR = false;
380689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        bool forceRTL = false;
381689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
382689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        switch (dirFlags) {
383689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
384689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
385689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
386689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
387689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
388689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
389689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        }
390689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
3915beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        bool useSingleRun = false;
3925beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        bool isRTL = forceRTL;
393689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        if (forceLTR || forceRTL) {
3945beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio            useSingleRun = true;
395689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        } else {
396689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            UBiDi* bidi = ubidi_open();
397689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio            if (bidi) {
398689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                UErrorCode status = U_ZERO_ERROR;
39906732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#if DEBUG_GLYPHS
4005baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("******** ComputeValues -- start");
4015baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
4025baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("      -- start = %d", start);
4035baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("      -- count = %d", count);
4045baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("      -- contextCount = %d", contextCount);
4055baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("      -- bidiReq = %d", bidiReq);
40606732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#endif
407689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
408689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                if (U_SUCCESS(status)) {
409689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
4105beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                    ssize_t rc = ubidi_countRuns(bidi, &status);
411689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#if DEBUG_GLYPHS
4125baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("      -- dirFlags = %d", dirFlags);
4135baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("      -- paraDir = %d", paraDir);
4145baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("      -- run-count = %d", int(rc));
415689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#endif
416bcf05a69090f342d328f1537d1d83406b883290bFabrice Di Meglio                    if (U_SUCCESS(status) && rc == 1) {
417bcf05a69090f342d328f1537d1d83406b883290bFabrice Di Meglio                        // Normal case: one run, status is ok
418bcf05a69090f342d328f1537d1d83406b883290bFabrice Di Meglio                        isRTL = (paraDir == 1);
419bcf05a69090f342d328f1537d1d83406b883290bFabrice Di Meglio                        useSingleRun = true;
420bcf05a69090f342d328f1537d1d83406b883290bFabrice Di Meglio                    } else if (!U_SUCCESS(status) || rc < 1) {
4218564c8da817a845353d213acd8636b76f567b234Steve Block                        ALOGW("Need to force to single run -- string = '%s',"
42256e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                                " status = %d, rc = %d",
423738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown                                String8(chars + start, count).string(), status, int(rc));
4245beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                        isRTL = (paraDir == 1);
4255beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                        useSingleRun = true;
426589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio                    } else {
4275c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                        int32_t end = start + count;
4285beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                        for (size_t i = 0; i < size_t(rc); ++i) {
4295beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            int32_t startRun = -1;
4305beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            int32_t lengthRun = -1;
431589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
432589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio
4335beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            if (startRun == -1 || lengthRun == -1) {
4345beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                // Something went wrong when getting the visual run, need to clear
4355beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                // already computed data before doing a single run pass
4368564c8da817a845353d213acd8636b76f567b234Steve Block                                ALOGW("Visual run is not valid");
4375beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                outGlyphs->clear();
4385beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                outAdvances->clear();
4392301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                                outPos->clear();
4405beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                *outTotalAdvance = 0;
4415beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                isRTL = (paraDir == 1);
4425beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                useSingleRun = true;
4435beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                break;
4445beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            }
4455beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio
4465c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            if (startRun >= end) {
4475c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                                continue;
4485c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            }
4495c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            int32_t endRun = startRun + lengthRun;
4505beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            if (endRun <= int32_t(start)) {
4515c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                                continue;
4525c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            }
4535beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            if (startRun < int32_t(start)) {
4545beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                                startRun = int32_t(start);
4555c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            }
4565c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            if (endRun > end) {
4575c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                                endRun = end;
4585c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            }
4595c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
4605c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                            lengthRun = endRun - startRun;
4615beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                            isRTL = (runDir == UBIDI_RTL);
462689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#if DEBUG_GLYPHS
4635baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
46456e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                                    i, startRun, lengthRun, isRTL);
465689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#endif
46656e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                            computeRunValues(paint, chars + startRun, lengthRun, isRTL,
4672301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
468689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
469689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                        }
470689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                    }
4715beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                } else {
4728564c8da817a845353d213acd8636b76f567b234Steve Block                    ALOGW("Cannot set Para");
4735beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                    useSingleRun = true;
4745beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
475689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                }
476689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                ubidi_close(bidi);
477589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio            } else {
4788564c8da817a845353d213acd8636b76f567b234Steve Block                ALOGW("Cannot ubidi_open()");
4795beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                useSingleRun = true;
4805beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
4815beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio            }
4825beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        }
4835beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio
4845beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        // Default single run case
4855beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        if (useSingleRun){
486589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#if DEBUG_GLYPHS
4875baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Using a SINGLE BiDi Run "
48856e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                    "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
489589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#endif
49056e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio            computeRunValues(paint, chars + start, count, isRTL,
4912301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                    outAdvances, outTotalAdvance, outGlyphs, outPos);
492689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        }
4935c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
494589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#if DEBUG_GLYPHS
4955baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("      -- Total returned glyphs-count = %d", outGlyphs->size());
4965baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("******** ComputeValues -- end");
497589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#endif
498689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio}
499689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
500abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Megliostatic void logGlyphs(HB_ShaperItem shaperItem) {
5015baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("         -- glyphs count=%d", shaperItem.num_glyphs);
502abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio    for (size_t i = 0; i < shaperItem.num_glyphs; i++) {
5035baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- glyph[%d] = %d, offset.x = %0.2f, offset.y = %0.2f", i,
504902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                shaperItem.glyphs[i],
505abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio                HBFixedToFloat(shaperItem.offsets[i].x),
506abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio                HBFixedToFloat(shaperItem.offsets[i].y));
507abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio    }
508abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio}
509abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio
510a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars,
511ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio        size_t count, bool isRTL,
5124dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
5132301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
514a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown    if (!count) {
515a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        // We cannot shape an empty run.
516a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        return;
517a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown    }
518ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
51957e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    // To be filled in later
52057e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    for (size_t i = 0; i < count; i++) {
52157e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien        outAdvances->add(0);
52257e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    }
523902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    UErrorCode error = U_ZERO_ERROR;
524902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    bool useNormalizedString = false;
525902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    for (ssize_t i = count - 1; i >= 0; --i) {
526902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio        UChar ch1 = chars[i];
527902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio        if (::ublock_getCode(ch1) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
528902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            // So we have found a diacritic, let's get now the main code point which is paired
529902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            // with it. As we can have several diacritics in a row, we need to iterate back again
530902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#if DEBUG_GLYPHS
5315baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("The BiDi run '%s' is containing a Diacritic at position %d",
532902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    String8(chars, count).string(), int(i));
533902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#endif
534902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            ssize_t j = i - 1;
535902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            for (; j >= 0;  --j) {
536902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                UChar ch2 = chars[j];
537902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                if (::ublock_getCode(ch2) != UBLOCK_COMBINING_DIACRITICAL_MARKS) {
538902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    break;
539902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                }
540902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            }
541902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
542902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            // We could not found the main code point, so we will just use the initial chars
543902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            if (j < 0) {
544902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                break;
545902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            }
546902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
547902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#if DEBUG_GLYPHS
5485baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Found main code point at index %d", int(j));
549902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#endif
5503632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio            // We found the main code point, so we can normalize the "chunk" and fill
551902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            // the remaining with ZWSP so that the Paint.getTextWidth() APIs will still be able
552902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            // to get one advance per char
553902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            mBuffer.remove();
554902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            Normalizer::normalize(UnicodeString(chars + j, i - j + 1),
555902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    UNORM_NFC, 0 /* no options */, mBuffer, error);
556902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            if (U_SUCCESS(error)) {
557902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                if (!useNormalizedString) {
558902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    useNormalizedString = true;
559902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mNormalizedString.setTo(false /* not terminated*/, chars, count);
560902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                }
561902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                // Set the normalized chars
562902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                for (ssize_t k = j; k < j + mBuffer.length(); ++k) {
563902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mNormalizedString.setCharAt(k, mBuffer.charAt(k - j));
564902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                }
565902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                // Fill the remain part with ZWSP (ZWNJ and ZWJ would lead to weird results
566902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                // because some fonts are missing those glyphs)
567902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                for (ssize_t k = j + mBuffer.length(); k <= i; ++k) {
568902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mNormalizedString.setCharAt(k, UNICODE_ZWSP);
569902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                }
570902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            }
571902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            i = j - 1;
572902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio        }
573902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    }
574902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
575ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    // Reverse "BiDi mirrored chars" in RTL mode only
576ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    // See: http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt
577ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    // This is a workaround because Harfbuzz is not able to do mirroring in all cases and
578ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    // script-run splitting with Harfbuzz is splitting on parenthesis
579ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    if (isRTL) {
580ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio        for (ssize_t i = 0; i < ssize_t(count); i++) {
5813632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio            UChar32 ch = chars[i];
5823632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio            if (!u_isMirrored(ch)) continue;
583ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio            if (!useNormalizedString) {
584ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio                useNormalizedString = true;
585ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio                mNormalizedString.setTo(false /* not terminated*/, chars, count);
586ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio            }
5873632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio            UChar result =  (UChar) u_charMirror(ch);
588ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio            mNormalizedString.setCharAt(i, result);
589ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio#if DEBUG_GLYPHS
590ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio            ALOGD("Rewriting codepoint '%d' to '%d' at position %d",
591ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio                    ch, mNormalizedString[i], int(i));
592ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio#endif
593ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio        }
594ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio    }
595ab8c73882e0c572f42a5c73ebabf18706b8cc7b6Fabrice Di Meglio
596902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#if DEBUG_GLYPHS
597902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    if (useNormalizedString) {
5985baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Will use normalized string '%s', length = %d",
599902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    String8(mNormalizedString.getTerminatedBuffer(),
600902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                            mNormalizedString.length()).string(),
601902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mNormalizedString.length());
602902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    } else {
6035baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Normalization is not needed or cannot be done, using initial string");
604902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    }
605902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#endif
606902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
607902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    assert(mNormalizedString.length() == count);
608902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
6090af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Set the string properties
610902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    mShaperItem.string = useNormalizedString ? mNormalizedString.getTerminatedBuffer() : chars;
6110af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.stringLength = count;
6120af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
6130af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Define shaping paint properties
6140af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setTextSize(paint->getTextSize());
6152301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    float skewX = paint->getTextSkewX();
6162301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mShapingPaint.setTextSkewX(skewX);
6170af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setTextScaleX(paint->getTextScaleX());
6180af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setFlags(paint->getFlags());
6190af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setHinting(paint->getHinting());
620ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    mShapingPaint.setFontVariant(paint->getFontVariant());
621ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett    mShapingPaint.setLanguage(paint->getLanguage());
6220af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
6230af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
6240af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // into the shaperItem
625902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio    ssize_t indexFontRun = isRTL ? mShaperItem.stringLength - 1 : 0;
6260af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    unsigned numCodePoints = 0;
6272301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    jfloat totalAdvance = *outTotalAdvance;
6280af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    while ((isRTL) ?
629902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, mShaperItem.string,
630902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mShaperItem.stringLength, &indexFontRun):
631902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio            hb_utf16_script_run_next(&numCodePoints, &mShaperItem.item, mShaperItem.string,
632902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio                    mShaperItem.stringLength, &indexFontRun)) {
633ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
63456e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio        ssize_t startScriptRun = mShaperItem.item.pos;
63556e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio        size_t countScriptRun = mShaperItem.item.length;
63656e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio        ssize_t endScriptRun = startScriptRun + countScriptRun;
637ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
638ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#if DEBUG_GLYPHS
6395baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("-------- Start of Script Run --------");
6405baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Shaping Script Run with");
6415baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- isRTL = %d", isRTL);
6425baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- HB script = %d", mShaperItem.item.script);
6435baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- startFontRun = %d", int(startScriptRun));
6445baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- endFontRun = %d", int(endScriptRun));
6455baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- countFontRun = %d", countScriptRun);
6465baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- run = '%s'", String8(chars + startScriptRun, countScriptRun).string());
6475baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- string = '%s'", String8(chars, count).string());
648ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#endif
649ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
6500af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // Initialize Harfbuzz Shaper and get the base glyph count for offsetting the glyphIDs
6510af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // and shape the Font run
6520af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        size_t glyphBaseCount = shapeFontRun(paint, isRTL);
65348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
6549c418dbc56efd334c68872d281f75138e16eae46Fabrice Di Meglio#if DEBUG_GLYPHS
6555baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Got from Harfbuzz");
6565baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- glyphBaseCount = %d", glyphBaseCount);
6575baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- num_glypth = %d", mShaperItem.num_glyphs);
6585baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- kerning_applied = %d", mShaperItem.kerning_applied);
6595baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- isDevKernText = %d", paint->isDevKernText());
660abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio
6610af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        logGlyphs(mShaperItem);
662ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#endif
66348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
6640af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        if (mShaperItem.advances == NULL || mShaperItem.num_glyphs == 0) {
66578b868ff42cc368c45f851443678a822560dc266Fabrice Di Meglio#if DEBUG_GLYPHS
6665baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Advances array is empty or num_glypth = 0");
66778b868ff42cc368c45f851443678a822560dc266Fabrice Di Meglio#endif
668ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio            continue;
669ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio        }
6704dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio
67103e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio#if DEBUG_GLYPHS
67203e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio        ALOGD("Returned logclusters");
67303e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio        for (size_t i = 0; i < mShaperItem.num_glyphs; i++) {
67403e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio            ALOGD("         -- lc[%d] = %d, hb-adv[%d] = %0.2f", i, mShaperItem.log_clusters[i],
67503e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio                    i, HBFixedToFloat(mShaperItem.advances[i]));
67603e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio        }
67703e250aefa29387f30a01243682eab2371103f8eFabrice Di Meglio#endif
6781b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien        jfloat totalFontRunAdvance = 0;
6791b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien        size_t clusterStart = 0;
6801b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien        for (size_t i = 0; i < countScriptRun; i++) {
6810af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio            size_t cluster = mShaperItem.log_clusters[i];
6821b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien            size_t clusterNext = i == countScriptRun - 1 ? mShaperItem.num_glyphs :
6831b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                mShaperItem.log_clusters[i + 1];
6841b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien            if (cluster != clusterNext) {
6851b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                jfloat advance = 0;
6861b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                // The advance for the cluster is the sum of the advances of all glyphs within
6871b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                // the cluster.
6881b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                for (size_t j = cluster; j < clusterNext; j++) {
6891b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                    advance += HBFixedToFloat(mShaperItem.advances[j]);
6901b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                }
6911b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                totalFontRunAdvance += advance;
6921b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                outAdvances->replaceAt(advance, startScriptRun + clusterStart);
6931b10241a8f0affab9f46719e46c6fedff9e69b8bRaph Levien                clusterStart = i + 1;
694ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio            }
69506732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio        }
696fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio
69706732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#if DEBUG_ADVANCES
6985baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Returned advances");
69956e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio        for (size_t i = 0; i < countScriptRun; i++) {
7005baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("         -- hb-adv[%d] = %0.2f, log_clusters = %d, total = %0.2f", i,
7015448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio                    (*outAdvances)[i], mShaperItem.log_clusters[i], totalFontRunAdvance);
702ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio        }
70306732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#endif
70457e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien
705ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio        // Get Glyphs and reverse them in place if RTL
706ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio        if (outGlyphs) {
7070af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio            size_t countGlyphs = mShaperItem.num_glyphs;
70856e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#if DEBUG_GLYPHS
7095baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Returned script run glyphs -- count = %d", countGlyphs);
71056e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#endif
711ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio            for (size_t i = 0; i < countGlyphs; i++) {
712ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio                jchar glyph = glyphBaseCount +
7130af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio                        (jchar) mShaperItem.glyphs[(!isRTL) ? i : countGlyphs - 1 - i];
7144dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio#if DEBUG_GLYPHS
7155baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("         -- glyph[%d] = %d", i, glyph);
7164dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio#endif
717ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio                outGlyphs->add(glyph);
718ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio            }
719fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio        }
7202301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien
7212301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        // Get glyph positions (and reverse them in place if RTL)
7222301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        if (outPos) {
7232301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            size_t countGlyphs = mShaperItem.num_glyphs;
7242301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            jfloat x = totalAdvance;
7252301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            for (size_t i = 0; i < countGlyphs; i++) {
7262301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                size_t index = (!isRTL) ? i : countGlyphs - 1 - i;
7272301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                float xo = HBFixedToFloat(mShaperItem.offsets[index].x);
7282301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                float yo = HBFixedToFloat(mShaperItem.offsets[index].y);
7292301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                // Apply skewX component of transform to position offsets. Note
7302301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                // that scale has already been applied through x_ and y_scale
7312301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                // set in the mFontRec.
7322301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                outPos->add(x + xo + yo * skewX);
7332301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                outPos->add(yo);
7344f3c8f7026d89a5d79e2621eb6428d5b9b1a25f3Raph Levien#if DEBUG_GLYPHS
7352301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                ALOGD("         -- hb adv[%d] = %f, log_cluster[%d] = %d",
7362301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                        index, HBFixedToFloat(mShaperItem.advances[index]),
7372301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                        index, mShaperItem.log_clusters[index]);
7382301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien#endif
7392301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien                x += HBFixedToFloat(mShaperItem.advances[index]);
7402301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            }
7412301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        }
7422301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien
7432301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        totalAdvance += totalFontRunAdvance;
744fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    }
7455448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio
746ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio    *outTotalAdvance = totalAdvance;
7475448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio
74856e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#if DEBUG_GLYPHS
7495baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("-------- End of Script Run --------");
75056e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#endif
75179df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio}
75279df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio
7531637dcd16cd314574a58602337a2c7222130b1b9Raph Levien/**
7541637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * Return the first typeface in the logical change, starting with this typeface,
7551637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * that contains the specified unichar, or NULL if none is found.
7561637dcd16cd314574a58602337a2c7222130b1b9Raph Levien *
7571637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * Note that this function does _not_ increment the reference count on the typeface, as the
7581637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * assumption is that its lifetime is managed elsewhere - in particular, the fallback typefaces
7591637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * for the default font live in a global cache.
7601637dcd16cd314574a58602337a2c7222130b1b9Raph Levien */
761d6deccb346e913d906f484d279b19e0f6ea18d94Billy HewlettSkTypeface* TextLayoutShaper::typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
762d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        HB_Script script) {
763d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    SkTypeface::Style currentStyle = SkTypeface::kNormal;
764d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    if (typeface) {
765d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        currentStyle = typeface->style();
766d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    }
767d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    typeface = SkCreateTypefaceForScript(script, currentStyle);
7686162876067cbaa93b870aee6e62c682104935fdeFabrice Di Meglio#if DEBUG_GLYPHS
769d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    ALOGD("Using Harfbuzz Script %d, Style %d", script, currentStyle);
7706162876067cbaa93b870aee6e62c682104935fdeFabrice Di Meglio#endif
771d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    return typeface;
772d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett}
773ff40ab7a418dd06cfe4758ceda17a775f2d4c776Fabrice Di Meglio
774d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlettbool TextLayoutShaper::isComplexScript(HB_Script script) {
775d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    switch (script) {
776d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    case HB_Script_Common:
777d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    case HB_Script_Greek:
778d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    case HB_Script_Cyrillic:
779d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    case HB_Script_Hangul:
780d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    case HB_Script_Inherited:
781d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        return false;
7820af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    default:
783d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        return true;
7840af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
7851637dcd16cd314574a58602337a2c7222130b1b9Raph Levien}
7860af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
7871637dcd16cd314574a58602337a2c7222130b1b9Raph Leviensize_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
7881637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    // Reset kerning
7891637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    mShaperItem.kerning_applied = false;
7900af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
7911637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    // Update Harfbuzz Shaper
7921637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    mShaperItem.item.bidiLevel = isRTL;
7931637dcd16cd314574a58602337a2c7222130b1b9Raph Levien
7941637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    SkTypeface* typeface = paint->getTypeface();
7950af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
7960af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Get the glyphs base count for offsetting the glyphIDs returned by Harfbuzz
7970af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // This is needed as the Typeface used for shaping can be not the default one
7980af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // when we are shaping any script that needs to use a fallback Font.
7990af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // If we are a "common" script we dont need to shift
8000af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    size_t baseGlyphCount = 0;
8011637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    SkUnichar firstUnichar = 0;
802d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    if (isComplexScript(mShaperItem.item.script)) {
803d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        const uint16_t* text16 = (const uint16_t*) (mShaperItem.string + mShaperItem.item.pos);
804b294435b5c6e0fee8c431ed3f6d77427d3d79ddeRaph Levien        const uint16_t* text16End = text16 + mShaperItem.item.length;
8051637dcd16cd314574a58602337a2c7222130b1b9Raph Levien        firstUnichar = SkUTF16_NextUnichar(&text16);
806b294435b5c6e0fee8c431ed3f6d77427d3d79ddeRaph Levien        while (firstUnichar == ' ' && text16 < text16End) {
807b294435b5c6e0fee8c431ed3f6d77427d3d79ddeRaph Levien            firstUnichar = SkUTF16_NextUnichar(&text16);
808b294435b5c6e0fee8c431ed3f6d77427d3d79ddeRaph Levien        }
8090af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
8100af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
8110af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
8121637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    if (baseGlyphCount != 0) {
813d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        typeface = typefaceForScript(paint, typeface, mShaperItem.item.script);
814d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        if (!typeface) {
815d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett            typeface = mDefaultTypeface;
816d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett            SkSafeRef(typeface);
817d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett#if DEBUG_GLYPHS
818d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett            ALOGD("Using Default Typeface");
819d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett#endif
820d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        }
821d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    } else {
822d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        if (!typeface) {
823d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett            typeface = mDefaultTypeface;
8241637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#if DEBUG_GLYPHS
825d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett            ALOGD("Using Default Typeface");
8261637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#endif
827d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        }
828d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        SkSafeRef(typeface);
8291637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    }
830d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett
8311637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    mShapingPaint.setTypeface(typeface);
8321637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    mShaperItem.face = getCachedHBFace(typeface);
8331637dcd16cd314574a58602337a2c7222130b1b9Raph Levien
8342301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    int textSize = paint->getTextSize();
8352301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    float scaleX = paint->getTextScaleX();
8362301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mFontRec.x_ppem = floor(scaleX * textSize + 0.5);
8372301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mFontRec.y_ppem = textSize;
8382301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    uint32_t unitsPerEm = SkFontHost::GetUnitsPerEm(typeface->uniqueID());
8392301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    // x_ and y_scale are the conversion factors from font design space
8402301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    // (unitsPerEm) to 1/64th of device pixels in 16.16 format.
8412301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    const int kDevicePixelFraction = 64;
8422301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    const int kMultiplyFor16Dot16 = 1 << 16;
8432301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    float emScale = kDevicePixelFraction * kMultiplyFor16Dot16 / (float)unitsPerEm;
8442301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mFontRec.x_scale = emScale * scaleX * textSize;
8452301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mFontRec.y_scale = emScale * textSize;
8462301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien
8471637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#if DEBUG_GLYPHS
8481637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    ALOGD("Run typeface = %p, uniqueID = %d, hb_face = %p",
8491637dcd16cd314574a58602337a2c7222130b1b9Raph Levien            typeface, typeface->uniqueID(), mShaperItem.face);
8501637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#endif
851d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    SkSafeUnref(typeface);
8521637dcd16cd314574a58602337a2c7222130b1b9Raph Levien
8530af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Shape
854a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown    assert(mShaperItem.item.length > 0); // Harfbuzz will overwrite other memory if length is 0.
855f62034d89611fbd3e1d41413847241757acd0c10Raph Levien    size_t size = mShaperItem.item.length * 3 / 2;
856f62034d89611fbd3e1d41413847241757acd0c10Raph Levien    while (!doShaping(size)) {
8570af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // We overflowed our glyph arrays. Resize and retry.
8580af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
859f62034d89611fbd3e1d41413847241757acd0c10Raph Levien        size = mShaperItem.num_glyphs * 2;
8600af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
8610af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    return baseGlyphCount;
8620af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
8630af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
864f62034d89611fbd3e1d41413847241757acd0c10Raph Levienbool TextLayoutShaper::doShaping(size_t size) {
8650af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    if (size > mShaperItemGlyphArraySize) {
8660af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        deleteShaperItemGlyphArrays();
8670af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        createShaperItemGlyphArrays(size);
8680af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
869f62034d89611fbd3e1d41413847241757acd0c10Raph Levien    mShaperItem.num_glyphs = mShaperItemGlyphArraySize;
870f62034d89611fbd3e1d41413847241757acd0c10Raph Levien    memset(mShaperItem.offsets, 0, mShaperItem.num_glyphs * sizeof(HB_FixedPoint));
871f62034d89611fbd3e1d41413847241757acd0c10Raph Levien    return HB_ShapeItem(&mShaperItem);
87279df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio}
87379df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio
874a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::createShaperItemGlyphArrays(size_t size) {
875ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#if DEBUG_GLYPHS
8765baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Creating Glyph Arrays with size = %d", size);
877ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#endif
8780af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItemGlyphArraySize = size;
879738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown
880738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown    // These arrays are all indexed by glyph.
8810af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.glyphs = new HB_Glyph[size];
8820af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.attributes = new HB_GlyphAttributes[size];
8830af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.advances = new HB_Fixed[size];
8840af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShaperItem.offsets = new HB_FixedPoint[size];
885738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown
886738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown    // Although the log_clusters array is indexed by character, Harfbuzz expects that
887738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown    // it is big enough to hold one element per glyph.  So we allocate log_clusters along
888738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown    // with the other glyph arrays above.
889738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown    mShaperItem.log_clusters = new unsigned short[size];
8900af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
8910af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
892a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::deleteShaperItemGlyphArrays() {
8930af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    delete[] mShaperItem.glyphs;
8940af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    delete[] mShaperItem.attributes;
8950af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    delete[] mShaperItem.advances;
8960af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    delete[] mShaperItem.offsets;
8970af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    delete[] mShaperItem.log_clusters;
8980af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
8990af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
900a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioHB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) {
9010af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    SkFontID fontId = typeface->uniqueID();
9020af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    ssize_t index = mCachedHBFaces.indexOfKey(fontId);
9030af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    if (index >= 0) {
9040af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        return mCachedHBFaces.valueAt(index);
9050af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
9060af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    HB_Face face = HB_NewFace(typeface, harfbuzzSkiaGetTable);
9070af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    if (face) {
9080af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#if DEBUG_GLYPHS
9095baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Created HB_NewFace %p from paint typeface = %p", face, typeface);
9100af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#endif
9110af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        mCachedHBFaces.add(fontId, face);
9120af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
9130af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    return face;
91479df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio}
91548796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
91615cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Megliovoid TextLayoutShaper::purgeCaches() {
91775394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    size_t cacheSize = mCachedHBFaces.size();
91875394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    for (size_t i = 0; i < cacheSize; i++) {
91975394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien        HB_FreeFace(mCachedHBFaces.valueAt(i));
92075394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    }
92115cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    mCachedHBFaces.clear();
92215cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    unrefTypefaces();
92315cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    init();
92415cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio}
92515cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio
926a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutEngine::TextLayoutEngine() {
927a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mShaper = new TextLayoutShaper();
928a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
929a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mTextLayoutCache = new TextLayoutCache(mShaper);
930a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#else
931a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mTextLayoutCache = NULL;
932a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#endif
933a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
934a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
935a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutEngine::~TextLayoutEngine() {
936a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    delete mTextLayoutCache;
937a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    delete mShaper;
938a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
939a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
940a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
941a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        jint start, jint count, jint contextCount, jint dirFlags) {
942a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value;
943a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
944a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    value = mTextLayoutCache->getValue(paint, text, start, count,
945a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio            contextCount, dirFlags);
946a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    if (value == NULL) {
947a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
948a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio                String8(text + start, count).string());
949a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    }
950a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#else
951a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    value = new TextLayoutValue(count);
952a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mShaper->computeValues(value.get(), paint,
953a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
954a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#endif
955a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    return value;
956a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
957a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
95830ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Megliovoid TextLayoutEngine::purgeCaches() {
95930ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
96013ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    mTextLayoutCache->purgeCaches();
96115cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio#if DEBUG_GLYPHS
96215cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    ALOGD("Purged TextLayoutEngine caches");
96315cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio#endif
96430ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio#endif
96530ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio}
96630ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio
96730ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio
968d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio} // namespace android
969