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