Merge "TextLayoutCache - add glyphs caching"

This commit is contained in:
Fabrice Di Meglio
2011-04-08 14:51:08 -07:00
committed by Android (Google) Code Review
8 changed files with 273 additions and 125 deletions

View File

@@ -27,6 +27,7 @@
#include "SkTemplates.h"
#include "TextLayout.h"
#include "TextLayoutCache.h"
#include "unicode/ubidi.h"
#include "unicode/ushape.h"
@@ -755,11 +756,57 @@ public:
env->ReleaseStringChars(text, textArray);
}
static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray glyphs, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray text, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
paint, textArray + index, 0, count, count, flags);
if (value != NULL) {
#if DEBUG_GLYPHS
LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
for (size_t i = 0; i < value->getGlyphsCount(); i++) {
LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]);
}
#endif
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
x, y, flags, paint);
}
#else
TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
#endif
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void drawTextWithGlyphs__StringIIFFIPaint(JNIEnv* env, jobject,
SkCanvas* canvas, jstring text,
int start, int end,
jfloat x, jfloat y, int flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
size_t count = end - start;
sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
paint, textArray, start, count, count, flags);
if (value != NULL) {
#if DEBUG_GLYPHS
LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
for (size_t i = 0; i < value->getGlyphsCount(); i++) {
LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]);
}
#endif
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
x, y, flags, paint);
}
#else
TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
#endif
env->ReleaseStringChars(text, textArray);
}
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
// TODO: need to suppress this code after the GL renderer is modified for not
// copying the paint
@@ -768,10 +815,18 @@ public:
// Define Glyph encoding
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
TextLayout::drawText(paint, glyphArray + index, count, flags, x, y, canvas);
canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
// Get back old encoding
paint->setTextEncoding(oldEncoding);
}
static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray glyphs, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
doDrawGlyphs(canvas, glyphArray, index, count, x, y, flags, paint);
env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
}
@@ -967,6 +1022,10 @@ static JNINativeMethod gCanvasMethods[] = {
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
{"native_drawTextWithGlyphs","(I[CIIFFII)V",
(void*) SkCanvasGlue::drawTextWithGlyphs___CIIFFIPaint},
{"native_drawTextWithGlyphs","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawTextWithGlyphs__StringIIFFIPaint},
{"native_drawGlyphs","(I[CIIFFII)V",
(void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFII)V",

View File

@@ -51,6 +51,8 @@ static RtlDebugLevel readRtlDebugLevel() {
// Define if we want (1) to have Advances debug values or not (0)
#define DEBUG_ADVANCES 0
// Define if we want (1) to have Glyphs debug values or not (0)
#define DEBUG_GLYPHS 0
} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H

View File

@@ -26,10 +26,6 @@
namespace android {
#if USE_TEXT_LAYOUT_CACHE
TextLayoutCache TextLayout::mCache;
#endif
// Returns true if we might need layout. If bidiFlags force LTR, assume no layout, if
// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
// looking for a character >= the first RTL character in unicode and assume we do if
@@ -260,12 +256,16 @@ void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint sta
jfloat* resultAdvances, jfloat& resultTotalAdvance) {
#if USE_TEXT_LAYOUT_CACHE
// Return advances from the cache. Compute them if needed
mCache.getRunAdvances(paint, chars, start, count, contextCount,
dirFlags, resultAdvances, &resultTotalAdvance);
sp<TextLayoutCacheValue> layout = gTextLayoutCache.getValue(
paint, chars, start, count, contextCount, dirFlags);
if (layout != NULL) {
memcpy(resultAdvances, layout->getAdvances(), layout->getAdvancesCount() * sizeof(jfloat));
resultTotalAdvance = layout->getTotalAdvance();
}
#else
// Compute advances and return them
TextLayoutCacheValue::computeAdvances(paint, chars, start, count, contextCount, dirFlags,
resultAdvances, &resultTotalAdvance);
TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, start, count, contextCount,
dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL );
#endif
}
@@ -273,8 +273,8 @@ 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::computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
resultAdvances, &resultTotalAdvance);
TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, start, count, contextCount,
dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL);
}
void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,

View File

@@ -41,6 +41,11 @@ namespace android {
*/
#define USE_TEXT_LAYOUT_CACHE 1
#if USE_TEXT_LAYOUT_CACHE
static TextLayoutCache gTextLayoutCache;
#endif
class TextLayout {
public:
@@ -106,10 +111,5 @@ private:
UErrorCode &status);
static void handleText(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat x, jfloat y, SkCanvas* canvas, SkPath* path);
#if USE_TEXT_LAYOUT_CACHE
static TextLayoutCache mCache;
#endif
};
}
} // namespace android

