Home | History | Annotate | Download | only in graphics
      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 
     17 package android.graphics;
     18 
     19 import com.android.ide.common.rendering.api.LayoutLog;
     20 import com.android.layoutlib.bridge.Bridge;
     21 import com.android.layoutlib.bridge.impl.DelegateManager;
     22 import com.android.layoutlib.bridge.util.CachedPathIteratorFactory;
     23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
     24 
     25 import com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator;
     26 
     27 import java.awt.geom.PathIterator;
     28 
     29 /**
     30  * Delegate implementing the native methods of {@link android.graphics.PathMeasure}
     31  * <p/>
     32  * Through the layoutlib_create tool, the original native methods of PathMeasure have been
     33  * replaced by
     34  * calls to methods of the same name in this delegate class.
     35  * <p/>
     36  * This class behaves like the original native implementation, but in Java, keeping previously
     37  * native data into its own objects and mapping them to int that are sent back and forth between it
     38  * and the original PathMeasure class.
     39  *
     40  * @see DelegateManager
     41  */
     42 public final class PathMeasure_Delegate {
     43 
     44     // ---- delegate manager ----
     45     private static final DelegateManager<PathMeasure_Delegate> sManager =
     46             new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class);
     47 
     48     // ---- delegate data ----
     49     private CachedPathIteratorFactory mOriginalPathIterator;
     50 
     51     private long mNativePath;
     52 
     53 
     54     private PathMeasure_Delegate(long native_path, boolean forceClosed) {
     55         mNativePath = native_path;
     56         if (native_path != 0) {
     57             if (forceClosed) {
     58                 // Copy the path and call close
     59                 native_path = Path_Delegate.nInit(native_path);
     60                 Path_Delegate.nClose(native_path);
     61             }
     62 
     63             Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
     64             mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
     65                     .getPathIterator(null));
     66         }
     67     }
     68 
     69     @LayoutlibDelegate
     70     /*package*/ static long native_create(long native_path, boolean forceClosed) {
     71         return sManager.addNewDelegate(new PathMeasure_Delegate(native_path, forceClosed));
     72     }
     73 
     74     @LayoutlibDelegate
     75     /*package*/ static void native_destroy(long native_instance) {
     76         sManager.removeJavaReferenceFor(native_instance);
     77     }
     78 
     79     @LayoutlibDelegate
     80     /*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[],
     81             float tan[]) {
     82         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
     83                 "PathMeasure.getPostTan is not supported.", null, null);
     84         return false;
     85     }
     86 
     87     @LayoutlibDelegate
     88     /*package*/ static boolean native_getMatrix(long native_instance, float distance, long
     89             native_matrix, int flags) {
     90         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
     91                 "PathMeasure.getMatrix is not supported.", null, null);
     92         return false;
     93     }
     94 
     95     @LayoutlibDelegate
     96     /*package*/ static boolean native_nextContour(long native_instance) {
     97         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
     98                 "PathMeasure.nextContour is not supported.", null, null);
     99         return false;
    100     }
    101 
    102     @LayoutlibDelegate
    103     /*package*/ static void native_setPath(long native_instance, long native_path, boolean
    104             forceClosed) {
    105         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
    106         assert pathMeasure != null;
    107 
    108         if (native_path != 0) {
    109             if (forceClosed) {
    110                 // Copy the path and call close
    111                 native_path = Path_Delegate.nInit(native_path);
    112                 Path_Delegate.nClose(native_path);
    113             }
    114 
    115             Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
    116             pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
    117                     .getPathIterator(null));
    118         }
    119 
    120         pathMeasure.mNativePath = native_path;
    121     }
    122 
    123     @LayoutlibDelegate
    124     /*package*/ static float native_getLength(long native_instance) {
    125         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
    126         assert pathMeasure != null;
    127 
    128         if (pathMeasure.mOriginalPathIterator == null) {
    129             return 0;
    130         }
    131 
    132         return pathMeasure.mOriginalPathIterator.iterator().getTotalLength();
    133     }
    134 
    135     @LayoutlibDelegate
    136     /*package*/ static boolean native_isClosed(long native_instance) {
    137         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
    138         assert pathMeasure != null;
    139 
    140         Path_Delegate path = Path_Delegate.getDelegate(pathMeasure.mNativePath);
    141         if (path == null) {
    142             return false;
    143         }
    144 
    145         int type = 0;
    146         float segment[] = new float[6];
    147         for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) {
    148             type = pi.currentSegment(segment);
    149         }
    150 
    151         // A path is a closed path if the last element is SEG_CLOSE
    152         return type == PathIterator.SEG_CLOSE;
    153     }
    154 
    155     @LayoutlibDelegate
    156     /*package*/ static boolean native_getSegment(long native_instance, float startD, float stopD,
    157             long native_dst_path, boolean startWithMoveTo) {
    158         if (startD < 0) {
    159             startD = 0;
    160         }
    161 
    162         if (startD >= stopD) {
    163             return false;
    164         }
    165 
    166         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
    167         assert pathMeasure != null;
    168 
    169         CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator();
    170         float accLength = startD;
    171         boolean isZeroLength = true; // Whether the output has zero length or not
    172         float[] points = new float[6];
    173 
    174         iterator.jumpToSegment(accLength);
    175         while (!iterator.isDone() && (stopD - accLength > 0.1f)) {
    176             int type = iterator.currentSegment(points, stopD - accLength);
    177 
    178             if (accLength - iterator.getCurrentSegmentLength() <= stopD) {
    179                 if (startWithMoveTo) {
    180                     startWithMoveTo = false;
    181 
    182                     // If this segment is a MOVETO, then we just use that one. If not, then we issue
    183                     // a first moveto
    184                     if (type != PathIterator.SEG_MOVETO) {
    185                         float[] lastPoint = new float[2];
    186                         iterator.getCurrentSegmentEnd(lastPoint);
    187                         Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]);
    188                     }
    189                 }
    190 
    191                 isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
    192                 switch (type) {
    193                     case PathIterator.SEG_MOVETO:
    194                         Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]);
    195                         break;
    196                     case PathIterator.SEG_LINETO:
    197                         Path_Delegate.nLineTo(native_dst_path, points[0], points[1]);
    198                         break;
    199                     case PathIterator.SEG_CLOSE:
    200                         Path_Delegate.nClose(native_dst_path);
    201                         break;
    202                     case PathIterator.SEG_CUBICTO:
    203                         Path_Delegate.nCubicTo(native_dst_path, points[0], points[1],
    204                                 points[2], points[3],
    205                                 points[4], points[5]);
    206                         break;
    207                     case PathIterator.SEG_QUADTO:
    208                         Path_Delegate.nQuadTo(native_dst_path, points[0], points[1],
    209                                 points[2],
    210                                 points[3]);
    211                         break;
    212                     default:
    213                         assert false;
    214                 }
    215             }
    216 
    217             accLength += iterator.getCurrentSegmentLength();
    218             iterator.next();
    219         }
    220 
    221         return !isZeroLength;
    222     }
    223 }
    224