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