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
19d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien#include <utils/JenkinsHash.h>
20d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien
21d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio#include "TextLayoutCache.h"
22689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#include "TextLayout.h"
23ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett#include "SkTypeface_android.h"
24aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#include "HarfBuzzNGFaceSkia.h"
25902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio#include <unicode/unistr.h>
263632b7f3ef0c6158507724a2496b24b457f3f007Fabrice Di Meglio#include <unicode/uchar.h>
27aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#include <hb-icu.h>
285de5b1a91e25ef4931661fdd089d7e0e2b7da035Fabrice Di Meglio
29d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglionamespace android {
30d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
31163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio//--------------------------------------------------------------------------------------------------
32ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
33a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
34b02d0ca5553300063e4332192632312600caf4b9Fabrice Di Meglio
35163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio//--------------------------------------------------------------------------------------------------
36163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio
37a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) :
38a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        mShaper(shaper),
39d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien        mCache(LruCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity),
40d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
41d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        mCacheHitCount(0), mNanosecondsSaved(0) {
42d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    init();
43d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
44d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
45d313c665e618af3194f504064bcd284fe5368682Fabrice Di MeglioTextLayoutCache::~TextLayoutCache() {
46d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.clear();
47d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
48d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
49d313c665e618af3194f504064bcd284fe5368682Fabrice Di Megliovoid TextLayoutCache::init() {
50d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.setOnEntryRemovedListener(this);
51d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
52d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mDebugLevel = readRtlDebugLevel();
53d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mDebugEnabled = mDebugLevel & kRtlDebugCaches;
545baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Using debug level = %d - Debug Enabled = %d", mDebugLevel, mDebugEnabled);
55d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
56d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCacheStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
579f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio
589f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio    if (mDebugEnabled) {
595baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Initialization is done - Start time = %lld", mCacheStartTime);
609f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio    }
619f82b580d744ce4baf057b061994394dcf239eedFabrice Di Meglio
62163268b3a8d4dd7e650e6c540f832bf60f6bf4c9Fabrice Di Meglio    mInitialized = true;
63d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
64d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
65d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/**
66d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio *  Callbacks
67d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
68a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) {
6906daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    size_t totalSizeToDelete = text.getSize() + desc->getSize();
7006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    mSize -= totalSizeToDelete;
7106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    if (mDebugEnabled) {
725baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Cache value %p deleted, size = %d", desc.get(), totalSizeToDelete);
73d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
74d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
75d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
76d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/*
77d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Cache clearing
78d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
7913ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levienvoid TextLayoutCache::purgeCaches() {
8013ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    AutoMutex _l(mLock);
81d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    mCache.clear();
8213ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    mShaper->purgeCaches();
83d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
84d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
85d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio/*
86d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio * Caching
87d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio */
88a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
89da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
90d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    AutoMutex _l(mLock);
91d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    nsecs_t startTime = 0;
92d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    if (mDebugEnabled) {
93d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        startTime = systemTime(SYSTEM_TIME_MONOTONIC);
94d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
95d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
96fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Create the key
97da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
98d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
99fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Get value from cache if possible
100a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value = mCache.get(key);
101d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
102fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    // Value not found for the key, we need to add a new value in the cache
103fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    if (value == NULL) {
104010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio        if (mDebugEnabled) {
105010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio            startTime = systemTime(SYSTEM_TIME_MONOTONIC);
106010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio        }
107010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio
108a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        value = new TextLayoutValue(contextCount);
109d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
110d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        // Compute advances and store them
111a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        mShaper->computeValues(value.get(), paint,
112832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                reinterpret_cast<const UChar*>(key.getText()), start, count,
113da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                size_t(contextCount), int(dirFlags));
114d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
11506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown        if (mDebugEnabled) {
11606daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
11706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown        }
118010d5c4e5ba7a229f621f08f5d1c5cbff7643402Fabrice Di Meglio
119d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        // Don't bother to add in the cache if the entry is too big
1201de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio        size_t size = key.getSize() + value->getSize();
121d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        if (size <= mMaxSize) {
122d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            // Cleanup to make some room if needed
123d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mSize + size > mMaxSize) {
124d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                if (mDebugEnabled) {
1255baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("Need to clean some entries for making some room for a new entry");
126d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                }
127d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                while (mSize + size > mMaxSize) {
128d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                    // This will call the callback
129d9e688cab3015d858110fb8240cf7378c6befd82Jeff Brown                    bool removedOne = mCache.removeOldest();
13006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    LOG_ALWAYS_FATAL_IF(!removedOne, "The cache is non-empty but we "
13106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                            "failed to remove the oldest entry.  "
13256e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                            "mSize = %u, size = %u, mMaxSize = %u, mCache.size() = %u",
13306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                            mSize, size, mMaxSize, mCache.size());
134d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                }
135d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
136d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
137d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            // Update current cache size
138d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            mSize += size;
139d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
14006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            bool putOne = mCache.put(key, value);
14106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            LOG_ALWAYS_FATAL_IF(!putOne, "Failed to put an entry into the cache.  "
14206daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    "This indicates that the cache already has an entry with the "
14306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                    "same key but it should not since we checked earlier!"
14456e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                    " - start = %d, count = %d, contextCount = %d - Text = '%s'",
145832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                    start, count, contextCount, String8(key.getText() + start, count).string());
146d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
14706daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown            if (mDebugEnabled) {
14806daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                nsecs_t totalTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
1495baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE MISS: Added entry %p "
15056e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "with start = %d, count = %d, contextCount = %d, "
15106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        "entry size %d bytes, remaining space %d bytes"
15256e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        " - Compute time %0.6f ms - Put time %0.6f ms - Text = '%s'",
15306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value.get(), start, count, contextCount, size, mMaxSize - mSize,
15406daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
15506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        (totalTime - value->getElapsedTime()) * 0.000001f,
156832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
157d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
158d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        } else {
159d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mDebugEnabled) {
1605baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE MISS: Calculated but not storing entry because it is too big "
16156e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "with start = %d, count = %d, contextCount = %d, "
162d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                        "entry size %d bytes, remaining space %d bytes"
16356e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        " - Compute time %0.6f ms - Text = '%s'",
16406daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        start, count, contextCount, size, mMaxSize - mSize,
16506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
166832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
167d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
168d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        }
169d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    } else {
170fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio        // This is a cache hit, just log timestamp and user infos
171d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        if (mDebugEnabled) {
172d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            nsecs_t elapsedTimeThruCacheGet = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
1731de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio            mNanosecondsSaved += (value->getElapsedTime() - elapsedTimeThruCacheGet);
174d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            ++mCacheHitCount;
175d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
1761de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio            if (value->getElapsedTime() > 0) {
1771de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio                float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet)
1781de9e7a9dffb4391a446000f748e4c017d948f6bFabrice Di Meglio                        / ((float)value->getElapsedTime()));
1795baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("CACHE HIT #%d with start = %d, count = %d, contextCount = %d"
18006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        "- Compute time %0.6f ms - "
18156e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                        "Cache get time %0.6f ms - Gain in percent: %2.2f - Text = '%s'",
1825c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio                        mCacheHitCount, start, count, contextCount,
18306daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        value->getElapsedTime() * 0.000001f,
18406daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        elapsedTimeThruCacheGet * 0.000001f,
18506daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown                        deltaPercent,
186832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien                        String8(key.getText() + start, count).string());
187d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
188d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) {
189d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio                dumpCacheStats();
190d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio            }
191d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio        }
192d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    }
193fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    return value;
194d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
195d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
196d313c665e618af3194f504064bcd284fe5368682Fabrice Di Megliovoid TextLayoutCache::dumpCacheStats() {
197d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    float remainingPercent = 100 * ((mMaxSize - mSize) / ((float)mMaxSize));
198d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    float timeRunningInSec = (systemTime(SYSTEM_TIME_MONOTONIC) - mCacheStartTime) / 1000000000;
19906daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown
20006daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown    size_t cacheSize = mCache.size();
20106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brown
2025baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
2035baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Cache stats");
2045baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
2055baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("pid       : %d", getpid());
2065baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("running   : %.0f seconds", timeRunningInSec);
2075baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("entries   : %d", cacheSize);
2085baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("max size  : %d bytes", mMaxSize);
209d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    ALOGD("used      : %d bytes according to mSize", mSize);
2105baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("remaining : %d bytes or %2.2f percent", mMaxSize - mSize, remainingPercent);
2115baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("hits      : %d", mCacheHitCount);
2125baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("saved     : %0.6f ms", mNanosecondsSaved * 0.000001f);
2135baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("------------------------------------------------");
214d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio}
215d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio
21648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio/**
21748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio * TextLayoutCacheKey
21848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio */
219832815cb53e951485ff5a0e6c705446d0bfb5883Raph LevienTextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
220da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
221d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger        hinting(SkPaint::kNo_Hinting) {
222d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger    paintOpts.setUseFontFallbacks(true);
22348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
22448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
2255c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di MeglioTextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
226da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags) :
227da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            start(start), count(count), contextCount(contextCount),
228da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            dirFlags(dirFlags) {
229832815cb53e951485ff5a0e6c705446d0bfb5883Raph Levien    textCopy.setTo(text, contextCount);
23048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    typeface = paint->getTypeface();
23148796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textSize = paint->getTextSize();
23248796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textSkewX = paint->getTextSkewX();
23348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    textScaleX = paint->getTextScaleX();
23448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    flags = paint->getFlags();
23548796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio    hinting = paint->getHinting();
236d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger    paintOpts = paint->getPaintOptionsAndroid();
23748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
23848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
239e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di MeglioTextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
240e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textCopy(other.textCopy),
2415c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        start(other.start),
2427aac2979605f4811cf096f7c62d363381c68f6b2Jeff Brown        count(other.count),
2435c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio        contextCount(other.contextCount),
244da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        dirFlags(other.dirFlags),
245e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        typeface(other.typeface),
246e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textSize(other.textSize),
247e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textSkewX(other.textSkewX),
248e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        textScaleX(other.textScaleX),
249e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio        flags(other.flags),
250ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett        hinting(other.hinting),
251d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger        paintOpts(other.paintOpts) {
252e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio}
253e74fef3b55dc1b5daf40b3a6aea857582071560fFabrice Di Meglio
254717060b076350ea811153290281075396a554fedFabrice Di Meglioint TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
2555c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    int deltaInt = lhs.start - rhs.start;
2565c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
2575c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
2585c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    deltaInt = lhs.count - rhs.count;
2595c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
2605c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
2615c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    deltaInt = lhs.contextCount - rhs.contextCount;
262717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
263717060b076350ea811153290281075396a554fedFabrice Di Meglio
264717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.typeface < rhs.typeface) return -1;
265717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.typeface > rhs.typeface) return +1;
266717060b076350ea811153290281075396a554fedFabrice Di Meglio
267717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSize < rhs.textSize) return -1;
268717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSize > rhs.textSize) return +1;
269717060b076350ea811153290281075396a554fedFabrice Di Meglio
270717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSkewX < rhs.textSkewX) return -1;
271717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textSkewX > rhs.textSkewX) return +1;
272717060b076350ea811153290281075396a554fedFabrice Di Meglio
273717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textScaleX < rhs.textScaleX) return -1;
274717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (lhs.textScaleX > rhs.textScaleX) return +1;
275717060b076350ea811153290281075396a554fedFabrice Di Meglio
276717060b076350ea811153290281075396a554fedFabrice Di Meglio    deltaInt = lhs.flags - rhs.flags;
277717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
278717060b076350ea811153290281075396a554fedFabrice Di Meglio
279717060b076350ea811153290281075396a554fedFabrice Di Meglio    deltaInt = lhs.hinting - rhs.hinting;
280717060b076350ea811153290281075396a554fedFabrice Di Meglio    if (deltaInt != 0) return (deltaInt);
281717060b076350ea811153290281075396a554fedFabrice Di Meglio
282da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio    deltaInt = lhs.dirFlags - rhs.dirFlags;
283da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio    if (deltaInt) return (deltaInt);
284da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio
285d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger    if (lhs.paintOpts != rhs.paintOpts)
286d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger        return memcmp(&lhs.paintOpts, &rhs.paintOpts, sizeof(SkPaintOptionsAndroid));
287ac1cbaf2e5575ac75a0160e13089d51a0bb232faBilly Hewlett
2885c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
28948796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
29048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
29106daa7b6b2186cf1e83e14d2adbb0d2050b79c39Jeff Brownsize_t TextLayoutCacheKey::getSize() const {
2925c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio    return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount;
29348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
29448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
295d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levienhash_t TextLayoutCacheKey::hash() const {
296d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    uint32_t hash = JenkinsHashMix(0, start);
297d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, count);
298d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    /* contextCount not needed because it's included in text, below */
299d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, hash_type(typeface));
300d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, hash_type(textSize));
301d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, hash_type(textSkewX));
302d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, hash_type(textScaleX));
303d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, flags);
304d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMix(hash, hinting);
305d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger    hash = JenkinsHashMix(hash, paintOpts.getFontVariant());
306d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    // Note: leaving out language is not problematic, as equality comparisons
307d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    // are still valid - the only bad thing that could happen is collisions.
308d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    hash = JenkinsHashMixShorts(hash, getText(), contextCount);
309d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien    return JenkinsHashWhiten(hash);
310d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien}
311d98efca7383f5f3cdae438a8a8a18f78451a95baRaph Levien
31248796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio/**
31348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio * TextLayoutCacheValue
31448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio */
315a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutValue::TextLayoutValue(size_t contextCount) :
3164dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio        mTotalAdvance(0), mElapsedTime(0) {
31741541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik    mBounds.setEmpty();
3180af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Give a hint for advances and glyphs vectors size
3190af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mAdvances.setCapacity(contextCount);
3200af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mGlyphs.setCapacity(contextCount);
3212301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mPos.setCapacity(contextCount * 2);
3220af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
3230af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
324a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosize_t TextLayoutValue::getSize() const {
325a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
3262301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien            sizeof(jchar) * mGlyphs.capacity() + sizeof(jfloat) * mPos.capacity();
32748796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
32848796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
329a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutValue::setElapsedTime(uint32_t time) {
330fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    mElapsedTime = time;
33148796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
33248796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
333a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliouint32_t TextLayoutValue::getElapsedTime() {
334fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    return mElapsedTime;
33548796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
33648796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
337aaedde51b76901ff05f2a2348eb41f0f5323d954Raph LevienTextLayoutShaper::TextLayoutShaper() {
338aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    mBuffer = hb_buffer_create();
3395c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio}
34048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
34115cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di MeglioTextLayoutShaper::~TextLayoutShaper() {
342aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_buffer_destroy(mBuffer);
34348796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio}
34448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
34541541825bc90dac740e424cdd41a8c997e15cdb7Chris Craikvoid TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint,
34641541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik        const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) {
347da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio    computeValues(paint, chars, start, count, contextCount, dirFlags,
34841541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            &value->mAdvances, &value->mTotalAdvance, &value->mBounds,
34941541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            &value->mGlyphs, &value->mPos);
3500af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#if DEBUG_ADVANCES
3515baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
3525448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio            contextCount, value->mTotalAdvance);
353a4f5aa87c73de7a2581dc4dd72e0f90ccea79a18Fabrice Di Meglio#endif
354208d4592f6e8db90eab30cfca3dc294731258d1cFabrice Di Meglio}
355208d4592f6e8db90eab30cfca3dc294731258d1cFabrice Di Meglio
356a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliovoid TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
357da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        size_t start, size_t count, size_t contextCount, int dirFlags,
35841541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
3592301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
3602301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        *outTotalAdvance = 0;
361a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        if (!count) {
362a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown            return;
363a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        }
364689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
365da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        UBiDiLevel bidiReq = 0;
366da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        bool forceLTR = false;
367da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        bool forceRTL = false;
368da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio
369da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        switch (dirFlags & kBidi_Mask) {
370da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
371da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
372da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
373da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
374da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
375da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
376da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        }
3776d9fe5bd22b531bfce69b146254a4791c76acddcFabrice Di Meglio
378da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        bool useSingleRun = false;
379da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        bool isRTL = forceRTL;
380da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        if (forceLTR || forceRTL) {
381da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            useSingleRun = true;
382da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        } else {
383da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            UBiDi* bidi = ubidi_open();
384da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            if (bidi) {
385da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                UErrorCode status = U_ZERO_ERROR;
38606732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#if DEBUG_GLYPHS
387da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("******** ComputeValues -- start");
388da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
389da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("      -- start = %d", start);
390da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("      -- count = %d", count);
391da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("      -- contextCount = %d", contextCount);
392da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGD("      -- bidiReq = %d", bidiReq);
39306732fde78b1caf8b5e6c0ef93357cfacedd1823Fabrice Di Meglio#endif
394da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
395da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                if (U_SUCCESS(status)) {
396da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
397da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    ssize_t rc = ubidi_countRuns(bidi, &status);
398689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#if DEBUG_GLYPHS
399da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    ALOGD("      -- dirFlags = %d", dirFlags);
400da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    ALOGD("      -- paraDir = %d", paraDir);
401da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    ALOGD("      -- run-count = %d", int(rc));
402689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#endif
403da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    if (U_SUCCESS(status) && rc == 1) {
404da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        // Normal case: one run, status is ok
405da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        isRTL = (paraDir == 1);
406da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        useSingleRun = true;
407da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    } else if (!U_SUCCESS(status) || rc < 1) {
408da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        ALOGW("Need to force to single run -- string = '%s',"
409da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                " status = %d, rc = %d",
410da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                String8(chars + start, count).string(), status, int(rc));
411da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        isRTL = (paraDir == 1);
412da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        useSingleRun = true;
413da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    } else {
414da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        int32_t end = start + count;
415da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        for (size_t i = 0; i < size_t(rc); ++i) {
416da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            int32_t startRun = -1;
417da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            int32_t lengthRun = -1;
418da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
419da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio
420da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            if (startRun == -1 || lengthRun == -1) {
421da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                // Something went wrong when getting the visual run, need to clear
422da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                // already computed data before doing a single run pass
423da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                ALOGW("Visual run is not valid");
424da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                outGlyphs->clear();
425da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                outAdvances->clear();
426da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                outPos->clear();
427da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                *outTotalAdvance = 0;
428da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                isRTL = (paraDir == 1);
429da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                useSingleRun = true;
430da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                break;
431da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            }
432da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio
433da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            if (startRun >= end) {
434da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                continue;
435da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            }
436da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            int32_t endRun = startRun + lengthRun;
437da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            if (endRun <= int32_t(start)) {
438da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                continue;
439da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            }
440da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            if (startRun < int32_t(start)) {
441da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                startRun = int32_t(start);
442da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            }
443da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            if (endRun > end) {
444da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                endRun = end;
445da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            }
446da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio
447da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            lengthRun = endRun - startRun;
448da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            isRTL = (runDir == UBIDI_RTL);
449689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#if DEBUG_GLYPHS
450da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
451da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                                    i, startRun, lengthRun, isRTL);
452689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio#endif
453da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
45441541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik                                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
455689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
456da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        }
457689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                    }
458da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                } else {
459da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    ALOGW("Cannot set Para");
460da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    useSingleRun = true;
461da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
462689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio                }
463da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ubidi_close(bidi);
464589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio            } else {
465da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                ALOGW("Cannot ubidi_open()");
4665beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                useSingleRun = true;
4675beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio                isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
4685beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio            }
4695beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        }
4705beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio
4715beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        // Default single run case
4725beeda08a7bd300ec22daaa9ae4e2d02a8c121adFabrice Di Meglio        if (useSingleRun){
473589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#if DEBUG_GLYPHS
4745baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Using a SINGLE BiDi Run "
47556e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio                    "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
476589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#endif
477aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            computeRunValues(paint, chars, start, count, contextCount, isRTL,
47841541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
479689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio        }
4805c863f741e8e484bb39decd516c9fa4c6322e671Fabrice Di Meglio
481589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#if DEBUG_GLYPHS
4825baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("      -- Total returned glyphs-count = %d", outGlyphs->size());
4835baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("******** ComputeValues -- end");
484589e4e27ee071f028a4bc72b91a1fb053ab13404Fabrice Di Meglio#endif
485689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio}
486689e515ed2b8064c15e54d8ab69d87de54c5e0d6Fabrice Di Meglio
487aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#define HB_IsHighSurrogate(ucs) \
488aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    (((ucs) & 0xfc00) == 0xd800)
489aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
490aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#define HB_IsLowSurrogate(ucs) \
491aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    (((ucs) & 0xfc00) == 0xdc00)
492aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
493aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#ifndef HB_SurrogateToUcs4
494aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#define HB_SurrogateToUcs4_(high, low) \
495aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    (((hb_codepoint_t)(high))<<10) + (low) - 0x35fdc00;
496aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#endif
497aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
498aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien#define HB_InvalidCodePoint ~0u
499aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
500aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_codepoint_t
501aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienutf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter) {
502aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const uint16_t v = chars[(*iter)++];
503aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (HB_IsHighSurrogate(v)) {
504aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    // surrogate pair
505aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (size_t(*iter) >= len) {
506aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      // the surrogate is incomplete.
507aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      return HB_InvalidCodePoint;
508aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
509aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const uint16_t v2 = chars[(*iter)++];
510aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (!HB_IsLowSurrogate(v2)) {
511aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      // invalidate surrogate pair.
512aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      (*iter)--;
513aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      return HB_InvalidCodePoint;
514aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
515aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
516aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return HB_SurrogateToUcs4(v, v2);
517aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
518aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
519aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (HB_IsLowSurrogate(v)) {
520aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    // this isn't a valid code point
521aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return HB_InvalidCodePoint;
522aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
523aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
524aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  return v;
525aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien}
526aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
527aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_codepoint_t
528aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienutf16_to_code_point_prev(const uint16_t *chars, size_t len, ssize_t *iter) {
529aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const uint16_t v = chars[(*iter)--];
530aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (HB_IsLowSurrogate(v)) {
531aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    // surrogate pair
532aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (*iter < 0) {
533aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      // the surrogate is incomplete.
534aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      return HB_InvalidCodePoint;
535aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
536aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const uint16_t v2 = chars[(*iter)--];
537aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (!HB_IsHighSurrogate(v2)) {
538aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      // invalidate surrogate pair.
539aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      (*iter)++;
540aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      return HB_InvalidCodePoint;
541aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
542aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
543aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return HB_SurrogateToUcs4(v2, v);
544aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
545aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
546aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (HB_IsHighSurrogate(v)) {
547aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    // this isn't a valid code point
548aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return HB_InvalidCodePoint;
549aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
550aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
551aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  return v;
552aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien}
553aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
554aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienstruct ScriptRun {
555aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_script_t script;
556aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    size_t pos;
557aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    size_t length;
558aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien};
559aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
560aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_script_t code_point_to_script(hb_codepoint_t codepoint) {
561aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    static hb_unicode_funcs_t* u;
562aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (!u) {
563aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        u = hb_icu_get_unicode_funcs();
564aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
565aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return hb_unicode_script(u, codepoint);
566aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien}
567aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
568aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienbool
569aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_utf16_script_run_next(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
570aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (size_t(*iter) == len)
571aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return false;
572aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
573aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->pos = *iter;
574aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const uint32_t init_cp = utf16_to_code_point(chars, len, iter);
575aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const hb_script_t init_script = code_point_to_script(init_cp);
576aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  hb_script_t current_script = init_script;
577aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->script = init_script;
578aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
579aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  for (;;) {
580aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (size_t(*iter) == len)
581aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      break;
582aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const ssize_t prev_iter = *iter;
583aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const uint32_t cp = utf16_to_code_point(chars, len, iter);
584aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const hb_script_t script = code_point_to_script(cp);
585aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
586aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (script != current_script) {
587aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        /* BEGIN android-changed
588aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien           The condition was not correct by doing "a == b == constant"
589aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien           END android-changed */
590aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
591aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        // If we started off as inherited, we take whatever we can find.
592aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        run->script = script;
593aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        current_script = script;
594aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        continue;
595aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      } else if (script == HB_SCRIPT_INHERITED) {
596aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        continue;
597aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      } else {
598aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        *iter = prev_iter;
599aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        break;
600aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      }
601aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
602aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
603aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
604aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (run->script == HB_SCRIPT_INHERITED)
605aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    run->script = HB_SCRIPT_COMMON;
606aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
607aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->length = *iter - run->pos;
608aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  return true;
609aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien}
610aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
611aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienbool
612aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_utf16_script_run_prev(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
613aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (*iter == -1)
614aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return false;
615aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
616aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const size_t ending_index = *iter;
617aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const uint32_t init_cp = utf16_to_code_point_prev(chars, len, iter);
618aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  const hb_script_t init_script = code_point_to_script(init_cp);
619aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  hb_script_t current_script = init_script;
620aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->script = init_script;
6219d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien  size_t break_iter = *iter;
622aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
623aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  for (;;) {
624aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (*iter < 0)
625aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      break;
626aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const uint32_t cp = utf16_to_code_point_prev(chars, len, iter);
627aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const hb_script_t script = code_point_to_script(cp);
628aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
629aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (script != current_script) {
630aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
631aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        // If we started off as inherited, we take whatever we can find.
632aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        run->script = script;
633aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        current_script = script;
6349d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien        // In cases of script1 + inherited + script2, always group the inherited
6359d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien        // with script1.
6369d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien        break_iter = *iter;
637aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        continue;
638aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      } else if (script == HB_SCRIPT_INHERITED) {
639aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        continue;
640aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      } else {
6419d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien        *iter = break_iter;
642aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        break;
643aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien      }
6449d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien    } else {
6459d47db23ff0f943dd959a9a8501563b6975c4781Raph Levien        break_iter = *iter;
646aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    }
647aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  }
648aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
649aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  if (run->script == HB_SCRIPT_INHERITED)
650aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    run->script = HB_SCRIPT_COMMON;
651aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
652aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->pos = *iter + 1;
653aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  run->length = ending_index - *iter;
654aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien  return true;
655aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien}
656aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
657aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
658aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienstatic void logGlyphs(hb_buffer_t* buffer) {
659aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    unsigned int numGlyphs;
660aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
661aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
662aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ALOGD("         -- glyphs count=%d", numGlyphs);
663aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    for (size_t i = 0; i < numGlyphs; i++) {
664aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- glyph[%d] = %d, cluster = %u, advance = %0.2f, offset.x = %0.2f, offset.y = %0.2f", i,
665aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                info[i].codepoint,
666aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                info[i].cluster,
667aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                HBFixedToFloat(positions[i].x_advance),
668aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                HBFixedToFloat(positions[i].x_offset),
669aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                HBFixedToFloat(positions[i].y_offset));
670abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio    }
671abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio}
672abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio
673aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienvoid TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* contextChars,
674aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        size_t start, size_t count, size_t contextCount, bool isRTL,
67541541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
6762301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
677a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown    if (!count) {
678a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        // We cannot shape an empty run.
679a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown        return;
680a03bdedbdf1022d1391f5f0a6ea507e2ebbb0e9aJeff Brown    }
681ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
68257e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    // To be filled in later
68357e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    for (size_t i = 0; i < count; i++) {
68457e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien        outAdvances->add(0);
68557e9723134e295c75a5aa0b20ca4764fc3959d25Raph Levien    }
686902a5b31c50022a1b7707be4d333e4ce6ec4a8faFabrice Di Meglio
6870af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Set the string properties
688aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    const UChar* chars = contextChars + start;
6890af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
6900af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Define shaping paint properties
6910af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setTextSize(paint->getTextSize());
6922301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    float skewX = paint->getTextSkewX();
6932301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    mShapingPaint.setTextSkewX(skewX);
6940af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setTextScaleX(paint->getTextScaleX());
6950af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setFlags(paint->getFlags());
6960af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    mShapingPaint.setHinting(paint->getHinting());
697d7a80774f0a2175f9ee81a7741f9a171c78e0b8bDerek Sollenberger    mShapingPaint.setPaintOptionsAndroid(paint->getPaintOptionsAndroid());
6980af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
6990af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
7000af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // into the shaperItem
701aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ssize_t indexFontRun = isRTL ? count - 1 : 0;
7022301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien    jfloat totalAdvance = *outTotalAdvance;
703aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ScriptRun run;  // relative to chars
7040af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    while ((isRTL) ?
705aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            hb_utf16_script_run_prev(&run, chars, count, &indexFontRun):
706aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            hb_utf16_script_run_next(&run, chars, count, &indexFontRun)) {
707ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
708ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#if DEBUG_GLYPHS
7095baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("-------- Start of Script Run --------");
7105baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Shaping Script Run with");
7115baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- isRTL = %d", isRTL);
712aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- HB script = %c%c%c%c", HB_UNTAG(run.script));
713aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- run.pos = %d", int(run.pos));
714aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- run.length = %d", int(run.length));
715aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- run = '%s'", String8(chars + run.pos, run.length).string());
7165baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- string = '%s'", String8(chars, count).string());
717ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#endif
718ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio
719aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_buffer_reset(mBuffer);
720aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        // Note: if we want to set unicode functions, etc., this is the place.
721aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
722aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_buffer_set_direction(mBuffer, isRTL ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
723aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_buffer_set_script(mBuffer, run.script);
724677726b376402937f53ddb192dc97078b92b7c9eRaph Levien        SkString langString = paint->getPaintOptionsAndroid().getLanguage().getTag();
725677726b376402937f53ddb192dc97078b92b7c9eRaph Levien        hb_buffer_set_language(mBuffer, hb_language_from_string(langString.c_str(), -1));
726aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_buffer_add_utf16(mBuffer, contextChars, contextCount, start + run.pos, run.length);
727aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien
7280af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // Initialize Harfbuzz Shaper and get the base glyph count for offsetting the glyphIDs
7290af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        // and shape the Font run
730aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        size_t glyphBaseCount = shapeFontRun(paint);
731aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        unsigned int numGlyphs;
732aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
733aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(mBuffer, NULL);
73448796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
7359c418dbc56efd334c68872d281f75138e16eae46Fabrice Di Meglio#if DEBUG_GLYPHS
7365baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Got from Harfbuzz");
7375baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- glyphBaseCount = %d", glyphBaseCount);
738aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- num_glyph = %d", numGlyphs);
7395baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("         -- isDevKernText = %d", paint->isDevKernText());
740aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        ALOGD("         -- initial totalAdvance = %f", totalAdvance);
741abb0f299fdc72755a18cf8848d57919890f0cd42Fabrice Di Meglio
742aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        logGlyphs(mBuffer);
7434dd99e5912c73d5a9db165cefd4852b51ea438e8Fabrice Di Meglio#endif
7442301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien
745aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        for (size_t i = 0; i < numGlyphs; i++) {
746aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            size_t cluster = info[i].cluster - start;
747aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            float xAdvance = HBFixedToFloat(positions[i].x_advance);
748aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            outAdvances->replaceAt(outAdvances->itemAt(cluster) + xAdvance, cluster);
74941541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            jchar glyphId = info[i].codepoint + glyphBaseCount;
75041541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            outGlyphs->add(glyphId);
751aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            float xo = HBFixedToFloat(positions[i].x_offset);
752aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            float yo = -HBFixedToFloat(positions[i].y_offset);
75341541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik
75441541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            float xpos = totalAdvance + xo + yo * skewX;
75541541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            float ypos = yo;
75641541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            outPos->add(xpos);
75741541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            outPos->add(ypos);
758aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            totalAdvance += xAdvance;
75941541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik
76041541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            // TODO: consider using glyph cache
76141541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            const SkGlyph& metrics = mShapingPaint.getGlyphMetrics(glyphId, NULL);
76241541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            outBounds->join(xpos + metrics.fLeft, ypos + metrics.fTop,
76341541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik                    xpos + metrics.fLeft + metrics.fWidth, ypos + metrics.fTop + metrics.fHeight);
76441541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik
7652301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien        }
766fcf2be1846935e7983ea2fe87fdd4d7af27764b6Fabrice Di Meglio    }
7675448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio
768ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio    *outTotalAdvance = totalAdvance;
7695448f0378ede9c5d33e7300fa318ef4a6925562fFabrice Di Meglio
77056e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#if DEBUG_GLYPHS
771aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ALOGD("         -- final totalAdvance = %f", totalAdvance);
7725baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("-------- End of Script Run --------");
77356e6e5492780feb3824ff076551b563aade6a2efFabrice Di Meglio#endif
77479df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio}
77579df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio
7761637dcd16cd314574a58602337a2c7222130b1b9Raph Levien/**
7771637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * Return the first typeface in the logical change, starting with this typeface,
7781637dcd16cd314574a58602337a2c7222130b1b9Raph Levien * that contains the specified unichar, or NULL if none is found.
7791637dcd16cd314574a58602337a2c7222130b1b9Raph Levien */
780d6deccb346e913d906f484d279b19e0f6ea18d94Billy HewlettSkTypeface* TextLayoutShaper::typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
781aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_script_t script) {
782d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    SkTypeface::Style currentStyle = SkTypeface::kNormal;
783d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    if (typeface) {
784d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        currentStyle = typeface->style();
785d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    }
786aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    typeface = SkCreateTypefaceForScriptNG(script, currentStyle);
7876162876067cbaa93b870aee6e62c682104935fdeFabrice Di Meglio#if DEBUG_GLYPHS
788ded5ed963c3939a2668ce1152ab60efb7bbbb2bdVictoria Lease    ALOGD("Using Harfbuzz Script %c%c%c%c, Style %d", HB_UNTAG(script), currentStyle);
7896162876067cbaa93b870aee6e62c682104935fdeFabrice Di Meglio#endif
790d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    return typeface;
791d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett}
792ff40ab7a418dd06cfe4758ceda17a775f2d4c776Fabrice Di Meglio
793aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienbool TextLayoutShaper::isComplexScript(hb_script_t script) {
794d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    switch (script) {
795aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    case HB_SCRIPT_COMMON:
796aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    case HB_SCRIPT_GREEK:
797aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    case HB_SCRIPT_CYRILLIC:
798aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    case HB_SCRIPT_HANGUL:
799aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    case HB_SCRIPT_INHERITED:
8006d191ed99491f209168e88f3d570e89c6836285bJunichi Monma    case HB_SCRIPT_HAN:
8016d191ed99491f209168e88f3d570e89c6836285bJunichi Monma    case HB_SCRIPT_KATAKANA:
8026d191ed99491f209168e88f3d570e89c6836285bJunichi Monma    case HB_SCRIPT_HIRAGANA:
803d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        return false;
8040af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    default:
805d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        return true;
8060af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
8071637dcd16cd314574a58602337a2c7222130b1b9Raph Levien}
8080af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
809aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Leviensize_t TextLayoutShaper::shapeFontRun(const SkPaint* paint) {
8101637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    // Update Harfbuzz Shaper
8111637dcd16cd314574a58602337a2c7222130b1b9Raph Levien
8121637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    SkTypeface* typeface = paint->getTypeface();
8130af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
8140af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // Get the glyphs base count for offsetting the glyphIDs returned by Harfbuzz
8150af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // This is needed as the Typeface used for shaping can be not the default one
8160af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // when we are shaping any script that needs to use a fallback Font.
8170af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    // If we are a "common" script we dont need to shift
8180af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    size_t baseGlyphCount = 0;
819aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_codepoint_t firstUnichar = 0;
820aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    if (isComplexScript(hb_buffer_get_script(mBuffer))) {
821aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        unsigned int numGlyphs;
822aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
823aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        for (size_t i = 0; i < numGlyphs; i++) {
824aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            firstUnichar = info[i].codepoint;
825aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            if (firstUnichar != ' ') {
826aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien                break;
827aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            }
828b294435b5c6e0fee8c431ed3f6d77427d3d79ddeRaph Levien        }
8290af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio        baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
8300af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
8310af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
832dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien    SkTypeface* scriptTypeface = NULL;
8331637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    if (baseGlyphCount != 0) {
834dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        scriptTypeface = typefaceForScript(paint, typeface,
835dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien            hb_buffer_get_script(mBuffer));
836d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett#if DEBUG_GLYPHS
837dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        ALOGD("Using Default Typeface for script %c%c%c%c",
838dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien            HB_UNTAG(hb_buffer_get_script(mBuffer)));
839d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett#endif
840dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien    }
841dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien    if (scriptTypeface) {
842dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        typeface = scriptTypeface;
843d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett    } else {
844dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        baseGlyphCount = 0;
845dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        if (typeface) {
846dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien            SkSafeRef(typeface);
847dd0a91294bc6b57c701bdb85b9e920207eeae55aRaph Levien        } else {
848af1653a851eefb2302d2cb1c7ef3c7325103f2ddVictoria Lease            typeface = SkTypeface::CreateFromName(NULL, SkTypeface::kNormal);
8491637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#if DEBUG_GLYPHS
850cc0f9d8469ac0aa39ca2c2c6e6afe309ab6e69a7Victoria Lease            ALOGD("Using Default Typeface (normal style)");
8511637dcd16cd314574a58602337a2c7222130b1b9Raph Levien#endif
852d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett        }
8531637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    }
854d6deccb346e913d906f484d279b19e0f6ea18d94Billy Hewlett
8551637dcd16cd314574a58602337a2c7222130b1b9Raph Levien    mShapingPaint.setTypeface(typeface);
856aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_face_t* face = referenceCachedHBFace(typeface);
8572301d32f7e2ba584abc31ac177dde754385d3c04Raph Levien
858aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    float sizeY = paint->getTextSize();
859aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    float sizeX = sizeY * paint->getTextScaleX();
860aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_font_t* font = createFont(face, &mShapingPaint, sizeX, sizeY);
861aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_face_destroy(face);
8621637dcd16cd314574a58602337a2c7222130b1b9Raph Levien
863ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#if DEBUG_GLYPHS
864aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ALOGD("Run typeface = %p, uniqueID = %d, face = %p",
865aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien            typeface, typeface->uniqueID(), face);
866ef9bb3c3ea3aa08071ea0c32a505b379c322e5b5Fabrice Di Meglio#endif
867aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    SkSafeUnref(typeface);
868738ef87eacd3e54132d1bf661dd9329050fddd2fJeff Brown
869aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_shape(font, mBuffer, NULL, 0);
870aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_font_destroy(font);
8710af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
8728450a6ef8b4282491857fd5af6574019983ec243Victoria Lease    mShapingPaint.setTypeface(paint->getTypeface());
873aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return baseGlyphCount;
8740af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio}
8750af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio
876aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levienhb_face_t* TextLayoutShaper::referenceCachedHBFace(SkTypeface* typeface) {
8770af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    SkFontID fontId = typeface->uniqueID();
8780af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    ssize_t index = mCachedHBFaces.indexOfKey(fontId);
8790af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    if (index >= 0) {
880aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        return hb_face_reference(mCachedHBFaces.valueAt(index));
8810af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio    }
882aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    // TODO: destroy function
883aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    hb_face_t* face = hb_face_create_for_tables(harfbuzzSkiaReferenceTable, typeface, NULL);
8840af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#if DEBUG_GLYPHS
885aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    ALOGD("Created HB_NewFace %p from paint typeface = %p", face, typeface);
8860af10b54bf110653b74cb92793484b412a90b657Fabrice Di Meglio#endif
887aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    mCachedHBFaces.add(fontId, face);
888aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    return hb_face_reference(face);
88979df5323e7ed541b854cea5684a89e8be8c2dfc9Fabrice Di Meglio}
89048796a81be31e42ee267347156c94445cb9fb67aFabrice Di Meglio
89115cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Megliovoid TextLayoutShaper::purgeCaches() {
89275394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    size_t cacheSize = mCachedHBFaces.size();
89375394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    for (size_t i = 0; i < cacheSize; i++) {
894aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien        hb_face_destroy(mCachedHBFaces.valueAt(i));
89575394d6d1ba633f6bf0218f563b8876b824c6fcfRaph Levien    }
89615cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    mCachedHBFaces.clear();
89715cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio}
89815cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio
899a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutEngine::TextLayoutEngine() {
900a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mShaper = new TextLayoutShaper();
901a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
902a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mTextLayoutCache = new TextLayoutCache(mShaper);
903a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#else
904a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mTextLayoutCache = NULL;
905a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#endif
906a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
907a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
908a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di MeglioTextLayoutEngine::~TextLayoutEngine() {
909a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    delete mTextLayoutCache;
910a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    delete mShaper;
911a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
912a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
913a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Megliosp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
914da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        jint start, jint count, jint contextCount, jint dirFlags) {
915a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    sp<TextLayoutValue> value;
916a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
917a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    value = mTextLayoutCache->getValue(paint, text, start, count,
918da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            contextCount, dirFlags);
919a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    if (value == NULL) {
920a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
921a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio                String8(text + start, count).string());
922a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    }
923a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#else
924a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    value = new TextLayoutValue(count);
925a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    mShaper->computeValues(value.get(), paint,
926da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
927a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio#endif
928a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio    return value;
929a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio}
930a731b082b2c43204e6e9f927ab82fb732934a83bFabrice Di Meglio
93130ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Megliovoid TextLayoutEngine::purgeCaches() {
93230ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio#if USE_TEXT_LAYOUT_CACHE
93313ba4e478d19001ddb6828bd1fd8fbc1e0cb208fRaph Levien    mTextLayoutCache->purgeCaches();
93415cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio#if DEBUG_GLYPHS
93515cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio    ALOGD("Purged TextLayoutEngine caches");
93615cc68ced062a0dbd174718abfb1c783ac1aa433Fabrice Di Meglio#endif
93730ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio#endif
93830ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio}
93930ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio
94030ca5cd11a23f06f2f8eeaa587685450826f800fFabrice Di Meglio
941d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio} // namespace android
942