xref: /aosp_15_r20/external/skia/tools/viewer/PathLerpSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2024 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
9*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
10*c8dee2aaSAndroid Build Coastguard Worker #include <deque>
11*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCubicMap.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathMeasure.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkPathRef.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkParsePath.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathPriv.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/Slide.h"
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker #include "imgui.h"
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker namespace {
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct PathDesc {
34*c8dee2aaSAndroid Build Coastguard Worker     const char* fName;
35*c8dee2aaSAndroid Build Coastguard Worker     const char* fSVGString;
36*c8dee2aaSAndroid Build Coastguard Worker } gSamplePaths[] = {
37*c8dee2aaSAndroid Build Coastguard Worker     { "Arc 1", "M0,0.5 Q0,0 0.5,0 Q1,0 1,0.5"},
38*c8dee2aaSAndroid Build Coastguard Worker     { "Arc 2", "M0,0.5 Q0,1 0.5,1 Q1,1 1,0.5 L1.1,0.5 L1.2,0.5 L1.3,0.5 L1.5,0.5"},
39*c8dee2aaSAndroid Build Coastguard Worker     { "Pentagon",
40*c8dee2aaSAndroid Build Coastguard Worker         R"(M10.1192 4.09438C10.7952 3.60324 11.1332 3.35767 11.5027 3.26278C11.829 3.17901 12.1712 3.17901 12.4975
41*c8dee2aaSAndroid Build Coastguard Worker         3.26278C12.867 3.35767 13.205 3.60324 13.881 4.09438L19.6298 8.27108C20.3058 8.76222 20.6437 9.0078 20.8482
42*c8dee2aaSAndroid Build Coastguard Worker         9.32992C21.0287 9.61436 21.1344 9.93978 21.1556 10.276C21.1795 10.6568 21.0504 11.0541 20.7922 11.8488L18.5964
43*c8dee2aaSAndroid Build Coastguard Worker         18.6068C18.3382 19.4015 18.2091 19.7989 17.9659 20.0928C17.7512 20.3524 17.4743 20.5535 17.1611 20.6775C16.8064
44*c8dee2aaSAndroid Build Coastguard Worker         20.818 16.3886 20.818 15.553 20.818H8.44718C7.6116 20.818 7.19381 20.818 6.83908 20.6775C6.52586 20.5535 6.24904
45*c8dee2aaSAndroid Build Coastguard Worker         20.3524 6.0343 20.0928C5.79111 19.7989 5.66201 19.4015 5.4038 18.6068L3.20798 11.8488C2.94977 11.0541 2.82066
46*c8dee2aaSAndroid Build Coastguard Worker         10.6568 2.84462 10.276C2.86577 9.93978 2.97151 9.61436 3.15202 9.32992C3.35645 9.0078 3.69445 8.76222 4.37045
47*c8dee2aaSAndroid Build Coastguard Worker         8.27108L10.1192 4.09438Z)"},
48*c8dee2aaSAndroid Build Coastguard Worker     { "Droplet",
49*c8dee2aaSAndroid Build Coastguard Worker         R"(M12 21.5C13.8565 21.5 15.637 20.7625 16.9497 19.4497C18.2625 18.137 19 16.3565 19 14.5C19 12.5 18 10.6 16 9
50*c8dee2aaSAndroid Build Coastguard Worker         C14 7.4 12.5 5 12 2.5C11.5 5 10 7.4 8 9C6 10.6 5 12.5 5 14.5C5 16.3565 5.7375 18.137 7.05025 19.4497
51*c8dee2aaSAndroid Build Coastguard Worker         C8.36301 20.7625 10.1435 21.5 12 21.5V21.5Z)"},
52*c8dee2aaSAndroid Build Coastguard Worker     { "Shield",
53*c8dee2aaSAndroid Build Coastguard Worker         R"(M20 6C20 6 19.1843 6 19.0001 6C16.2681 6 13.8871 4.93485 11.9999 3C10.1128 4.93478 7.73199 6 5.00009 6
54*c8dee2aaSAndroid Build Coastguard Worker         C4.81589 6 4.00009 6 4.00009 6C4.00009 6 4 8 4 9.16611C4 14.8596 7.3994 19.6436 12 21C16.6006 19.6436 20 14.8596 20 9.16611
55*c8dee2aaSAndroid Build Coastguard Worker         C20 8 20 6 20 6Z)"},
56*c8dee2aaSAndroid Build Coastguard Worker     { "Spiral",
57*c8dee2aaSAndroid Build Coastguard Worker         R"(M297,7888.302 L297,7886.302 C297,7885.75 296.552,7885 296,7885 L292,7885 C291.448,7885 291,7885.75 291,7886.302
58*c8dee2aaSAndroid Build Coastguard Worker         L291,7892.302 C291,7892.854 291.448,7893 292,7893 L300,7893 C300.552,7893 301,7892.854 301,7892.302 L301,7882.302
59*c8dee2aaSAndroid Build Coastguard Worker         C301,7881.75 300.552,7881 300,7881 L288,7881 C287.448,7881 287,7881.75 287,7882.302 L287,7896.302
60*c8dee2aaSAndroid Build Coastguard Worker         C287,7896.854 287.448,7897 288,7897 L302,7897 C302.552,7897 303,7897.524 303,7898.076 L303,7898.151
61*c8dee2aaSAndroid Build Coastguard Worker         C303,7898.703 302.552,7899 302,7899 L287,7899 C285.896,7899 285,7898.407 285,7897.302 L285,7881.302
62*c8dee2aaSAndroid Build Coastguard Worker         C285,7880.197 285.896,7879 287,7879 L301,7879 C302.105,7879 303,7880.197 303,7881.302 L303,7893.302
63*c8dee2aaSAndroid Build Coastguard Worker         C303,7894.407 302.105,7895 301,7895 L291,7895 C289.896,7895 289,7894.407 289,7893.302 L289,7885.302
64*c8dee2aaSAndroid Build Coastguard Worker         C289,7884.197 289.896,7883 291,7883 L297,7883 C298.105,7883 299,7884.197 299,7885.302 L299,7889.302
65*c8dee2aaSAndroid Build Coastguard Worker         C299,7890.407 298.105,7891 297,7891 L295,7891 C293.896,7891 293,7890.407 293,7889.302 L293,7888.302
66*c8dee2aaSAndroid Build Coastguard Worker         C293,7887.75 293.448,7887.302 294,7887.302 C294.552,7887.302 295,7887.75 295,7888.302
67*c8dee2aaSAndroid Build Coastguard Worker         C295,7888.854 295.448,7889.302 296,7889.302 C296.552,7889.302 297,7888.854 297,7888.302)"},
68*c8dee2aaSAndroid Build Coastguard Worker     { "Cat",
69*c8dee2aaSAndroid Build Coastguard Worker         R"(M26.753,210.905c-4.68,19.271-1.375,33.856,8.258,46.243c9.633,12.387-1.102,19.543-9.082,23.398
70*c8dee2aaSAndroid Build Coastguard Worker 		s-11.012,6.332-11.562,11.836s6.883,26.978,10.461,30.556s11.563,11.285,16.789,19.27c5.231,7.98,12.11,2.754,12.11,2.754
71*c8dee2aaSAndroid Build Coastguard Worker 		c4.953,3.855,9.91,0,9.91,0c8.809,4.129,14.039-1.652,14.039-1.652c4.402-5.23-4.953-10.734-4.953-10.734
72*c8dee2aaSAndroid Build Coastguard Worker 		c-5.781-10.184-10.184-1.926-11.836-4.129s-3.027-2.477-11.836-12.66s14.039-6.883,22.02-8.809s23.122-12.109,23.122-12.109
73*c8dee2aaSAndroid Build Coastguard Worker 		c0,12.109,4.129,10.184,10.184,16.516s8.809,10.461,16.789,13.762c7.98,3.305,11.836,2.754,18.993,7.434s22.02,3.855,22.02,3.855
74*c8dee2aaSAndroid Build Coastguard Worker 		c6.605,2.204,12.938,0,12.938,0c15.965,0,9.359-5.504,3.578-12.938s-17.34-1.102-22.57-4.68s-18.168-9.082-24.774-12.938
75*c8dee2aaSAndroid Build Coastguard Worker 		c-6.605-3.855,0-10.734,0-17.066s4.953-11.285,4.953-11.285h25.598c0,0,19.816-1.375,25.047,9.359s13.211,12.938,13.488,18.719
76*c8dee2aaSAndroid Build Coastguard Worker 		c0.278,5.781-4.68,6.332-4.68,6.332c-11.012-3.027-11.285,14.59-11.285,14.59c13.488,17.892,39.638-7.434,39.638-7.434
77*c8dee2aaSAndroid Build Coastguard Worker 		c30.277-2.754,28.074-47.344,28.074-47.344c6.055-4.402,15.691-15.965,22.02-26.427c6.332-10.461,24.223-18.441,40.188-10.734
78*c8dee2aaSAndroid Build Coastguard Worker 		c15.965,7.707,18.719-5.23,18.719-5.23c5.504,0.824,7.156-6.332,7.156-6.332c7.156-7.98-5.504-9.91-5.781-29.727
79*c8dee2aaSAndroid Build Coastguard Worker 		s-16.789-23.399-15.965-29.176c0.824-5.781,17.617-24.223,13.488-22.571c-3.603,1.44-18.739,8.964-22.53,10.853
80*c8dee2aaSAndroid Build Coastguard Worker 		c-0.126-0.498-0.375-1.208-0.868-2.317c-2.204-4.953-26.427,10.734-26.427,10.734s-38.396,22.709-45.83,24.362
81*c8dee2aaSAndroid Build Coastguard Worker 		c-7.435,1.652-6.605-3.305-15.688-2.477c-9.083,0.824-13.628,1.652-54.501-15.692c-40.877-17.34-115.325,10.546-115.325,10.546
82*c8dee2aaSAndroid Build Coastguard Worker 		S-8.608,82.798,40.935,41.924S24.215-33.009,8.111,56.167C-7.992,145.344,31.433,191.64,26.753,210.905z)" },
83*c8dee2aaSAndroid Build Coastguard Worker     { "Rabit",
84*c8dee2aaSAndroid Build Coastguard Worker         R"(M526.834,235.822c-6.308-15.153-11.856-30.576-18.748-45.546c-5.969-12.966-15.985-20.689-27.282-27.287
85*c8dee2aaSAndroid Build Coastguard Worker 		c-6.455-3.766-13.681-6.205-20.563-8.865c-2.102-0.812-3.447-3.309-3.007-5.517c1.126-5.643,2.379-11.607,3.187-17.629
86*c8dee2aaSAndroid Build Coastguard Worker 		c0.489-3.664-0.425-7.495-0.47-11.253c-0.061-5.101-0.012-10.204,0.196-15.3c0.363-8.829-1.918-17.157-4.039-25.614
87*c8dee2aaSAndroid Build Coastguard Worker 		c-1.359-5.423-0.367-11.478-1.959-16.789c-1.652-5.521,0.322-12.212-4.961-16.614c-0.118-0.098-0.184-0.343-0.167-0.51
88*c8dee2aaSAndroid Build Coastguard Worker 		c0.844-8.576-5.484-14.574-8.373-21.714c-2.933-7.246-7.752-14.157-15.879-17.617c-2.881-1.225-5.516-3.023-8.482-4.974
89*c8dee2aaSAndroid Build Coastguard Worker 		c-1.881-1.24-4.007-0.466-4.745,1.664c-2.546,7.364-5.116,14.035-6.622,20.935c-1.488,6.847-5.111,13.048-3.998,20.898
90*c8dee2aaSAndroid Build Coastguard Worker 		c0.8,5.618-2.685,11.771-3.88,17.764c-0.633,3.17-0.963,6.397-1.302,9.649c-0.232,2.24-1.656,2.685-3.06,0.918
91*c8dee2aaSAndroid Build Coastguard Worker 		c-3.366-4.243-6.328-8.507-10.38-11.004c-6.977-4.296-12.162-10.689-18.996-14.745c-10.674-6.332-21.519-12.917-33.138-16.956
92*c8dee2aaSAndroid Build Coastguard Worker 		c-11.519-4.007-24.027-5.463-36.23-7.047c-3.212-0.416-6.643,0.845-10.507,2.049c-2.15,0.669-3.076,2.713-2.036,4.712
93*c8dee2aaSAndroid Build Coastguard Worker 		c3.594,6.908,6.817,13.358,10.457,19.563c6.027,10.278,12.286,20.433,18.813,30.4c3.701,5.651,8.192,10.779,12.232,16.214
94*c8dee2aaSAndroid Build Coastguard Worker 		c4.153,5.594,7.988,11.437,12.342,16.867c3.015,3.758,6.744,6.936,10.017,10.497c3.606,3.926,7.299,7.802,10.526,12.028
95*c8dee2aaSAndroid Build Coastguard Worker 		c8.841,11.579,12.276,25.182,14.116,39.319c0.069,0.538,0.151,1.117,0.396,1.591c4.636,8.895-0.236,14.582-6.527,19.935
96*c8dee2aaSAndroid Build Coastguard Worker 		c-0.886,0.755-0.959,2.444-1.453,3.685c-0.844,2.113-1.313,4.533-2.66,6.259c-4.174,5.332-4.953,11.493-5.471,17.911
97*c8dee2aaSAndroid Build Coastguard Worker 		c-0.322,3.978-1.502,7.874-2.068,11.844c-0.09,0.637-0.041,1.294,0.053,1.901c0.159,1.041-0.534,3.477-1.469,5.528
98*c8dee2aaSAndroid Build Coastguard Worker 		c-3.473,7.634-5.899,16.026-13.064,21.172c-1.832,1.313-2.35,1.921-0.91,1.75c1.44-0.171,2.641-0.18,2.686-0.021
99*c8dee2aaSAndroid Build Coastguard Worker 		s-1.637,0.926-3.746,1.714c-0.318,0.118-0.641,0.236-0.963,0.358c-2.113,0.788-2.848,1.689-1.644,2.016
100*c8dee2aaSAndroid Build Coastguard Worker 		c1.203,0.327,0.461,1.2-1.665,1.955c-1.889,0.669-3.709,1.313-5.569,1.975c-2.126,0.75-3.035,1.767-2.036,2.264
101*c8dee2aaSAndroid Build Coastguard Worker 		c1,0.498,0.245,1.294-1.681,1.779s-3.272,1.375-3.003,1.979c0.27,0.604-1.306,1.444-3.509,1.91
102*c8dee2aaSAndroid Build Coastguard Worker 		c-3.966,0.836-7.939,1.701-11.963,2.068c-1.301,0.118-2.7-0.086-4.08-0.478c-2.166-0.616-5.605-1.624-7.858-1.575
103*c8dee2aaSAndroid Build Coastguard Worker 		c-13.17,0.282-35.672,4.391-44.778,6.148c-2.211,0.429-5.818,0.979-8.062,1.212c-3.052,0.314-6.308,0.649-9.666,0.996
104*c8dee2aaSAndroid Build Coastguard Worker 		c-2.24,0.232-3.77,0.689-3.411,1.023c0.355,0.335-1.089,1.184-3.228,1.897c-9.833,3.288-19.849,6.634-29.906,9.996
105*c8dee2aaSAndroid Build Coastguard Worker 		c-2.138,0.714-3.297,1.611-2.583,2.003c0.714,0.392-0.4,1.403-2.521,2.171c-5.675,2.048-11.355,3.725-15.802,7.054
106*c8dee2aaSAndroid Build Coastguard Worker 		c-4.814,3.607-10.164,6.479-14.913,10.286c-5.349,4.284-12.795,5.944-19.331,8.747c-0.62,0.266-1.24,0.53-2.056,0.886
107*c8dee2aaSAndroid Build Coastguard Worker 		c-1.139,0.489-1.155,1.293-0.033,1.795s0.563,1.999-1.245,3.346c-3.929,2.922-7.813,5.814-11.738,8.735
108*c8dee2aaSAndroid Build Coastguard Worker 		c-1.808,1.347-2.734,2.746-2.069,3.129c0.665,0.384-0.396,1.571-2.371,2.656c-1.33,0.73-2.64,1.448-3.941,2.167
109*c8dee2aaSAndroid Build Coastguard Worker 		c-1.975,1.085-3.484,2.146-3.375,2.37c0.114,0.225,1.424,0.188,2.934-0.086c1.505-0.273,1.408,0.771-0.22,2.326
110*c8dee2aaSAndroid Build Coastguard Worker 		c-7.181,6.854-14.125,13.492-21.094,20.106c-0.718,0.681-1.481,1.313-2.436,2.101c-1.375,1.131-1.008,1.648,0.808,1.146
111*c8dee2aaSAndroid Build Coastguard Worker 		c1.816-0.497,2.272,0.62,1.044,2.51c-3.472,5.32-6.842,10.579-10.453,15.667c-2.317,3.26-5.271,6.071-7.899,9.114
112*c8dee2aaSAndroid Build Coastguard Worker 		c-0.082,0.099-0.065,0.282-0.029,0.485c0.045,0.273,0.796,0.359,1.681,0.196s0.526,1.179-0.8,3.003
113*c8dee2aaSAndroid Build Coastguard Worker 		c-2.199,3.015-4.345,5.965-6.679,9.168c-1.326,1.819-0.947,2.518,0.844,1.555c1.792-0.963,2.518-0.062,1.559,1.979
114*c8dee2aaSAndroid Build Coastguard Worker 		c-3.537,7.52-7.226,14.052-7.789,21.93c-0.277,3.88-2.317,7.63-4.304,11.824c-0.963,2.036-0.853,3.162,0.126,2.46
115*c8dee2aaSAndroid Build Coastguard Worker 		c0.979-0.702,1.469,0.534,1.085,2.754c-1.812,10.457-3.578,20.669-5.328,30.768c-0.384,2.22-0.106,3.773,0.624,3.468
116*c8dee2aaSAndroid Build Coastguard Worker 		s0.812,1.199,0.184,3.366c-0.498,1.709-0.979,3.361-1.457,5.015c-0.628,2.162-0.481,3.745,0.322,3.533
117*c8dee2aaSAndroid Build Coastguard Worker 		c0.808-0.213,0.795,1.334,0.404,3.554c-1.02,5.797-0.355,11.938-4.602,16.703c-1.498,1.681-2.236,2.628-1.159,2.628
118*c8dee2aaSAndroid Build Coastguard Worker 		s0.877,1.48-0.441,3.312c-0.359,0.498-0.714,0.995-1.081,1.501c-1.318,1.828-1.665,3.068-0.779,2.763s1.677-0.44,1.767-0.306
119*c8dee2aaSAndroid Build Coastguard Worker 		c0.062,0.089,0.11,0.175,0.114,0.261c0.029,0.538,0.057,1.085-0.004,1.615c-1.134,9.771,2.023,17.349,11.33,21.555
120*c8dee2aaSAndroid Build Coastguard Worker 		c6.749,3.052,11.62,9.915,20.433,9.078c2.762-0.261,5.822,2.709,8.764,4.158c0.114,0.057,0.286,0.004,0.469-0.07
121*c8dee2aaSAndroid Build Coastguard Worker 		c0.253-0.098,0.265-0.628,0.029-1.187c-0.237-0.56,1.358-0.641,3.566-0.176c1.583,0.335,3.17,0.669,4.773,1.008
122*c8dee2aaSAndroid Build Coastguard Worker 		c2.208,0.465,3.705,0.229,3.354-0.526c-0.351-0.751,1.061-0.673,3.199,0.033c18.458,6.091,37.271,3.562,55.928,3.912
123*c8dee2aaSAndroid Build Coastguard Worker 		c2.252,0.041,3.832-0.229,3.534-0.661c-0.302-0.437,1.285-0.787,3.542-0.783c6.417,0.013,12.889,0.037,19.355-0.032
124*c8dee2aaSAndroid Build Coastguard Worker 		c3.007-0.033,6.03-0.217,9.008-0.62c6.626-0.894,13.244-1.849,19.829-2.991c7.222-1.252,14.517,1.604,21.962-2.746
125*c8dee2aaSAndroid Build Coastguard Worker 		c4.357-2.545,8.319-4.476,9.854-7.833c0.934-2.048,2.415-4.423,4.61-4.941c4.08-0.967,7.936-1.848,11.706-3.007
126*c8dee2aaSAndroid Build Coastguard Worker 		c5.283-1.623,9.849-3.541,10.967-10.521c0.792-4.958,0.396-9.507-4.1-12.146c-0.441-0.257-0.682-0.849-0.849-1.469
127*c8dee2aaSAndroid Build Coastguard Worker 		c-0.245-0.927-2.211-1.849-4.456-2.036c-0.498-0.041-1.008-0.086-1.53-0.131c-2.244-0.188-3.125-1.905-1.962-3.839
128*c8dee2aaSAndroid Build Coastguard Worker 		c0.673-1.118,1.302-2.162,1.905-3.17c1.163-1.93,2.375-3.35,2.709-3.175c0.334,0.176,0.702,1.657,0.816,3.31
129*c8dee2aaSAndroid Build Coastguard Worker 		s1.02,1.362,2.016-0.661c0.489-0.991,0.958-1.942,1.412-2.868c0.996-2.02,2.048-3.574,2.346-3.469
130*c8dee2aaSAndroid Build Coastguard Worker 		c0.298,0.106,0.673,1.506,0.833,3.117c0.159,1.612,0.967,1.225,1.808-0.869c0.269-0.673,0.539-1.342,0.812-2.027
131*c8dee2aaSAndroid Build Coastguard Worker 		c0.836-2.093,1.636-2.276,1.787-0.416c0.151,1.86,0.71,1.583,1.64-0.474c1.856-4.101,4.762-7.188,9.323-9.127
132*c8dee2aaSAndroid Build Coastguard Worker 		c6.304-2.676,12.371-5.916,18.675-8.604c1.061-0.453,3.337,0.2,4.104,1.126c3.08,3.705,5.699,7.789,8.666,11.6
133*c8dee2aaSAndroid Build Coastguard Worker 		c3.112,4.003,6.344,7.919,9.673,11.742c4.239,4.863,8.63,9.592,12.946,14.39c0.245,0.273,0.461,0.567,0.686,0.882
134*c8dee2aaSAndroid Build Coastguard Worker 		c0.354,0.506,0.967,0.399,1.362-0.229s1.457,0.53,2.375,2.591c0.322,0.722,0.648,1.456,0.983,2.216
135*c8dee2aaSAndroid Build Coastguard Worker 		c0.913,2.06,1.827,2.599,2.035,1.203s1.412-1.024,2.685,0.832c3.396,4.953,6.684,9.752,9.891,14.427
136*c8dee2aaSAndroid Build Coastguard Worker 		c1.272,1.861,2.305,2.203,2.305,0.771s1.024-1.077,2.285,0.787c1.885,2.787,3.676,5.431,5.59,8.258
137*c8dee2aaSAndroid Build Coastguard Worker 		c1.265,1.865,2.093,1.946,1.86,0.18c-0.236-1.767-0.139-3.406,0.212-3.659c0.351-0.257,1.714,1.012,3.04,2.831
138*c8dee2aaSAndroid Build Coastguard Worker 		c0.755,1.032,1.505,2.064,2.256,3.097c1.326,1.82,2.844,2.844,3.293,2.216c0.465-0.648,0.51-0.959,0.53-1.27
139*c8dee2aaSAndroid Build Coastguard Worker 		c0.012-0.171-0.139-0.354-0.123-0.525c0.005-0.065,0.09-0.119,0.241-0.221c0.15-0.102,1.75,0.877,3.578,2.195
140*c8dee2aaSAndroid Build Coastguard Worker 		c1.248,0.897,2.514,1.815,3.818,2.754c1.828,1.317,3.224,1.562,3.117,0.551c-0.105-1.012,1.498-1.135,3.562-0.232
141*c8dee2aaSAndroid Build Coastguard Worker 		c1.782,0.779,3.479,1.469,5.242,1.746c4.517,0.718,9.393-0.147,13.705,1.089c8.629,2.469,15.851-1.326,21.596-5.899
142*c8dee2aaSAndroid Build Coastguard Worker 		c3.603-2.868,6.98-3.644,10.901-3.998c2.244-0.204,5.397-1.53,7.034-3.081c2.244-2.13,4.545-4.316,6.72-6.377
143*c8dee2aaSAndroid Build Coastguard Worker 		c1.632-1.55,2.179-4.459,1.167-6.475c-2.525-5.035-5.292-9.417-10.698-11.021c-2.158-0.641-3.178-1.338-2.142-2.207
144*c8dee2aaSAndroid Build Coastguard Worker 		s0.049-1.575-2.203-1.575c-0.629,0-1.236,0-1.828,0c-2.252,0-4.08-0.114-4.084-0.257s0.881-0.494,1.982-0.787
145*c8dee2aaSAndroid Build Coastguard Worker 		c1.102-0.294,0.339-1.302-1.705-2.252c-0.612-0.282-1.212-0.563-1.812-0.841c-2.044-0.946-2.905-1.909-1.922-2.142
146*c8dee2aaSAndroid Build Coastguard Worker 		c0.983-0.237,0.172-1.298-1.812-2.371c-3.741-2.031-7.495-4.08-11.293-6.055c-0.8-0.416-1.661-0.714-2.677-1.04
147*c8dee2aaSAndroid Build Coastguard Worker 		c-1.514-0.485-1.778-1.175-0.6-1.522c1.179-0.343,1.085-1.122-0.204-1.737c-1.289-0.616-1.102-1.31,0.424-1.547
148*c8dee2aaSAndroid Build Coastguard Worker 		c1.526-0.236,1.073-1.126-1.007-1.987c-1.751-0.722-3.489-1.439-5.149-2.125c-2.081-0.861-3.044-2.534-2.081-3.676
149*c8dee2aaSAndroid Build Coastguard Worker 		c0.865-1.028,1.498-1.808,1.318-2.273c-0.481-1.244-1.176-2.402-1.954-3.59c-1.241-1.881-1.629-3.362-0.841-3.329
150*c8dee2aaSAndroid Build Coastguard Worker 		c0.787,0.032,1.138-0.897,0.791-2.077c-0.212-0.714-0.407-1.428-0.555-2.15c-0.897-4.394-0.856-9.232-2.766-13.117
151*c8dee2aaSAndroid Build Coastguard Worker 		c-2.611-5.316-2.102-9.433,0.832-13.121c1.403-1.763,3.187-2.407,3.574-1.808c0.392,0.6,1.403-0.269,2.256-1.941
152*c8dee2aaSAndroid Build Coastguard Worker 		c0.856-1.673,1.759-2.521,2.016-1.897s1.645-0.27,3.097-1.991c1.208-1.432,2.439-2.893,3.692-4.378
153*c8dee2aaSAndroid Build Coastguard Worker 		c1.452-1.722,2.885-2.428,3.19-1.574c0.311,0.853,1.208-0.168,2.228-2.18c5.104-10.094,13.729-18.106,15.725-29.62
154*c8dee2aaSAndroid Build Coastguard Worker 		c0.008-0.049,0.106-0.086,0.216-0.118c0.135-0.041,0.734,0.379,1.335,0.942c0.6,0.562,1.599-0.734,2.231-2.897
155*c8dee2aaSAndroid Build Coastguard Worker 		c3.525-12.117,6.936-23.852,10.416-35.813c0.629-2.163,2.293-5.341,3.615-7.165c6.536-8.979,8.209-15.063,8.434-18.649
156*c8dee2aaSAndroid Build Coastguard Worker 		c0.143-2.248-1.987-5.153-3.187-7.062c-2.362-3.762-1.856-7.776-2.163-11.706c-0.416-5.271,0.168-10.62,0.608-15.862
157*c8dee2aaSAndroid Build Coastguard Worker 		c0.188-2.244,0.534-3.958,1.012-3.741c0.474,0.216,0.457-1.416,0.498-3.668c0.167-9.657,8.706-12.102,15.973-15.137
158*c8dee2aaSAndroid Build Coastguard Worker 		c2.081-0.869,5.316-2.204,7.3-2.832c1.252-0.396,2.436-0.873,3.354-1.656c2.591-2.207,4.488-5.243,6.617-7.98
159*c8dee2aaSAndroid Build Coastguard Worker 		c1.946-2.501,4.293-4.35,6.879-6.263c4.419-3.264,7.598-8.164,11.539-12.13c3.271-3.288,6.658-6.561,10.42-9.241
160*c8dee2aaSAndroid Build Coastguard Worker 		c4.79-3.407,5.814-9.878,2.436-15.043C532.355,246.691,529.156,241.407,526.834,235.822z)"},
161*c8dee2aaSAndroid Build Coastguard Worker     { "Fish",
162*c8dee2aaSAndroid Build Coastguard Worker         R"(M522.697,299.679c13.88-10.49,25.688-19.413,38.038-28.744c-1.648-2.281-2.497-4.243-3.979-5.374
163*c8dee2aaSAndroid Build Coastguard Worker 		c-26.703-20.388-53.346-40.865-80.294-60.931c-26.104-19.437-56.994-25.949-88.075-32.102c-5.618-1.114-10.882-5.141-15.77-8.588
164*c8dee2aaSAndroid Build Coastguard Worker 		c-12.089-8.535-23.321-18.434-36.01-25.883c-5.459-3.207-13.676-1.706-22.428-2.509c-0.098,0.404-0.804,3.256-1.726,6.989
165*c8dee2aaSAndroid Build Coastguard Worker 		c-4.035-2.469-7.446-4.554-11.359-6.948c-0.244,4.247-0.452,7.833-0.722,12.497c-3.582-0.661-6.504-1.204-9.775-1.807
166*c8dee2aaSAndroid Build Coastguard Worker 		c-1.311,4.088-2.636,8.229-4.224,13.17c-4.197-1.774-7.491-3.17-11.326-4.794c-1.188,4.056-2.366,8.07-3.807,12.991
167*c8dee2aaSAndroid Build Coastguard Worker 		c-4.635-1.428-8.36-2.579-12.791-3.945c-0.849,11.473-7.107,11.844-11.685,9.176c-6.997,2.737-10.902,4.451-14.929,5.806
168*c8dee2aaSAndroid Build Coastguard Worker 		c-14.17,4.77-28.531,9.013-42.542,14.202c-17.871,6.622-35.472,13.97-55.786,22.041c1.342,9.065,3.011,20.322,4.753,32.057
169*c8dee2aaSAndroid Build Coastguard Worker 		c-15.386,2.427-31.298,1.057-46.087-10.375c-16.071-12.428-32.771-24.284-50.278-34.537c-10.865-6.361-23.745-9.278-35.72-13.742
170*c8dee2aaSAndroid Build Coastguard Worker 		c-0.567,1.232-1.134,2.464-1.701,3.692c2.57,6.471,6.173,12.742,7.479,19.458c2.326,11.958,3.786,24.149,4.61,36.312
171*c8dee2aaSAndroid Build Coastguard Worker 		c0.722,10.669-0.763,21.51,0.225,32.134c1.673,18.014-2.375,34.569-10.025,50.579c-1.75,3.664-3.345,7.401-6.765,15.011
172*c8dee2aaSAndroid Build Coastguard Worker 		c11.481-2.216,20.714-2.183,28.201-5.781c21.269-10.225,42.95-20.277,62.391-33.46c27.14-18.401,52.22-7.903,78.079,0.946
173*c8dee2aaSAndroid Build Coastguard Worker 		c0.763,0.262,1.044,1.926,2.497,4.839c-25.296,1.755-23.097,19.27-22.334,36.622c0.318,7.263-1.604,14.619-2.676,23.31
174*c8dee2aaSAndroid Build Coastguard Worker 		c15.369,0.212,29.16-6.933,42.656-14.606c6.32-3.595,11.473-9.69,20.123-5.929c1.604,0.697,4.924-0.959,6.671-2.443
175*c8dee2aaSAndroid Build Coastguard Worker 		c10.273-8.74,20.11-6.59,31.877-1.89c30.914,12.342,63.416,15.9,96.598,12.954c3.149-0.277,6.345-0.037,13.056-0.037
176*c8dee2aaSAndroid Build Coastguard Worker 		c-15.263,6.822-12.57,15.644-8.801,25.872c4.831,13.112,7.956,26.854,12.392,42.33c3.391-3.844,7.479-6.761,9.184-10.706
177*c8dee2aaSAndroid Build Coastguard Worker 		c7.716-17.83,15.549-35.692,21.633-54.105c2.333-7.066,4.859-9.755,11.954-10.987c37.969-6.581,75.994-13.007,113.665-21.064
178*c8dee2aaSAndroid Build Coastguard Worker 		c13.97-2.987,27.111-10.062,40.424-15.749c2.555-1.094,4.158-4.419,6.198-6.716c-2.763-2.109-5.305-5.594-8.327-6.075
179*c8dee2aaSAndroid Build Coastguard Worker 		C545.79,301.29,535.933,300.849,522.697,299.679z)"},
180*c8dee2aaSAndroid Build Coastguard Worker     { "Turtle",
181*c8dee2aaSAndroid Build Coastguard Worker         R"(M565.399,246.059c0.196-6.079-4.357-10.624-10.514-10.812c-2.342-0.069-4.696-0.143-7.034,0.012
182*c8dee2aaSAndroid Build Coastguard Worker 		c-1.824,0.123-3.619,0.094-5.394-0.041c-0.412-0.094-0.837-0.135-1.273-0.11c-6.581-0.689-12.885-2.803-19.322-4.529
183*c8dee2aaSAndroid Build Coastguard Worker 		c-5.117-1.371-10.764-0.795-16.174-1.057c-0.697-0.033-1.42,0.27-2.105,0.188c-5.177-0.608-9.559,1.163-13.284,4.582
184*c8dee2aaSAndroid Build Coastguard Worker 		c-2.488,2.285-5.373,3.093-8.617,3.093c-7.221,0-14.442,0-21.562,0c-1.714-5.443-3.366-10.881-5.055-16.3
185*c8dee2aaSAndroid Build Coastguard Worker 		c-2.134-9.311-5.316-18.307-9.466-26.81c-4.876-11.208-11.09-21.677-19.458-31.008c-9.249-10.311-20.416-17.887-32.203-24.823
186*c8dee2aaSAndroid Build Coastguard Worker 		c-8.915-5.247-17.784-10.608-26.341-16.41c-6.675-4.528-12.889-9.747-19.208-14.786c-6.259-4.994-13.692-7.503-21.024-10.212
187*c8dee2aaSAndroid Build Coastguard Worker 		c-7.393-2.729-14.88-5.214-22.326-7.813c-6.426-2.244-12.754-4.839-19.302-6.626c-4.092-1.118-8.568-1.644-12.783-1.314
188*c8dee2aaSAndroid Build Coastguard Worker 		c-4.524,0.355-9.017,1.808-13.407,3.158c-12.056,3.705-24.088,7.503-36.063,11.46c-11.995,3.962-23.978,3.142-36.251,1.326
189*c8dee2aaSAndroid Build Coastguard Worker 		c-11.501-1.701-23.105-2.052-34.851-0.535c-11.539,1.489-20.331,6.92-28.258,14.835c-4.243,4.235-8.743,8.111-13.472,11.673
190*c8dee2aaSAndroid Build Coastguard Worker 		c-9.078,4.664-17.858,9.768-26.01,15.704c-3.46,1.616-7.062,2.95-10.588,4.435c-7.833,3.296-12.317,9.874-16.487,16.777
191*c8dee2aaSAndroid Build Coastguard Worker 		c-6.414,10.612-11.346,21.938-14.872,33.75c-2.774,9.303-4.304,18.976-6.446,28.47c-1.448,6.435-2.88,12.914-9.996,15.786
192*c8dee2aaSAndroid Build Coastguard Worker 		c-2.603,1.053-5.182,2.17-7.789,3.219c-0.559,0.225-1.098,0.478-1.62,0.743c-1.64,0.571-3.28,1.138-4.921,1.709
193*c8dee2aaSAndroid Build Coastguard Worker 		c-0.449-0.024-0.901-0.049-1.35-0.069c-1.102-0.065-2.163,0.126-3.15,0.498c-0.212,0.041-0.424,0.094-0.637,0.151
194*c8dee2aaSAndroid Build Coastguard Worker 		c-4.675,1.285-7.927,6.52-6.41,11.29c4.288,13.472,11.123,25.944,20,36.748c0.037,0.062,0.069,0.122,0.106,0.184
195*c8dee2aaSAndroid Build Coastguard Worker 		c2.982,5.039,7.438,9.355,11.775,13.415c6.202,5.81,5.977,5.455,3.603,13.542c-2.138,7.274-4.941,14.431-5.177,22.239
196*c8dee2aaSAndroid Build Coastguard Worker 		c-0.196,6.353,1.909,12.069,3.696,17.937c0.094,0.306,0.188,0.615,0.282,0.922c0,0.021,0.004,0.045,0.008,0.065
197*c8dee2aaSAndroid Build Coastguard Worker 		c0.135,0.979,0.453,1.954,0.89,2.904c0.996,3.313,1.954,6.639,2.726,10.005c0.559,2.447,0.224,4.622-0.755,6.531
198*c8dee2aaSAndroid Build Coastguard Worker 		c-0.625,0.67-1.146,1.429-1.55,2.253c-0.637,0.722-1.367,1.399-2.187,2.023c-4.549,3.468-7.654,7.503-7.405,13.668
199*c8dee2aaSAndroid Build Coastguard Worker 		c0.13,3.223,1.897,5.218,3.852,7.226c2.485,2.55,5.259,4.826,7.634,7.467c3.717,4.137,8.445,5.94,13.741,5.871
200*c8dee2aaSAndroid Build Coastguard Worker 		c6.711-0.086,12.448,2.248,17.516,6.263c3.733,2.958,7.401,2.949,11.102,0.571c3.798-2.444,7.417-2.469,11.62-1.004
201*c8dee2aaSAndroid Build Coastguard Worker 		c3.17,1.105,6.72,1.118,10.098,1.619c2.24,0.335,3.888-0.347,4.88-1.615c0.241-0.249,0.453-0.522,0.636-0.832
202*c8dee2aaSAndroid Build Coastguard Worker 		c0.661-1.126,0.767-2.444,0.412-3.627c-0.082-0.751-0.257-1.526-0.547-2.313c-0.6-1.633-1.424-3.19-2.044-4.807
203*c8dee2aaSAndroid Build Coastguard Worker 		c-0.122-0.914-0.383-1.804-0.771-2.647c-0.478-2.375-0.375-4.655,0.143-6.843c2.261-3.35,4.08-6.984,5.443-10.783
204*c8dee2aaSAndroid Build Coastguard Worker 		c3.905-7.507,3.644-15.562,2.733-23.811c-0.098-0.873-0.204-1.742-0.297-2.469c2.533,0.453,5.067,0.901,7.601,1.354
205*c8dee2aaSAndroid Build Coastguard Worker 		c5.529,1.771,11.126,3.558,16.781,5.137c3.464,0.967,6.969,1.787,10.498,2.514c6.324,1.66,12.791,2.7,19.323,3.007
206*c8dee2aaSAndroid Build Coastguard Worker 		c1.84,0.208,3.68,0.412,5.516,0.628c6.916,0.816,13.823,1.812,20.767,2.289c7.605,0.526,15.243,0.624,22.869,0.775
207*c8dee2aaSAndroid Build Coastguard Worker 		c5.74,0.114,5.577,0.098,7.993,5.169c0.494,1.032,1.048,2.04,1.624,3.031c1.188,2.514,2.33,5.047,3.436,7.602
208*c8dee2aaSAndroid Build Coastguard Worker 		c1.081,2.664,2.122,5.341,3.113,8.037c0.29,3.717-0.596,7.394-3.239,10.927c-2.848,3.807-5.692,7.621-8.47,11.477
209*c8dee2aaSAndroid Build Coastguard Worker 		c-4.806,6.659-6.124,14.027-4.072,21.935c0.334,1.297,1.293,2.55,2.256,3.541c5.304,5.455,10.677,10.845,16.083,16.202
210*c8dee2aaSAndroid Build Coastguard Worker 		c0.767,0.763,1.758,1.42,2.766,1.791c4.594,1.693,9.38,2.876,12.403,7.393c0.64,0.959,2.697,1.249,4.129,1.339
211*c8dee2aaSAndroid Build Coastguard Worker 		c0.171,0.012,0.338,0.028,0.506,0.04c1.313,0.779,2.909,0.983,4.402,0.661c1.995,0.449,3.954,1.081,5.981,1.897
212*c8dee2aaSAndroid Build Coastguard Worker 		c3.015,1.216,7.609,2.203,11.077-1.021c1.146-1.064,2.811-1.546,4.096-2.492c1.22-0.897,2.448-1.384,3.725-1.302
213*c8dee2aaSAndroid Build Coastguard Worker 		c0.853,0.396,1.738,0.706,2.636,0.935c7.947,4.084,16.111-1.347,20.396-5.811c1.865-1.941,2.077-5.765,0.429-8.486
214*c8dee2aaSAndroid Build Coastguard Worker 		c-1.322-2.183-2.737-4.309-4.166-6.43c-1.391-2.497-2.782-4.994-4.174-7.487c-0.611-2.713,0.307-5.169,2.819-7.923
215*c8dee2aaSAndroid Build Coastguard Worker 		c7.189-7.858,13.501-16.304,18.548-25.741c2.469-4.614,2.99-9.563,3.529-14.479c0.146-1.334,0.265-2.673,0.375-4.011
216*c8dee2aaSAndroid Build Coastguard Worker 		c0.307-1.538,0.408-3.084,0.327-4.606c0.257-4.309,0.411-8.625,0.628-12.934c0.081-1.656,0.682-2.199,2.374-2.366
217*c8dee2aaSAndroid Build Coastguard Worker 		c9.038-0.901,18.111-1.632,27.071-3.064c10.608-1.697,21.139-3.921,31.648-6.181c3.599-0.775,7.07-2.224,10.515-3.582
218*c8dee2aaSAndroid Build Coastguard Worker 		c2.611-1.032,4.528-0.845,5.63,0.596c0.188,1.465,0.56,2.88,1.094,4.255c0.44,6.969,0.562,13.97,1.281,20.906
219*c8dee2aaSAndroid Build Coastguard Worker 		c0.616,5.978,1.86,11.897,3.007,17.805c0.253,1.306,1.008,2.746,1.971,3.647c1.652,1.551,3.011,3.256,4.17,5.067
220*c8dee2aaSAndroid Build Coastguard Worker 		c0.432,0.768,0.877,1.53,1.334,2.285c1.636,3.056,2.855,6.332,4.051,9.633c0.359,1.889,0.976,3.68,1.918,5.279
221*c8dee2aaSAndroid Build Coastguard Worker 		c0.151,0.392,0.302,0.783,0.465,1.171c2.317,5.614,7.34,6.178,13.917,5.753c2.669-0.171,5.41-0.143,8.042,0.273
222*c8dee2aaSAndroid Build Coastguard Worker 		c3.06,0.481,5.998,1.718,9.054,2.216c3.986,0.652,7.731-0.44,11.42-2.073c0.583-0.257,1.228-0.469,1.897-0.62
223*c8dee2aaSAndroid Build Coastguard Worker 		c0.534,0.168,1.093,0.282,1.668,0.331c1.562,0.139,3.113,0.114,4.644-0.041c2.28,0.098,4.394-0.425,6.373-1.502
224*c8dee2aaSAndroid Build Coastguard Worker 		c2.031-0.767,3.97-1.786,5.772-3.027c1.339-0.367,2.746-0.506,4.276-0.403c3.554,0.236,7.132,0.057,10.702,0.053
225*c8dee2aaSAndroid Build Coastguard Worker 		c0.566,0,1.109-0.065,1.636-0.18c0.975-0.102,1.877-0.514,2.647-1.13c2.893-1.95,4.293-5.757,2.521-9.221
226*c8dee2aaSAndroid Build Coastguard Worker 		c-0.27-0.53-0.571-1.057-0.885-1.579c-0.421-1.354-1.253-2.591-2.407-3.342c-0.882-1.02-1.845-1.95-2.877-2.717
227*c8dee2aaSAndroid Build Coastguard Worker 		c-6.642-4.929-11.722-10.775-13.496-19.009c-0.657-3.048-1.081-6.186-1.24-9.299c-0.314-6.083-0.649-12.187-0.478-18.266
228*c8dee2aaSAndroid Build Coastguard Worker 		c0.326-11.542-2.313-21.999-8.642-31.375c-2.023-3.84-4.524-7.405-7.471-10.588c-0.979-1.546-1.934-3.093-2.921-4.586
229*c8dee2aaSAndroid Build Coastguard Worker 		c0.832-0.905,1.66-1.815,2.488-2.722c3.668-2.79,8.124-3.378,12.461-3.855c5.618-0.62,10-3.431,14.3-6.564
230*c8dee2aaSAndroid Build Coastguard Worker 		c2.697-1.963,4.97-4.549,7.781-6.291c5.218-3.235,11.236-4.166,17.209-5.092c10.755-1.673,21.375-3.688,30.556-10.185
231*c8dee2aaSAndroid Build Coastguard Worker 		c5.01-3.541,7.58-8.747,9.225-14.198c2.023-6.69,3.149-13.668,4.438-20.567c0.033-0.179,0.062-0.362,0.09-0.546
232*c8dee2aaSAndroid Build Coastguard Worker 		c0.245-0.584,0.453-1.188,0.629-1.812l0.546-4.068c0-0.763-0.057-1.521-0.171-2.268
233*c8dee2aaSAndroid Build Coastguard Worker 		C565.33,247.536,565.375,246.798,565.399,246.059z)"},
234*c8dee2aaSAndroid Build Coastguard Worker };
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker /*
237*c8dee2aaSAndroid Build Coastguard Worker * Helper function that gets the all of the t-values that need to be added between
238*c8dee2aaSAndroid Build Coastguard Worker * one t-value on a path to the next, from a sorted queue |tValuesToAdd|. Converts
239*c8dee2aaSAndroid Build Coastguard Worker * the value from its proportion across the whole line to it's proportion relative
240*c8dee2aaSAndroid Build Coastguard Worker * to the current segment.
241*c8dee2aaSAndroid Build Coastguard Worker */
getTValuesForSegment(std::deque<float> * tValuesToAdd,float t,float tNext)242*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkScalar> getTValuesForSegment(std::deque<float>* tValuesToAdd, float t, float tNext) {
243*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkScalar> tVector;
244*c8dee2aaSAndroid Build Coastguard Worker     while (!tValuesToAdd->empty() && tValuesToAdd->front() > t && tValuesToAdd->front() < tNext) {
245*c8dee2aaSAndroid Build Coastguard Worker         SkScalar total_t = tValuesToAdd->front();
246*c8dee2aaSAndroid Build Coastguard Worker         tValuesToAdd->pop_front();
247*c8dee2aaSAndroid Build Coastguard Worker         SkScalar relative_t = (total_t - t) / (tNext - t);
248*c8dee2aaSAndroid Build Coastguard Worker         tVector.push_back(relative_t);
249*c8dee2aaSAndroid Build Coastguard Worker     }
250*c8dee2aaSAndroid Build Coastguard Worker     return tVector;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker /*
254*c8dee2aaSAndroid Build Coastguard Worker * Helper function that takes a vector of t-values and chops a cubic at those correct
255*c8dee2aaSAndroid Build Coastguard Worker * values, added it to the path |out|.
256*c8dee2aaSAndroid Build Coastguard Worker */
addSegmentsFromTValues(const SkPoint cubic_pts[4],std::vector<SkScalar> t_values,SkPath * out)257*c8dee2aaSAndroid Build Coastguard Worker void addSegmentsFromTValues(const SkPoint cubic_pts[4], std::vector<SkScalar> t_values, SkPath* out) {
258*c8dee2aaSAndroid Build Coastguard Worker     const size_t arr_size = t_values.size();
259*c8dee2aaSAndroid Build Coastguard Worker     const int dst_size = (3*arr_size) + 4;
260*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkPoint> split_pts(dst_size);
261*c8dee2aaSAndroid Build Coastguard Worker     SkChopCubicAt(cubic_pts, split_pts.data(), t_values.data(), arr_size);
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < arr_size + 1; i++) {
264*c8dee2aaSAndroid Build Coastguard Worker         out->cubicTo(split_pts[(i*3)+1], split_pts[(i*3)+2], split_pts[(i*3)+3]);
265*c8dee2aaSAndroid Build Coastguard Worker     }
266*c8dee2aaSAndroid Build Coastguard Worker }
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker /*
269*c8dee2aaSAndroid Build Coastguard Worker * Helper function that given a path, it's t-values (sorted), and t-values to add
270*c8dee2aaSAndroid Build Coastguard Worker * (sorted), returns a new path that is all cubic beziers, with verbs at each of
271*c8dee2aaSAndroid Build Coastguard Worker * those t-values.
272*c8dee2aaSAndroid Build Coastguard Worker */
createPathFromTValues(const SkPath & in,std::deque<float> tValuesToAdd,std::vector<float> tValues,SkPath * out)273*c8dee2aaSAndroid Build Coastguard Worker bool createPathFromTValues(const SkPath& in, std::deque<float> tValuesToAdd, std::vector<float> tValues, SkPath* out) {
274*c8dee2aaSAndroid Build Coastguard Worker     SkPath::Iter iter(in, false);
275*c8dee2aaSAndroid Build Coastguard Worker     bool fBreak = false;
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker     // Only increment if we draw on the path.
278*c8dee2aaSAndroid Build Coastguard Worker     size_t t_value_idx = 0;
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker     for (;;) {
281*c8dee2aaSAndroid Build Coastguard Worker         if (fBreak) break;
282*c8dee2aaSAndroid Build Coastguard Worker         bool needToSplit = false;
283*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
284*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Verb verb = iter.next(pts);
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker         // The last t-value is always the end of the path (when t=1).
287*c8dee2aaSAndroid Build Coastguard Worker         if (t_value_idx >= tValues.size() - 1) {
288*c8dee2aaSAndroid Build Coastguard Worker             break;
289*c8dee2aaSAndroid Build Coastguard Worker         }
290*c8dee2aaSAndroid Build Coastguard Worker         // t and tNext are the start and end of the current segment.
291*c8dee2aaSAndroid Build Coastguard Worker         float t = tValues[t_value_idx];
292*c8dee2aaSAndroid Build Coastguard Worker         float tNext = tValues[t_value_idx+1];
293*c8dee2aaSAndroid Build Coastguard Worker 
294*c8dee2aaSAndroid Build Coastguard Worker         // Check if current tValueToAdd is on this current segment.
295*c8dee2aaSAndroid Build Coastguard Worker         if (!tValuesToAdd.empty() && tValuesToAdd.front() > t && tValuesToAdd.front() < tNext) {
296*c8dee2aaSAndroid Build Coastguard Worker             needToSplit = true;
297*c8dee2aaSAndroid Build Coastguard Worker         }
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
300*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kMove_Verb:
301*c8dee2aaSAndroid Build Coastguard Worker                // Only supports one contour currently.
302*c8dee2aaSAndroid Build Coastguard Worker                out->moveTo(pts[0]);
303*c8dee2aaSAndroid Build Coastguard Worker             break;
304*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kLine_Verb: {
305*c8dee2aaSAndroid Build Coastguard Worker                 t_value_idx++;
306*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint pt1, pt2;
307*c8dee2aaSAndroid Build Coastguard Worker                 pt1 = pts[0]*(1.0f / 3.0f) + pts[1]*(2.0f / 3.0f);
308*c8dee2aaSAndroid Build Coastguard Worker                 pt2 = pts[0]*(2.0f / 3.0f) + pts[1]*(1.0f / 3.0f);
309*c8dee2aaSAndroid Build Coastguard Worker                 if (!needToSplit) {
310*c8dee2aaSAndroid Build Coastguard Worker                     out->cubicTo(pt1, pt2, pts[1]);
311*c8dee2aaSAndroid Build Coastguard Worker                 } else {
312*c8dee2aaSAndroid Build Coastguard Worker                     std::vector<SkScalar> tVector = getTValuesForSegment(&tValuesToAdd, t, tNext);
313*c8dee2aaSAndroid Build Coastguard Worker                     const SkPoint cubic_pts[4] = {pts[0], pt1, pt2, pts[1]};
314*c8dee2aaSAndroid Build Coastguard Worker                     addSegmentsFromTValues(cubic_pts, tVector, out);
315*c8dee2aaSAndroid Build Coastguard Worker                 }
316*c8dee2aaSAndroid Build Coastguard Worker                 break;
317*c8dee2aaSAndroid Build Coastguard Worker             }
318*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kQuad_Verb: {
319*c8dee2aaSAndroid Build Coastguard Worker                 t_value_idx++;
320*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint pt1, pt2;
321*c8dee2aaSAndroid Build Coastguard Worker                 pt1 = pts[0] + (pts[1]-pts[0])*(2.0f / 3.0f);
322*c8dee2aaSAndroid Build Coastguard Worker                 pt2 = pts[2] + (pts[1]-pts[2])*(2.0f / 3.0f);
323*c8dee2aaSAndroid Build Coastguard Worker                 if (!needToSplit) {
324*c8dee2aaSAndroid Build Coastguard Worker                     out->cubicTo(pt1, pt2, pts[2]);
325*c8dee2aaSAndroid Build Coastguard Worker                 } else {
326*c8dee2aaSAndroid Build Coastguard Worker                     std::vector<SkScalar> tVector = getTValuesForSegment(&tValuesToAdd, t, tNext);
327*c8dee2aaSAndroid Build Coastguard Worker                     const SkPoint cubic_pts[4] = {pts[0], pt1, pt2, pts[2]};
328*c8dee2aaSAndroid Build Coastguard Worker                     addSegmentsFromTValues(cubic_pts, tVector, out);
329*c8dee2aaSAndroid Build Coastguard Worker                 }
330*c8dee2aaSAndroid Build Coastguard Worker                 break;
331*c8dee2aaSAndroid Build Coastguard Worker             }
332*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kCubic_Verb:
333*c8dee2aaSAndroid Build Coastguard Worker                 t_value_idx++;
334*c8dee2aaSAndroid Build Coastguard Worker                 if (!needToSplit) {
335*c8dee2aaSAndroid Build Coastguard Worker                     out->cubicTo(pts[1], pts[2], pts[3]);
336*c8dee2aaSAndroid Build Coastguard Worker                 } else {
337*c8dee2aaSAndroid Build Coastguard Worker                     std::vector<SkScalar> tVector = getTValuesForSegment(&tValuesToAdd, t, tNext);
338*c8dee2aaSAndroid Build Coastguard Worker                     addSegmentsFromTValues(pts, tVector, out);
339*c8dee2aaSAndroid Build Coastguard Worker                 }
340*c8dee2aaSAndroid Build Coastguard Worker                 break;
341*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kConic_Verb:
342*c8dee2aaSAndroid Build Coastguard Worker                 // Conic not yet supported.
343*c8dee2aaSAndroid Build Coastguard Worker                 return false;
344*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kClose_Verb:
345*c8dee2aaSAndroid Build Coastguard Worker                 // Close not yet supported.
346*c8dee2aaSAndroid Build Coastguard Worker                 out->close();
347*c8dee2aaSAndroid Build Coastguard Worker                 break;
348*c8dee2aaSAndroid Build Coastguard Worker             case SkPath::kDone_Verb:
349*c8dee2aaSAndroid Build Coastguard Worker                 fBreak = true;
350*c8dee2aaSAndroid Build Coastguard Worker         }
351*c8dee2aaSAndroid Build Coastguard Worker     }
352*c8dee2aaSAndroid Build Coastguard Worker     return true;
353*c8dee2aaSAndroid Build Coastguard Worker }
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker /*
356*c8dee2aaSAndroid Build Coastguard Worker * Helper function to get the total lengths the verbs take of a path and put it
357*c8dee2aaSAndroid Build Coastguard Worker * into a vector.
358*c8dee2aaSAndroid Build Coastguard Worker */
getTValues(const SkPath & path)359*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkScalar> getTValues(const SkPath& path) {
360*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkScalar> tValues;
361*c8dee2aaSAndroid Build Coastguard Worker     SkPathMeasure measure(path, false);
362*c8dee2aaSAndroid Build Coastguard Worker     SkScalar length = measure.getLength();
363*c8dee2aaSAndroid Build Coastguard Worker     if (length <= 0) {
364*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Length of path is 0.\n");
365*c8dee2aaSAndroid Build Coastguard Worker         return tValues;
366*c8dee2aaSAndroid Build Coastguard Worker     }
367*c8dee2aaSAndroid Build Coastguard Worker     const SkContourMeasure* cmeasure = measure.currentMeasure();
368*c8dee2aaSAndroid Build Coastguard Worker     tValues.push_back(0.0f);
369*c8dee2aaSAndroid Build Coastguard Worker     for (const auto vmeasure: *cmeasure) {
370*c8dee2aaSAndroid Build Coastguard Worker         tValues.push_back(vmeasure.fDistance / length);
371*c8dee2aaSAndroid Build Coastguard Worker     }
372*c8dee2aaSAndroid Build Coastguard Worker 
373*c8dee2aaSAndroid Build Coastguard Worker     if (measure.nextContour()) {
374*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Path has more than 1 contour.\n");
375*c8dee2aaSAndroid Build Coastguard Worker         return {};
376*c8dee2aaSAndroid Build Coastguard Worker     }
377*c8dee2aaSAndroid Build Coastguard Worker     return tValues;
378*c8dee2aaSAndroid Build Coastguard Worker }
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker /*
381*c8dee2aaSAndroid Build Coastguard Worker * Helper function that creates a deque from a sorted vector |original| and adds
382*c8dee2aaSAndroid Build Coastguard Worker * values from a sorted vector |additional| in sorted order.
383*c8dee2aaSAndroid Build Coastguard Worker */
getTValuesToAdd(std::vector<SkScalar> original,std::vector<SkScalar> additional)384*c8dee2aaSAndroid Build Coastguard Worker std::deque<float> getTValuesToAdd(std::vector<SkScalar> original, std::vector<SkScalar> additional) {
385*c8dee2aaSAndroid Build Coastguard Worker     std::deque<float> tValuesToAdd;
386*c8dee2aaSAndroid Build Coastguard Worker     size_t i = 0, j = 0;
387*c8dee2aaSAndroid Build Coastguard Worker     while (i < original.size() && j < additional.size()) {
388*c8dee2aaSAndroid Build Coastguard Worker         if (additional[j] < original[i]) {
389*c8dee2aaSAndroid Build Coastguard Worker             tValuesToAdd.push_back(additional[j]);
390*c8dee2aaSAndroid Build Coastguard Worker             j++;
391*c8dee2aaSAndroid Build Coastguard Worker         } else if (additional[j] > original[i]) {
392*c8dee2aaSAndroid Build Coastguard Worker             i++;
393*c8dee2aaSAndroid Build Coastguard Worker         } else { // additional[j] == original[i]
394*c8dee2aaSAndroid Build Coastguard Worker             i++;
395*c8dee2aaSAndroid Build Coastguard Worker             j++;
396*c8dee2aaSAndroid Build Coastguard Worker         }
397*c8dee2aaSAndroid Build Coastguard Worker     }
398*c8dee2aaSAndroid Build Coastguard Worker     while (j < additional.size()) {
399*c8dee2aaSAndroid Build Coastguard Worker         tValuesToAdd.push_back(additional[j]);
400*c8dee2aaSAndroid Build Coastguard Worker         j++;
401*c8dee2aaSAndroid Build Coastguard Worker     }
402*c8dee2aaSAndroid Build Coastguard Worker     return tValuesToAdd;
403*c8dee2aaSAndroid Build Coastguard Worker }
404*c8dee2aaSAndroid Build Coastguard Worker 
405*c8dee2aaSAndroid Build Coastguard Worker /*
406*c8dee2aaSAndroid Build Coastguard Worker * Extension to SkPath::Interpolate function that takes two arbitrary SkPaths.
407*c8dee2aaSAndroid Build Coastguard Worker *
408*c8dee2aaSAndroid Build Coastguard Worker * The current functionality of SkPath::Interpolate requires that the two paths
409*c8dee2aaSAndroid Build Coastguard Worker * have identical verbs (same number of verbs and verb types). This function does
410*c8dee2aaSAndroid Build Coastguard Worker * preprocessing on the two paths to create two new paths that fit this requirement
411*c8dee2aaSAndroid Build Coastguard Worker * without modifying the original path.
412*c8dee2aaSAndroid Build Coastguard Worker *
413*c8dee2aaSAndroid Build Coastguard Worker * The function uses a list of t-values to determine where to place points along
414*c8dee2aaSAndroid Build Coastguard Worker * the path, and adds more of these points based on the other paths values. Then all
415*c8dee2aaSAndroid Build Coastguard Worker * verbs are converted to cubic functions. When t-values need to be added, the cubic
416*c8dee2aaSAndroid Build Coastguard Worker * is chopped at the correct positions in accordance to the t-values.
417*c8dee2aaSAndroid Build Coastguard Worker *
418*c8dee2aaSAndroid Build Coastguard Worker * TODO: Add support for multiple contours, conic verbs, and close verbs.
419*c8dee2aaSAndroid Build Coastguard Worker * TODO: Fix phrasing as we don't use actual t-values of the curves just proportional
420*c8dee2aaSAndroid Build Coastguard Worker * distances(?)
421*c8dee2aaSAndroid Build Coastguard Worker */
generalInterpolate(const SkPath & beginning,const SkPath & ending,SkScalar weight,SkPath * out)422*c8dee2aaSAndroid Build Coastguard Worker bool generalInterpolate(const SkPath& beginning, const SkPath& ending, SkScalar weight, SkPath* out) {
423*c8dee2aaSAndroid Build Coastguard Worker     // Use existing path interpolation if possible.
424*c8dee2aaSAndroid Build Coastguard Worker     if (beginning.isInterpolatable(ending)) {
425*c8dee2aaSAndroid Build Coastguard Worker         return beginning.interpolate(ending, weight, out);
426*c8dee2aaSAndroid Build Coastguard Worker     }
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Check if isValid()?
429*c8dee2aaSAndroid Build Coastguard Worker     if (beginning.isEmpty() || !beginning.isFinite() || ending.isEmpty() || !ending.isFinite()) {
430*c8dee2aaSAndroid Build Coastguard Worker         return false;
431*c8dee2aaSAndroid Build Coastguard Worker     }
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker     // New paths to store the transformed paths.
434*c8dee2aaSAndroid Build Coastguard Worker     SkPath beginningCubic;
435*c8dee2aaSAndroid Build Coastguard Worker     SkPath endingCubic;
436*c8dee2aaSAndroid Build Coastguard Worker     beginningCubic.reset();
437*c8dee2aaSAndroid Build Coastguard Worker     endingCubic.reset();
438*c8dee2aaSAndroid Build Coastguard Worker 
439*c8dee2aaSAndroid Build Coastguard Worker     // Append the total distances up to each verb in the path into a vector.
440*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkScalar> tValues1 = getTValues(beginning);
441*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkScalar> tValues2 = getTValues(ending);
442*c8dee2aaSAndroid Build Coastguard Worker     if (tValues1.empty() || tValues2.empty()) {
443*c8dee2aaSAndroid Build Coastguard Worker         return false;
444*c8dee2aaSAndroid Build Coastguard Worker     }
445*c8dee2aaSAndroid Build Coastguard Worker 
446*c8dee2aaSAndroid Build Coastguard Worker     // The t-values to add for the respective paths from the other.
447*c8dee2aaSAndroid Build Coastguard Worker     std::deque<float> tValuesToAdd1 = getTValuesToAdd(tValues1, tValues2);
448*c8dee2aaSAndroid Build Coastguard Worker     std::deque<float> tValuesToAdd2 = getTValuesToAdd(tValues2, tValues1);
449*c8dee2aaSAndroid Build Coastguard Worker 
450*c8dee2aaSAndroid Build Coastguard Worker     // Form the cubic versions of each path with the new points along it.
451*c8dee2aaSAndroid Build Coastguard Worker     createPathFromTValues(beginning, tValuesToAdd1, tValues1, &beginningCubic);
452*c8dee2aaSAndroid Build Coastguard Worker     createPathFromTValues(ending, tValuesToAdd2, tValues2, &endingCubic);
453*c8dee2aaSAndroid Build Coastguard Worker 
454*c8dee2aaSAndroid Build Coastguard Worker     return beginningCubic.interpolate(endingCubic, weight, out);
455*c8dee2aaSAndroid Build Coastguard Worker }
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker class PathLerpSlide final : public Slide {
458*c8dee2aaSAndroid Build Coastguard Worker public:
PathLerpSlide()459*c8dee2aaSAndroid Build Coastguard Worker     PathLerpSlide()
460*c8dee2aaSAndroid Build Coastguard Worker         : fTimeMapper({0.5f, 0}, {0.5f, 1}) {
461*c8dee2aaSAndroid Build Coastguard Worker         fName = "PathLerp";
462*c8dee2aaSAndroid Build Coastguard Worker     }
463*c8dee2aaSAndroid Build Coastguard Worker 
464*c8dee2aaSAndroid Build Coastguard Worker private:
load(SkScalar w,SkScalar h)465*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override {
466*c8dee2aaSAndroid Build Coastguard Worker         fSize = {w, h};
467*c8dee2aaSAndroid Build Coastguard Worker 
468*c8dee2aaSAndroid Build Coastguard Worker         this->updateAnimatingPaths();
469*c8dee2aaSAndroid Build Coastguard Worker     }
470*c8dee2aaSAndroid Build Coastguard Worker 
resize(SkScalar w,SkScalar h)471*c8dee2aaSAndroid Build Coastguard Worker     void resize(SkScalar w, SkScalar h) override { fSize = {w, h}; }
472*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)473*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
474*c8dee2aaSAndroid Build Coastguard Worker         SkPaint path_paint;
475*c8dee2aaSAndroid Build Coastguard Worker         path_paint.setColor(0xff424242);
476*c8dee2aaSAndroid Build Coastguard Worker         path_paint.setStyle(SkPaint::kStroke_Style);
477*c8dee2aaSAndroid Build Coastguard Worker         path_paint.setAntiAlias(true);
478*c8dee2aaSAndroid Build Coastguard Worker         path_paint.setStrokeCap(SkPaint::kRound_Cap);
479*c8dee2aaSAndroid Build Coastguard Worker         path_paint.setStrokeWidth(10 / fPathTransform.getScaleX());
480*c8dee2aaSAndroid Build Coastguard Worker 
481*c8dee2aaSAndroid Build Coastguard Worker         SkAutoCanvasRestore acr(canvas, true);
482*c8dee2aaSAndroid Build Coastguard Worker         canvas->concat(fPathTransform);
483*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(fInterpolatedPath, path_paint);
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker         const auto draw_vertices = [this](SkCanvas* canvas, const SkPath& path, float opacity) {
486*c8dee2aaSAndroid Build Coastguard Worker             SkPaint vertex_paint, ctrl_paint;
487*c8dee2aaSAndroid Build Coastguard Worker             vertex_paint.setColor4f({1, 0, 0, opacity});
488*c8dee2aaSAndroid Build Coastguard Worker             vertex_paint.setAntiAlias(true);
489*c8dee2aaSAndroid Build Coastguard Worker             ctrl_paint.setColor4f({0, 0, 1, opacity});
490*c8dee2aaSAndroid Build Coastguard Worker             ctrl_paint.setAntiAlias(true);
491*c8dee2aaSAndroid Build Coastguard Worker 
492*c8dee2aaSAndroid Build Coastguard Worker             const float vertex_radius = 6 / fPathTransform.getScaleX(),
493*c8dee2aaSAndroid Build Coastguard Worker                           ctrl_radius = 4 / fPathTransform.getScaleX();
494*c8dee2aaSAndroid Build Coastguard Worker 
495*c8dee2aaSAndroid Build Coastguard Worker             for (const auto [verb, pts, weights] : SkPathPriv::Iterate(path)) {
496*c8dee2aaSAndroid Build Coastguard Worker                 switch (verb) {
497*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kMove: // pts: [ vertex ]
498*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[0], vertex_radius, vertex_paint);
499*c8dee2aaSAndroid Build Coastguard Worker                         break;
500*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kLine: // pts: [ prev_vertex, vertex ]
501*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[1], vertex_radius, vertex_paint);
502*c8dee2aaSAndroid Build Coastguard Worker                         break;
503*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kQuad: // pts: [ prev_vertex, ctrl, vertex ]
504*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[1], ctrl_radius, ctrl_paint);
505*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[2], vertex_radius, vertex_paint);
506*c8dee2aaSAndroid Build Coastguard Worker                         break;
507*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kCubic: // pts: [ prev_vertex, ctrl0, ctrl1, vertex ]
508*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[1], ctrl_radius, ctrl_paint);
509*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[2], ctrl_radius, ctrl_paint);
510*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[3], vertex_radius, vertex_paint);
511*c8dee2aaSAndroid Build Coastguard Worker                         break;
512*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kConic: // pts: [ prev_vertex, ctrl, vertex ]
513*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[1], ctrl_radius, ctrl_paint);
514*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawCircle(pts[2], vertex_radius, vertex_paint);
515*c8dee2aaSAndroid Build Coastguard Worker                         break;
516*c8dee2aaSAndroid Build Coastguard Worker                     case SkPathVerb::kClose: // pts: []
517*c8dee2aaSAndroid Build Coastguard Worker                         break;
518*c8dee2aaSAndroid Build Coastguard Worker                 }
519*c8dee2aaSAndroid Build Coastguard Worker             }
520*c8dee2aaSAndroid Build Coastguard Worker         };
521*c8dee2aaSAndroid Build Coastguard Worker 
522*c8dee2aaSAndroid Build Coastguard Worker         if (fShowVertices) {
523*c8dee2aaSAndroid Build Coastguard Worker             draw_vertices(canvas, fInterpolatedPath, 1);
524*c8dee2aaSAndroid Build Coastguard Worker 
525*c8dee2aaSAndroid Build Coastguard Worker             // also show the input paths & vertices
526*c8dee2aaSAndroid Build Coastguard Worker             path_paint.setAlphaf(.15f);
527*c8dee2aaSAndroid Build Coastguard Worker             path_paint.setStrokeWidth(3 / fPathTransform.getScaleX());
528*c8dee2aaSAndroid Build Coastguard Worker 
529*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPath(fPaths.first , path_paint);
530*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPath(fPaths.second, path_paint);
531*c8dee2aaSAndroid Build Coastguard Worker             draw_vertices(canvas, fPaths.first , .15f);
532*c8dee2aaSAndroid Build Coastguard Worker             draw_vertices(canvas, fPaths.second, .15f);
533*c8dee2aaSAndroid Build Coastguard Worker         }
534*c8dee2aaSAndroid Build Coastguard Worker 
535*c8dee2aaSAndroid Build Coastguard Worker         this->drawControls();
536*c8dee2aaSAndroid Build Coastguard Worker     }
537*c8dee2aaSAndroid Build Coastguard Worker 
animate(double nanos)538*c8dee2aaSAndroid Build Coastguard Worker     bool animate(double nanos) override {
539*c8dee2aaSAndroid Build Coastguard Worker         if (!fTimeBase) {
540*c8dee2aaSAndroid Build Coastguard Worker             fTimeBase = nanos;
541*c8dee2aaSAndroid Build Coastguard Worker         }
542*c8dee2aaSAndroid Build Coastguard Worker 
543*c8dee2aaSAndroid Build Coastguard Worker         if (fDraggingProgress) {
544*c8dee2aaSAndroid Build Coastguard Worker             // When progress is controlled by dragging the slidebar, adjust the time base such
545*c8dee2aaSAndroid Build Coastguard Worker             // that the animation continues seamlessly when the slider is released.
546*c8dee2aaSAndroid Build Coastguard Worker 
547*c8dee2aaSAndroid Build Coastguard Worker             // what the (signed) progress should be according to the clock
548*c8dee2aaSAndroid Build Coastguard Worker             const float clock_progress_signed =
549*c8dee2aaSAndroid Build Coastguard Worker                 std::fmod((nanos - fTimeBase)*0.000000001*fAnimationSpeed, 2) - 1;
550*c8dee2aaSAndroid Build Coastguard Worker             // what progress should be to match the slidebar
551*c8dee2aaSAndroid Build Coastguard Worker             const float clock_progress_adjusted =
552*c8dee2aaSAndroid Build Coastguard Worker                 std::copysign(fCurrentProgress, clock_progress_signed);
553*c8dee2aaSAndroid Build Coastguard Worker             // what the clock should be to match the slidebar
554*c8dee2aaSAndroid Build Coastguard Worker             const float nanos_adjusted = (clock_progress_adjusted + 1)*1000000000/fAnimationSpeed;
555*c8dee2aaSAndroid Build Coastguard Worker 
556*c8dee2aaSAndroid Build Coastguard Worker             fTimeBase = nanos - nanos_adjusted;
557*c8dee2aaSAndroid Build Coastguard Worker         } else {
558*c8dee2aaSAndroid Build Coastguard Worker             // Oscillating between 0..1
559*c8dee2aaSAndroid Build Coastguard Worker             fCurrentProgress =
560*c8dee2aaSAndroid Build Coastguard Worker                     std::abs((std::fmod((nanos - fTimeBase)*0.000000001*fAnimationSpeed, 2) - 1));
561*c8dee2aaSAndroid Build Coastguard Worker         }
562*c8dee2aaSAndroid Build Coastguard Worker 
563*c8dee2aaSAndroid Build Coastguard Worker         // Interpolate with easing
564*c8dee2aaSAndroid Build Coastguard Worker         // TODO: generate the synthetic paths once, in updateAnimatingPaths(), then use
565*c8dee2aaSAndroid Build Coastguard Worker         //       regular interpolation here.
566*c8dee2aaSAndroid Build Coastguard Worker         return generalInterpolate(fPaths.first,
567*c8dee2aaSAndroid Build Coastguard Worker                                   fPaths.second,
568*c8dee2aaSAndroid Build Coastguard Worker                                   fTimeMapper.computeYFromX(fCurrentProgress),
569*c8dee2aaSAndroid Build Coastguard Worker                                   &fInterpolatedPath);
570*c8dee2aaSAndroid Build Coastguard Worker     }
571*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar c)572*c8dee2aaSAndroid Build Coastguard Worker     bool onChar(SkUnichar c) override {
573*c8dee2aaSAndroid Build Coastguard Worker         switch (c) {
574*c8dee2aaSAndroid Build Coastguard Worker             case 'v':
575*c8dee2aaSAndroid Build Coastguard Worker                 fShowVertices = !fShowVertices;
576*c8dee2aaSAndroid Build Coastguard Worker                 return true;
577*c8dee2aaSAndroid Build Coastguard Worker             default:
578*c8dee2aaSAndroid Build Coastguard Worker                 return false;
579*c8dee2aaSAndroid Build Coastguard Worker         }
580*c8dee2aaSAndroid Build Coastguard Worker     }
581*c8dee2aaSAndroid Build Coastguard Worker 
onMouse(SkScalar x,SkScalar y,skui::InputState state,skui::ModifierKey)582*c8dee2aaSAndroid Build Coastguard Worker     bool onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey) override {
583*c8dee2aaSAndroid Build Coastguard Worker         // Show the progress slider when hovering the bottom third.
584*c8dee2aaSAndroid Build Coastguard Worker         fShowSlider = y > fSize.height() * .66f;
585*c8dee2aaSAndroid Build Coastguard Worker 
586*c8dee2aaSAndroid Build Coastguard Worker         return false;
587*c8dee2aaSAndroid Build Coastguard Worker     }
588*c8dee2aaSAndroid Build Coastguard Worker 
updateAnimatingPaths()589*c8dee2aaSAndroid Build Coastguard Worker     void updateAnimatingPaths() {
590*c8dee2aaSAndroid Build Coastguard Worker         SkPath p0, p1;
591*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(SkParsePath::FromSVGString(fSelectedPaths[0]->fSVGString, &p0));
592*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(SkParsePath::FromSVGString(fSelectedPaths[1]->fSVGString, &p1));
593*c8dee2aaSAndroid Build Coastguard Worker 
594*c8dee2aaSAndroid Build Coastguard Worker         const SkRect b0 = p0.computeTightBounds(),
595*c8dee2aaSAndroid Build Coastguard Worker                      b1 = p1.computeTightBounds();
596*c8dee2aaSAndroid Build Coastguard Worker 
597*c8dee2aaSAndroid Build Coastguard Worker         // Transform all paths to a normalized size, such that they occupy roughly the same space.
598*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkRect kNormRect = {0, 0, 512, 512};
599*c8dee2aaSAndroid Build Coastguard Worker 
600*c8dee2aaSAndroid Build Coastguard Worker         fPaths = {
601*c8dee2aaSAndroid Build Coastguard Worker             p0.transform(SkMatrix::MakeRectToRect(b0, kNormRect, SkMatrix::kCenter_ScaleToFit)),
602*c8dee2aaSAndroid Build Coastguard Worker             p1.transform(SkMatrix::MakeRectToRect(b1, kNormRect, SkMatrix::kCenter_ScaleToFit)),
603*c8dee2aaSAndroid Build Coastguard Worker         };
604*c8dee2aaSAndroid Build Coastguard Worker 
605*c8dee2aaSAndroid Build Coastguard Worker 
606*c8dee2aaSAndroid Build Coastguard Worker         // Scale and center such that the path animation fills 90% of the view.
607*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds = p0.computeTightBounds();
608*c8dee2aaSAndroid Build Coastguard Worker         bounds.join(p1.computeTightBounds());
609*c8dee2aaSAndroid Build Coastguard Worker 
610*c8dee2aaSAndroid Build Coastguard Worker         const SkRect dst_rect = SkRect::MakeSize(fSize)
611*c8dee2aaSAndroid Build Coastguard Worker             .makeInset(fSize.width() * .05f, fSize.height() * .05f);
612*c8dee2aaSAndroid Build Coastguard Worker         fPathTransform =
613*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix::MakeRectToRect(kNormRect, dst_rect, SkMatrix::kCenter_ScaleToFit);
614*c8dee2aaSAndroid Build Coastguard Worker     }
615*c8dee2aaSAndroid Build Coastguard Worker 
drawControls()616*c8dee2aaSAndroid Build Coastguard Worker     void drawControls() {
617*c8dee2aaSAndroid Build Coastguard Worker         // path controls
618*c8dee2aaSAndroid Build Coastguard Worker         if (ImGui::Begin("Path Options")) {
619*c8dee2aaSAndroid Build Coastguard Worker             for (size_t i = 0; i < 2; ++i) {
620*c8dee2aaSAndroid Build Coastguard Worker                 const SkString label = SkStringPrintf("Path %zu", i + 1);
621*c8dee2aaSAndroid Build Coastguard Worker                 if (ImGui::BeginCombo(label.c_str(), fSelectedPaths[i]->fName)) {
622*c8dee2aaSAndroid Build Coastguard Worker                     for (const auto& path_desc : gSamplePaths) {
623*c8dee2aaSAndroid Build Coastguard Worker                         const auto is_selected = (fSelectedPaths[i] == &path_desc);
624*c8dee2aaSAndroid Build Coastguard Worker                         if (ImGui::Selectable(path_desc.fName) && !is_selected) {
625*c8dee2aaSAndroid Build Coastguard Worker                             fSelectedPaths[i] = &path_desc;
626*c8dee2aaSAndroid Build Coastguard Worker                             this->updateAnimatingPaths();
627*c8dee2aaSAndroid Build Coastguard Worker                         }
628*c8dee2aaSAndroid Build Coastguard Worker                         if (is_selected) {
629*c8dee2aaSAndroid Build Coastguard Worker                             ImGui::SetItemDefaultFocus();
630*c8dee2aaSAndroid Build Coastguard Worker                         }
631*c8dee2aaSAndroid Build Coastguard Worker                     }
632*c8dee2aaSAndroid Build Coastguard Worker                     ImGui::EndCombo();
633*c8dee2aaSAndroid Build Coastguard Worker                 }
634*c8dee2aaSAndroid Build Coastguard Worker             }
635*c8dee2aaSAndroid Build Coastguard Worker 
636*c8dee2aaSAndroid Build Coastguard Worker             ImGui::Checkbox("Show vertices", &fShowVertices);
637*c8dee2aaSAndroid Build Coastguard Worker 
638*c8dee2aaSAndroid Build Coastguard Worker         }
639*c8dee2aaSAndroid Build Coastguard Worker         ImGui::End();
640*c8dee2aaSAndroid Build Coastguard Worker 
641*c8dee2aaSAndroid Build Coastguard Worker         if (!fShowSlider) {
642*c8dee2aaSAndroid Build Coastguard Worker             return;
643*c8dee2aaSAndroid Build Coastguard Worker         }
644*c8dee2aaSAndroid Build Coastguard Worker 
645*c8dee2aaSAndroid Build Coastguard Worker         // progress slider
646*c8dee2aaSAndroid Build Coastguard Worker         ImGui::SetNextWindowBgAlpha(.75f);
647*c8dee2aaSAndroid Build Coastguard Worker         if (ImGui::Begin("Progress Slider", nullptr, ImGuiWindowFlags_NoDecoration |
648*c8dee2aaSAndroid Build Coastguard Worker                                                      ImGuiWindowFlags_NoResize |
649*c8dee2aaSAndroid Build Coastguard Worker                                                      ImGuiWindowFlags_NoMove |
650*c8dee2aaSAndroid Build Coastguard Worker                                                      ImGuiWindowFlags_NoSavedSettings |
651*c8dee2aaSAndroid Build Coastguard Worker                                                      ImGuiWindowFlags_NoFocusOnAppearing |
652*c8dee2aaSAndroid Build Coastguard Worker                                                      ImGuiWindowFlags_NoNav)) {
653*c8dee2aaSAndroid Build Coastguard Worker             static constexpr float kSliderHeight = 100;
654*c8dee2aaSAndroid Build Coastguard Worker             ImGui::SetWindowPos({0, fSize.height() - kSliderHeight});
655*c8dee2aaSAndroid Build Coastguard Worker             ImGui::SetWindowSize({fSize.width(), kSliderHeight});
656*c8dee2aaSAndroid Build Coastguard Worker 
657*c8dee2aaSAndroid Build Coastguard Worker             ImGui::PushItemWidth(-1);
658*c8dee2aaSAndroid Build Coastguard Worker             ImGui::SliderFloat("", &fCurrentProgress, 0, 1, nullptr, ImGuiSliderFlags_NoInput);
659*c8dee2aaSAndroid Build Coastguard Worker             fDraggingProgress = ImGui::IsItemActive();
660*c8dee2aaSAndroid Build Coastguard Worker             ImGui::PopItemWidth();
661*c8dee2aaSAndroid Build Coastguard Worker         }
662*c8dee2aaSAndroid Build Coastguard Worker         ImGui::End();
663*c8dee2aaSAndroid Build Coastguard Worker     }
664*c8dee2aaSAndroid Build Coastguard Worker 
665*c8dee2aaSAndroid Build Coastguard Worker     SkSize                    fSize = {0,0};
666*c8dee2aaSAndroid Build Coastguard Worker     std::pair<SkPath, SkPath> fPaths;        // currently morphing paths
667*c8dee2aaSAndroid Build Coastguard Worker     SkPath                    fInterpolatedPath;
668*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix                  fPathTransform = SkMatrix::I();
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker     float                     fAnimationSpeed   = 1.f;
671*c8dee2aaSAndroid Build Coastguard Worker     double                    fTimeBase         = 0;
672*c8dee2aaSAndroid Build Coastguard Worker     const SkCubicMap          fTimeMapper;   // for animation easing
673*c8dee2aaSAndroid Build Coastguard Worker     float                     fCurrentProgress  = 0; // Interpolation progress [0..1]
674*c8dee2aaSAndroid Build Coastguard Worker 
675*c8dee2aaSAndroid Build Coastguard Worker     // UI stuff
676*c8dee2aaSAndroid Build Coastguard Worker     const PathDesc*           fSelectedPaths[2] = {&gSamplePaths[0], &gSamplePaths[1]};
677*c8dee2aaSAndroid Build Coastguard Worker     bool                      fDraggingProgress = false;
678*c8dee2aaSAndroid Build Coastguard Worker     bool                      fShowVertices     = false;
679*c8dee2aaSAndroid Build Coastguard Worker     bool                      fShowSlider       = false;
680*c8dee2aaSAndroid Build Coastguard Worker };
681*c8dee2aaSAndroid Build Coastguard Worker 
682*c8dee2aaSAndroid Build Coastguard Worker }  // namespace
683*c8dee2aaSAndroid Build Coastguard Worker 
684*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE(return new PathLerpSlide();)
685*c8dee2aaSAndroid Build Coastguard Worker 
686*c8dee2aaSAndroid Build Coastguard Worker 
687