diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 4528a38761770..6dbcd3f0f1f1e 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 @@ 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(glyphs, glyphCount); - addOp(alloc().create_trivial( - *(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(glyphs, 1); + addOp(alloc().create_trivial( + *(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 372be241042a3..11773d4c10324 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -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() { diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 99ea83176b95b..09775496af722 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 #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -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); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index c76971c6e0411..0e506f4d9412d 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -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 { diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp index f264a3597ef21..c4556c4f5cfb4 100644 --- a/libs/hwui/SkiaCanvasProxy.cpp +++ b/libs/hwui/SkiaCanvasProxy.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -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"); diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h index d1c9c6b2ad707..5bb4231e61231 100644 --- a/libs/hwui/SkiaCanvasProxy.h +++ b/libs/hwui/SkiaCanvasProxy.h @@ -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; diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 461363f5e8d83..b18e7942d142f 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -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; diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 0b4209925bd4b..57db0f2d19fca 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -26,6 +26,10 @@ #include #include +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;