drawTextRSXform
authorreed <reed@google.com>
Thu, 7 Jul 2016 19:47:17 +0000 (12:47 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 7 Jul 2016 19:47:17 +0000 (12:47 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2130643004

Review-Url: https://codereview.chromium.org/2130643004

28 files changed:
gm/drawatlas.cpp
include/core/SkCanvas.h
include/core/SkDevice.h
include/core/SkPicture.h
include/private/SkRecords.h
include/utils/SkDumpCanvas.h
include/utils/SkLuaCanvas.h
include/utils/SkNWayCanvas.h
include/utils/SkPaintFilterCanvas.h
src/core/SkCanvas.cpp
src/core/SkDevice.cpp
src/core/SkPictureFlat.h
src/core/SkPicturePlayback.cpp
src/core/SkPictureRecord.cpp
src/core/SkPictureRecord.h
src/core/SkRecordDraw.cpp
src/core/SkRecorder.cpp
src/core/SkRecorder.h
src/utils/SkDumpCanvas.cpp
src/utils/SkLuaCanvas.cpp
src/utils/SkNWayCanvas.cpp
src/utils/SkPaintFilterCanvas.cpp
tools/android/SkAndroidSDKCanvas.cpp
tools/android/SkAndroidSDKCanvas.h
tools/debugger/SkDebugCanvas.cpp
tools/debugger/SkDebugCanvas.h
tools/debugger/SkDrawCommand.cpp
tools/debugger/SkDrawCommand.h

index a906cbe..ba71eae 100644 (file)
@@ -100,3 +100,68 @@ private:
     typedef GM INHERITED;
 };
 DEF_GM( return new DrawAtlasGM; )
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkPath.h"
+#include "SkPathMeasure.h"
+
+static void draw_text_on_path_rigid(SkCanvas* canvas, const void* text, size_t length,
+                                    const SkPoint xy[], const SkPath& path, const SkPaint& paint) {
+    SkPathMeasure meas(path, false);
+
+    int count = paint.countText(text, length);
+    SkAutoSTArray<100, SkRSXform> xform(count);
+
+    for (int i = 0; i < count; ++i) {
+        SkPoint pos;
+        SkVector tan;
+        if (!meas.getPosTan(xy[i].x(), &pos, &tan)) {
+            pos = xy[i];
+            tan.set(1, 0);
+        }
+        xform[i].fSCos = tan.x();
+        xform[i].fSSin = tan.y();
+        xform[i].fTx   = pos.x();
+        xform[i].fTy   = pos.y();
+    }
+
+    canvas->drawTextRSXform(text, length, &xform[0], nullptr, paint);
+}
+
+DEF_SIMPLE_GM(drawTextRSXform, canvas, 510, 310) {
+    const char text[] = "ABCDFGHJKLMNOPQRSTUVWXYZ";
+    const int N = sizeof(text) - 1;
+    SkPoint pos[N];
+    SkRSXform xform[N];
+
+    canvas->translate(0, 30);
+
+    SkScalar x = 20;
+    SkScalar dx = 20;
+    SkScalar rad = 0;
+    SkScalar drad = 2 * SK_ScalarPI / (N - 1);
+    for (int i = 0; i < N; ++i) {
+        xform[i].fSCos = SkScalarCos(rad);
+        xform[i].fSSin = SkScalarSin(rad);
+        xform[i].fTx = x;
+        xform[i].fTy = 0;
+        pos[i].set(x, 0);
+        x += dx;
+        rad += drad;
+    }
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setTextSize(20);
+    canvas->drawTextRSXform(text, N, xform, nullptr, paint);
+
+    SkPath path;
+    path.addOval(SkRect::MakeXYWH(150, 50, 200, 200));
+
+    draw_text_on_path_rigid(canvas, text, N, pos, path, paint);
+
+    paint.setStyle(SkPaint::kStroke_Style);
+    canvas->drawPath(path, paint);
+}
+
+
index ec14829..7dd0189 100644 (file)
@@ -989,6 +989,14 @@ public:
     void drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                         const SkMatrix* matrix, const SkPaint& paint);
 
