blob: 7276c456a37c3ea6f45b9dc0bee831773b505d3e [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.util.CachedPathIteratorFactory;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator;
import java.awt.geom.PathIterator;
/**
* Delegate implementing the native methods of {@link android.graphics.PathMeasure}
* <p/>
* Through the layoutlib_create tool, the original native methods of PathMeasure have been
* replaced by
* calls to methods of the same name in this delegate class.
* <p/>
* This class behaves like the original native implementation, but in Java, keeping previously
* native data into its own objects and mapping them to int that are sent back and forth between it
* and the original PathMeasure class.
*
* @see DelegateManager
*/
public final class PathMeasure_Delegate {
// ---- delegate manager ----
private static final DelegateManager<PathMeasure_Delegate> sManager =
new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class);
// ---- delegate data ----
private CachedPathIteratorFactory mOriginalPathIterator;
private long mNativePath;
private PathMeasure_Delegate(long native_path, boolean forceClosed) {
mNativePath = native_path;
if (native_path != 0) {
if (forceClosed) {
// Copy the path and call close
native_path = Path_Delegate.nInit(native_path);
Path_Delegate.nClose(native_path);
}
Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
.getPathIterator(null));
}
}
@LayoutlibDelegate
/*package*/ static long native_create(long native_path, boolean forceClosed) {
return sManager.addNewDelegate(new PathMeasure_Delegate(native_path, forceClosed));
}
@LayoutlibDelegate
/*package*/ static void native_destroy(long native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
@LayoutlibDelegate
/*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[],
float tan[]) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"PathMeasure.getPostTan is not supported.", null, null, null);
return false;
}
@LayoutlibDelegate
/*package*/ static boolean native_getMatrix(long native_instance, float distance, long
native_matrix, int flags) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"PathMeasure.getMatrix is not supported.", null, null, null);
return false;
}
@LayoutlibDelegate
/*package*/ static boolean native_nextContour(long native_instance) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"PathMeasure.nextContour is not supported.", null, null, null);
return false;
}
@LayoutlibDelegate
/*package*/ static void native_setPath(long native_instance, long native_path, boolean
forceClosed) {
PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
assert pathMeasure != null;
if (native_path != 0) {
if (forceClosed) {
// Copy the path and call close
native_path = Path_Delegate.nInit(native_path);
Path_Delegate.nClose(native_path);
}
Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
.getPathIterator(null));
}
pathMeasure.mNativePath = native_path;
}
@LayoutlibDelegate
/*package*/ static float native_getLength(long native_instance) {
PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
assert pathMeasure != null;
if (pathMeasure.mOriginalPathIterator == null) {
return 0;
}
return pathMeasure.mOriginalPathIterator.iterator().getTotalLength();
}
@LayoutlibDelegate
/*package*/ static boolean native_isClosed(long native_instance) {
PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
assert pathMeasure != null;
Path_Delegate path = Path_Delegate.getDelegate(pathMeasure.mNativePath);
if (path == null) {
return false;
}
int type = 0;
float segment[] = new float[6];
for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) {
type = pi.currentSegment(segment);
}
// A path is a closed path if the last element is SEG_CLOSE
return type == PathIterator.SEG_CLOSE;
}
@LayoutlibDelegate
/*package*/ static boolean native_getSegment(long native_instance, float startD, float stopD,
long native_dst_path, boolean startWithMoveTo) {
if (startD < 0) {
startD = 0;
}
if (startD >= stopD) {
return false;
}
PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
assert pathMeasure != null;
CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator();
float accLength = startD;
boolean isZeroLength = true; // Whether the output has zero length or not
float[] points = new float[6];
iterator.jumpToSegment(accLength);
while (!iterator.isDone() && (stopD - accLength > 0.1f)) {
int type = iterator.currentSegment(points, stopD - accLength);
if (accLength - iterator.getCurrentSegmentLength() <= stopD) {
if (startWithMoveTo) {
startWithMoveTo = false;
// If this segment is a MOVETO, then we just use that one. If not, then we issue
// a first moveto
if (type != PathIterator.SEG_MOVETO) {
float[] lastPoint = new float[2];
iterator.getCurrentSegmentEnd(lastPoint);
Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]);
}
}
isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
switch (type) {
case PathIterator.SEG_MOVETO:
Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]);
break;
case PathIterator.SEG_LINETO:
Path_Delegate.nLineTo(native_dst_path, points[0], points[1]);
break;
case PathIterator.SEG_CLOSE:
Path_Delegate.nClose(native_dst_path);
break;
case PathIterator.SEG_CUBICTO:
Path_Delegate.nCubicTo(native_dst_path, points[0], points[1],
points[2], points[3],
points[4], points[5]);
break;
case PathIterator.SEG_QUADTO:
Path_Delegate.nQuadTo(native_dst_path, points[0], points[1],
points[2],
points[3]);
break;
default:
assert false;
}
}
accLength += iterator.getCurrentSegmentLength();
iterator.next();
}
return !isZeroLength;
}
}