More efficient text rendering on path

Change-Id: I004c15473b527df0f296c54a6a3e9b29505fd9b9
This commit is contained in:
Yuqian Li
2016-07-18 13:07:42 -04:00
parent 0979352b1a
commit afc221499d
8 changed files with 75 additions and 29 deletions

View File

@@ -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 @@ void RecordingCanvas::drawGlyphs(const uint16_t* glyphs, const float* positions,
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) {

View File

@@ -196,8 +196,8 @@ protected:
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() {

View File

@@ -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 @@ void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int co
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);
}
// ----------------------------------------------------------------------------

View File

@@ -161,8 +161,8 @@ protected:
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 {

View File

@@ -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::onDrawPosTextH(const void* text, size_t byteLength, const
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");

View File

@@ -81,6 +81,8 @@ protected:
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;

View File

@@ -185,13 +185,7 @@ public:
}
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;

View File

@@ -26,6 +26,10 @@
#include <SkCanvas.h>
#include <SkMatrix.h>
namespace minikin {
class Layout;
}
namespace android {
namespace uirenderer {
@@ -242,10 +246,8 @@ protected:
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;