+    /**
+     *  Draw the text with each character/glyph individually transformed by its xform.
+     *  If cullRect is not null, it is a conservative bounds of what will be drawn
+     *  taking into account the xforms and the paint) and will be used to accelerate culling.
+     */
+    void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
+                         const SkRect* cullRect, const SkPaint& paint);
+
     /** Draw the text blob, offset by (x,y), using the specified paint.
         @param blob     The text blob to be drawn
         @param x        The x-offset of the text being drawn
@@ -1324,6 +1332,8 @@ protected:
     virtual void onDrawTextOnPath(const void* text, size_t byteLength,
                                   const SkPath& path, const SkMatrix* matrix,
                                   const SkPaint& paint);
+    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);
index e066500..d23aa69 100644 (file)
@@ -273,6 +273,8 @@ protected:
 
     virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath&,
                                 const SkMatrix*, const SkPaint&);
+    virtual void drawTextRSXform(const SkDraw&, const void* text, size_t len, const SkRSXform[],
+                                 const SkPaint&);
 
     bool readPixels(const SkImageInfo&, void* dst, size_t rowBytes, int x, int y);
 
index eb35ef6..8e3d1c8 100644 (file)
@@ -206,10 +206,11 @@ private:
     // V43: Added DRAW_IMAGE and DRAW_IMAGE_RECT opt codes to serialized data
     // V44: Move annotations from paint to drawAnnotation
     // V45: Add invNormRotation to SkLightingShader.
+    // V46: Add drawTextRSXform
 
     // Only SKPs within the min/current picture version range (inclusive) can be read.
     static const uint32_t     MIN_PICTURE_VERSION = 35;     // Produced by Chrome M39.
-    static const uint32_t CURRENT_PICTURE_VERSION = 45;
+    static const uint32_t CURRENT_PICTURE_VERSION = 46;
 
     static_assert(MIN_PICTURE_VERSION <= 41,
                   "Remove kFontFileName and related code from SkFontDescriptor.cpp.");
index d6ef12f..9ec2d21 100644 (file)
@@ -72,6 +72,7 @@ namespace SkRecords {
     M(DrawPosTextH)                                                 \
     M(DrawText)                                                     \
     M(DrawTextOnPath)                                               \
+    M(DrawTextRSXform)                                              \
     M(DrawRRect)                                                    \
     M(DrawRect)                                                     \
     M(DrawTextBlob)                                                 \
@@ -344,6 +345,12 @@ RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag,
         size_t byteLength;
         PreCachedPath path;
         TypedMatrix matrix);
+RECORD(DrawTextRSXform, kDraw_Tag|kHasText_Tag,
+        SkPaint paint;
+        PODArray<char> text;
+        size_t byteLength;
+        PODArray<SkRSXform> xforms;
+        Optional<SkRect> cull);
 RECORD(DrawPatch, kDraw_Tag,
         SkPaint paint;
         PODArray<SkPoint> cubics;
index 35d694e..fc058be 100644 (file)
@@ -87,6 +87,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;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint& paint) override;
     virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) override;
     virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
index 37e82be..64f285b 100644 (file)
@@ -37,6 +37,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;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint& paint) override;
     virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) override;
 
index f2a99db..a4b9c59 100644 (file)
@@ -49,6 +49,8 @@ protected:
                                   const SkMatrix* matrix, const SkPaint&) override;
     virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) override;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint& paint) override;
     virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
                              const SkPoint texCoords[4], SkXfermode* xmode,
                              const SkPaint& paint) override;
index 909cf3b..037bac6 100644 (file)
@@ -95,6 +95,8 @@ protected:
                         SkScalar constY, const SkPaint&) override;
     void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                           const SkMatrix* matrix, const SkPaint&) override;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint& paint) override;
     void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                         const SkPaint& paint) override;
 
index ce90275..733ff19 100644 (file)
@@ -2647,6 +2647,21 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat
     LOOPER_END
 }
 
+void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                 const SkRect* cullRect, const SkPaint& paint) {
+    if (cullRect && this->quickReject(*cullRect)) {
+        return;
+    }
+
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
+
+    while (iter.next()) {
+        iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
+    }
+
+    LOOPER_END
+}
+
 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                               const SkPaint& paint) {
 
@@ -2699,6 +2714,13 @@ void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath&
     TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
     this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
 }
+void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                               const SkRect* cullRect, const SkPaint& paint) {
+    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
+    if (byteLength) {
+        this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
+    }
+}
 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                             const SkPaint& paint) {
     RETURN_ON_NULL(blob);
index 185b9bb..2dcedb4 100644 (file)
@@ -403,6 +403,47 @@ void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t b
     }
 }
 
+#include "SkUtils.h"
+typedef int (*CountTextProc)(const char* text);
+static int count_utf16(const char* text) {
+    const uint16_t* prev = (uint16_t*)text;
+    (void)SkUTF16_NextUnichar(&prev);
+    return SkToInt((const char*)prev - text);
+}
+static int return_4(const char* text) { return 4; }
+static int return_2(const char* text) { return 2; }
+
+void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t len,
+                                   const SkRSXform xform[], const SkPaint& paint) {
+    CountTextProc proc = nullptr;
+    switch (paint.getTextEncoding()) {
+        case SkPaint::kUTF8_TextEncoding:
+            proc = SkUTF8_CountUTF8Bytes;
+            break;
+        case SkPaint::kUTF16_TextEncoding:
+            proc = count_utf16;
+            break;
+        case SkPaint::kUTF32_TextEncoding:
+            proc = return_4;
+            break;
+        case SkPaint::kGlyphID_TextEncoding:
+            proc = return_2;
+            break;
+    }
+
+    SkDraw localD(draw);
+    SkMatrix localM, currM;
+    const void* stopText = (const char*)text + len;
+    while ((const char*)text < (const char*)stopText) {
+        localM.setRSXform(*xform++);
+        currM.setConcat(*draw.fMatrix, localM);
+        localD.fMatrix = &currM;
+        int subLen = proc((const char*)text);
+        this->drawText(localD, text, subLen, 0, 0, paint);
+        text = (const char*)text + subLen;
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 
 void SkBaseDevice::drawSpriteWithFilter(const SkDraw& draw, const SkBitmap& bitmap,
index d4c8c1f..3546fb2 100644 (file)
@@ -79,6 +79,7 @@ enum DrawType {
     DRAW_ANNOTATION,
     DRAW_DRAWABLE,
     DRAW_DRAWABLE_MATRIX,
+    DRAW_TEXT_RSXFORM,
 
     LAST_DRAWTYPE_ENUM = DRAW_DRAWABLE_MATRIX,
 };
@@ -98,6 +99,10 @@ enum DrawAtlasFlags {
     DRAW_ATLAS_HAS_CULL     = 1 << 1,
 };
 
+enum DrawTextRSXformFlags {
+    DRAW_TEXT_RSXFORM_HAS_CULL  = 1 << 0,
+};
+
 enum SaveLayerRecFlatFlags {
     SAVELAYERREC_HAS_BOUNDS     = 1 << 0,
     SAVELAYERREC_HAS_PAINT      = 1 << 1,
index 3cbcdbb..6b89304 100644 (file)
@@ -501,6 +501,19 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
                 canvas->drawTextOnPath(text.text(), text.length(), path, &matrix, *paint);
             }
         } break;
+        case DRAW_TEXT_RSXFORM: {
+            const SkPaint* paint = fPictureData->getPaint(reader);
+            int count = reader->readInt();
+            uint32_t flags = reader->read32();
+            TextContainer text;
+            get_text(reader, &text);
+            const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform));
+            const SkRect* cull = nullptr;
+            if (flags & DRAW_TEXT_RSXFORM_HAS_CULL) {
+                cull = (const SkRect*)reader->skip(sizeof(SkRect));
+            }
+            canvas->drawTextRSXform(text.text(), text.length(), xform, cull, *paint);
+        } break;
         case DRAW_VERTICES: {
             sk_sp<SkXfermode> xfer;
             const SkPaint* paint = fPictureData->getPaint(reader);
index 4a6ece1..17ed1aa 100644 (file)
@@ -603,6 +603,30 @@ void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, cons
     this->validate(initialOffset, size);
 }
 
+void SkPictureRecord::onDrawTextRSXform(const void* text, size_t byteLength,
+                                        const SkRSXform xform[], const SkRect* cull,
+                                        const SkPaint& paint) {
+    const int count = paint.countText(text, byteLength);
+    // [op + paint-index + count + flags + length] + [text] + [xform] + cull
+    size_t size = 5 * kUInt32Size + SkAlign4(byteLength) + count * sizeof(SkRSXform);
+    uint32_t flags = 0;
+    if (cull) {
+        flags |= DRAW_TEXT_RSXFORM_HAS_CULL;
+        size += sizeof(SkRect);
+    }
+
+    size_t initialOffset = this->addDraw(DRAW_TEXT_RSXFORM, &size);
+    this->addPaint(paint);
+    this->addInt(count);
+    this->addInt(flags);
+    this->addText(text, byteLength);
+    fWriter.write(xform, count * sizeof(SkRSXform));
+    if (cull) {
+        fWriter.write(cull, sizeof(SkRect));
+    }
+    this->validate(initialOffset, size);
+}
+
 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                      const SkPaint& paint) {
 
index 8504c00..bdb6609 100644 (file)
@@ -167,6 +167,8 @@ protected:
                         const SkPaint&) override;
     void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) override;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint&) override;
     void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) override;
 
index d0e8c4c..ec9aee9 100644 (file)
@@ -114,6 +114,7 @@ DRAW(DrawRect, drawRect(r.rect, r.paint));
 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
 DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
+DRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.paint));
 DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
                                 r.xmode, r.indices, r.indexCount, r.paint));
@@ -454,6 +455,8 @@ private:
 
     Bounds bounds(const DrawAtlas& op) const {
         if (op.cull) {
+            // TODO: <reed> can we pass nullptr for the paint? Isn't cull already "correct"
+            // for the paint (by the caller)?
             return this->adjustAndMap(*op.cull, op.paint);
         } else {
             return fCurrentClipBounds;
@@ -508,6 +511,14 @@ private:
         return this->adjustAndMap(dst, &op.paint);
     }
 
+    Bounds bounds(const DrawTextRSXform& op) const {
+        if (op.cull) {
+            return this->adjustAndMap(*op.cull, nullptr);
+        } else {
+            return fCurrentClipBounds;
+        }
+    }
+
     Bounds bounds(const DrawTextBlob& op) const {
         SkRect dst = op.blob->bounds();
         dst.offset(op.x, op.y);
index ff5c27d..19cb663 100644 (file)
@@ -278,6 +278,16 @@ void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkP
            matrix ? *matrix : SkMatrix::I());
 }
 
+void SkRecorder::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                   const SkRect* cull, const SkPaint& paint) {
+    APPEND(DrawTextRSXform,
+           paint,
+           this->copy((const char*)text, byteLength),
+           byteLength,
+           this->copy(xform, paint.countText(text, byteLength)),
+           this->copy(cull));
+}
+
 void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) {
     TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint);
index 1299efb..3cf0be9 100644 (file)
@@ -82,6 +82,11 @@ public:
                           const SkPath& path,
                           const SkMatrix* matrix,
                           const SkPaint& paint) override;
+    void onDrawTextRSXform(const void* text,
+                           size_t byteLength,
+                           const SkRSXform[],
+                           const SkRect* cull,
+                           const SkPaint& paint) override;
     void onDrawTextBlob(const SkTextBlob* blob,
                         SkScalar x,
                         SkScalar y,
index 7a37fcb..5166640 100644 (file)
@@ -429,6 +429,14 @@ void SkDumpCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const S
                str.c_str(), byteLength);
 }
 
+void SkDumpCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                     const SkRect* cull, const SkPaint& paint) {
+    SkString str;
+    toString(text, byteLength, paint.getTextEncoding(), &str);
+    this->dump(kDrawText_Verb, &paint, "drawTextRSXform(%s [%d])",
+               str.c_str(), byteLength);
+}
+
 void SkDumpCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                   const SkPaint& paint) {
     SkString str;
index c51b0d8..a3160af 100644 (file)
@@ -273,6 +273,14 @@ void SkLuaCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const Sk
     lua.pushPaint(paint, "paint");
 }
 
+void SkLuaCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                    const SkRect* cull, const SkPaint& paint) {
+    AUTO_LUA("drawTextRSXform");
+    lua.pushEncodedText(paint.getTextEncoding(), text, byteLength);
+    // TODO: export other params
+    lua.pushPaint(paint, "paint");
+}
+
 void SkLuaCanvas::onDrawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y,
                                  const SkPaint &paint) {
     AUTO_LUA("drawTextBlob");
index 4397814..dc9437c 100644 (file)
@@ -254,6 +254,14 @@ void SkNWayCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const S
     }
 }
 
+void SkNWayCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                     const SkRect* cull, const SkPaint& paint) {
+    Iter iter(fList);
+    while (iter.next()) {
+        iter->drawTextRSXform(text, byteLength, xform, cull, paint);
+    }
+}
+
 void SkNWayCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                   const SkPaint &paint) {
     Iter iter(fList);
index ea94068..75a7930 100644 (file)
@@ -204,6 +204,15 @@ void SkPaintFilterCanvas::onDrawTextOnPath(const void* text, size_t byteLength,
     }
 }
 
+void SkPaintFilterCanvas::onDrawTextRSXform(const void* text, size_t byteLength,
+                                            const SkRSXform xform[], const SkRect* cull,
+                                            const SkPaint& paint) {
+    AutoPaintFilter apf(this, kText_Type, paint);
+    if (apf.shouldDraw()) {
+        this->INHERITED::onDrawTextRSXform(text, byteLength, xform, cull, *apf.paint());
+    }
+}
+
 void SkPaintFilterCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                          const SkPaint& paint) {
     AutoPaintFilter apf(this, kTextBlob_Type, paint);
index c1a40f4..8d95d8a 100644 (file)
@@ -200,13 +200,19 @@ void SkAndroidSDKCanvas::onDrawPosTextH(const void* text,
     fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint);
 }
 void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text,
-                                                   size_t byteLength,
-                                                   const SkPath& path,
-                                                   const SkMatrix* matrix,
-                                                   const SkPaint& paint) {
+                                          size_t byteLength,
+                                          const SkPath& path,
+                                          const SkMatrix* matrix,
+                                          const SkPaint& paint) {
     FILTER(paint);
     fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint);
 }
+void SkAndroidSDKCanvas::onDrawTextRSXform(const void* text, size_t byteLength,
+                                           const SkRSXform xform[], const SkRect* cull,
+                                           const SkPaint& paint) {
+    FILTER(paint);
+    fProxyTarget->drawTextRSXform(text, byteLength, xform, cull, filteredPaint);
+}
 void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob,
                                                  SkScalar x,
                                                  SkScalar y,
index 78cfa93..b7be797 100644 (file)
@@ -62,6 +62,8 @@ protected:
                         SkScalar constY, const SkPaint& paint) override;
     void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                           const SkMatrix* matrix, const SkPaint& paint) override;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cull, const SkPaint& paint) override;
     void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                         const SkPaint& paint) override;
 
index ceea782..b80eeea 100644 (file)
@@ -644,6 +644,11 @@ void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const
         new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
 }
 
+void SkDebugCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                      const SkRect* cull, const SkPaint& paint) {
+    this->addDrawCommand(new SkDrawTextRSXformCommand(text, byteLength, xform, cull, paint));
+}
+
 void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                    const SkPaint& paint) {
     this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
index d0cdf82..e8d9113 100644 (file)
@@ -204,6 +204,8 @@ protected:
                         SkScalar constY, const SkPaint&) override;
     void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                           const SkMatrix* matrix, const SkPaint&) override;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], const SkRect*,
+                           const SkPaint&) override;
     void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                         const SkPaint& paint) override;
 
index 6c9287f..d58b3c9 100644 (file)
@@ -204,6 +204,7 @@ const char* SkDrawCommand::GetCommandString(OpType type) {
         case kDrawText_OpType: return "DrawText";
         case kDrawTextBlob_OpType: return "DrawTextBlob";
         case kDrawTextOnPath_OpType: return "DrawTextOnPath";
+        case kDrawTextRSXform_OpType: return "drawTextRSXform";
         case kDrawVertices_OpType: return "DrawVertices";
         case kEndDrawPicture_OpType: return "EndDrawPicture";
         case kRestore_OpType: return "Restore";
@@ -257,6 +258,7 @@ SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& url
         INSTALL_FACTORY(DrawPosText);
         INSTALL_FACTORY(DrawPosTextH);
         INSTALL_FACTORY(DrawTextOnPath);
+        INSTALL_FACTORY(DrawTextRSXform);
         INSTALL_FACTORY(DrawTextBlob);
 
         INSTALL_FACTORY(DrawRect);
@@ -2956,6 +2958,8 @@ SkDrawTextCommand* SkDrawTextCommand::fromJSON(Json::Value& command,
                                  paint);
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 SkDrawTextOnPathCommand::SkDrawTextOnPathCommand(const void* text, size_t byteLength,
                                                  const SkPath& path, const SkMatrix* matrix,
                                                  const SkPaint& paint)
@@ -3017,6 +3021,62 @@ SkDrawTextOnPathCommand* SkDrawTextOnPathCommand::fromJSON(Json::Value& command,
     return new SkDrawTextOnPathCommand(text, strlen(text), path, matrixPtr, paint);
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkDrawTextRSXformCommand::SkDrawTextRSXformCommand(const void* text, size_t byteLength,
+                                                   const SkRSXform xform[], const SkRect* cull,
+                                                   const SkPaint& paint)
+    : INHERITED(kDrawTextOnPath_OpType)
+{
+    fText = new char[byteLength];
+    memcpy(fText, text, byteLength);
+    fByteLength = byteLength;
+    int count = paint.countText(text, byteLength);
+    fXform = new SkRSXform[count];
+    memcpy(fXform, xform, count * sizeof(SkRSXform));
+    if (cull) {
+        fCullStorage = *cull;
+        fCull = &fCullStorage;
+    } else {
+        fCull = nullptr;
+    }
+    fPaint = paint;
+
+    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
+    fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawTextRSXformCommand::execute(SkCanvas* canvas) const {
+    canvas->drawTextRSXform(fText, fByteLength, fXform, fCull, fPaint);
+}
+
+Json::Value SkDrawTextRSXformCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
+    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
+                                                       ((const char*) fText) + fByteLength);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
+    return result;
+}
+
+SkDrawTextRSXformCommand* SkDrawTextRSXformCommand::fromJSON(Json::Value& command,
+                                                             UrlDataManager& urlDataManager) {
+    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
+    size_t byteLength = strlen(text);
+    SkPaint paint;
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
+
+    // TODO: handle xform and cull
+    int count = paint.countText(text, byteLength);
+    SkAutoTArray<SkRSXform> xform(count);
+    for (int i = 0; i < count; ++i) {
+        xform[i].fSCos = 1;
+        xform[i].fSSin = xform[i].fTx = xform[i].fTy = 0;
+    }
+    return new SkDrawTextRSXformCommand(text, byteLength, &xform[0], nullptr, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 SkDrawVerticesCommand::SkDrawVerticesCommand(SkCanvas::VertexMode vmode, int vertexCount,
                                              const SkPoint vertices[], const SkPoint texs[],
                                              const SkColor colors[], SkXfermode* xfermode,
index 8b8ada2..dc639ec 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkTLazy.h"
 #include "SkPath.h"
 #include "SkRRect.h"
+#include "SkRSXform.h"
 #include "SkString.h"
 #include "SkTDArray.h"
 #include "SkJSONCPP.h"
@@ -48,6 +49,7 @@ public:
         kDrawText_OpType,
         kDrawTextBlob_OpType,
         kDrawTextOnPath_OpType,
+        kDrawTextRSXform_OpType,
         kDrawVertices_OpType,
         kEndDrawPicture_OpType,
         kRestore_OpType,
@@ -526,6 +528,26 @@ private:
     typedef SkDrawCommand INHERITED;
 };
 
+class SkDrawTextRSXformCommand : public SkDrawCommand {
+public:
+    SkDrawTextRSXformCommand(const void* text, size_t byteLength, const SkRSXform[],
+                             const SkRect*, const SkPaint& paint);
+    ~SkDrawTextRSXformCommand() override { delete[] fText; delete[] fXform; }
+    void execute(SkCanvas* canvas) const override;
+    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
+    static SkDrawTextRSXformCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
+
+private:
+    char*       fText;
+    size_t      fByteLength;
+    SkRSXform*  fXform;
+    SkRect*     fCull;
+    SkRect      fCullStorage;
+    SkPaint     fPaint;
+
+    typedef SkDrawCommand INHERITED;
+};
+
 class SkDrawPosTextHCommand : public SkDrawCommand {
 public:
     SkDrawPosTextHCommand(const void* text, size_t byteLength, const SkScalar xpos[],