diff options
author | Fabrice Di Meglio <fdimeglio@google.com> | 2011-09-18 12:58:47 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-09-18 12:58:47 -0700 |
commit | bfb9a9ae1005998818dd2e75ac7e7f23277a1f03 (patch) | |
tree | cf0f9b2f6f874d4deaafd956dd4836f93564adb3 | |
parent | 4a5c14d6dda736f420ae90e461719af8a0bc1949 (diff) | |
parent | 9c418dbc56efd334c68872d281f75138e16eae46 (diff) | |
download | frameworks_base-bfb9a9ae1005998818dd2e75ac7e7f23277a1f03.zip frameworks_base-bfb9a9ae1005998818dd2e75ac7e7f23277a1f03.tar.gz frameworks_base-bfb9a9ae1005998818dd2e75ac7e7f23277a1f03.tar.bz2 |
Merge "Revert "Fix bug #5332081 TextLayoutCache needs to be able to have more cache hits""
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 30 | ||||
-rw-r--r-- | core/jni/android/graphics/Paint.cpp | 18 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayout.cpp | 90 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayout.h | 6 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.cpp | 314 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.h | 56 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 32 |
7 files changed, 240 insertions, 306 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index f3e9d39..9313d0a 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -758,7 +758,21 @@ public: jfloat x, jfloat y, int flags, SkPaint* paint) { jint count = end - start; - drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint); + sp<TextLayoutCacheValue> value; +#if USE_TEXT_LAYOUT_CACHE + value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count, + end, flags); + if (value == NULL) { + LOGE("Cannot get TextLayoutCache value"); + return ; + } +#else + value = new TextLayoutCacheValue(); + value->computeValues(paint, textArray, start, count, end, flags); +#endif + + doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), + x, y, flags, paint); } static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, @@ -767,23 +781,19 @@ public: sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE - value = TextLayoutCache::getInstance().getValue(paint, textArray, contextCount, flags); + value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count, + contextCount, flags); if (value == NULL) { LOGE("Cannot get TextLayoutCache value"); return ; } #else value = new TextLayoutCacheValue(); - value->computeValues(paint, textArray, contextCount, flags); + value->computeValues(paint, textArray, start, count, contextCount, flags); #endif - size_t startIndex = 0; - size_t glyphsCount = 0; - value->getGlyphsIndexAndCount(start, count, &startIndex, &glyphsCount); - jchar* glyphs = new jchar[glyphsCount]; - value->getGlyphs(startIndex, glyphsCount, glyphs); - doDrawGlyphs(canvas, glyphs, 0, glyphsCount, x, y, flags, paint); - delete[] glyphs; + doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), + x, y, flags, paint); } static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 415346c..7d222f6 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -352,7 +352,7 @@ public: jfloat result = 0; #if RTL_USE_HARFBUZZ TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength, - paint->getFlags(), NULL /* dont need all advances */, &result); + paint->getFlags(), NULL /* dont need all advances */, result); #else // we double count, since measureText wants a byteLength SkScalar width = paint->measureText(textArray + index, count << 1); @@ -382,7 +382,7 @@ public: #if RTL_USE_HARFBUZZ TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength, - paint->getFlags(), NULL /* dont need all advances */, &width); + paint->getFlags(), NULL /* dont need all advances */, width); #else width = SkScalarToFloat(paint->measureText(textArray + start, count << 1)); @@ -406,7 +406,7 @@ public: #if RTL_USE_HARFBUZZ TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength, - paint->getFlags(), NULL /* dont need all advances */, &width); + paint->getFlags(), NULL /* dont need all advances */, width); #else width = SkScalarToFloat(paint->measureText(textArray, textLength << 1)); #endif @@ -435,8 +435,10 @@ public: jfloat* widthsArray = autoWidths.ptr(); #if RTL_USE_HARFBUZZ + jfloat totalAdvance; + TextLayout::getTextRunAdvances(paint, text, 0, count, count, - paint->getFlags(), widthsArray, NULL); + paint->getFlags(), widthsArray, totalAdvance); #else SkScalar* scalarArray = (SkScalar*)widthsArray; @@ -487,7 +489,7 @@ public: HB_FontRec font; FontData fontData; TextLayoutCacheValue::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text, - contextCount, flags); + start, count, contextCount, flags); int glyphCount = shaperItem.num_glyphs; for (int i = 0; i < glyphCount; i++) { @@ -531,7 +533,7 @@ public: jfloat totalAdvance = 0; TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags, - advancesArray, &totalAdvance); + advancesArray, totalAdvance); if (advances != NULL) { env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray); @@ -602,8 +604,10 @@ public: jint count, jint flags, jint offset, jint opt) { #if RTL_USE_HARFBUZZ jfloat scalarArray[count]; + jfloat totalAdvance = 0; + TextLayout::getTextRunAdvances(paint, text, start, count, count, flags, - scalarArray, NULL); + scalarArray, totalAdvance); #else SkScalar scalarArray[count]; jchar buffer[count]; diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp index 97a3cde..fa9a7b7 100644 --- a/core/jni/android/graphics/TextLayout.cpp +++ b/core/jni/android/graphics/TextLayout.cpp @@ -253,22 +253,21 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars, void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, - jfloat* resultAdvances, jfloat* resultTotalAdvance) { + 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, contextCount, dirFlags); + value = TextLayoutCache::getInstance().getValue( + paint, chars, start, count, contextCount, dirFlags); #else value = new TextLayoutCacheValue(); - value->computeValues(paint, chars, contextCount, dirFlags); + value->computeValues(paint, chars, start, count, contextCount, dirFlags); #endif if (value != NULL) { - if (resultAdvances) { - value->getAdvances(start, count, resultAdvances); - } - if (resultTotalAdvance) { - *resultTotalAdvance = value->getTotalAdvance(start, count); + if (resultAdvances != NULL) { + memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat)); } + resultTotalAdvance = value->getTotalAdvance(); } } @@ -276,87 +275,18 @@ void TextLayout::getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint s jint count, jint contextCount, jint dirFlags, jfloat* resultAdvances, jfloat& resultTotalAdvance) { // Compute advances and return them - TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, contextCount, - dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL, NULL); + TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, start, count, contextCount, + dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL); } void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, jfloat* resultAdvances, jfloat& resultTotalAdvance) { // Compute advances and return them - computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags, + TextLayoutCacheValue::computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags, resultAdvances, &resultTotalAdvance); } -void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars, - size_t start, size_t count, size_t contextCount, int dirFlags, - jfloat* outAdvances, jfloat* outTotalAdvance) { - SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); - jchar* buffer = tempBuffer.get(); - SkScalar* scalarArray = (SkScalar*)outAdvances; - - // this is where we'd call harfbuzz - // for now we just use ushape.c - size_t widths; - const jchar* text; - if (dirFlags & 0x1) { // rtl, call arabic shaping in case - UErrorCode status = U_ZERO_ERROR; - // Use fixed length since we need to keep start and count valid - u_shapeArabic(chars, contextCount, buffer, contextCount, - U_SHAPE_LENGTH_FIXED_SPACES_NEAR | - U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | - U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); - // we shouldn't fail unless there's an out of memory condition, - // in which case we're hosed anyway - for (int i = start, e = i + count; i < e; ++i) { - if (buffer[i] == UNICODE_NOT_A_CHAR) { - buffer[i] = UNICODE_ZWSP; // zero-width-space for skia - } - } - text = buffer + start; - widths = paint->getTextWidths(text, count << 1, scalarArray); - } else { - text = chars + start; - widths = paint->getTextWidths(text, count << 1, scalarArray); - } - - jfloat totalAdvance = 0; - if (widths < count) { -#if DEBUG_ADVANCES - LOGD("ICU -- count=%d", widths); -#endif - // Skia operates on code points, not code units, so surrogate pairs return only - // one value. Expand the result so we have one value per UTF-16 code unit. - - // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, - // leaving the remaining widths zero. Not nice. - for (size_t i = 0, p = 0; i < widths; ++i) { - totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]); - if (p < count && - text[p] >= UNICODE_FIRST_LOW_SURROGATE && - text[p] < UNICODE_FIRST_PRIVATE_USE && - text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE && - text[p-1] < UNICODE_FIRST_LOW_SURROGATE) { - outAdvances[p++] = 0; - } -#if DEBUG_ADVANCES - LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); -#endif - } - } else { -#if DEBUG_ADVANCES - LOGD("ICU -- count=%d", count); -#endif - for (size_t i = 0; i < count; i++) { - totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]); -#if DEBUG_ADVANCES - LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); -#endif - } - } - *outTotalAdvance = totalAdvance; -} - // Draws a paragraph of text on a single line, running bidi and shaping void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len, int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas) { diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h index 5dc50ff..0a29d78 100644 --- a/core/jni/android/graphics/TextLayout.h +++ b/core/jni/android/graphics/TextLayout.h @@ -71,7 +71,7 @@ public: static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, - jfloat* resultAdvances, jfloat* resultTotalAdvance); + jfloat* resultAdvances, jfloat& resultTotalAdvance); static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start, jint count, jint contextCount, jint dirFlags, @@ -106,9 +106,5 @@ private: UErrorCode &status); static void handleText(SkPaint* paint, const jchar* text, jsize len, int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path); - - static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, - size_t start, size_t count, size_t contextCount, int dirFlags, - jfloat* outAdvances, jfloat* outTotalAdvance); }; } // namespace android diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index cf87a99..d04e059 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -111,8 +111,8 @@ void TextLayoutCache::clear() { /* * Caching */ -sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, const jchar* text, - jint contextCount, jint dirFlags) { +sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, + const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) { AutoMutex _l(mLock); nsecs_t startTime = 0; if (mDebugEnabled) { @@ -120,7 +120,7 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, const jchar* } // Create the key - TextLayoutCacheKey key(paint, text, contextCount, dirFlags); + TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags); // Get value from cache if possible sp<TextLayoutCacheValue> value = mCache.get(key); @@ -134,7 +134,7 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, const jchar* value = new TextLayoutCacheValue(); // Compute advances and store them - value->computeValues(paint, text, contextCount, dirFlags); + value->computeValues(paint, text, start, count, contextCount, dirFlags); nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC); @@ -163,19 +163,19 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, const jchar* // Update timing information for statistics value->setElapsedTime(endTime - startTime); - LOGD("CACHE MISS: Added entry with " + LOGD("CACHE MISS: Added entry with start=%d, count=%d, " "contextCount=%d, entry size %d bytes, remaining space %d bytes" " - Compute time in nanos: %d - Text='%s' ", - contextCount, size, mMaxSize - mSize, value->getElapsedTime(), + start, count, contextCount, size, mMaxSize - mSize, value->getElapsedTime(), String8(text, contextCount).string()); } } else { if (mDebugEnabled) { LOGD("CACHE MISS: Calculated but not storing entry because it is too big " - "with contextCount=%d, " + "with start=%d, count=%d, contextCount=%d, " "entry size %d bytes, remaining space %d bytes" " - Compute time in nanos: %lld - Text='%s'", - contextCount, size, mMaxSize - mSize, endTime, + start, count, contextCount, size, mMaxSize - mSize, endTime, String8(text, contextCount).string()); } value.clear(); @@ -190,10 +190,10 @@ sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint, const jchar* if (value->getElapsedTime() > 0) { float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet) / ((float)value->getElapsedTime())); - LOGD("CACHE HIT #%d with contextCount=%d " + LOGD("CACHE HIT #%d with start=%d, count=%d, contextCount=%d " "- Compute time in nanos: %d - " "Cache get time in nanos: %lld - Gain in percent: %2.2f - Text='%s' ", - mCacheHitCount, contextCount, + mCacheHitCount, start, count, contextCount, value->getElapsedTime(), elapsedTimeThruCacheGet, deltaPercent, String8(text, contextCount).string()); } @@ -224,14 +224,15 @@ void TextLayoutCache::dumpCacheStats() { /** * TextLayoutCacheKey */ -TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), contextCount(0), +TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), start(0), count(0), contextCount(0), dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0), hinting(SkPaint::kNo_Hinting) { } TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, - const UChar* text, size_t contextCount, int dirFlags) : - text(text), contextCount(contextCount), + const UChar* text, size_t start, size_t count, + size_t contextCount, int dirFlags) : + text(text), start(start), count(count), contextCount(contextCount), dirFlags(dirFlags) { typeface = paint->getTypeface(); textSize = paint->getTextSize(); @@ -241,32 +242,20 @@ TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, hinting = paint->getHinting(); } -TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) : - text(NULL), - textCopy(other.textCopy), - contextCount(other.contextCount), - dirFlags(other.dirFlags), - typeface(other.typeface), - textSize(other.textSize), - textSkewX(other.textSkewX), - textScaleX(other.textScaleX), - flags(other.flags), - hinting(other.hinting) { - if (other.text) { - textCopy.setTo(other.text); - } -} - bool TextLayoutCacheKey::operator<(const TextLayoutCacheKey& rhs) const { - LTE_INT(contextCount) { - LTE_INT(typeface) { - LTE_FLOAT(textSize) { - LTE_FLOAT(textSkewX) { - LTE_FLOAT(textScaleX) { - LTE_INT(flags) { - LTE_INT(hinting) { - LTE_INT(dirFlags) { - return strncmp16(getText(), rhs.getText(), contextCount) < 0; + LTE_INT(count) { + LTE_INT(contextCount) { + LTE_INT(start) { + LTE_INT(typeface) { + LTE_FLOAT(textSize) { + LTE_FLOAT(textSkewX) { + LTE_FLOAT(textScaleX) { + LTE_INT(flags) { + LTE_INT(hinting) { + LTE_INT(dirFlags) { + return strncmp16(text, rhs.text, contextCount) < 0; + } + } } } } @@ -280,7 +269,7 @@ bool TextLayoutCacheKey::operator<(const TextLayoutCacheKey& rhs) const { void TextLayoutCacheKey::internalTextCopy() { textCopy.setTo(text, contextCount); - text = NULL; + text = textCopy.string(); } size_t TextLayoutCacheKey::getSize() { @@ -292,13 +281,12 @@ size_t TextLayoutCacheKey::getSize() { */ TextLayoutCacheValue::TextLayoutCacheValue() : mAdvances(NULL), mTotalAdvance(0), mAdvancesCount(0), - mGlyphs(NULL), mGlyphsCount(0), mLogClusters(NULL), mElapsedTime(0) { + mGlyphs(NULL), mGlyphsCount(0), mElapsedTime(0) { } TextLayoutCacheValue::~TextLayoutCacheValue() { delete[] mAdvances; delete[] mGlyphs; - delete[] mLogClusters; } void TextLayoutCacheValue::setElapsedTime(uint32_t time) { @@ -309,16 +297,21 @@ uint32_t TextLayoutCacheValue::getElapsedTime() { return mElapsedTime; } -void TextLayoutCacheValue::computeValues(SkPaint* paint, const UChar* chars, size_t contextCount, - int dirFlags) { - mAdvancesCount = contextCount; - mAdvances = new float[contextCount]; +void TextLayoutCacheValue::computeValues(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, int dirFlags) { + mAdvancesCount = count; + mAdvances = new float[count]; - computeValuesWithHarfbuzz(paint, chars, contextCount, dirFlags, - mAdvances, &mTotalAdvance, &mGlyphs, &mGlyphsCount, &mLogClusters); +#if RTL_USE_HARFBUZZ + computeValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags, + mAdvances, &mTotalAdvance, &mGlyphs, &mGlyphsCount); +#else + computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags, + mAdvances, &mTotalAdvance); +#endif #if DEBUG_ADVANCES - LOGD("Advances - countextCount=%d - totalAdvance=%f - " - "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", contextCount, mTotalAdvance, + LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - " + "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, mTotalAdvance, mAdvances[0], mAdvances[1], mAdvances[2], mAdvances[3]); #endif } @@ -329,7 +322,8 @@ size_t TextLayoutCacheValue::getSize() { } void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, - FontData* fontData, SkPaint* paint, const UChar* chars, size_t contextCount, bool isRTL) { + FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, + size_t contextCount, bool isRTL) { font->klass = &harfbuzzSkiaClass; font->userData = 0; // The values which harfbuzzSkiaClass returns are already scaled to @@ -358,8 +352,8 @@ void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec } shaperItem->log_clusters = new unsigned short[contextCount]; - shaperItem->item.pos = 0; - shaperItem->item.length = contextCount; + shaperItem->item.pos = start; + shaperItem->item.length = count; shaperItem->item.bidiLevel = isRTL; shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common; @@ -378,9 +372,11 @@ void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec } void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, - FontData* fontData, SkPaint* paint, const UChar* chars, size_t contextCount, bool isRTL) { + FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count, + size_t contextCount, bool isRTL) { // Setup Harfbuzz Shaper - setupShaperItem(shaperItem, font, fontData, paint, chars, contextCount, isRTL); + setupShaperItem(shaperItem, font, fontData, paint, chars, start, count, + contextCount, isRTL); // Shape resetGlyphArrays(shaperItem); @@ -395,12 +391,11 @@ void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontR struct GlyphRun { inline GlyphRun() {} - inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL, unsigned short* logClusters) : - glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL), logClusters(logClusters) { } + inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL) : + glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL) { } jchar* glyphs; size_t glyphsCount; int isRTL; - unsigned short* logClusters; }; void static reverseGlyphArray(jchar* glyphs, size_t count) { @@ -412,9 +407,9 @@ void static reverseGlyphArray(jchar* glyphs, size_t count) { } void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, - size_t contextCount, int dirFlags, + size_t start, size_t count, size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance, - jchar** outGlyphs, size_t* outGlyphsCount, unsigned short** outLogClusters) { + jchar** outGlyphs, size_t* outGlyphsCount) { UBiDiLevel bidiReq = 0; bool forceLTR = false; @@ -434,8 +429,8 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d", forceLTR, forceRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars, contextCount, forceRTL, - outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount, outLogClusters); + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, forceRTL, + outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); if (forceRTL && *outGlyphsCount > 1) { reverseGlyphArray(*outGlyphs, *outGlyphsCount); @@ -458,10 +453,10 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar bool isRTL = (paraDir == 1); #if DEBUG_GLYPHS LOGD("computeValuesWithHarfbuzz -- processing SINGLE run " - "-- contextCount=%d isRTL=%d", contextCount, isRTL); + "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars, contextCount, - isRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount, outLogClusters); + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, + isRTL, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); if (isRTL && *outGlyphsCount > 1) { reverseGlyphArray(*outGlyphs, *outGlyphsCount); @@ -470,22 +465,40 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar Vector<GlyphRun> glyphRuns; jchar* runGlyphs; size_t runGlyphsCount = 0; - unsigned short* runLogClusters; + int32_t end = start + count; for (size_t i = 0; i < rc; ++i) { int32_t startRun; int32_t lengthRun; UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun); + if (startRun >= end) { + break; + } + + int32_t endRun = startRun + lengthRun; + if (endRun <= start) { + continue; + } + + if (startRun < start) { + startRun = start; + } + if (endRun > end) { + endRun = end; + } + + lengthRun = endRun - startRun; + bool isRTL = (runDir == UBIDI_RTL); jfloat runTotalAdvance = 0; #if DEBUG_GLYPHS LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d isRTL=%d", startRun, lengthRun, isRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars + startRun, - lengthRun, isRTL, + computeRunValuesWithHarfbuzz(paint, chars, startRun, + lengthRun, contextCount, isRTL, outAdvances, &runTotalAdvance, - &runGlyphs, &runGlyphsCount, &runLogClusters); + &runGlyphs, &runGlyphsCount); outAdvances += lengthRun; *outTotalAdvance += runTotalAdvance; @@ -497,14 +510,11 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar LOGD(" -- glyphs[%d]=%d", j, runGlyphs[j]); } #endif - glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, isRTL, runLogClusters)); + glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, isRTL)); } *outGlyphs = new jchar[*outGlyphsCount]; - *outLogClusters = new unsigned short[*outGlyphsCount]; jchar* glyphs = *outGlyphs; - unsigned short* logClusters = *outLogClusters; - for (size_t i = 0; i < glyphRuns.size(); i++) { const GlyphRun& glyphRun = glyphRuns.itemAt(i); if (glyphRun.isRTL) { @@ -514,13 +524,8 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar } else { memcpy(glyphs, glyphRun.glyphs, glyphRun.glyphsCount * sizeof(jchar)); } - memcpy(logClusters, glyphRun.logClusters, glyphRun.glyphsCount * sizeof(unsigned short)); - glyphs += glyphRun.glyphsCount; - logClusters += glyphRun.glyphsCount; - delete[] glyphRun.glyphs; - delete[] glyphRun.logClusters; } } } @@ -530,10 +535,10 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar bool isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL); #if DEBUG_GLYPHS LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering a SINGLE Run " - "-- contextCount=%d isRTL=%d", contextCount, isRTL); + "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL); #endif - computeRunValuesWithHarfbuzz(paint, chars, contextCount, isRTL, - outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount, outLogClusters); + computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, isRTL, + outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount); if (isRTL && *outGlyphsCount > 1) { reverseGlyphArray(*outGlyphs, *outGlyphsCount); @@ -555,16 +560,17 @@ static void logGlyphs(HB_ShaperItem shaperItem) { } void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, - size_t contextCount, bool isRTL, + size_t start, size_t count, size_t contextCount, bool isRTL, jfloat* outAdvances, jfloat* outTotalAdvance, - jchar** outGlyphs, size_t* outGlyphsCount, unsigned short** outLogClusters) { + jchar** outGlyphs, size_t* outGlyphsCount) { HB_ShaperItem shaperItem; HB_FontRec font; FontData fontData; - shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, contextCount, isRTL); + shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count, + contextCount, isRTL); -#if DEBUG_GLYPHS || DEBUG_ADVANCES +#if DEBUG_GLYPHS LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs, shaperItem.kerning_applied); LOGD(" -- string= '%s'", String8(chars + start, count).string()); @@ -577,7 +583,7 @@ void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UC #if DEBUG_GLYPHS LOGD("HARFBUZZ -- advances array is empty or num_glypth = 0"); #endif - for (size_t i = 0; i < contextCount; i++) { + for (size_t i = 0; i < count; i++) { outAdvances[i] = 0; } *outTotalAdvance = 0; @@ -594,13 +600,13 @@ void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UC } // Get Advances and their total jfloat totalAdvance = outAdvances[0] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[0]]); - for (size_t i = 1; i < contextCount; i++) { + for (size_t i = 1; i < count; i++) { size_t clusterPrevious = shaperItem.log_clusters[i - 1]; size_t cluster = shaperItem.log_clusters[i]; if (cluster == clusterPrevious) { outAdvances[i] = 0; } else { - totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[cluster]); + totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[i]]); } } *outTotalAdvance = totalAdvance; @@ -621,19 +627,80 @@ void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UC } } - // Get LogClusters - if (outLogClusters) { - *outLogClusters = new unsigned short[shaperItem.num_glyphs]; - for (size_t i = 0; i < shaperItem.num_glyphs; i++) { - (*outLogClusters)[i] = shaperItem.log_clusters[i]; - } - } - // Cleaning deleteGlyphArrays(&shaperItem); HB_FreeFace(shaperItem.face); } +void TextLayoutCacheValue::computeAdvancesWithICU(SkPaint* paint, const UChar* chars, + size_t start, size_t count, size_t contextCount, int dirFlags, + jfloat* outAdvances, jfloat* outTotalAdvance) { + SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount); + jchar* buffer = tempBuffer.get(); + SkScalar* scalarArray = (SkScalar*)outAdvances; + + // this is where we'd call harfbuzz + // for now we just use ushape.c + size_t widths; + const jchar* text; + if (dirFlags & 0x1) { // rtl, call arabic shaping in case + UErrorCode status = U_ZERO_ERROR; + // Use fixed length since we need to keep start and count valid + u_shapeArabic(chars, contextCount, buffer, contextCount, + U_SHAPE_LENGTH_FIXED_SPACES_NEAR | + U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | + U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); + // we shouldn't fail unless there's an out of memory condition, + // in which case we're hosed anyway + for (int i = start, e = i + count; i < e; ++i) { + if (buffer[i] == UNICODE_NOT_A_CHAR) { + buffer[i] = UNICODE_ZWSP; // zero-width-space for skia + } + } + text = buffer + start; + widths = paint->getTextWidths(text, count << 1, scalarArray); + } else { + text = chars + start; + widths = paint->getTextWidths(text, count << 1, scalarArray); + } + + jfloat totalAdvance = 0; + if (widths < count) { +#if DEBUG_ADVANCES + LOGD("ICU -- count=%d", widths); +#endif + // Skia operates on code points, not code units, so surrogate pairs return only + // one value. Expand the result so we have one value per UTF-16 code unit. + + // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, + // leaving the remaining widths zero. Not nice. + for (size_t i = 0, p = 0; i < widths; ++i) { + totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]); + if (p < count && + text[p] >= UNICODE_FIRST_LOW_SURROGATE && + text[p] < UNICODE_FIRST_PRIVATE_USE && + text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE && + text[p-1] < UNICODE_FIRST_LOW_SURROGATE) { + outAdvances[p++] = 0; + } +#if DEBUG_ADVANCES + LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); +#endif + } + } else { +#if DEBUG_ADVANCES + LOGD("ICU -- count=%d", count); +#endif + for (size_t i = 0; i < count; i++) { + totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]); +#if DEBUG_ADVANCES + LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance); +#endif + } + } + *outTotalAdvance = totalAdvance; +} + void TextLayoutCacheValue::deleteGlyphArrays(HB_ShaperItem* shaperItem) { delete[] shaperItem->glyphs; delete[] shaperItem->attributes; @@ -659,62 +726,5 @@ void TextLayoutCacheValue::resetGlyphArrays(HB_ShaperItem* shaperItem) { memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0])); } -void TextLayoutCacheValue::getAdvances(size_t start, size_t count, jfloat* outAdvances) { - memcpy(outAdvances, mAdvances + start, count * sizeof(jfloat)); -#if DEBUG_ADVANCES - LOGD("getAdvances - start=%d count=%d", start, count); - for (size_t i = 0; i < count; i++) { - LOGD(" adv[%d] = %f", i, outAdvances[i]); - } -#endif -} - -jfloat TextLayoutCacheValue::getTotalAdvance(size_t start, size_t count) { - jfloat outTotalAdvance = 0; - for (size_t i = start; i < start + count; i++) { - outTotalAdvance += mAdvances[i]; - } -#if DEBUG_ADVANCES - LOGD("getTotalAdvance - start=%d count=%d - total=%f", start, count, outTotalAdvance); -#endif - return outTotalAdvance; -} - -void TextLayoutCacheValue::getGlyphsIndexAndCount(size_t start, size_t count, size_t* outStartIndex, - size_t* outGlyphsCount) { - *outStartIndex = 0; - size_t endIndex = 0; - for(size_t i = 0; i < mGlyphsCount; i++) { - if (mLogClusters[i] <= start) { - *outStartIndex = i; - endIndex = i; - continue; - } - if (mLogClusters[i] <= start + count) { - endIndex = i; - } - } - *outGlyphsCount = endIndex - *outStartIndex + 1; -#if DEBUG_GLYPHS - LOGD("getGlyphsIndexes - start=%d count=%d - startIndex=%d count=%d", start, count, - *outStartIndex, *outGlyphsCount); - for(size_t i = 0; i < mGlyphsCount; i++) { - LOGD("getGlyphs - all - glyph[%d] = %d", i, mGlyphs[i]); - } - for(size_t i = 0; i < mGlyphsCount; i++) { - LOGD("getGlyphs - all - logcl[%d] = %d", i, mLogClusters[i]); - } -#endif -} - -void TextLayoutCacheValue::getGlyphs(size_t startIndex, size_t count, jchar* outGlyphs) { - memcpy(outGlyphs, mGlyphs + startIndex, count * sizeof(jchar)); -#if DEBUG_GLYPHS - for (size_t i = 0; i < count; i++) { - LOGD("getGlyphs - result - glyph[%d] = %d", i, outGlyphs[i]); - } -#endif -} - } // namespace android diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h index 964c647..0d8d71f 100644 --- a/core/jni/android/graphics/TextLayoutCache.h +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -69,9 +69,8 @@ public: TextLayoutCacheKey(); TextLayoutCacheKey(const SkPaint* paint, - const UChar* text, size_t contextCount, int dirFlags); - - TextLayoutCacheKey(const TextLayoutCacheKey& other); + const UChar* text, size_t start, size_t count, + size_t contextCount, int dirFlags); bool operator<(const TextLayoutCacheKey& rhs) const; @@ -87,8 +86,10 @@ public: size_t getSize(); private: - const UChar* text; // if text is NULL, use textCopy + const UChar* text; String16 textCopy; + size_t start; + size_t count; size_t contextCount; int dirFlags; SkTypeface* typeface; @@ -97,10 +98,6 @@ private: SkScalar textScaleX; uint32_t flags; SkPaint::Hinting hinting; - - inline const UChar* getText() const { - return text ? text : textCopy.string(); - } }; // TextLayoutCacheKey /* @@ -116,16 +113,14 @@ public: void setElapsedTime(uint32_t time); uint32_t getElapsedTime(); - void computeValues(SkPaint* paint, const UChar* chars, size_t contextCount, int dirFlags); - - void getAdvances(size_t start, size_t count, jfloat* outAdvances); - - jfloat getTotalAdvance(size_t start, size_t count); + void computeValues(SkPaint* paint, const UChar* chars, size_t start, size_t count, + size_t contextCount, int dirFlags); - void getGlyphsIndexAndCount(size_t start, size_t count, size_t* outStartIndex, - size_t* outGlyphsCount); - - void getGlyphs(size_t startIndex, size_t count, jchar* outGlyphs); + inline const jfloat* getAdvances() const { return mAdvances; } + inline size_t getAdvancesCount() const { return mAdvancesCount; } + inline jfloat getTotalAdvance() const { return mTotalAdvance; } + inline const jchar* getGlyphs() const { return mGlyphs; } + inline size_t getGlyphsCount() const { return mGlyphsCount; } /** * Get the size of the Cache entry @@ -133,15 +128,17 @@ public: size_t getSize(); static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, - SkPaint* paint, const UChar* chars, size_t contextCount, bool isRTL); + SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, + bool isRTL); static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData, - SkPaint* paint, const UChar* chars, size_t contextCount, bool isRTL); + SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, + bool isRTL); - static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, - size_t contextCount, int dirFlags, + static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance, - jchar** outGlyphs, size_t* outGlyphsCount, unsigned short** outLogClusters); + jchar** outGlyphs, size_t* outGlyphsCount); static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags, @@ -174,11 +171,6 @@ private: size_t mGlyphsCount; /** - * Harfbuzz Log Clusters - */ - unsigned short* mLogClusters; - - /** * Time for computing the values (in milliseconds) */ uint32_t mElapsedTime; @@ -187,10 +179,10 @@ private: static void createGlyphArrays(HB_ShaperItem* shaperItem, int size); static void resetGlyphArrays(HB_ShaperItem* shaperItem); - static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, - size_t contextCount, bool isRTL, + static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start, + size_t count, size_t contextCount, bool isRTL, jfloat* outAdvances, jfloat* outTotalAdvance, - jchar** outGlyphs, size_t* outGlyphsCount, unsigned short** outLogClusters); + jchar** outGlyphs, size_t* outGlyphsCount); }; // TextLayoutCacheValue /** @@ -214,8 +206,8 @@ public: */ void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc); - sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint contextCount, - jint dirFlags); + sp<TextLayoutCacheValue> getValue(SkPaint* paint, + const jchar* text, jint start, jint count, jint contextCount, jint dirFlags); /** * Clear the cache diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 0c35a16..395e417 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -477,23 +477,19 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count, #if RTL_USE_HARFBUZZ sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE - value = TextLayoutCache::getInstance().getValue(paint, text, count, flags); + value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags); if (value == NULL) { LOGE("Cannot get TextLayoutCache value"); return ; } #else value = new TextLayoutCacheValue(); - value->computeValues(paint, text, count, flags); + value->computeValues(paint, text, 0, count, count, flags); #endif - size_t startIndex = 0; - size_t glyphsCount = 0; - value->getGlyphsIndexAndCount(0, count, &startIndex, &glyphsCount); - jchar* glyphs = new jchar[glyphsCount]; - value->getGlyphs(startIndex, glyphsCount, glyphs); - int bytesCount = glyphsCount * sizeof(jchar); - renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint); - delete[] glyphs; + const jchar* glyphArray = value->getGlyphs(); + int glyphCount = value->getGlyphsCount(); + int bytesCount = glyphCount * sizeof(jchar); + renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint); #else const jchar *workText; jchar* buffer = NULL; @@ -511,23 +507,19 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text, #if RTL_USE_HARFBUZZ sp<TextLayoutCacheValue> value; #if USE_TEXT_LAYOUT_CACHE - value = TextLayoutCache::getInstance().getValue(paint, text, contextCount, flags); + value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags); if (value == NULL) { LOGE("Cannot get TextLayoutCache value"); return ; } #else value = new TextLayoutCacheValue(); - value->computeValues(paint, text, contextCount, flags); + value->computeValues(paint, text, start, count, contextCount, flags); #endif - size_t startIndex = 0; - size_t glyphsCount = 0; - value->getGlyphsIndexAndCount(start, count, &startIndex, &glyphsCount); - jchar* glyphs = new jchar[glyphsCount]; - value->getGlyphs(startIndex, glyphsCount, glyphs); - int bytesCount = glyphsCount * sizeof(jchar); - renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint); - delete[] glyphs; + const jchar* glyphArray = value->getGlyphs(); + int glyphCount = value->getGlyphsCount(); + int bytesCount = glyphCount * sizeof(jchar); + renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint); #else uint8_t rtl = flags & 0x1; if (rtl) { |