Loading core/jni/android/graphics/Canvas.cpp +3 −12 Original line number Diff line number Diff line Loading @@ -757,20 +757,11 @@ public: int start, int count, int contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count, contextCount, flags); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, textArray, start, count, contextCount, flags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(textArray + start, count).string()); return; } #else value = new TextLayoutCacheValue(contextCount); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags); #endif doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint); } Loading core/jni/android/graphics/Paint.cpp +10 −28 Original line number Diff line number Diff line Loading @@ -465,11 +465,10 @@ public: jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL); TextLayoutCacheValue value(contextCount); TextLayoutEngine::getInstance().computeValues(&value, paint, text, start, count, contextCount, flags); const jchar* shapedGlyphs = value.getGlyphs(); size_t glyphsCount = value.getGlyphsCount(); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, start, count, contextCount, flags); const jchar* shapedGlyphs = value->getGlyphs(); size_t glyphsCount = value->getGlyphsCount(); memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount); env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT); Loading Loading @@ -677,20 +676,11 @@ public: static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[], int count, float maxWidth, jfloatArray jmeasured, SkPaint::TextBufferDirection tbd) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); return 0; } #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), &paint, reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags()); #endif SkScalar measured; size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1, SkFloatToScalar(maxWidth), &measured, tbd); Loading Loading @@ -756,19 +746,11 @@ public: SkRect r; SkIRect ir; sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); } #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), &paint, reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags()); #endif return; } paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r); r.roundOut(&ir); GraphicsJNI::irect_to_jrect(ir, env, bounds); Loading core/jni/android/graphics/TextLayout.cpp +8 −36 Original line number Diff line number Diff line Loading @@ -53,19 +53,9 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) { // a path representing the text that would have been drawn. void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags, jfloat x, jfloat y, SkPath *path) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE // Return advances from the cache. Compute them if needed value = TextLayoutCache::getInstance().getValue(paint, text, 0, len, len, bidiFlags); #else value = new TextLayoutCacheValue(len); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, 0, len, len, bidiFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, len).string()); return ; } SkScalar x_ = SkFloatToScalar(x); Loading @@ -77,19 +67,9 @@ void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, jfloat* resultAdvances, jfloat* resultTotalAdvance) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE // Return advances from the cache. Compute them if needed value = TextLayoutCache::getInstance().getValue(paint, chars, start, count, contextCount, dirFlags); #else value = new TextLayoutCacheValue(contextCount); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, chars, start, count, contextCount, dirFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(chars + start, count).string()); return ; } if (resultAdvances) { Loading Loading @@ -126,20 +106,12 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count, return; } sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, bidiFlags); #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, 0, count, count, bidiFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); return; } // Beware: this needs Glyph encoding (already done on the Paint constructor) canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint); } Loading core/jni/android/graphics/TextLayoutCache.cpp +66 −32 Original line number Diff line number Diff line Loading @@ -35,18 +35,13 @@ namespace android { #define TYPEFACE_BENGALI "/system/fonts/Lohit-Bengali.ttf" #define TYPEFACE_THAI "/system/fonts/DroidSansThai.ttf" #if USE_TEXT_LAYOUT_CACHE ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache); #endif ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine); //-------------------------------------------------------------------------------------------------- TextLayoutCache::TextLayoutCache() : mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity), TextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) : mShaper(shaper), mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)), mCacheHitCount(0), mNanosecondsSaved(0) { init(); Loading Loading @@ -75,7 +70,7 @@ void TextLayoutCache::init() { /** * Callbacks */ void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc) { void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) { size_t totalSizeToDelete = text.getSize() + desc->getSize(); mSize -= totalSizeToDelete; if (mDebugEnabled) { Loading @@ -93,7 +88,7 @@ void TextLayoutCache::clear() { /* * Caching */ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) { AutoMutex _l(mLock); nsecs_t startTime = 0; Loading @@ -105,7 +100,7 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags); // Get value from cache if possible sp<TextLayoutCacheValue> value = mCache.get(key); sp<TextLayoutValue> value = mCache.get(key); // Value not found for the key, we need to add a new value in the cache if (value == NULL) { Loading @@ -113,10 +108,10 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, startTime = systemTime(SYSTEM_TIME_MONOTONIC); } value = new TextLayoutCacheValue(contextCount); value = new TextLayoutValue(contextCount); // Compute advances and store them TextLayoutEngine::getInstance().computeValues(value.get(), paint, mShaper->computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), start, count, size_t(contextCount), int(dirFlags)); Loading Loading @@ -312,31 +307,33 @@ size_t TextLayoutCacheKey::getSize() const { /** * TextLayoutCacheValue */ TextLayoutCacheValue::TextLayoutCacheValue(size_t contextCount) : TextLayoutValue::TextLayoutValue(size_t contextCount) : mTotalAdvance(0), mElapsedTime(0) { // Give a hint for advances and glyphs vectors size mAdvances.setCapacity(contextCount); mGlyphs.setCapacity(contextCount); } size_t TextLayoutCacheValue::getSize() const { return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvances.capacity() + size_t TextLayoutValue::getSize() const { return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() + sizeof(jchar) * mGlyphs.capacity(); } void TextLayoutCacheValue::setElapsedTime(uint32_t time) { void TextLayoutValue::setElapsedTime(uint32_t time) { mElapsedTime = time; } uint32_t TextLayoutCacheValue::getElapsedTime() { uint32_t TextLayoutValue::getElapsedTime() { return mElapsedTime; } TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) { TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) { mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal); mArabicTypeface = NULL; mHebrewRegularTypeface = NULL; mHebrewBoldTypeface = NULL; mBengaliTypeface = NULL; mThaiTypeface = NULL; mFontRec.klass = &harfbuzzSkiaClass; mFontRec.userData = 0; Loading @@ -355,12 +352,17 @@ TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) { mShaperItem.font->userData = &mShapingPaint; } TextLayoutEngine::~TextLayoutEngine() { // FIXME should free fonts and caches but since this class is a singleton, // we don't bother at the moment TextLayoutShaper::~TextLayoutShaper() { SkSafeUnref(mDefaultTypeface); SkSafeUnref(mArabicTypeface); SkSafeUnref(mHebrewRegularTypeface); SkSafeUnref(mHebrewBoldTypeface); SkSafeUnref(mBengaliTypeface); SkSafeUnref(mThaiTypeface); deleteShaperItemGlyphArrays(); } void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) { computeValues(paint, chars, start, count, contextCount, dirFlags, Loading @@ -371,7 +373,7 @@ void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, const SkPaint* #endif } void TextLayoutEngine::computeValues(const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { Loading Loading @@ -513,7 +515,7 @@ static void logGlyphs(HB_ShaperItem shaperItem) { } } void TextLayoutEngine::computeRunValues(const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars, size_t count, bool isRTL, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { Loading Loading @@ -719,7 +721,7 @@ void TextLayoutEngine::computeRunValues(const SkPaint* paint, const UChar* chars } size_t TextLayoutEngine::shapeFontRun(const SkPaint* paint, bool isRTL) { size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) { // Reset kerning mShaperItem.kerning_applied = false; Loading Loading @@ -833,14 +835,14 @@ size_t TextLayoutEngine::shapeFontRun(const SkPaint* paint, bool isRTL) { return baseGlyphCount; } void TextLayoutEngine::ensureShaperItemGlyphArrays(size_t size) { void TextLayoutShaper::ensureShaperItemGlyphArrays(size_t size) { if (size > mShaperItemGlyphArraySize) { deleteShaperItemGlyphArrays(); createShaperItemGlyphArrays(size); } } void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) { void TextLayoutShaper::createShaperItemGlyphArrays(size_t size) { #if DEBUG_GLYPHS ALOGD("Creating Glyph Arrays with size = %d", size); #endif Loading @@ -858,7 +860,7 @@ void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) { mShaperItem.log_clusters = new unsigned short[size]; } void TextLayoutEngine::deleteShaperItemGlyphArrays() { void TextLayoutShaper::deleteShaperItemGlyphArrays() { delete[] mShaperItem.glyphs; delete[] mShaperItem.attributes; delete[] mShaperItem.advances; Loading @@ -866,7 +868,7 @@ void TextLayoutEngine::deleteShaperItemGlyphArrays() { delete[] mShaperItem.log_clusters; } SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const char path[]) { SkTypeface* TextLayoutShaper::getCachedTypeface(SkTypeface** typeface, const char path[]) { if (!*typeface) { *typeface = SkTypeface::CreateFromFile(path); // CreateFromFile(path) can return NULL if the path is non existing Loading @@ -884,7 +886,7 @@ SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const cha return *typeface; } HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) { HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) { SkFontID fontId = typeface->uniqueID(); ssize_t index = mCachedHBFaces.indexOfKey(fontId); if (index >= 0) { Loading @@ -900,4 +902,36 @@ HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) { return face; } TextLayoutEngine::TextLayoutEngine() { mShaper = new TextLayoutShaper(); #if USE_TEXT_LAYOUT_CACHE mTextLayoutCache = new TextLayoutCache(mShaper); #else mTextLayoutCache = NULL; #endif } TextLayoutEngine::~TextLayoutEngine() { delete mTextLayoutCache; delete mShaper; } sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) { sp<TextLayoutValue> value; #if USE_TEXT_LAYOUT_CACHE value = mTextLayoutCache->getValue(paint, text, start, count, contextCount, dirFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text + start, count).string()); } #else value = new TextLayoutValue(count); mShaper->computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags); #endif return value; } } // namespace android core/jni/android/graphics/TextLayoutCache.h +81 −67 Original line number Diff line number Diff line Loading @@ -115,11 +115,11 @@ inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& } /* * TextLayoutCacheValue is the Cache value * TextLayoutValue is the Cache value */ class TextLayoutCacheValue : public RefBase { class TextLayoutValue : public RefBase { public: TextLayoutCacheValue(size_t contextCount); TextLayoutValue(size_t contextCount); void setElapsedTime(uint32_t time); uint32_t getElapsedTime(); Loading Loading @@ -159,72 +159,14 @@ private: }; // TextLayoutCacheValue /** * Cache of text layout information. * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library) */ class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >, public Singleton<TextLayoutCache> { class TextLayoutShaper { public: TextLayoutCache(); virtual ~TextLayoutCache(); bool isInitialized() { return mInitialized; } /** * Used as a callback when an entry is removed from the cache * Do not invoke directly */ void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc); sp<TextLayoutCacheValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); /** * Clear the cache */ void clear(); private: Mutex mLock; bool mInitialized; GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache; uint32_t mSize; uint32_t mMaxSize; uint32_t mCacheHitCount; uint64_t mNanosecondsSaved; TextLayoutShaper(); virtual ~TextLayoutShaper(); uint64_t mCacheStartTime; RtlDebugLevel mDebugLevel; bool mDebugEnabled; /* * Class initialization */ void init(); /** * Dump Cache statistics */ void dumpCacheStats(); }; // TextLayoutCache /** * The TextLayoutEngine is responsible for shaping with Harfbuzz library */ class TextLayoutEngine : public Singleton<TextLayoutEngine> { public: TextLayoutEngine(); virtual ~TextLayoutEngine(); void computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars, void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags); private: Loading Loading @@ -292,8 +234,80 @@ private: void createShaperItemGlyphArrays(size_t size); void deleteShaperItemGlyphArrays(); }; // TextLayoutEngine }; // TextLayoutShaper /** * Cache of text layout information. */ class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> > { public: TextLayoutCache(TextLayoutShaper* shaper); ~TextLayoutCache(); bool isInitialized() { return mInitialized; } /** * Used as a callback when an entry is removed from the cache * Do not invoke directly */ void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc); sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); /** * Clear the cache */ void clear(); private: TextLayoutShaper* mShaper; Mutex mLock; bool mInitialized; GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache; uint32_t mSize; uint32_t mMaxSize; uint32_t mCacheHitCount; uint64_t mNanosecondsSaved; uint64_t mCacheStartTime; RtlDebugLevel mDebugLevel; bool mDebugEnabled; /* * Class initialization */ void init(); /** * Dump Cache statistics */ void dumpCacheStats(); }; // TextLayoutCache /** * The TextLayoutEngine is reponsible for computing TextLayoutValues */ class TextLayoutEngine : public Singleton<TextLayoutEngine> { public: TextLayoutEngine(); virtual ~TextLayoutEngine(); sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); private: TextLayoutCache* mTextLayoutCache; TextLayoutShaper* mShaper; }; // TextLayoutEngine } // namespace android #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */ Loading Loading
core/jni/android/graphics/Canvas.cpp +3 −12 Original line number Diff line number Diff line Loading @@ -757,20 +757,11 @@ public: int start, int count, int contextCount, jfloat x, jfloat y, int flags, SkPaint* paint) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count, contextCount, flags); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, textArray, start, count, contextCount, flags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(textArray + start, count).string()); return; } #else value = new TextLayoutCacheValue(contextCount); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags); #endif doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint); } Loading
core/jni/android/graphics/Paint.cpp +10 −28 Original line number Diff line number Diff line Loading @@ -465,11 +465,10 @@ public: jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL); TextLayoutCacheValue value(contextCount); TextLayoutEngine::getInstance().computeValues(&value, paint, text, start, count, contextCount, flags); const jchar* shapedGlyphs = value.getGlyphs(); size_t glyphsCount = value.getGlyphsCount(); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, start, count, contextCount, flags); const jchar* shapedGlyphs = value->getGlyphs(); size_t glyphsCount = value->getGlyphsCount(); memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount); env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT); Loading Loading @@ -677,20 +676,11 @@ public: static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[], int count, float maxWidth, jfloatArray jmeasured, SkPaint::TextBufferDirection tbd) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); return 0; } #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), &paint, reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags()); #endif SkScalar measured; size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1, SkFloatToScalar(maxWidth), &measured, tbd); Loading Loading @@ -756,19 +746,11 @@ public: SkRect r; SkIRect ir; sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, text, 0, count, count, paint.getFlags()); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); } #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), &paint, reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags()); #endif return; } paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r); r.roundOut(&ir); GraphicsJNI::irect_to_jrect(ir, env, bounds); Loading
core/jni/android/graphics/TextLayout.cpp +8 −36 Original line number Diff line number Diff line Loading @@ -53,19 +53,9 @@ bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) { // a path representing the text that would have been drawn. void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, jint bidiFlags, jfloat x, jfloat y, SkPath *path) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE // Return advances from the cache. Compute them if needed value = TextLayoutCache::getInstance().getValue(paint, text, 0, len, len, bidiFlags); #else value = new TextLayoutCacheValue(len); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, 0, len, len, bidiFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, len).string()); return ; } SkScalar x_ = SkFloatToScalar(x); Loading @@ -77,19 +67,9 @@ void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len, void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, jfloat* resultAdvances, jfloat* resultTotalAdvance) { sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE // Return advances from the cache. Compute them if needed value = TextLayoutCache::getInstance().getValue(paint, chars, start, count, contextCount, dirFlags); #else value = new TextLayoutCacheValue(contextCount); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, chars, start, count, contextCount, dirFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(chars + start, count).string()); return ; } if (resultAdvances) { Loading Loading @@ -126,20 +106,12 @@ void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count, return; } sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, bidiFlags); #else value = new TextLayoutCacheValue(count); TextLayoutEngine::getInstance().computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags); #endif sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, 0, count, count, bidiFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text, count).string()); return; } // Beware: this needs Glyph encoding (already done on the Paint constructor) canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint); } Loading
core/jni/android/graphics/TextLayoutCache.cpp +66 −32 Original line number Diff line number Diff line Loading @@ -35,18 +35,13 @@ namespace android { #define TYPEFACE_BENGALI "/system/fonts/Lohit-Bengali.ttf" #define TYPEFACE_THAI "/system/fonts/DroidSansThai.ttf" #if USE_TEXT_LAYOUT_CACHE ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache); #endif ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine); //-------------------------------------------------------------------------------------------------- TextLayoutCache::TextLayoutCache() : mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity), TextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) : mShaper(shaper), mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)), mCacheHitCount(0), mNanosecondsSaved(0) { init(); Loading Loading @@ -75,7 +70,7 @@ void TextLayoutCache::init() { /** * Callbacks */ void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc) { void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) { size_t totalSizeToDelete = text.getSize() + desc->getSize(); mSize -= totalSizeToDelete; if (mDebugEnabled) { Loading @@ -93,7 +88,7 @@ void TextLayoutCache::clear() { /* * Caching */ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) { AutoMutex _l(mLock); nsecs_t startTime = 0; Loading @@ -105,7 +100,7 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags); // Get value from cache if possible sp<TextLayoutCacheValue> value = mCache.get(key); sp<TextLayoutValue> value = mCache.get(key); // Value not found for the key, we need to add a new value in the cache if (value == NULL) { Loading @@ -113,10 +108,10 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint, startTime = systemTime(SYSTEM_TIME_MONOTONIC); } value = new TextLayoutCacheValue(contextCount); value = new TextLayoutValue(contextCount); // Compute advances and store them TextLayoutEngine::getInstance().computeValues(value.get(), paint, mShaper->computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), start, count, size_t(contextCount), int(dirFlags)); Loading Loading @@ -312,31 +307,33 @@ size_t TextLayoutCacheKey::getSize() const { /** * TextLayoutCacheValue */ TextLayoutCacheValue::TextLayoutCacheValue(size_t contextCount) : TextLayoutValue::TextLayoutValue(size_t contextCount) : mTotalAdvance(0), mElapsedTime(0) { // Give a hint for advances and glyphs vectors size mAdvances.setCapacity(contextCount); mGlyphs.setCapacity(contextCount); } size_t TextLayoutCacheValue::getSize() const { return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvances.capacity() + size_t TextLayoutValue::getSize() const { return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() + sizeof(jchar) * mGlyphs.capacity(); } void TextLayoutCacheValue::setElapsedTime(uint32_t time) { void TextLayoutValue::setElapsedTime(uint32_t time) { mElapsedTime = time; } uint32_t TextLayoutCacheValue::getElapsedTime() { uint32_t TextLayoutValue::getElapsedTime() { return mElapsedTime; } TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) { TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) { mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal); mArabicTypeface = NULL; mHebrewRegularTypeface = NULL; mHebrewBoldTypeface = NULL; mBengaliTypeface = NULL; mThaiTypeface = NULL; mFontRec.klass = &harfbuzzSkiaClass; mFontRec.userData = 0; Loading @@ -355,12 +352,17 @@ TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) { mShaperItem.font->userData = &mShapingPaint; } TextLayoutEngine::~TextLayoutEngine() { // FIXME should free fonts and caches but since this class is a singleton, // we don't bother at the moment TextLayoutShaper::~TextLayoutShaper() { SkSafeUnref(mDefaultTypeface); SkSafeUnref(mArabicTypeface); SkSafeUnref(mHebrewRegularTypeface); SkSafeUnref(mHebrewBoldTypeface); SkSafeUnref(mBengaliTypeface); SkSafeUnref(mThaiTypeface); deleteShaperItemGlyphArrays(); } void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) { computeValues(paint, chars, start, count, contextCount, dirFlags, Loading @@ -371,7 +373,7 @@ void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, const SkPaint* #endif } void TextLayoutEngine::computeValues(const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { Loading Loading @@ -513,7 +515,7 @@ static void logGlyphs(HB_ShaperItem shaperItem) { } } void TextLayoutEngine::computeRunValues(const SkPaint* paint, const UChar* chars, void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars, size_t count, bool isRTL, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { Loading Loading @@ -719,7 +721,7 @@ void TextLayoutEngine::computeRunValues(const SkPaint* paint, const UChar* chars } size_t TextLayoutEngine::shapeFontRun(const SkPaint* paint, bool isRTL) { size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) { // Reset kerning mShaperItem.kerning_applied = false; Loading Loading @@ -833,14 +835,14 @@ size_t TextLayoutEngine::shapeFontRun(const SkPaint* paint, bool isRTL) { return baseGlyphCount; } void TextLayoutEngine::ensureShaperItemGlyphArrays(size_t size) { void TextLayoutShaper::ensureShaperItemGlyphArrays(size_t size) { if (size > mShaperItemGlyphArraySize) { deleteShaperItemGlyphArrays(); createShaperItemGlyphArrays(size); } } void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) { void TextLayoutShaper::createShaperItemGlyphArrays(size_t size) { #if DEBUG_GLYPHS ALOGD("Creating Glyph Arrays with size = %d", size); #endif Loading @@ -858,7 +860,7 @@ void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) { mShaperItem.log_clusters = new unsigned short[size]; } void TextLayoutEngine::deleteShaperItemGlyphArrays() { void TextLayoutShaper::deleteShaperItemGlyphArrays() { delete[] mShaperItem.glyphs; delete[] mShaperItem.attributes; delete[] mShaperItem.advances; Loading @@ -866,7 +868,7 @@ void TextLayoutEngine::deleteShaperItemGlyphArrays() { delete[] mShaperItem.log_clusters; } SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const char path[]) { SkTypeface* TextLayoutShaper::getCachedTypeface(SkTypeface** typeface, const char path[]) { if (!*typeface) { *typeface = SkTypeface::CreateFromFile(path); // CreateFromFile(path) can return NULL if the path is non existing Loading @@ -884,7 +886,7 @@ SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const cha return *typeface; } HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) { HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) { SkFontID fontId = typeface->uniqueID(); ssize_t index = mCachedHBFaces.indexOfKey(fontId); if (index >= 0) { Loading @@ -900,4 +902,36 @@ HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) { return face; } TextLayoutEngine::TextLayoutEngine() { mShaper = new TextLayoutShaper(); #if USE_TEXT_LAYOUT_CACHE mTextLayoutCache = new TextLayoutCache(mShaper); #else mTextLayoutCache = NULL; #endif } TextLayoutEngine::~TextLayoutEngine() { delete mTextLayoutCache; delete mShaper; } sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) { sp<TextLayoutValue> value; #if USE_TEXT_LAYOUT_CACHE value = mTextLayoutCache->getValue(paint, text, start, count, contextCount, dirFlags); if (value == NULL) { ALOGE("Cannot get TextLayoutCache value for text = '%s'", String8(text + start, count).string()); } #else value = new TextLayoutValue(count); mShaper->computeValues(value.get(), paint, reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags); #endif return value; } } // namespace android
core/jni/android/graphics/TextLayoutCache.h +81 −67 Original line number Diff line number Diff line Loading @@ -115,11 +115,11 @@ inline int compare_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& } /* * TextLayoutCacheValue is the Cache value * TextLayoutValue is the Cache value */ class TextLayoutCacheValue : public RefBase { class TextLayoutValue : public RefBase { public: TextLayoutCacheValue(size_t contextCount); TextLayoutValue(size_t contextCount); void setElapsedTime(uint32_t time); uint32_t getElapsedTime(); Loading Loading @@ -159,72 +159,14 @@ private: }; // TextLayoutCacheValue /** * Cache of text layout information. * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library) */ class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >, public Singleton<TextLayoutCache> { class TextLayoutShaper { public: TextLayoutCache(); virtual ~TextLayoutCache(); bool isInitialized() { return mInitialized; } /** * Used as a callback when an entry is removed from the cache * Do not invoke directly */ void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc); sp<TextLayoutCacheValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); /** * Clear the cache */ void clear(); private: Mutex mLock; bool mInitialized; GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache; uint32_t mSize; uint32_t mMaxSize; uint32_t mCacheHitCount; uint64_t mNanosecondsSaved; TextLayoutShaper(); virtual ~TextLayoutShaper(); uint64_t mCacheStartTime; RtlDebugLevel mDebugLevel; bool mDebugEnabled; /* * Class initialization */ void init(); /** * Dump Cache statistics */ void dumpCacheStats(); }; // TextLayoutCache /** * The TextLayoutEngine is responsible for shaping with Harfbuzz library */ class TextLayoutEngine : public Singleton<TextLayoutEngine> { public: TextLayoutEngine(); virtual ~TextLayoutEngine(); void computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars, void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags); private: Loading Loading @@ -292,8 +234,80 @@ private: void createShaperItemGlyphArrays(size_t size); void deleteShaperItemGlyphArrays(); }; // TextLayoutEngine }; // TextLayoutShaper /** * Cache of text layout information. */ class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> > { public: TextLayoutCache(TextLayoutShaper* shaper); ~TextLayoutCache(); bool isInitialized() { return mInitialized; } /** * Used as a callback when an entry is removed from the cache * Do not invoke directly */ void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc); sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); /** * Clear the cache */ void clear(); private: TextLayoutShaper* mShaper; Mutex mLock; bool mInitialized; GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache; uint32_t mSize; uint32_t mMaxSize; uint32_t mCacheHitCount; uint64_t mNanosecondsSaved; uint64_t mCacheStartTime; RtlDebugLevel mDebugLevel; bool mDebugEnabled; /* * Class initialization */ void init(); /** * Dump Cache statistics */ void dumpCacheStats(); }; // TextLayoutCache /** * The TextLayoutEngine is reponsible for computing TextLayoutValues */ class TextLayoutEngine : public Singleton<TextLayoutEngine> { public: TextLayoutEngine(); virtual ~TextLayoutEngine(); sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); private: TextLayoutCache* mTextLayoutCache; TextLayoutShaper* mShaper; }; // TextLayoutEngine } // namespace android #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */ Loading