summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2011-06-01 14:56:19 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-06-01 14:56:19 -0700
commitcb0975b3c1c73d8bcadaca80e1ee99383750af60 (patch)
tree34828ffaae61de90897a11c92ae932a8e11502d4
parent0523c55e5fd31db06d78f742a79db94f21c2eece (diff)
parent726aeba80ffc6778a9bc3e0ee957b8d644183505 (diff)
downloadframeworks_base-cb0975b3c1c73d8bcadaca80e1ee99383750af60.zip
frameworks_base-cb0975b3c1c73d8bcadaca80e1ee99383750af60.tar.gz
frameworks_base-cb0975b3c1c73d8bcadaca80e1ee99383750af60.tar.bz2
Merge "Add support to OpenGLRendere to draw BiDi text. Bug #4350336"
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp12
-rw-r--r--libs/hwui/DisplayListRenderer.cpp1
-rw-r--r--libs/hwui/FontRenderer.cpp43
-rw-r--r--libs/hwui/FontRenderer.h61
-rw-r--r--libs/hwui/OpenGLRenderer.cpp22
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/Properties.h3
-rw-r--r--libs/hwui/TextDropShadowCache.h1
-rw-r--r--tests/BiDiTests/AndroidManifest.xml2
-rw-r--r--tests/BiDiTests/res/layout/basic.xml15
10 files changed, 99 insertions, 63 deletions
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e539cd2..e2832ed 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -42,7 +42,7 @@
#include <SkiaColorFilter.h>
#include <Rect.h>
-#include "TextLayout.h"
+#include <TextLayout.h>
namespace android {
@@ -419,7 +419,7 @@ static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
-#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
+#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
paint, text, 0, count, count, flags);
if (value == NULL) {
@@ -431,7 +431,8 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
#endif
const jchar* glyphArray = value->getGlyphs();
int glyphCount = value->getGlyphsCount();
- renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
+ int bytesCount = glyphCount * sizeof(jchar);
+ renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint);
#else
const jchar *workText;
jchar* buffer = NULL;
@@ -446,7 +447,7 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
-#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
+#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
paint, text, start, count, contextCount, flags);
if (value == NULL) {
@@ -458,7 +459,8 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
#endif
const jchar* glyphArray = value->getGlyphs();
int glyphCount = value->getGlyphsCount();
- renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
+ int bytesCount = glyphCount * sizeof(jchar);
+ renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint);
#else
uint8_t rtl = flags & 0x1;
if (rtl) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f8582d8..afab26a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -1151,6 +1151,7 @@ void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {
void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
float x, float y, SkPaint* paint) {
+ if (count <= 0) return;
addOp(DisplayList::DrawText);
addText(text, bytesCount);
addInt(count);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1ca0a19..9bf3de8 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -35,6 +35,7 @@ namespace uirenderer {
#define DEFAULT_TEXT_CACHE_WIDTH 1024
#define DEFAULT_TEXT_CACHE_HEIGHT 256
+// We should query these values from the GL context
#define MAX_TEXT_CACHE_WIDTH 2048
#define MAX_TEXT_CACHE_HEIGHT 2048
@@ -58,8 +59,7 @@ Font::~Font() {
}
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
- CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i);
- delete glyph;
+ delete mCachedGlyphs.valueAt(i);
}
}
@@ -134,48 +134,49 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
}
-Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
+Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
CachedGlyphInfo* cachedGlyph = NULL;
- ssize_t index = mCachedGlyphs.indexOfKey(utfChar);
+ ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
if (index >= 0) {
cachedGlyph = mCachedGlyphs.valueAt(index);
} else {
- cachedGlyph = cacheGlyph(paint, utfChar);
+ cachedGlyph = cacheGlyph(paint, textUnit);
}
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
- const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
+ const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
updateGlyphCache(paint, skiaGlyph, cachedGlyph);
}
return cachedGlyph;
}
-void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
- renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
+ render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
bitmapW, bitmapH, NULL);
} else {
- renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL);
+ render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
+ 0, 0, NULL);
}
}
-void Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds) {
if (bounds == NULL) {
LOGE("No return rectangle provided to measure text");
return;
}
bounds->set(1e6, -1e6, -1e6, 1e6);
- renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
+ render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
}
#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16)
-void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) {
if (numGlyphs == 0 || text == NULL || len == 0) {
@@ -195,14 +196,14 @@ void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t
text += start;
while (glyphsLeft > 0) {
- int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text);
+ glyph_t glyph = GET_GLYPH(text);
// Reached the end of the string
- if (utfChar < 0) {
+ if (IS_END_OF_STRING(glyph)) {
break;
}
- CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar);
+ CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta);
prevRsbDelta = cachedGlyph->mRsbDelta;
@@ -268,11 +269,11 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
mState->mUploadTexture = true;
}
-Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) {
+Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
mCachedGlyphs.add(glyph, newGlyph);
- const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph);
+ const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
newGlyph->mGlyphIndex = skiaGlyph.fID;
newGlyph->mIsValid = false;
@@ -672,7 +673,7 @@ void FontRenderer::precacheLatin(SkPaint* paint) {
uint32_t remainingCapacity = getRemainingCacheCapacity();
uint32_t precacheIdx = 0;
while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
- mCurrentFont->getCachedUTFChar(paint, (int32_t) mLatinPrecache[precacheIdx]);
+ mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]);
remainingCapacity = getRemainingCacheCapacity();
precacheIdx ++;
}
@@ -714,7 +715,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
}
Rect bounds;
- mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds);
+ mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
@@ -725,7 +726,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
int penX = radius - bounds.left;
int penY = radius - bounds.bottom;
- mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY,
+ mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
dataBuffer, paddedWidth, paddedHeight);
blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
@@ -755,7 +756,7 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text
mDrawn = false;
mBounds = bounds;
mClip = clip;
- mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
+ mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
mBounds = NULL;
if (mCurrentQuadIndex != 0) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 95f714f..24ed6fa 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -33,8 +33,32 @@
namespace android {
namespace uirenderer {
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#if RENDER_TEXT_AS_GLYPHS
+ typedef uint16_t glyph_t;
+ #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
+ #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
+ #define IS_END_OF_STRING(glyph) false
+#else
+ typedef SkUnichar glyph_t;
+ #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
+ #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
+ #define IS_END_OF_STRING(glyph) glyph < 0
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Declarations
+///////////////////////////////////////////////////////////////////////////////
+
class FontRenderer;
+///////////////////////////////////////////////////////////////////////////////
+// Font
+///////////////////////////////////////////////////////////////////////////////
+
/**
* Represents a font, defined by a Skia font id and a font size. A font is used
* to generate glyphs and cache them in the FontState.
@@ -51,9 +75,9 @@ public:
* Renders the specified string of text.
* If bitmap is specified, it will be used as the render target
*/
- void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
- int numGlyphs, int x, int y,
- uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);
+ void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+ int numGlyphs, int x, int y, uint8_t *bitmap = NULL,
+ uint32_t bitmapW = 0, uint32_t bitmapH = 0);
/**
* Creates a new font associated with the specified font state.
*/
@@ -69,13 +93,12 @@ protected:
MEASURE,
};
- void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
- int numGlyphs, int x, int y, RenderMode mode,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect *bounds);
+ void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
+ int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect *bounds);
- void measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
- int numGlyphs, Rect *bounds);
+ void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
+ int numGlyphs, Rect *bounds);
struct CachedGlyphInfo {
// Has the cache been invalidated?
@@ -107,18 +130,26 @@ protected:
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
uint32_t scaleX);
- DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs;
+ // Cache of glyphs
+ DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
void invalidateTextureCache();
- CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_t glyph);
+ CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph);
void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph);
void measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds);
void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);
+ uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);
- CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar);
+ CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit);
+
+ static glyph_t nextGlyph(const uint16_t** srcPtr) {
+ const uint16_t* src = *srcPtr;
+ glyph_t g = *src++;
+ *srcPtr = src;
+ return g;
+ }
FontRenderer* mState;
uint32_t mFontId;
@@ -128,6 +159,10 @@ protected:
uint32_t mScaleX;
};
+///////////////////////////////////////////////////////////////////////////////
+// Renderer
+///////////////////////////////////////////////////////////////////////////////
+
class FontRenderer {
public:
FontRenderer();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6243b01..45f4a42 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2073,11 +2073,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
}
-void OpenGLRenderer::drawGlyphs(const char* glyphs, int index, int count, float x, float y,
- SkPaint* paint) {
- // TODO
-}
-
void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
@@ -2230,14 +2225,19 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
// Handle underline and strike-through
uint32_t flags = paint->getFlags();
if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+ SkPaint paintCopy(*paint);
+#if RENDER_TEXT_AS_GLYPHS
+ paintCopy.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+#endif
+
float underlineWidth = length;
// If length is > 0.0f, we already measured the text for the text alignment
if (length <= 0.0f) {
- underlineWidth = paint->measureText(text, bytesCount);
+ underlineWidth = paintCopy.measureText(text, bytesCount);
}
float offsetX = 0;
- switch (paint->getTextAlign()) {
+ switch (paintCopy.getTextAlign()) {
case SkPaint::kCenter_Align:
offsetX = underlineWidth * 0.5f;
break;
@@ -2249,8 +2249,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
}
if (underlineWidth > 0.0f) {
- const float textSize = paint->getTextSize();
- // TODO: Support stroke width < 1.0f when we have AA lines
+ const float textSize = paintCopy.getTextSize();
const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
const float left = x - offsetX;
@@ -2280,10 +2279,9 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
points[currentPoint++] = top;
}
- SkPaint linesPaint(*paint);
- linesPaint.setStrokeWidth(strokeWidth);
+ paintCopy.setStrokeWidth(strokeWidth);
- drawLines(&points[0], pointsCount, &linesPaint);
+ drawLines(&points[0], pointsCount, &paintCopy);
}
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e2dbba0..549d6e9 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -123,8 +123,6 @@ public:
virtual void drawPoints(float* points, int count, SkPaint* paint);
virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
SkPaint* paint);
- virtual void drawGlyphs(const char* glyphs, int index, int count, float x, float y,
- SkPaint* paint);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 2d8b6f3..7c10518 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -28,6 +28,9 @@
// If turned on, layers drawn inside FBOs are optimized with regions
#define RENDER_LAYERS_AS_REGIONS 1
+// If turned on, text is interpreted as glyphs instead of UTF-16
+#define RENDER_TEXT_AS_GLYPHS 1
+
/**
* Debug level for app developers.
*/
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index d46686d..28dba13 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -73,7 +73,6 @@ struct ShadowText {
text = str.string();
}
- // TODO: Should take into account fake bold and text skew
bool operator<(const ShadowText& rhs) const {
LTE_INT(len) {
LTE_INT(radius) {
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 8a77519..e54194c 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <application android:label="BiDiTests">
+ <application android:label="BiDiTests" android:hardwareAccelerated="true">
<activity android:name=".BiDiTestActivity"
android:windowSoftInputMode="stateAlwaysHidden">
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index c4807ff..f254e3c 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -27,22 +27,21 @@
<Button android:id="@+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:onClick="onButtonClick"
android:text="@string/button_text"
android:textSize="32dip"
/>
<TextView android:id="@+id/textview"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="32dip"
- android:text="@string/textview_text"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="32dip"
+ android:text="@string/textview_text"
/>
<EditText android:id="@+id/edittext"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:textSize="32dip"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:textSize="32dip"
/>
</LinearLayout>