Reland "[svg] Absolute positioning support for text"
This reverts commit e2f62453523e8eeb98968570b48b229f1cc1e712.
Reason for revert: relanding with fixes
Original change's description:
> Revert "[svg] Absolute positioning support for text"
>
> This reverts commit febb1b87a5e73bdbe2cb598783082d3644d0e969.
>
> Reason for revert: breaking the android roll
>
> Original change's description:
> > [svg] Absolute positioning support for text
> >
> > Implement per-character position attribute lookup based on [1]:
> >
> > - convert "x" and "y" attributes to arrays
> > - introduce ScopedPosResolver to handle positioning attribute lookup
> > and fallback
> > - push a new resolver every time we enter a text positioning element
> > scope (<text>, <tspan>, etc).
> > - flush/reposition a new text chunk every time we encounter explicit
> > absolute positions
> >
> > The position attribute fallback logic is complex enough to warrant a
> > unit test.
> >
> > [1] https://www.w3.org/TR/SVG11/text.html#TSpanElementXAttribute
> >
> > Bug: skia:10840
> > Change-Id: I66c478fea4a179fdb8b1a6a9ff00c4dd9509f8d2
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/345161
> > Commit-Queue: Florin Malita <fmalita@chromium.org>
> > Commit-Queue: Florin Malita <fmalita@google.com>
> > Reviewed-by: Tyler Denniston <tdenniston@google.com>
>
> TBR=fmalita@chromium.org,fmalita@google.com,tdenniston@google.com
>
> Change-Id: I80e3396d555369fe835ee73102135061f63e8bf0
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:10840
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/345417
> Reviewed-by: Derek Sollenberger <djsollen@google.com>
> Commit-Queue: Derek Sollenberger <djsollen@google.com>
TBR=djsollen@google.com,fmalita@chromium.org,fmalita@google.com,tdenniston@google.com
# Not skipping CQ checks because this is a reland.
Bug: skia:10840
Change-Id: I4c6f6a9f19c0f7598bdcf34e915f43c139b995a9
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/345420
Reviewed-by: Florin Malita <fmalita@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
diff --git a/modules/svg/tests/Text.cpp b/modules/svg/tests/Text.cpp
new file mode 100644
index 0000000..fc09649
--- /dev/null
+++ b/modules/svg/tests/Text.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <vector>
+
+#include "modules/svg/src/SkSVGTextPriv.h"
+#include "tests/Test.h"
+
+DEF_TEST(Svg_Text_PosProvider, r) {
+ const auto L = [](float x) { return SkSVGLength(x); };
+ const float N = SkSVGTextContext::PosAttrs()[SkSVGTextContext::PosAttrs::kX];
+
+ static const struct PosTestDesc {
+ size_t offseta;
+ std::vector<SkSVGLength> xa, ya;
+
+ size_t offsetb;
+ std::vector<SkSVGLength> xb, yb;
+
+ std::vector<SkPoint> expected;
+ } gTests[] = {
+ {
+ 0, {}, {},
+ 0, {}, {},
+
+ { {N,N} }
+ },
+
+ {
+ 0, { L(1) }, {},
+ 0, { }, {},
+
+ { {1,N}, {N,N} }
+ },
+ {
+ 0, { }, {},
+ 0, { L(10) }, {},
+
+ { {10,N}, {N,N} }
+ },
+ {
+ 0, { L( 1) }, {},
+ 0, { L(10) }, {},
+
+ { {10,N}, {N,N} }
+ },
+ {
+ 0, { L( 1), L(2) }, {},
+ 0, { L(10) }, {},
+
+ { {10,N}, {2,N}, {N,N} }
+ },
+ {
+ 0, { L(1), L( 2) }, {},
+ 1, { L(20) }, {},
+
+ { {1,N}, {20,N}, {N,N} }
+ },
+ {
+ 0, { L(1), L( 2), L(3) }, {},
+ 1, { L(20) }, {},
+
+ { {1,N}, {20,N}, {3,N}, {N,N} }
+ },
+ {
+ 0, { L(1), L(2), L( 3) }, {},
+ 2, { L(30) }, {},
+
+ { {1,N}, {2,N}, {30,N}, {N,N} }
+ },
+ {
+ 0, { L(1) }, {},
+ 2, { L(30) }, {},
+
+ { {1,N}, {N,N}, {30,N}, {N,N} }
+ },
+
+
+ {
+ 0, {}, { L(4) },
+ 0, {}, { },
+
+ { {N,4}, {N,N} }
+ },
+ {
+ 0, {}, { },
+ 0, {}, { L(40) },
+
+ { {N,40}, {N,N} }
+ },
+ {
+ 0, {}, { L( 4) },
+ 0, {}, { L(40) },
+
+ { {N,40}, {N,N} }
+ },
+ {
+ 0, {}, { L( 4), L(5) },
+ 0, {}, { L(40) },
+
+ { {N,40}, {N,5}, {N,N} }
+ },
+ {
+ 0, {}, { L(4), L( 5) },
+ 1, {}, { L(50) },
+
+ { {N,4}, {N,50}, {N,N} }
+ },
+ {
+ 0, {}, { L(4), L( 5), L(6) },
+ 1, {}, { L(50) },
+
+ { {N,4}, {N,50}, {N,6}, {N,N} }
+ },
+ {
+ 0, {}, { L(4), L(5), L( 6) },
+ 2, {}, { L(60) },
+
+ { {N,4}, {N,5}, {N,60}, {N,N} }
+ },
+ {
+ 0, {}, { L(4) },
+ 2, {}, { L(60) },
+
+ { {N,4}, {N,N}, {N,60}, {N,N} }
+ },
+
+ {
+ 0, { L( 1), L(2)}, { L( 4) },
+ 0, { L(10) }, { L(40), L(50) },
+
+ { {10,40}, {2,50}, {N,N} }
+ },
+ {
+ 0, { L(1), L( 2), L(3) }, { L(4), L( 5) },
+ 1, { L(20) }, { L(50), L(60) },
+
+ { {1,4}, {20,50}, {3,60}, {N,N} }
+ },
+ };
+
+ auto test = [&](const PosTestDesc& tst) {
+ auto a = SkSVGText::Make();
+ auto b = SkSVGTSpan::Make();
+ a->appendChild(b);
+
+ a->setX(tst.xa);
+ a->setY(tst.ya);
+ b->setX(tst.xb);
+ b->setY(tst.yb);
+
+ SkSVGTextContext tctx(SkSVGPresentationContext(), nullptr);
+ SkSVGLengthContext lctx({0,0});
+ SkSVGTextContext::ScopedPosResolver pa(*a, lctx, &tctx, tst.offseta);
+ SkSVGTextContext::ScopedPosResolver pb(*b, lctx, &tctx, tst.offsetb);
+
+ for (size_t i = 0; i < tst.expected.size(); ++i) {
+ const auto& exp = tst.expected[i];
+ auto pos = i >= tst.offsetb ? pb.resolve(i) : pa.resolve(i);
+
+ REPORTER_ASSERT(r, pos[SkSVGTextContext::PosAttrs::kX] == exp.fX);
+ REPORTER_ASSERT(r, pos[SkSVGTextContext::PosAttrs::kY] == exp.fY);
+ }
+ };
+
+ for (const auto& tst : gTests) {
+ test(tst);
+ }
+}