View File

@@ -18,15 +18,15 @@
namespace android {
TextLayoutCache::TextLayoutCache():
mCache(GenerationCache<TextLayoutCacheKey, TextLayoutCacheValue*>::kUnlimitedCapacity),
TextLayoutCache::TextLayoutCache() :
mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
mCacheHitCount(0), mNanosecondsSaved(0) {
init();
}
TextLayoutCache::TextLayoutCache(uint32_t max):
mCache(GenerationCache<TextLayoutCacheKey, TextLayoutCacheValue*>::kUnlimitedCapacity),
mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
mSize(0), mMaxSize(max),
mCacheHitCount(0), mNanosecondsSaved(0) {
init();
@@ -88,14 +88,14 @@ void TextLayoutCache::removeOldests() {
/**
* Callbacks
*/
void TextLayoutCache::operator()(TextLayoutCacheKey& text, TextLayoutCacheValue*& desc) {
if (desc) {
void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc) {
if (desc != NULL) {
size_t totalSizeToDelete = text.getSize() + desc->getSize();
mSize -= totalSizeToDelete;
if (mDebugEnabled) {
LOGD("Cache value deleted, size = %d", totalSizeToDelete);
}
delete desc;
desc.clear();
}
}
@@ -109,29 +109,26 @@ void TextLayoutCache::clear() {
/*
* Caching
*/
void TextLayoutCache::getRunAdvances(SkPaint* paint, const jchar* text,
jint start, jint count, jint contextCount, jint dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance) {
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) {
startTime = systemTime(SYSTEM_TIME_MONOTONIC);
}
// Create the key
TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
// Get entry for cache if possible
TextLayoutCacheValue* value = mCache.get(key);
// Get value from cache if possible
sp<TextLayoutCacheValue> value = mCache.get(key);
// Value not found for the entry, we need to add a new value in the cache
if (!value) {
// Value not found for the key, we need to add a new value in the cache
if (value == NULL) {
value = new TextLayoutCacheValue();
// Compute advances and store them
value->computeAdvances(paint, text, start, count, contextCount, dirFlags);
value->copyResult(outAdvances, outTotalAdvance);
value->computeValues(paint, text, start, count, contextCount, dirFlags);
// Don't bother to add in the cache if the entry is too big
size_t size = key.getSize() + value->getSize();
@@ -156,7 +153,7 @@ void TextLayoutCache::getRunAdvances(SkPaint* paint, const jchar* text,
mCache.put(key, value);
if (mDebugEnabled) {
// Update timing information for statistics.
// Update timing information for statistics
value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
LOGD("CACHE MISS: Added entry for text='%s' with start=%d, count=%d, "
@@ -174,11 +171,10 @@ void TextLayoutCache::getRunAdvances(SkPaint* paint, const jchar* text,
String8(text, contextCount).string(), start, count, contextCount,
size, mMaxSize - mSize, value->getElapsedTime());
}
delete value;
value.clear();
}
} else {
// This is a cache hit, just copy the pre-computed results
value->copyResult(outAdvances, outTotalAdvance);
// This is a cache hit, just log timestamp and user infos
if (mDebugEnabled) {
nsecs_t elapsedTimeThruCacheGet = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
mNanosecondsSaved += (value->getElapsedTime() - elapsedTimeThruCacheGet);
@@ -199,6 +195,7 @@ void TextLayoutCache::getRunAdvances(SkPaint* paint, const jchar* text,
}
}
}
return value;
}
void TextLayoutCache::dumpCacheStats() {
@@ -218,7 +215,7 @@ void TextLayoutCache::dumpCacheStats() {
/**
* TextLayoutCacheKey
*/
TextLayoutCacheKey::TextLayoutCacheKey() : text(NULL), start(0), count(0), 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) {
}
@@ -273,49 +270,46 @@ size_t TextLayoutCacheKey::getSize() {
/**
* TextLayoutCacheValue
*/
TextLayoutCacheValue::TextLayoutCacheValue() {
advances = NULL;
totalAdvance = 0;
TextLayoutCacheValue::TextLayoutCacheValue() :
mAdvances(NULL), mTotalAdvance(0), mAdvancesCount(0),
mGlyphs(NULL), mGlyphsCount(0), mElapsedTime(0) {
}
TextLayoutCacheValue::~TextLayoutCacheValue() {
delete[] advances;
delete[] mAdvances;
delete[] mGlyphs;
}
void TextLayoutCacheValue::setElapsedTime(uint32_t time) {
elapsedTime = time;
mElapsedTime = time;
}
uint32_t TextLayoutCacheValue::getElapsedTime() {
return elapsedTime;
return mElapsedTime;
}
void TextLayoutCacheValue::computeAdvances(SkPaint* paint, const UChar* chars, size_t start,
void TextLayoutCacheValue::computeValues(SkPaint* paint, const UChar* chars, size_t start,
size_t count, size_t contextCount, int dirFlags) {
advances = new float[count];
this->count = count;
mAdvancesCount = count;
mAdvances = new float[count];
#if RTL_USE_HARFBUZZ
computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
advances, &totalAdvance);
computeValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
mAdvances, &mTotalAdvance, &mGlyphs, &mGlyphsCount);
#else
computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
advances, &totalAdvance);
mAdvances, &mTotalAdvance);
#endif
#if DEBUG_ADVANCES
LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - "
"adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, totalAdvance,
advances[0], advances[1], advances[2], advances[3]);
"adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, mTotalAdvance,
mAdvances[0], mAdvances[1], mAdvances[2], mAdvances[3]);
#endif
}
void TextLayoutCacheValue::copyResult(jfloat* outAdvances, jfloat* outTotalAdvance) {
memcpy(outAdvances, advances, count * sizeof(jfloat));
*outTotalAdvance = totalAdvance;
}
size_t TextLayoutCacheValue::getSize() {
return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * count;
return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvancesCount +
sizeof(jchar) * mGlyphsCount;
}
void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font,
@@ -387,49 +381,56 @@ void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontR
}
}
void TextLayoutCacheValue::computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars,
void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance) {
jfloat* outAdvances, jfloat* outTotalAdvance,
jchar** outGlyphs, size_t* outGlyphsCount) {
bool isRTL = dirFlags & 0x1;
// TODO: need to run BiDi algo here to breakdown the text in several runs
HB_ShaperItem shaperItem;
HB_FontRec font;
FontData fontData;
shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
contextCount, dirFlags);
#if DEBUG_ADVANCES
#if DEBUG_GLYPHS
LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
shaperItem.kerning_applied);
LOGD(" -- string= '%s'", String8(chars, contextCount).string());
LOGD(" -- isDevKernText=%d", paint->isDevKernText());
#endif
// Get Advances and their total
jfloat totalAdvance = 0;
for (size_t i = 0; i < count; i++) {
totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[i]);
#if DEBUG_ADVANCES
LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
totalAdvance);
#endif
}
*outTotalAdvance = totalAdvance;
// Get Glyphs
if (outGlyphs) {
*outGlyphsCount = shaperItem.num_glyphs;
*outGlyphs = new jchar[shaperItem.num_glyphs];
for (size_t i = 0; i < shaperItem.num_glyphs; i++) {
(*outGlyphs)[i] = (jchar) shaperItem.glyphs[i];
}
}
// Cleaning
deleteGlyphArrays(&shaperItem);
HB_FreeFace(shaperItem.face);
*outTotalAdvance = totalAdvance;
}
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

