[SkPathBuilder] Add rMoveTo

This is adapted from SkPath::rMoveTo.

Bug: b/40040287
Change-Id: Ib559199e1ee4c2f29d697a17e1a52fa33a96d9e2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1028776
Reviewed-by: Florin Malita <fmalita@google.com>
Auto-Submit: Eric Boren <borenet@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
diff --git a/include/core/SkPathBuilder.h b/include/core/SkPathBuilder.h
index 833a219..8f36e42 100644
--- a/include/core/SkPathBuilder.h
+++ b/include/core/SkPathBuilder.h
@@ -357,6 +357,18 @@
 
     // Relative versions of segments, relative to the previous position.
 
+    /** Adds beginning of contour relative to last point.
+        If SkPathBuilder is empty, starts contour at (dx, dy).
+        Otherwise, start contour at last point offset by (dx, dy).
+        Function name stands for "relative move to".
+
+        @param pt  vector offset from last point to contour start
+        @return    reference to SkPathBuilder
+
+        example: https://fiddle.skia.org/c/@Path_rMoveTo
+    */
+    SkPathBuilder& rMoveTo(SkPoint pt);
+
     /** Adds line from last point to vector given by pt. If SkPathBuilder is empty, or last
         SkPath::Verb is kClose_Verb, last point is set to (0, 0) before adding line.
 
diff --git a/src/core/SkPathBuilder.cpp b/src/core/SkPathBuilder.cpp
index 1daa8f7..4f624bd 100644
--- a/src/core/SkPathBuilder.cpp
+++ b/src/core/SkPathBuilder.cpp
@@ -240,6 +240,19 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////
 
+SkPathBuilder& SkPathBuilder::rMoveTo(SkPoint pt) {
+    SkPoint lastPt = {0,0};
+    int count = fPts.size();
+    if (count > 0) {
+        if (!fNeedsMoveVerb) {
+            lastPt = fPts[count - 1];
+        } else {
+            lastPt = fPts[fLastMoveIndex];
+        }
+    }
+    return this->moveTo(lastPt.fX + pt.fX, lastPt.fY + pt.fY);
+}
+
 SkPathBuilder& SkPathBuilder::rLineTo(SkPoint p1) {
     this->ensureMove();
     return this->lineTo(fPts.back() + p1);
diff --git a/tests/PathBuilderTest.cpp b/tests/PathBuilderTest.cpp
index 2dddbd4..69b8c1a 100644
--- a/tests/PathBuilderTest.cpp
+++ b/tests/PathBuilderTest.cpp
@@ -842,3 +842,62 @@
                       .close()
                       .detach());
 }
+
+static void check_move(skiatest::Reporter* reporter, SkPathRaw::Iter* iter,
+                       SkScalar x0, SkScalar y0) {
+    auto rec = iter->next().value();
+    REPORTER_ASSERT(reporter, rec.vrb == SkPathVerb::kMove);
+    REPORTER_ASSERT(reporter, rec.pts[0].fX == x0);
+    REPORTER_ASSERT(reporter, rec.pts[0].fY == y0);
+}
+
+static void check_line(skiatest::Reporter* reporter, SkPathRaw::Iter* iter,
+                       SkScalar x1, SkScalar y1) {
+    auto rec = iter->next().value();
+    REPORTER_ASSERT(reporter, rec.vrb == SkPathVerb::kLine);
+    REPORTER_ASSERT(reporter, rec.pts[1].fX == x1);
+    REPORTER_ASSERT(reporter, rec.pts[1].fY == y1);
+}
+
+static void check_close(skiatest::Reporter* reporter, SkPathRaw::Iter* iter) {
+    auto rec = iter->next().value();
+    REPORTER_ASSERT(reporter, rec.vrb == SkPathVerb::kClose);
+}
+
+static void check_done(skiatest::Reporter* reporter, SkPathBuilder* p, SkPathRaw::Iter* iter) {
+    REPORTER_ASSERT(reporter, !iter->next().has_value());
+}
+
+static void check_done_and_reset(skiatest::Reporter* reporter, SkPathBuilder* p,
+                                 SkPathRaw::Iter* iter) {
+    check_done(reporter, p, iter);
+    p->reset();
+}
+
+DEF_TEST(SkPathBuilder_rMoveTo, reporter) {
+    SkPathBuilder p;
+    p.moveTo(10, 11);
+    p.lineTo(20, 21);
+    p.close();
+    p.rMoveTo({30, 31});
+    SkPathRaw::Iter iter = SkPathRaw::Iter(p.points(), p.verbs(), {} /* no conics */);
+    check_move(reporter, &iter, 10, 11);
+    check_line(reporter, &iter, 20, 21);
+    check_close(reporter, &iter);
+    check_move(reporter, &iter, 10 + 30, 11 + 31);
+    check_done_and_reset(reporter, &p, &iter);
+
+    p.moveTo(10, 11);
+    p.lineTo(20, 21);
+    p.rMoveTo({30, 31});
+    iter = SkPathRaw::Iter(p.points(), p.verbs(), {} /* no conics */);
+    check_move(reporter, &iter, 10, 11);
+    check_line(reporter, &iter, 20, 21);
+    check_move(reporter, &iter, 20 + 30, 21 + 31);
+    check_done_and_reset(reporter, &p, &iter);
+
+    p.rMoveTo({30, 31});
+    iter = SkPathRaw::Iter(p.points(), p.verbs(), {} /* no conics */);
+    check_move(reporter, &iter, 30, 31);
+    check_done_and_reset(reporter, &p, &iter);
+}