diff options
author | Romain Guy <romainguy@google.com> | 2011-06-01 14:56:19 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-06-01 14:56:19 -0700 |
commit | cb0975b3c1c73d8bcadaca80e1ee99383750af60 (patch) | |
tree | 34828ffaae61de90897a11c92ae932a8e11502d4 | |
parent | 0523c55e5fd31db06d78f742a79db94f21c2eece (diff) | |
parent | 726aeba80ffc6778a9bc3e0ee957b8d644183505 (diff) | |
download | frameworks_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.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 43 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 61 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 3 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.h | 1 | ||||
-rw-r--r-- | tests/BiDiTests/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | tests/BiDiTests/res/layout/basic.xml | 15 |
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> |