diff options
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 4 | ||||
-rw-r--r-- | docs/html/guide/topics/graphics/hardware-accel.jd | 5 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 162 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 30 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 78 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java | 13 |
6 files changed, 217 insertions, 75 deletions
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 3bf28eb..064dcac 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -585,10 +585,10 @@ static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count const jchar* glyphs = value->getGlyphs(); size_t glyphsCount = value->getGlyphsCount(); + if (count < int(glyphsCount)) glyphsCount = count; int bytesCount = glyphsCount * sizeof(jchar); - renderer->drawPosText((const char*) glyphs, bytesCount, - count < int(glyphsCount) ? count : glyphsCount, positions, paint); + renderer->drawPosText((const char*) glyphs, bytesCount, glyphsCount, positions, paint); } static void android_view_GLES20Canvas_drawPosTextArray(JNIEnv* env, jobject clazz, diff --git a/docs/html/guide/topics/graphics/hardware-accel.jd b/docs/html/guide/topics/graphics/hardware-accel.jd index c8703a5..e3ff215 100644 --- a/docs/html/guide/topics/graphics/hardware-accel.jd +++ b/docs/html/guide/topics/graphics/hardware-accel.jd @@ -283,8 +283,6 @@ changed.</li> <li>{@link android.graphics.Canvas#drawPicture drawPicture()}</li> - <li>{@link android.graphics.Canvas#drawPosText drawPosText()}</li> - <li>{@link android.graphics.Canvas#drawTextOnPath drawTextOnPath()}</li> <li>{@link android.graphics.Canvas#drawVertices drawVertices()}</li> @@ -318,9 +316,6 @@ changed.</li> <li>{@link android.graphics.Canvas#drawBitmapMesh drawBitmapMesh()}: colors array is ignored</li> - <li>{@link android.graphics.Canvas#drawLines drawLines()}: anti-aliasing is not - supported</li> - <li>{@link android.graphics.Canvas#setDrawFilter setDrawFilter()}: can be set, but is ignored</li> </ul> diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 790c143..74efda2 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -94,7 +94,8 @@ void Font::invalidateTextureCache(CacheTextureLine *cacheLine) { } } -void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { +void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { int nPenX = x + glyph->mBitmapLeft; int nPenY = y + glyph->mBitmapTop; @@ -115,7 +116,8 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds } } -void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { +void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { int nPenX = x + glyph->mBitmapLeft; int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; @@ -133,8 +135,8 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); } -void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, - uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { +void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, + uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { int nPenX = x + glyph->mBitmapLeft; int nPenY = y + glyph->mBitmapTop; @@ -181,13 +183,19 @@ 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) { render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, - bitmapW, bitmapH, NULL); + bitmapW, bitmapH, NULL, NULL); } else { render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, - 0, 0, NULL); + 0, 0, NULL, NULL); } } +void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, + int numGlyphs, int x, int y, const float* positions) { + render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, + 0, 0, NULL, positions); +} + void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, int numGlyphs, Rect *bounds) { if (bounds == NULL) { @@ -195,62 +203,95 @@ void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t le return; } bounds->set(1e6, -1e6, -1e6, 1e6); - render(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, NULL); } #define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) 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) { + uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions) { if (numGlyphs == 0 || text == NULL || len == 0) { return; } - float penX = x; - int penY = y; - int glyphsLeft = 1; - if (numGlyphs > 0) { - glyphsLeft = numGlyphs; - } - - SkFixed prevRsbDelta = 0; - penX += 0.5f; + int glyphsCount = 0; text += start; - while (glyphsLeft > 0) { - glyph_t glyph = GET_GLYPH(text); + static RenderGlyph gRenderGlyph[] = { + &android::uirenderer::Font::drawCachedGlyph, + &android::uirenderer::Font::drawCachedGlyphBitmap, + &android::uirenderer::Font::measureCachedGlyph + }; + RenderGlyph render = gRenderGlyph[mode]; - // Reached the end of the string - if (IS_END_OF_STRING(glyph)) { - break; - } + if (positions == NULL) { + SkFixed prevRsbDelta = 0; - CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); - penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta)); - prevRsbDelta = cachedGlyph->mRsbDelta; + float penX = x; + int penY = y; - // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage - if (cachedGlyph->mIsValid) { - switch(mode) { - case FRAMEBUFFER: - drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY); - break; - case BITMAP: - drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bitmap, bitmapW, bitmapH); - break; - case MEASURE: - measureCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bounds); + penX += 0.5f; + + while (glyphsCount < numGlyphs) { + glyph_t glyph = GET_GLYPH(text); + + // Reached the end of the string + if (IS_END_OF_STRING(glyph)) { break; } + + CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); + penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta)); + prevRsbDelta = cachedGlyph->mRsbDelta; + + // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage + if (cachedGlyph->mIsValid) { + (*this.*render)(cachedGlyph, (int) floorf(penX), penY, + bitmap, bitmapW, bitmapH, bounds, positions); + } + + penX += SkFixedToFloat(cachedGlyph->mAdvanceX); + + glyphsCount++; } + } else { + const SkPaint::Align align = paint->getTextAlign(); - penX += SkFixedToFloat(cachedGlyph->mAdvanceX); + // This is for renderPosText() + while (glyphsCount < numGlyphs) { + glyph_t glyph = GET_GLYPH(text); + + // Reached the end of the string + if (IS_END_OF_STRING(glyph)) { + break; + } - // If we were given a specific number of glyphs, decrement - if (numGlyphs > 0) { - glyphsLeft--; + CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); + + // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage + if (cachedGlyph->mIsValid) { + int penX = x + positions[(glyphsCount << 1)]; + int penY = y + positions[(glyphsCount << 1) + 1]; + + switch (align) { + case SkPaint::kRight_Align: + penX -= SkFixedToFloat(cachedGlyph->mAdvanceX); + penY -= SkFixedToFloat(cachedGlyph->mAdvanceY); + break; + case SkPaint::kCenter_Align: + penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1); + penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1); + default: + break; + } + + (*this.*render)(cachedGlyph, penX, penY, + bitmap, bitmapW, bitmapH, bounds, positions); + } + + glyphsCount++; } } } @@ -866,21 +907,15 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch return image; } -bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, - uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { +void FontRenderer::initRender(const Rect* clip, Rect* bounds) { checkInit(); - if (!mCurrentFont) { - ALOGE("No font set"); - return false; - } - mDrawn = false; mBounds = bounds; mClip = clip; +} - mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); - +void FontRenderer::finishRender() { mBounds = NULL; mClip = NULL; @@ -888,6 +923,33 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text issueDrawCommand(); mCurrentQuadIndex = 0; } +} + +bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, + uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { + if (!mCurrentFont) { + ALOGE("No font set"); + return false; + } + + initRender(clip, bounds); + mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); + finishRender(); + + return mDrawn; +} + +bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text, + uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, + const float* positions, Rect* bounds) { + if (!mCurrentFont) { + ALOGE("No font set"); + return false; + } + + initRender(clip, bounds); + mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions); + finishRender(); return mDrawn; } diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 005cdde..b767be5 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -151,6 +151,10 @@ public: 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); + + void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, + int numGlyphs, int x, int y, const float* positions); + /** * Creates a new font associated with the specified font state. */ @@ -160,6 +164,8 @@ public: protected: friend class FontRenderer; + typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*, + uint32_t, uint32_t, Rect*, const float*); enum RenderMode { FRAMEBUFFER, @@ -169,7 +175,7 @@ protected: 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); + uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions); void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, int numGlyphs, Rect *bounds); @@ -183,11 +189,17 @@ protected: void invalidateTextureCache(CacheTextureLine *cacheLine = NULL); 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); + void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph); + + void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, + Rect* bounds, const float* pos); + void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, + Rect* bounds, const float* pos); + void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, + uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, + Rect* bounds, const float* pos); CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit); @@ -226,8 +238,12 @@ public: } void setFont(SkPaint* paint, uint32_t fontId, float fontSize); + // bounds is an out parameter bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds); + // bounds is an out parameter + bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, + uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds); struct DropShadow { DropShadow() { }; @@ -297,6 +313,8 @@ protected: void initVertexArrayBuffers(); void checkInit(); + void initRender(const Rect* clip, Rect* bounds); + void finishRender(); String16 mLatinPrecache; void precacheLatin(SkPaint* paint); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 6ec87f3..786a4f1 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2084,23 +2084,81 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { - if (text == NULL || count == 0) { + if (text == NULL || count == 0 || mSnapshot->isIgnored() || + (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { return; } - if (mSnapshot->isIgnored()) return; - // TODO: implement properly - drawText(text, bytesCount, count, 0, 0, paint); + // NOTE: Skia does not support perspective transform on drawPosText yet + if (!mSnapshot->transform->isSimple()) { + return; + } + + float x = 0.0f; + float y = 0.0f; + const bool pureTranslate = mSnapshot->transform->isPureTranslate(); + if (pureTranslate) { + x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); + } + + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), + paint->getTextSize()); + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + // Pick the appropriate texture filtering + bool linearFilter = mSnapshot->transform->changesBounds(); + if (pureTranslate && !linearFilter) { + linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; + } + + mCaches.activeTexture(0); + setupDraw(); + setupDrawDirtyRegionsDisabled(); + setupDrawWithTexture(true); + setupDrawAlpha8Color(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(x, y, x, y, pureTranslate, true); + setupDrawTexture(fontRenderer.getTexture(linearFilter)); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(pureTranslate); + + const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); + Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); + +#if RENDER_LAYERS_AS_REGIONS + bool hasActiveLayer = hasLayer(); +#else + bool hasActiveLayer = false; +#endif + + if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, + positions, hasActiveLayer ? &bounds : NULL)) { +#if RENDER_LAYERS_AS_REGIONS + if (hasActiveLayer) { + if (!pureTranslate) { + mSnapshot->transform->mapRect(bounds); + } + dirtyLayerUnchecked(bounds, getRegion()); + } +#endif + } } void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint, float length) { - if (text == NULL || count == 0) { + if (text == NULL || count == 0 || mSnapshot->isIgnored() || + (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { return; } - if (mSnapshot->isIgnored()) return; - - // NOTE: AA and glyph id encoding are set in DisplayListRenderer.cpp switch (paint->getTextAlign()) { case SkPaint::kCenter_Align: @@ -2177,10 +2235,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } - if (paint->getAlpha() == 0 && paint->getXfermode() == NULL) { - return; - } - // Pick the appropriate texture filtering bool linearFilter = mSnapshot->transform->changesBounds(); if (pureTranslate && !linearFilter) { diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java index f0ff737..1c868d2 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java @@ -58,8 +58,21 @@ public class PosTextActivity extends Activity { canvas.drawRGB(255, 255, 255); canvas.save(); + + canvas.drawLine(100.0f, 0.0f, 100.0f, getHeight(), mLargePaint); + canvas.translate(100.0f, 100.0f); + mLargePaint.setTextAlign(Paint.Align.LEFT); + canvas.drawPosText(mText, mPos, mLargePaint); + + canvas.translate(0.0f, 50.0f); + mLargePaint.setTextAlign(Paint.Align.CENTER); canvas.drawPosText(mText, mPos, mLargePaint); + + canvas.translate(0.0f, 50.0f); + mLargePaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawPosText(mText, mPos, mLargePaint); + canvas.restore(); } } |