PathMeasure_Delegate.java revision 081cebf52b19e848c07fb781b35fa1f96695c311
1/* 2 * Copyright (C) 2015 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 17package android.graphics; 18 19import com.android.ide.common.rendering.api.LayoutLog; 20import com.android.layoutlib.bridge.Bridge; 21import com.android.layoutlib.bridge.impl.DelegateManager; 22import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 23 24import java.awt.geom.PathIterator; 25import java.awt.geom.Point2D; 26 27/** 28 * Delegate implementing the native methods of {@link android.graphics.PathMeasure} 29 * <p/> 30 * Through the layoutlib_create tool, the original native methods of PathMeasure have been 31 * replaced by 32 * calls to methods of the same name in this delegate class. 33 * <p/> 34 * This class behaves like the original native implementation, but in Java, keeping previously 35 * native data into its own objects and mapping them to int that are sent back and forth between it 36 * and the original PathMeasure class. 37 * 38 * @see DelegateManager 39 */ 40public final class PathMeasure_Delegate { 41 // ---- delegate manager ---- 42 private static final DelegateManager<PathMeasure_Delegate> sManager = 43 new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class); 44 45 // ---- delegate data ---- 46 // This governs how accurate the approximation of the Path is. 47 private static final float PRECISION = 0.002f; 48 49 /** 50 * Array containing the path points components. There are three components for each point: 51 * <ul> 52 * <li>Fraction along the length of the path that the point resides</li> 53 * <li>The x coordinate of the point</li> 54 * <li>The y coordinate of the point</li> 55 * </ul> 56 */ 57 private float mPathPoints[]; 58 private long mNativePath; 59 60 private PathMeasure_Delegate(long native_path, boolean forceClosed) { 61 mNativePath = native_path; 62 if (forceClosed && mNativePath != 0) { 63 // Copy the path and call close 64 mNativePath = Path_Delegate.init2(native_path); 65 Path_Delegate.native_close(mNativePath); 66 } 67 68 mPathPoints = 69 mNativePath != 0 ? Path_Delegate.native_approximate(mNativePath, PRECISION) : null; 70 } 71 72 @LayoutlibDelegate 73 /*package*/ static long native_create(long native_path, boolean forceClosed) { 74 return sManager.addNewDelegate(new PathMeasure_Delegate(native_path, forceClosed)); 75 } 76 77 @LayoutlibDelegate 78 /*package*/ static void native_destroy(long native_instance) { 79 sManager.removeJavaReferenceFor(native_instance); 80 } 81 82 @LayoutlibDelegate 83 /*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[], 84 float tan[]) { 85 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 86 "PathMeasure.getPostTan is not supported.", null, null); 87 return false; 88 } 89 90 @LayoutlibDelegate 91 /*package*/ static boolean native_getMatrix(long native_instance, float distance, long 92 native_matrix, int flags) { 93 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 94 "PathMeasure.getMatrix is not supported.", null, null); 95 return false; 96 } 97 98 @LayoutlibDelegate 99 /*package*/ static boolean native_nextContour(long native_instance) { 100 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 101 "PathMeasure.nextContour is not supported.", null, null); 102 return false; 103 } 104 105 @LayoutlibDelegate 106 /*package*/ static void native_setPath(long native_instance, long native_path, boolean 107 forceClosed) { 108 PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 109 assert pathMeasure != null; 110 111 if (forceClosed && native_path != 0) { 112 // Copy the path and call close 113 native_path = Path_Delegate.init2(native_path); 114 Path_Delegate.native_close(native_path); 115 } 116 pathMeasure.mNativePath = native_path; 117 pathMeasure.mPathPoints = Path_Delegate.native_approximate(native_path, PRECISION); 118 } 119 120 @LayoutlibDelegate 121 /*package*/ static float native_getLength(long native_instance) { 122 PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 123 assert pathMeasure != null; 124 125 if (pathMeasure.mPathPoints == null) { 126 return 0; 127 } 128 129 float length = 0; 130 int nPoints = pathMeasure.mPathPoints.length / 3; 131 for (int i = 1; i < nPoints; i++) { 132 length += Point2D.distance( 133 pathMeasure.mPathPoints[(i - 1) * 3 + 1], 134 pathMeasure.mPathPoints[(i - 1) * 3 + 2], 135 pathMeasure.mPathPoints[i*3 + 1], 136 pathMeasure.mPathPoints[i*3 + 2]); 137 } 138 139 return length; 140 } 141 142 @LayoutlibDelegate 143 /*package*/ static boolean native_isClosed(long native_instance) { 144 PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 145 assert pathMeasure != null; 146 147 Path_Delegate path = Path_Delegate.getDelegate(pathMeasure.mNativePath); 148 if (path == null) { 149 return false; 150 } 151 152 PathIterator pathIterator = path.getJavaShape().getPathIterator(null); 153 154 int type = 0; 155 float segment[] = new float[6]; 156 while (!pathIterator.isDone()) { 157 type = pathIterator.currentSegment(segment); 158 pathIterator.next(); 159 } 160 161 // A path is a closed path if the last element is SEG_CLOSE 162 return type == PathIterator.SEG_CLOSE; 163 } 164 165 @LayoutlibDelegate 166 /*package*/ static boolean native_getSegment(long native_instance, float startD, float stopD, 167 long native_dst_path, boolean startWithMoveTo) { 168 if (startD < 0) { 169 startD = 0; 170 } 171 172 if (startD >= stopD) { 173 return false; 174 } 175 176 PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 177 assert pathMeasure != null; 178 179 if (pathMeasure.mPathPoints == null) { 180 return false; 181 } 182 183 float accLength = 0; 184 boolean isZeroLength = true; // Whether the output has zero length or not 185 int nPoints = pathMeasure.mPathPoints.length / 3; 186 for (int i = 0; i < nPoints; i++) { 187 float x = pathMeasure.mPathPoints[i * 3 + 1]; 188 float y = pathMeasure.mPathPoints[i * 3 + 2]; 189 if (accLength >= startD && accLength <= stopD) { 190 if (startWithMoveTo) { 191 startWithMoveTo = false; 192 Path_Delegate.native_moveTo(native_dst_path, x, y); 193 } else { 194 isZeroLength = false; 195 Path_Delegate.native_lineTo(native_dst_path, x, y); 196 } 197 } 198 199 if (i > 0) { 200 accLength += Point2D.distance( 201 pathMeasure.mPathPoints[(i - 1) * 3 + 1], 202 pathMeasure.mPathPoints[(i - 1) * 3 + 2], 203 pathMeasure.mPathPoints[i * 3 + 1], 204 pathMeasure.mPathPoints[i * 3 + 2]); 205 } 206 } 207 208 return !isZeroLength; 209 } 210} 211