118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez/* 218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * Copyright (C) 2015 The Android Open Source Project 318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * 418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * Licensed under the Apache License, Version 2.0 (the "License"); 518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * you may not use this file except in compliance with the License. 618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * You may obtain a copy of the License at 718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * 818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * http://www.apache.org/licenses/LICENSE-2.0 918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * 1018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * Unless required by applicable law or agreed to in writing, software 1118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * distributed under the License is distributed on an "AS IS" BASIS, 1218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * See the License for the specific language governing permissions and 1418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * limitations under the License. 1518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez */ 1618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 1718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezpackage android.graphics; 1818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 1918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezimport com.android.ide.common.rendering.api.LayoutLog; 2018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezimport com.android.layoutlib.bridge.Bridge; 2118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezimport com.android.layoutlib.bridge.impl.DelegateManager; 22a1c6015169815e90684917ac215926ae22e61d7aDiego Perezimport com.android.layoutlib.bridge.util.CachedPathIteratorFactory; 2318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 2418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 25a1c6015169815e90684917ac215926ae22e61d7aDiego Perezimport com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator; 26a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 2718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezimport java.awt.geom.PathIterator; 2818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 2918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez/** 3018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * Delegate implementing the native methods of {@link android.graphics.PathMeasure} 3118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * <p/> 3218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * Through the layoutlib_create tool, the original native methods of PathMeasure have been 3318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * replaced by 3418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * calls to methods of the same name in this delegate class. 3518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * <p/> 3618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * This class behaves like the original native implementation, but in Java, keeping previously 3718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * native data into its own objects and mapping them to int that are sent back and forth between it 3818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * and the original PathMeasure class. 3918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * 4018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez * @see DelegateManager 4118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez */ 4218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perezpublic final class PathMeasure_Delegate { 43a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 4418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez // ---- delegate manager ---- 4518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez private static final DelegateManager<PathMeasure_Delegate> sManager = 4618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class); 4718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 4818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez // ---- delegate data ---- 49a1c6015169815e90684917ac215926ae22e61d7aDiego Perez private CachedPathIteratorFactory mOriginalPathIterator; 50a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 5118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez private long mNativePath; 5218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 53a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 5418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez private PathMeasure_Delegate(long native_path, boolean forceClosed) { 5518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez mNativePath = native_path; 56a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (native_path != 0) { 57a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (forceClosed) { 58a1c6015169815e90684917ac215926ae22e61d7aDiego Perez // Copy the path and call close 598e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard native_path = Path_Delegate.nInit(native_path); 608e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nClose(native_path); 61a1c6015169815e90684917ac215926ae22e61d7aDiego Perez } 6218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 63a1c6015169815e90684917ac215926ae22e61d7aDiego Perez Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path); 64a1c6015169815e90684917ac215926ae22e61d7aDiego Perez mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape() 65a1c6015169815e90684917ac215926ae22e61d7aDiego Perez .getPathIterator(null)); 66a1c6015169815e90684917ac215926ae22e61d7aDiego Perez } 6718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 6818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 6918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 7018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static long native_create(long native_path, boolean forceClosed) { 7118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return sManager.addNewDelegate(new PathMeasure_Delegate(native_path, forceClosed)); 7218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 7318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 7418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 7518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static void native_destroy(long native_instance) { 7618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez sManager.removeJavaReferenceFor(native_instance); 7718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 7818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 7918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 8018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[], 8118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez float tan[]) { 8218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 8318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez "PathMeasure.getPostTan is not supported.", null, null); 8418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return false; 8518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 8618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 8718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 8818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static boolean native_getMatrix(long native_instance, float distance, long 8918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez native_matrix, int flags) { 9018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 9118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez "PathMeasure.getMatrix is not supported.", null, null); 9218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return false; 9318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 9418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 9518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 9618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static boolean native_nextContour(long native_instance) { 9718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 9818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez "PathMeasure.nextContour is not supported.", null, null); 9918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return false; 10018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 10118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 10218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 10318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static void native_setPath(long native_instance, long native_path, boolean 10418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez forceClosed) { 10518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 10618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez assert pathMeasure != null; 10718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 108a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (native_path != 0) { 109a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (forceClosed) { 110a1c6015169815e90684917ac215926ae22e61d7aDiego Perez // Copy the path and call close 1118e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard native_path = Path_Delegate.nInit(native_path); 1128e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nClose(native_path); 113a1c6015169815e90684917ac215926ae22e61d7aDiego Perez } 114a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 115a1c6015169815e90684917ac215926ae22e61d7aDiego Perez Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path); 116a1c6015169815e90684917ac215926ae22e61d7aDiego Perez pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape() 117a1c6015169815e90684917ac215926ae22e61d7aDiego Perez .getPathIterator(null)); 11818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 119a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 12018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez pathMeasure.mNativePath = native_path; 12118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 12218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 12318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 12418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static float native_getLength(long native_instance) { 12518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 12618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez assert pathMeasure != null; 12718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 128a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (pathMeasure.mOriginalPathIterator == null) { 12918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return 0; 13018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 13118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 132a1c6015169815e90684917ac215926ae22e61d7aDiego Perez return pathMeasure.mOriginalPathIterator.iterator().getTotalLength(); 13318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 13418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 13518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 13618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static boolean native_isClosed(long native_instance) { 13718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 13818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez assert pathMeasure != null; 13918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 14018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez Path_Delegate path = Path_Delegate.getDelegate(pathMeasure.mNativePath); 14118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez if (path == null) { 14218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return false; 14318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 14418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 14518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez int type = 0; 14618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez float segment[] = new float[6]; 147a1c6015169815e90684917ac215926ae22e61d7aDiego Perez for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) { 148a1c6015169815e90684917ac215926ae22e61d7aDiego Perez type = pi.currentSegment(segment); 14918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 15018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 15118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez // A path is a closed path if the last element is SEG_CLOSE 15218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return type == PathIterator.SEG_CLOSE; 15318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 15418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 15518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez @LayoutlibDelegate 15618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez /*package*/ static boolean native_getSegment(long native_instance, float startD, float stopD, 15718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez long native_dst_path, boolean startWithMoveTo) { 15818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez if (startD < 0) { 15918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez startD = 0; 16018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 16118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 16218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez if (startD >= stopD) { 16318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return false; 16418fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 16518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 16618fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance); 16718fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez assert pathMeasure != null; 16818fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 169a1c6015169815e90684917ac215926ae22e61d7aDiego Perez CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator(); 170a1c6015169815e90684917ac215926ae22e61d7aDiego Perez float accLength = startD; 17118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez boolean isZeroLength = true; // Whether the output has zero length or not 172a1c6015169815e90684917ac215926ae22e61d7aDiego Perez float[] points = new float[6]; 173a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 174a1c6015169815e90684917ac215926ae22e61d7aDiego Perez iterator.jumpToSegment(accLength); 175a1c6015169815e90684917ac215926ae22e61d7aDiego Perez while (!iterator.isDone() && (stopD - accLength > 0.1f)) { 176a1c6015169815e90684917ac215926ae22e61d7aDiego Perez int type = iterator.currentSegment(points, stopD - accLength); 177a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 178a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (accLength - iterator.getCurrentSegmentLength() <= stopD) { 17918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez if (startWithMoveTo) { 18018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez startWithMoveTo = false; 181a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 182a1c6015169815e90684917ac215926ae22e61d7aDiego Perez // If this segment is a MOVETO, then we just use that one. If not, then we issue 183a1c6015169815e90684917ac215926ae22e61d7aDiego Perez // a first moveto 184a1c6015169815e90684917ac215926ae22e61d7aDiego Perez if (type != PathIterator.SEG_MOVETO) { 185a1c6015169815e90684917ac215926ae22e61d7aDiego Perez float[] lastPoint = new float[2]; 186a1c6015169815e90684917ac215926ae22e61d7aDiego Perez iterator.getCurrentSegmentEnd(lastPoint); 1878e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]); 188a1c6015169815e90684917ac215926ae22e61d7aDiego Perez } 18918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 19018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 191a1c6015169815e90684917ac215926ae22e61d7aDiego Perez isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0; 192a1c6015169815e90684917ac215926ae22e61d7aDiego Perez switch (type) { 193a1c6015169815e90684917ac215926ae22e61d7aDiego Perez case PathIterator.SEG_MOVETO: 1948e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]); 195a1c6015169815e90684917ac215926ae22e61d7aDiego Perez break; 196a1c6015169815e90684917ac215926ae22e61d7aDiego Perez case PathIterator.SEG_LINETO: 1978e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nLineTo(native_dst_path, points[0], points[1]); 198a1c6015169815e90684917ac215926ae22e61d7aDiego Perez break; 199a1c6015169815e90684917ac215926ae22e61d7aDiego Perez case PathIterator.SEG_CLOSE: 2008e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nClose(native_dst_path); 201a1c6015169815e90684917ac215926ae22e61d7aDiego Perez break; 202a1c6015169815e90684917ac215926ae22e61d7aDiego Perez case PathIterator.SEG_CUBICTO: 2038e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nCubicTo(native_dst_path, points[0], points[1], 204a1c6015169815e90684917ac215926ae22e61d7aDiego Perez points[2], points[3], 205a1c6015169815e90684917ac215926ae22e61d7aDiego Perez points[4], points[5]); 206a1c6015169815e90684917ac215926ae22e61d7aDiego Perez break; 207a1c6015169815e90684917ac215926ae22e61d7aDiego Perez case PathIterator.SEG_QUADTO: 2088e7e4cf314f05d82250d0d4429c02d760d988acdJerome Gaillard Path_Delegate.nQuadTo(native_dst_path, points[0], points[1], 209a1c6015169815e90684917ac215926ae22e61d7aDiego Perez points[2], 210a1c6015169815e90684917ac215926ae22e61d7aDiego Perez points[3]); 211a1c6015169815e90684917ac215926ae22e61d7aDiego Perez break; 212a1c6015169815e90684917ac215926ae22e61d7aDiego Perez default: 213a1c6015169815e90684917ac215926ae22e61d7aDiego Perez assert false; 214a1c6015169815e90684917ac215926ae22e61d7aDiego Perez } 21518fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 216a1c6015169815e90684917ac215926ae22e61d7aDiego Perez 217a1c6015169815e90684917ac215926ae22e61d7aDiego Perez accLength += iterator.getCurrentSegmentLength(); 218a1c6015169815e90684917ac215926ae22e61d7aDiego Perez iterator.next(); 21918fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 22018fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez 22118fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez return !isZeroLength; 22218fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez } 22318fdccbb190f8478db6fedef748a868e9cdea6f4Diego Perez} 224