View File

@@ -24,6 +24,7 @@
#include <utils/String16.h>
#include <utils/GenerationCache.h>
#include <utils/Compare.h>
#include <utils/RefBase.h>
#include <SkPaint.h>
#include <SkTemplates.h>
@@ -101,18 +102,24 @@ private:
/*
* TextLayoutCacheValue is the Cache value
*/
class TextLayoutCacheValue {
class TextLayoutCacheValue : public RefBase {
protected:
~TextLayoutCacheValue();
public:
TextLayoutCacheValue();
~TextLayoutCacheValue();
void setElapsedTime(uint32_t time);
uint32_t getElapsedTime();
void computeAdvances(SkPaint* paint, const UChar* chars, 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 copyResult(jfloat* outAdvances, jfloat* outTotalAdvance);
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
@@ -127,20 +134,45 @@ public:
SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
int dirFlags);
static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance);
jfloat* outAdvances, jfloat* outTotalAdvance,
jchar** outGlyphs, size_t* outGlyphsCount);
static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start,
size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance);
private:
jfloat* advances;
jfloat totalAdvance;
size_t count;
/**
* Advances array
*/
jfloat* mAdvances;
uint32_t elapsedTime;
/**
* Total number of advances
*/
jfloat mTotalAdvance;
/**
* Allocated size for advances array
*/
size_t mAdvancesCount;
/**
* Glyphs array
*/
jchar* mGlyphs;
/**
* Total number of glyphs
*/
size_t mGlyphsCount;
/**
* Time for computing the values (in milliseconds)
*/
uint32_t mElapsedTime;
static void deleteGlyphArrays(HB_ShaperItem* shaperItem);
static void createGlyphArrays(HB_ShaperItem* shaperItem, int size);
@@ -148,8 +180,10 @@ private:
}; // TextLayoutCacheValue
class TextLayoutCache: public OnEntryRemoved<TextLayoutCacheKey, TextLayoutCacheValue*>
/**
* Cache of text layout information.
*/
class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >
{
public:
TextLayoutCache();
@@ -162,17 +196,13 @@ public:
}
/**
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
* Used as a callback when an entry is removed from the cache
* Do not invoke directly
*/
void operator()(TextLayoutCacheKey& text, TextLayoutCacheValue*& desc);
void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
/**
* Get cache entries
*/
void getRunAdvances(SkPaint* paint, const jchar* text,
jint start, jint count, jint contextCount, jint dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance);
sp<TextLayoutCacheValue> getValue(SkPaint* paint,
const jchar* text, jint start, jint count, jint contextCount, jint dirFlags);
/**
* Clear the cache
@@ -180,17 +210,17 @@ public:
void clear();
/**
* Sets the maximum size of the cache in bytes.
* Sets the maximum size of the cache in bytes
*/
void setMaxSize(uint32_t maxSize);
/**
* Returns the maximum size of the cache in bytes.
* Returns the maximum size of the cache in bytes
*/
uint32_t getMaxSize();
/**
* Returns the current size of the cache in bytes.
* Returns the current size of the cache in bytes
*/
uint32_t getSize();
@@ -198,7 +228,7 @@ private:
Mutex mLock;
bool mInitialized;
GenerationCache<TextLayoutCacheKey, TextLayoutCacheValue*> mCache;
GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache;
uint32_t mSize;
uint32_t mMaxSize;

