1 /* 2 * Copyright (C) 2007 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 android.graphics; 18 19 @android.ravenwood.annotation.RavenwoodKeepWholeClass 20 public class PathMeasure { 21 private Path mPath; 22 23 /** 24 * Create an empty PathMeasure object. To uses this to measure the length 25 * of a path, and/or to find the position and tangent along it, call 26 * setPath. 27 * 28 * Note that once a path is associated with the measure object, it is 29 * undefined if the path is subsequently modified and the measure object 30 * is used. If the path is modified, you must call setPath with the path. 31 */ PathMeasure()32 public PathMeasure() { 33 mPath = null; 34 native_instance = native_create(0, false); 35 } 36 37 /** 38 * Create a PathMeasure object associated with the specified path object 39 * (already created and specified). The measure object can now return the 40 * path's length, and the position and tangent of any position along the 41 * path. 42 * 43 * Note that once a path is associated with the measure object, it is 44 * undefined if the path is subsequently modified and the measure object 45 * is used. If the path is modified, you must call setPath with the path. 46 * 47 * @param path The path that will be measured by this object 48 * @param forceClosed If true, then the path will be considered as "closed" 49 * even if its contour was not explicitly closed. 50 */ PathMeasure(Path path, boolean forceClosed)51 public PathMeasure(Path path, boolean forceClosed) { 52 // The native implementation does not copy the path, prevent it from being GC'd 53 mPath = path; 54 native_instance = native_create(path != null ? path.readOnlyNI() : 0, 55 forceClosed); 56 } 57 58 /** 59 * Assign a new path, or null to have none. 60 */ setPath(Path path, boolean forceClosed)61 public void setPath(Path path, boolean forceClosed) { 62 mPath = path; 63 native_setPath(native_instance, 64 path != null ? path.readOnlyNI() : 0, 65 forceClosed); 66 } 67 68 /** 69 * Return the total length of the current contour, or 0 if no path is 70 * associated with this measure object. 71 */ getLength()72 public float getLength() { 73 return native_getLength(native_instance); 74 } 75 76 /** 77 * Pins distance to 0 <= distance <= getLength(), and then computes the 78 * corresponding position and tangent. Returns false if there is no path, 79 * or a zero-length path was specified, in which case position and tangent 80 * are unchanged. 81 * 82 * @param distance The distance along the current contour to sample 83 * @param pos If not null, returns the sampled position (x==[0], y==[1]) 84 * @param tan If not null, returns the sampled tangent (x==[0], y==[1]) 85 * @return false if there was no path associated with this measure object 86 */ getPosTan(float distance, float pos[], float tan[])87 public boolean getPosTan(float distance, float pos[], float tan[]) { 88 if (pos != null && pos.length < 2 || 89 tan != null && tan.length < 2) { 90 throw new ArrayIndexOutOfBoundsException(); 91 } 92 return native_getPosTan(native_instance, distance, pos, tan); 93 } 94 95 public static final int POSITION_MATRIX_FLAG = 0x01; // must match flags in SkPathMeasure.h 96 public static final int TANGENT_MATRIX_FLAG = 0x02; // must match flags in SkPathMeasure.h 97 98 /** 99 * Pins distance to 0 <= distance <= getLength(), and then computes the 100 * corresponding matrix. Returns false if there is no path, or a zero-length 101 * path was specified, in which case matrix is unchanged. 102 * 103 * @param distance The distance along the associated path 104 * @param matrix Allocated by the caller, this is set to the transformation 105 * associated with the position and tangent at the specified distance 106 * @param flags Specified what aspects should be returned in the matrix. 107 */ getMatrix(float distance, Matrix matrix, int flags)108 public boolean getMatrix(float distance, Matrix matrix, int flags) { 109 return native_getMatrix(native_instance, distance, matrix.ni(), flags); 110 } 111 112 /** 113 * Given a start and stop distance, return in dst the intervening 114 * segment(s). If the segment is zero-length, return false, else return 115 * true. startD and stopD are pinned to legal values (0..getLength()). 116 * If startD >= stopD then return false (and leave dst untouched). 117 * Begin the segment with a moveTo if startWithMoveTo is true. 118 * 119 * <p>On {@link android.os.Build.VERSION_CODES#KITKAT} and earlier 120 * releases, the resulting path may not display on a hardware-accelerated 121 * Canvas. A simple workaround is to add a single operation to this path, 122 * such as <code>dst.rLineTo(0, 0)</code>.</p> 123 */ getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)124 public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) { 125 // Skia used to enforce this as part of its API, but has since relaxed that restriction 126 // so to maintain consistency in our API we enforce the preconditions here. 127 float length = getLength(); 128 if (startD < 0) { 129 startD = 0; 130 } 131 if (stopD > length) { 132 stopD = length; 133 } 134 if (startD >= stopD) { 135 return false; 136 } 137 138 return native_getSegment(native_instance, startD, stopD, dst.mutateNI(), startWithMoveTo); 139 } 140 141 /** 142 * Return true if the current contour is closed() 143 */ isClosed()144 public boolean isClosed() { 145 return native_isClosed(native_instance); 146 } 147 148 /** 149 * Move to the next contour in the path. Return true if one exists, or 150 * false if we're done with the path. 151 */ nextContour()152 public boolean nextContour() { 153 return native_nextContour(native_instance); 154 } 155 finalize()156 protected void finalize() throws Throwable { 157 native_destroy(native_instance); 158 native_instance = 0; // Other finalizers can still call us. 159 } 160 native_create(long native_path, boolean forceClosed)161 private static native long native_create(long native_path, boolean forceClosed); native_setPath(long native_instance, long native_path, boolean forceClosed)162 private static native void native_setPath(long native_instance, long native_path, boolean forceClosed); native_getLength(long native_instance)163 private static native float native_getLength(long native_instance); native_getPosTan(long native_instance, float distance, float pos[], float tan[])164 private static native boolean native_getPosTan(long native_instance, float distance, float pos[], float tan[]); native_getMatrix(long native_instance, float distance, long native_matrix, int flags)165 private static native boolean native_getMatrix(long native_instance, float distance, long native_matrix, int flags); native_getSegment(long native_instance, float startD, float stopD, long native_path, boolean startWithMoveTo)166 private static native boolean native_getSegment(long native_instance, float startD, float stopD, long native_path, boolean startWithMoveTo); native_isClosed(long native_instance)167 private static native boolean native_isClosed(long native_instance); native_nextContour(long native_instance)168 private static native boolean native_nextContour(long native_instance); native_destroy(long native_instance)169 private static native void native_destroy(long native_instance); 170 171 /* package */private long native_instance; 172 } 173 174