Hardware implementation of glyph positioning (bug 5443796)
This implementation adds a drawGeneralText() method to the OpenGL
Renderer, which supports both a global x, y position, an array of
individual glyph positions, and also a length parameter (which enables
drawing of underline and strikethrough. It also adds the method to the
display list (with marshalling and unmarshalling).
With this change, the existing drawText() method is removed entirely, as
it's subsumed by the new method. It's easy enough to revert to the old
functionality if needed by passing in a NULL positions array.
Change-Id: I8c9e6ce4309fd51cc5511db85df99f6de8f4f6f5
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 133f63f..7161c58 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -61,9 +61,9 @@
"DrawPath",
"DrawLines",
"DrawPoints",
- "DrawText",
"DrawTextOnPath",
"DrawPosText",
+ "DrawGeneralText",
"ResetShader",
"SetupShader",
"ResetColorFilter",
@@ -572,17 +572,6 @@
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
- case DrawText: {
- getText(&text);
- int32_t count = getInt();
- float x = getFloat();
- float y = getFloat();
- SkPaint* paint = getPaint(renderer);
- float length = getFloat();
- ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op],
- text.text(), text.length(), count, x, y, paint, length);
- }
- break;
case DrawTextOnPath: {
getText(&text);
int32_t count = getInt();
@@ -603,6 +592,17 @@
ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
text.text(), text.length(), count, paint);
}
+ break;
+ case DrawGeneralText: {
+ getText(&text);
+ int count = getInt();
+ int positionsCount = 0;
+ float* positions = getFloats(positionsCount);
+ SkPaint* paint = getPaint(renderer);
+ ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
+ text.text(), text.length(), count, paint);
+ }
+ break;
case ResetShader: {
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
@@ -1196,19 +1196,6 @@
drawGlStatus |= renderer.drawPoints(points, count, paint);
}
break;
- case DrawText: {
- getText(&text);
- int32_t count = getInt();
- float x = getFloat();
- float y = getFloat();
- SkPaint* paint = getPaint(renderer);
- float length = getFloat();
- DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
- OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
- drawGlStatus |= renderer.drawText(text.text(), text.length(), count, x, y,
- paint, length);
- }
- break;
case DrawTextOnPath: {
getText(&text);
int32_t count = getInt();
@@ -1234,6 +1221,21 @@
positions, paint);
}
break;
+ case DrawGeneralText: {
+ getText(&text);
+ int32_t count = getInt();
+ float x = getFloat();
+ float y = getFloat();
+ int32_t positionsCount = 0;
+ float* positions = getFloats(positionsCount);
+ SkPaint* paint = getPaint(renderer);
+ float length = getFloat();
+ DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
+ OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
+ drawGlStatus |= renderer.drawGeneralText(text.text(), text.length(), count,
+ x, y, positions, paint, length);
+ }
+ break;
case ResetShader: {
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.resetShader();
@@ -1684,37 +1686,6 @@
return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
- float x, float y, SkPaint* paint, float length) {
- if (!text || count <= 0) return DrawGlInfo::kStatusDone;
-
- // TODO: We should probably make a copy of the paint instead of modifying
- // it; modifying the paint will change its generationID the first
- // time, which might impact caches. More investigation needed to
- // see if it matters.
- // If we make a copy, then drawTextDecorations() should *not* make
- // its own copy as it does right now.
- // Beware: this needs Glyph encoding (already done on the Paint constructor)
- paint->setAntiAlias(true);
- if (length < 0.0f) length = paint->measureText(text, bytesCount);
-
- bool reject = false;
- if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
- SkPaint::FontMetrics metrics;
- paint->getFontMetrics(&metrics, 0.0f);
- reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom);
- }
-
- uint32_t* location = addOp(DisplayList::DrawText, reject);
- addText(text, bytesCount);
- addInt(count);
- addPoint(x, y);
- addPaint(paint);
- addFloat(length);
- addSkip(location);
- return DrawGlInfo::kStatusDone;
-}
-
status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
SkPath* path, float hOffset, float vOffset, SkPaint* paint) {
if (!text || count <= 0) return DrawGlInfo::kStatusDone;
@@ -1741,6 +1712,39 @@
return DrawGlInfo::kStatusDone;
}
+status_t DisplayListRenderer::drawGeneralText(const char* text, int bytesCount, int count,
+ float x, float y, const float* positions, SkPaint* paint, float length) {
+ if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+
+ // TODO: We should probably make a copy of the paint instead of modifying
+ // it; modifying the paint will change its generationID the first
+ // time, which might impact caches. More investigation needed to
+ // see if it matters.
+ // If we make a copy, then drawTextDecorations() should *not* make
+ // its own copy as it does right now.
+ // Beware: this needs Glyph encoding (already done on the Paint constructor)
+ paint->setAntiAlias(true);
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
+
+ bool reject = false;
+ if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
+ SkPaint::FontMetrics metrics;
+ paint->getFontMetrics(&metrics, 0.0f);
+ reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom);
+ }
+
+ uint32_t* location = addOp(DisplayList::DrawGeneralText, reject);
+ addText(text, bytesCount);
+ addInt(count);
+ addFloat(x);
+ addFloat(y);
+ addFloats(positions, count * 2);
+ addPaint(paint);
+ addFloat(length);
+ addSkip(location);
+ return DrawGlInfo::kStatusDone;
+}
+
void DisplayListRenderer::resetShader() {
addOp(DisplayList::ResetShader);
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6b4c6b2..f3041dd 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -103,9 +103,9 @@
DrawPath,
DrawLines,
DrawPoints,
- DrawText,
DrawTextOnPath,
DrawPosText,
+ DrawGeneralText,
ResetShader,
SetupShader,
ResetColorFilter,
@@ -599,12 +599,12 @@
virtual status_t drawPath(SkPath* path, SkPaint* paint);
virtual status_t drawLines(float* points, int count, SkPaint* paint);
virtual status_t drawPoints(float* points, int count, SkPaint* paint);
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
- SkPaint* paint, float length = -1.0f);
virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
float hOffset, float vOffset, SkPaint* paint);
virtual status_t drawPosText(const char* text, int bytesCount, int count,
const float* positions, SkPaint* paint);
+ virtual status_t drawGeneralText(const char* text, int bytesCount, int count,
+ float x, float y, const float* positions, SkPaint* paint, float length);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6d781c7..07281cc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2421,8 +2421,8 @@
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
- float x, float y, SkPaint* paint, float length) {
+status_t OpenGLRenderer::drawGeneralText(const char* text, int bytesCount, int count,
+ float x, float y, const float* positions, SkPaint* paint, float length) {
if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
(paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) {
return DrawGlInfo::kStatusDone;
@@ -2455,7 +2455,8 @@
}
#if DEBUG_GLYPHS
- ALOGD("OpenGLRenderer drawText() with FontID=%d", SkTypeface::UniqueID(paint->getTypeface()));
+ ALOGD("OpenGLRenderer drawGeneralText() with FontID=%d",
+ SkTypeface::UniqueID(paint->getTypeface()));
#endif
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
@@ -2467,7 +2468,8 @@
getAlphaAndMode(paint, &alpha, &mode);
if (CC_UNLIKELY(mHasShadow)) {
- drawTextShadow(paint, text, bytesCount, count, NULL, fontRenderer, alpha, mode, oldX, oldY);
+ drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
+ oldX, oldY);
}
// Pick the appropriate texture filtering
@@ -2505,8 +2507,16 @@
const bool hasActiveLayer = false;
#endif
- if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
- hasActiveLayer ? &bounds : NULL)) {
+ bool status;
+ if (positions != NULL) {
+ status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
+ positions, hasActiveLayer ? &bounds : NULL);
+ } else {
+ // TODO: would it be okay to call renderPosText with null positions?
+ status = fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
+ hasActiveLayer ? &bounds : NULL);
+ }
+ if (status) {
#if RENDER_LAYERS_AS_REGIONS
if (hasActiveLayer) {
if (!pureTranslate) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 441e9fd..378fc8c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -138,12 +138,12 @@
virtual status_t drawPath(SkPath* path, SkPaint* paint);
virtual status_t drawLines(float* points, int count, SkPaint* paint);
virtual status_t drawPoints(float* points, int count, SkPaint* paint);
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
- SkPaint* paint, float length = -1.0f);
virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
float hOffset, float vOffset, SkPaint* paint);
virtual status_t drawPosText(const char* text, int bytesCount, int count,
const float* positions, SkPaint* paint);
+ virtual status_t drawGeneralText(const char* text, int bytesCount, int count, float x, float y,
+ const float* positions, SkPaint* paint, float length = -1.0f);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);