1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.widget.remotecompose.player.platform;
17 
18 import static com.android.internal.widget.remotecompose.core.operations.Utils.idFromNan;
19 
20 import android.graphics.Path;
21 import android.graphics.PathMeasure;
22 import android.os.Build;
23 
24 import com.android.internal.widget.remotecompose.core.operations.PathData;
25 
26 public class FloatsToPath {
genPath(Path retPath, float[] floatPath, float start, float stop)27     public static void genPath(Path retPath,
28                                float[] floatPath,
29                                float start,
30                                float stop) {
31         int i = 0;
32         Path path = new Path(); // todo this should be cached for performance
33         while (i < floatPath.length) {
34             switch (idFromNan(floatPath[i])) {
35                 case PathData.MOVE: {
36                     i++;
37                     path.moveTo(floatPath[i + 0], floatPath[i + 1]);
38                     i += 2;
39                 }
40                 break;
41                 case PathData.LINE: {
42                     i += 3;
43                     path.lineTo(floatPath[i + 0], floatPath[i + 1]);
44                     i += 2;
45                 }
46                 break;
47                 case PathData.QUADRATIC: {
48                     i += 3;
49                     path.quadTo(
50                             floatPath[i + 0],
51                             floatPath[i + 1],
52                             floatPath[i + 2],
53                             floatPath[i + 3]
54                     );
55                     i += 4;
56 
57                 }
58                 break;
59                 case PathData.CONIC: {
60                     i += 3;
61                     if (Build.VERSION.SDK_INT >= 34) {
62                         path.conicTo(
63                                 floatPath[i + 0], floatPath[i + 1],
64                                 floatPath[i + 2], floatPath[i + 3],
65                                 floatPath[i + 4]
66                         );
67                     }
68                     i += 5;
69                 }
70                 break;
71                 case PathData.CUBIC: {
72                     i += 3;
73                     path.cubicTo(
74                             floatPath[i + 0], floatPath[i + 1],
75                             floatPath[i + 2], floatPath[i + 3],
76                             floatPath[i + 4], floatPath[i + 5]
77                     );
78                     i += 6;
79                 }
80                 break;
81                 case PathData.CLOSE: {
82 
83                     path.close();
84                     i++;
85                 }
86                 break;
87                 case PathData.DONE: {
88                     i++;
89                 }
90                 break;
91                 default: {
92                     System.err.println(" Odd command "
93                             + idFromNan(floatPath[i]));
94                 }
95             }
96         }
97 
98         retPath.reset();
99         if (start > 0f || stop < 1f) {
100             if (start < stop) {
101 
102                 PathMeasure measure = new PathMeasure(); // todo cached
103                 measure.setPath(path, false);
104                 float len = measure.getLength();
105                 float scaleStart = Math.max(start, 0f) * len;
106                 float scaleStop = Math.min(stop, 1f) * len;
107                 measure.getSegment(scaleStart, scaleStop, retPath,
108                         true);
109             }
110         } else {
111 
112             retPath.addPath(path);
113         }
114     }
115 }
116