summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2012-01-18 12:39:17 -0800
committerRomain Guy <romainguy@google.com>2012-01-18 18:00:12 -0800
commit671d6cf460531825a321edb200523d0faa7792c9 (patch)
tree7fde21ba8f48911629c3dd67a1138bd6a569c084 /libs/hwui
parentfb9ffe02609c9c4ffca64927e72bc935cfe87768 (diff)
downloadframeworks_base-671d6cf460531825a321edb200523d0faa7792c9.zip
frameworks_base-671d6cf460531825a321edb200523d0faa7792c9.tar.gz
frameworks_base-671d6cf460531825a321edb200523d0faa7792c9.tar.bz2
Full support for Canvas.drawPosText
This also introduces a small optimization when rendering text. Change-Id: Iff620ac97bf878eaac406bccc6daa07052c93890
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/FontRenderer.cpp162
-rw-r--r--libs/hwui/FontRenderer.h30
-rw-r--r--libs/hwui/OpenGLRenderer.cpp78
3 files changed, 202 insertions, 68 deletions
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) {