View File

@@ -1329,29 +1329,6 @@ public class Canvas {
paint.mNativePaint);
}
/**
* Draw the glyphs, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param glyphs The glyphs to be drawn
* @param x The x-coordinate of the origin of the text being drawn
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*
* @hide
*
* Used only for BiDi / RTL Tests
*/
public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
Paint paint) {
if ((index | count | (index + count) |
(glyphs.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
@@ -1417,6 +1394,70 @@ public class Canvas {
}
}
/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param text The text to be drawn
* @param x The x-coordinate of the origin of the text being drawn
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*
* @hide
*
* Used only for BiDi / RTL Tests
*/
public void drawTextWithGlyphs(char[] text, int index, int count, float x, float y,
Paint paint) {
if ((index | count | (index + count) |
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
native_drawTextWithGlyphs(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
* Draw the text, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param text The text to be drawn
* @param x The x-coordinate of the origin of the text being drawn
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*
* @hide
*
* Used only for BiDi / RTL Tests
*/
public void drawTextWithGlyphs(String text, float x, float y, Paint paint) {
native_drawTextWithGlyphs(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
* Draw the glyphs, with origin at (x,y), using the specified paint. The
* origin is interpreted based on the Align setting in the paint.
*
* @param glyphs The glyphs to be drawn
* @param x The x-coordinate of the origin of the text being drawn
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*
* @hide
*
* Used only for BiDi / RTL Tests
*/
public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
Paint paint) {
if ((index | count | (index + count) |
(glyphs.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
paint.mNativePaint);
}
/**
* Render a run of all LTR or all RTL text, with shaping. This does not run
* bidi on the provided text, but renders it as a uniform right-to-left or
@@ -1745,9 +1786,17 @@ public class Canvas {
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int flags, int paint);
private static native void native_drawTextWithGlyphs(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int flags, int paint);
private static native void native_drawTextWithGlyphs(int nativeCanvas, String text,
int start, int end, float x,
float y, int flags, int paint);
private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
int index, int count, float x,
float y, int flags, int paint);
private static native void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int flags, int paint);

View File

@@ -150,11 +150,13 @@ public class BiDiTestView extends View {
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
paint.setColor(Color.WHITE);
char[] glyphs = new char[2*length];
int count = getGlyphs(text, glyphs, dir);
// char[] glyphs = new char[2*length];
// int count = getGlyphs(text, glyphs, dir);
//
// logGlypths(glyphs, count);
drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
// drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
@@ -167,6 +169,11 @@ public class BiDiTestView extends View {
canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
}
private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
paint.setBidiFlags(dir);
canvas.drawTextWithGlyphs(text, x, y, paint);
}
private void logGlypths(char[] glyphs, int count) {
Log.v(TAG, "GlyphIds - count=" + count);
for (int n = 0; n < count; n++) {