More efficient text rendering on path
Change-Id: I004c15473b527df0f296c54a6a3e9b29505fd9b9
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4528a38..6dbcd3f 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -20,6 +20,7 @@
#include "RecordedOp.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
+#include "hwui/MinikinUtils.h"
namespace android {
namespace uirenderer {
@@ -541,14 +542,20 @@
drawTextDecorations(x, y, totalAdvance, paint);
}
-void RecordingCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) {
- if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
- glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
- addOp(alloc().create_trivial<TextOnPathOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
+void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
+ const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ uint16_t glyphs[1];
+ for (size_t i = start; i < end; i++) {
+ glyphs[0] = layout.getGlyphId(i);
+ float x = hOffset + layout.getX(i);
+ float y = vOffset + layout.getY(i);
+ if (PaintUtils::paintWillNotDrawText(paint)) return;
+ const uint16_t* tempGlyphs = refBuffer<glyph_t>(glyphs, 1);
+ addOp(alloc().create_trivial<TextOnPathOp>(
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(),
+ refPaint(&paint), tempGlyphs, 1, refPath(&path), x, y));
+ }
}
void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 372be24..11773d4 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -196,8 +196,8 @@
const SkPaint& paint, float x, float y,
float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
float totalAdvance) override;
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) override;
+ virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
+ const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
private:
const ClipBase* getRecordedClip() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 99ea831..09775496 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -18,6 +18,7 @@
#include "CanvasProperty.h"
#include "VectorDrawable.h"
+#include "hwui/MinikinUtils.h"
#include <SkDrawable.h>
#include <SkDevice.h>
@@ -25,6 +26,7 @@
#include <SkDrawFilter.h>
#include <SkGraphics.h>
#include <SkImage.h>
+#include <SkRSXform.h>
#include <SkShader.h>
#include <SkTemplates.h>
@@ -624,9 +626,32 @@
drawTextDecorations(x, y, totalAdvance, paint);
}
-void SkiaCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) {
- mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint);
+void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
+ const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ const int N = end - start;
+ SkAutoSMalloc<1024> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
+ SkRSXform* xform = (SkRSXform*)storage.get();
+ uint16_t* glyphs = (uint16_t*)(xform + N);
+ SkPathMeasure meas(path, false);
+
+ for (size_t i = start; i < end; i++) {
+ glyphs[i - start] = layout.getGlyphId(i);
+ float x = hOffset + layout.getX(i);
+ float y = vOffset + layout.getY(i);
+
+ SkPoint pos;
+ SkVector tan;
+ if (!meas.getPosTan(x, &pos, &tan)) {
+ pos.set(x, y);
+ tan.set(1, 0);
+ }
+ xform[i - start].fSCos = tan.x();
+ xform[i - start].fSSin = tan.y();
+ xform[i - start].fTx = pos.x() - tan.y() * y;
+ xform[i - start].fTy = pos.y() + tan.x() * y;
+ }
+
+ this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index c76971c..0e506f4 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -161,8 +161,8 @@
const SkPaint& paint, float x, float y,
float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
float totalAdvance) override;
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) override;
+ virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
+ const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
private:
struct SaveRec {
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index f264a35..c4556c4 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -23,6 +23,7 @@
#include <SkPixelRef.h>
#include <SkRect.h>
#include <SkRRect.h>
+#include <SkRSXform.h>
#include <SkSurface.h>
#include <memory>
@@ -348,11 +349,26 @@
void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
const SkMatrix* matrix, const SkPaint& origPaint) {
- // convert to glyphIDs if necessary
- GlyphIDConverter glyphs(text, byteLength, origPaint);
- mCanvas->drawGlyphsOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
+ SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
}
+void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
+ const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint) {
+ GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
+ SkMatrix localM, currM, origM;
+ mCanvas->getMatrix(&currM);
+ origM = currM;
+ for (int i = 0; i < glyphs.count; i++) {
+ localM.setRSXform(*xform++);
+ currM.setConcat(origM, localM);
+ mCanvas->setMatrix(currM);
+ this->onDrawText((char*)text + (byteLength / glyphs.count * i),
+ byteLength / glyphs.count, 0, 0, paint);
+ }
+ mCanvas->setMatrix(origM);
+}
+
+
void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index d1c9c6b..5bb4231 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -81,6 +81,8 @@
SkScalar constY, const SkPaint&) override;
virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
const SkMatrix* matrix, const SkPaint&) override;
+ virtual void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
+ const SkRect* cullRect, const SkPaint& paint);
virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) override;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 461363f..b18e794 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -185,13 +185,7 @@
}
void operator()(size_t start, size_t end) {
- uint16_t glyphs[1];
- for (size_t i = start; i < end; i++) {
- glyphs[0] = layout.getGlyphId(i);
- float x = hOffset + layout.getX(i);
- float y = vOffset + layout.getY(i);
- canvas->drawGlyphsOnPath(glyphs, 1, path, x, y, paint);
- }
+ canvas->drawLayoutOnPath(layout, hOffset, vOffset, paint, path, start, end);
}
private:
const minikin::Layout& layout;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 0b42099..57db0f2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -26,6 +26,10 @@
#include <SkCanvas.h>
#include <SkMatrix.h>
+namespace minikin {
+ class Layout;
+}
+
namespace android {
namespace uirenderer {
@@ -242,10 +246,8 @@
const SkPaint& paint, float x, float y,
float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
float totalAdvance) = 0;
- /** drawTextOnPath: count is of glyphs */
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) = 0;
-
+ virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
+ const SkPaint& paint, const SkPath& path, size_t start, size_t end) = 0;
friend class DrawTextFunctor;
friend class DrawTextOnPathFunctor;
friend class uirenderer::SkiaCanvasProxy;