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