1 /*
2  * Copyright 2022 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 
17 package androidx.graphics.path
18 
19 /**
20  * This class converts a given Conic object to the equivalent set of Quadratic objects. It stores
21  * all quadratics from a conversion in the call to [convert], but returns only one at a time, from
22  * nextQuadratic(), storing the rest for later retrieval (since a PathIterator only retrieves one
23  * object at a time).
24  *
25  * This object is stateful, using quadraticCount, currentQuadratic, and quadraticData to send back
26  * the next quadratic when requested, in [nextQuadratic].
27  */
28 internal class ConicConverter {
29     /** The total number of quadratics currently stored in the converter */
30     var quadraticCount: Int = 0
31         private set
32 
33     /**
34      * The index of the current Quadratic; this is the next quadratic to be returned in the call to
35      * nextQuadratic().
36      */
37     var currentQuadratic = 0
38 
39     /**
40      * Storage for all quadratics for a particular conic. Set to reasonable default size, will need
41      * to resize if we ever get a return count larger than the current size. Initial size holds up
42      * to 5 quadratic subdivisions: 2^5 quadratics, with 3 points per quadratic, and 2 floats per
43      * point, where all quadratics overlap in one point except the ends.
44      */
45     private var quadraticData = FloatArray(32 * 2 * 2 + 2)
46 
47     /**
48      * This function stores the next converted quadratic in the given points array, returning true
49      * if this happened, false if there was no quadratic to be returned.
50      */
nextQuadraticnull51     fun nextQuadratic(points: FloatArray, offset: Int = 0): Boolean {
52         if (currentQuadratic < quadraticCount) {
53             val index = currentQuadratic * 2 * 2 // Quadratics overlap by 1 point
54             points[0 + offset] = quadraticData[index]
55             points[1 + offset] = quadraticData[index + 1]
56             points[2 + offset] = quadraticData[index + 2]
57             points[3 + offset] = quadraticData[index + 3]
58             points[4 + offset] = quadraticData[index + 4]
59             points[5 + offset] = quadraticData[index + 5]
60             currentQuadratic++
61             return true
62         }
63         return false
64     }
65 
66     /** Converts the conic in [points] to a series of quadratics, which will all be stored */
convertnull67     fun convert(points: FloatArray, weight: Float, tolerance: Float, offset: Int = 0) {
68         quadraticCount = internalConicToQuadratics(points, offset, quadraticData, weight, tolerance)
69         // 3 points per quadratic, 2 floats per point, with one point of overlap
70         val newDataSize = quadraticCount * 2 * 2 + 2
71         if (newDataSize > quadraticData.size) {
72             quadraticData = FloatArray(newDataSize)
73             quadraticCount =
74                 internalConicToQuadratics(points, offset, quadraticData, weight, tolerance)
75         }
76         currentQuadratic = 0
77     }
78 
79     /**
80      * The actual conversion from conic to quadratic data happens in native code, in the library
81      * loaded elsewhere. This JNI function wraps that native functionality.
82      */
83     @Suppress("KotlinJniMissingFunction")
internalConicToQuadraticsnull84     private external fun internalConicToQuadratics(
85         conicPoints: FloatArray,
86         offset: Int,
87         quadraticPoints: FloatArray,
88         weight: Float,
89         tolerance: Float
90     ): Int
91 }
92