Path.cpp revision e55bc7f1575fc5dacac70c4cb209e6aa0c582e71
1/* libs/android_runtime/android/graphics/Path.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18// This file was generated from the C++ include file: SkPath.h 19// Any changes made to this file will be discarded by the build. 20// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, 21// or one of the auxilary file specifications in device/tools/gluemaker. 22 23#include "jni.h" 24#include "GraphicsJNI.h" 25#include <android_runtime/AndroidRuntime.h> 26 27#include "SkPath.h" 28#include "pathops/SkPathOps.h" 29 30#include <Caches.h> 31#include <vector> 32#include <map> 33 34namespace android { 35 36class SkPathGlue { 37public: 38 39 static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) { 40 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 41#ifdef USE_OPENGL_RENDERER 42 if (android::uirenderer::Caches::hasInstance()) { 43 android::uirenderer::Caches::getInstance().resourceCache.destructor(obj); 44 return; 45 } 46#endif 47 delete obj; 48 } 49 50 static jlong init1(JNIEnv* env, jobject clazz) { 51 return reinterpret_cast<jlong>(new SkPath()); 52 } 53 54 static jlong init2(JNIEnv* env, jobject clazz, jlong valHandle) { 55 SkPath* val = reinterpret_cast<SkPath*>(valHandle); 56 return reinterpret_cast<jlong>(new SkPath(*val)); 57 } 58 59 static void reset(JNIEnv* env, jobject clazz, jlong objHandle) { 60 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 61 obj->reset(); 62 } 63 64 static void rewind(JNIEnv* env, jobject clazz, jlong objHandle) { 65 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 66 obj->rewind(); 67 } 68 69 static void assign(JNIEnv* env, jobject clazz, jlong dstHandle, jlong srcHandle) { 70 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); 71 const SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 72 *dst = *src; 73 } 74 75 static jint getFillType(JNIEnv* env, jobject clazz, jlong objHandle) { 76 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 77 return obj->getFillType(); 78 } 79 80 static void setFillType(JNIEnv* env, jobject clazz, jlong pathHandle, jint ftHandle) { 81 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 82 SkPath::FillType ft = static_cast<SkPath::FillType>(ftHandle); 83 path->setFillType(ft); 84 } 85 86 static jboolean isEmpty(JNIEnv* env, jobject clazz, jlong objHandle) { 87 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 88 return obj->isEmpty(); 89 } 90 91 static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject rect) { 92 SkRect rect_; 93 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 94 jboolean result = obj->isRect(&rect_); 95 GraphicsJNI::rect_to_jrectf(rect_, env, rect); 96 return result; 97 } 98 99 static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject bounds) { 100 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 101 const SkRect& bounds_ = obj->getBounds(); 102 GraphicsJNI::rect_to_jrectf(bounds_, env, bounds); 103 } 104 105 static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) { 106 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 107 obj->incReserve(extraPtCount); 108 } 109 110 static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) { 111 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 112 SkScalar x_ = SkFloatToScalar(x); 113 SkScalar y_ = SkFloatToScalar(y); 114 obj->moveTo(x_, y_); 115 } 116 117 static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { 118 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 119 SkScalar dx_ = SkFloatToScalar(dx); 120 SkScalar dy_ = SkFloatToScalar(dy); 121 obj->rMoveTo(dx_, dy_); 122 } 123 124 static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) { 125 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 126 SkScalar x_ = SkFloatToScalar(x); 127 SkScalar y_ = SkFloatToScalar(y); 128 obj->lineTo(x_, y_); 129 } 130 131 static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { 132 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 133 SkScalar dx_ = SkFloatToScalar(dx); 134 SkScalar dy_ = SkFloatToScalar(dy); 135 obj->rLineTo(dx_, dy_); 136 } 137 138 static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) { 139 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 140 SkScalar x1_ = SkFloatToScalar(x1); 141 SkScalar y1_ = SkFloatToScalar(y1); 142 SkScalar x2_ = SkFloatToScalar(x2); 143 SkScalar y2_ = SkFloatToScalar(y2); 144 obj->quadTo(x1_, y1_, x2_, y2_); 145 } 146 147 static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) { 148 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 149 SkScalar dx1_ = SkFloatToScalar(dx1); 150 SkScalar dy1_ = SkFloatToScalar(dy1); 151 SkScalar dx2_ = SkFloatToScalar(dx2); 152 SkScalar dy2_ = SkFloatToScalar(dy2); 153 obj->rQuadTo(dx1_, dy1_, dx2_, dy2_); 154 } 155 156 static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { 157 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 158 SkScalar x1_ = SkFloatToScalar(x1); 159 SkScalar y1_ = SkFloatToScalar(y1); 160 SkScalar x2_ = SkFloatToScalar(x2); 161 SkScalar y2_ = SkFloatToScalar(y2); 162 SkScalar x3_ = SkFloatToScalar(x3); 163 SkScalar y3_ = SkFloatToScalar(y3); 164 obj->cubicTo(x1_, y1_, x2_, y2_, x3_, y3_); 165 } 166 167 static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { 168 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 169 SkScalar x1_ = SkFloatToScalar(x1); 170 SkScalar y1_ = SkFloatToScalar(y1); 171 SkScalar x2_ = SkFloatToScalar(x2); 172 SkScalar y2_ = SkFloatToScalar(y2); 173 SkScalar x3_ = SkFloatToScalar(x3); 174 SkScalar y3_ = SkFloatToScalar(y3); 175 obj->rCubicTo(x1_, y1_, x2_, y2_, x3_, y3_); 176 } 177 178 static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) { 179 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 180 SkRect oval_; 181 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 182 SkScalar startAngle_ = SkFloatToScalar(startAngle); 183 SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle); 184 obj->arcTo(oval_, startAngle_, sweepAngle_, forceMoveTo); 185 } 186 187 static void close(JNIEnv* env, jobject clazz, jlong objHandle) { 188 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 189 obj->close(); 190 } 191 192 static void addRect__RectFI(JNIEnv* env, jobject clazz, jlong objHandle, jobject rect, jint dirHandle) { 193 SkRect rect_; 194 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 195 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 196 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 197 obj->addRect(rect_, dir); 198 } 199 200 static void addRect__FFFFI(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) { 201 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 202 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 203 SkScalar left_ = SkFloatToScalar(left); 204 SkScalar top_ = SkFloatToScalar(top); 205 SkScalar right_ = SkFloatToScalar(right); 206 SkScalar bottom_ = SkFloatToScalar(bottom); 207 obj->addRect(left_, top_, right_, bottom_, dir); 208 } 209 210 static void addOval(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jint dirHandle) { 211 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 212 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 213 SkRect oval_; 214 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 215 obj->addOval(oval_, dir); 216 } 217 218 static void addCircle(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y, jfloat radius, jint dirHandle) { 219 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 220 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 221 SkScalar x_ = SkFloatToScalar(x); 222 SkScalar y_ = SkFloatToScalar(y); 223 SkScalar radius_ = SkFloatToScalar(radius); 224 obj->addCircle(x_, y_, radius_, dir); 225 } 226 227 static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) { 228 SkRect oval_; 229 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 230 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 231 SkScalar startAngle_ = SkFloatToScalar(startAngle); 232 SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle); 233 obj->addArc(oval_, startAngle_, sweepAngle_); 234 } 235 236 static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject rect, 237 jfloat rx, jfloat ry, jint dirHandle) { 238 SkRect rect_; 239 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 240 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 241 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 242 SkScalar rx_ = SkFloatToScalar(rx); 243 SkScalar ry_ = SkFloatToScalar(ry); 244 obj->addRoundRect(rect_, rx_, ry_, dir); 245 } 246 247 static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jobject rect, 248 jfloatArray array, jint dirHandle) { 249 SkRect rect_; 250 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 251 SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); 252 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 253 AutoJavaFloatArray afa(env, array, 8); 254 const float* src = afa.ptr(); 255 SkScalar dst[8]; 256 257 for (int i = 0; i < 8; i++) { 258 dst[i] = SkFloatToScalar(src[i]); 259 } 260 obj->addRoundRect(rect_, dst, dir); 261 } 262 263 static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) { 264 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 265 SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 266 SkScalar dx_ = SkFloatToScalar(dx); 267 SkScalar dy_ = SkFloatToScalar(dy); 268 obj->addPath(*src, dx_, dy_); 269 } 270 271 static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) { 272 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 273 SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 274 obj->addPath(*src); 275 } 276 277 static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) { 278 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 279 SkPath* src = reinterpret_cast<SkPath*>(srcHandle); 280 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 281 obj->addPath(*src, *matrix); 282 } 283 284 static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) { 285 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 286 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); 287 SkScalar dx_ = SkFloatToScalar(dx); 288 SkScalar dy_ = SkFloatToScalar(dy); 289 obj->offset(dx_, dy_, dst); 290 } 291 292 static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { 293 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 294 SkScalar dx_ = SkFloatToScalar(dx); 295 SkScalar dy_ = SkFloatToScalar(dy); 296 obj->offset(dx_, dy_); 297 } 298 299 static void setLastPoint(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { 300 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 301 SkScalar dx_ = SkFloatToScalar(dx); 302 SkScalar dy_ = SkFloatToScalar(dy); 303 obj->setLastPt(dx_, dy_); 304 } 305 306 static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) { 307 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 308 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 309 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); 310 obj->transform(*matrix, dst); 311 } 312 313 static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) { 314 SkPath* obj = reinterpret_cast<SkPath*>(objHandle); 315 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); 316 obj->transform(*matrix); 317 } 318 319 static jboolean op(JNIEnv* env, jobject clazz, jlong p1Handle, jlong p2Handle, jint opHandle, jlong rHandle) { 320 SkPath* p1 = reinterpret_cast<SkPath*>(p1Handle); 321 SkPath* p2 = reinterpret_cast<SkPath*>(p2Handle); 322 SkPathOp op = static_cast<SkPathOp>(opHandle); 323 SkPath* r = reinterpret_cast<SkPath*>(rHandle); 324 return Op(*p1, *p2, op, r); 325 } 326 327 typedef SkPoint (*bezierCalculation)(float t, const SkPoint* points); 328 329 static void addMove(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, 330 const SkPoint& point) { 331 float length = 0; 332 if (!lengths.empty()) { 333 length = lengths.back(); 334 } 335 segmentPoints.push_back(point); 336 lengths.push_back(length); 337 } 338 339 static void addLine(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, 340 const SkPoint& toPoint) { 341 if (segmentPoints.empty()) { 342 segmentPoints.push_back(SkPoint::Make(0, 0)); 343 lengths.push_back(0); 344 } else if (segmentPoints.back() == toPoint) { 345 return; // Empty line 346 } 347 float length = lengths.back() + SkPoint::Distance(segmentPoints.back(), toPoint); 348 segmentPoints.push_back(toPoint); 349 lengths.push_back(length); 350 } 351 352 static float cubicCoordinateCalculation(float t, float p0, float p1, float p2, float p3) { 353 float oneMinusT = 1 - t; 354 float oneMinusTSquared = oneMinusT * oneMinusT; 355 float oneMinusTCubed = oneMinusTSquared * oneMinusT; 356 float tSquared = t * t; 357 float tCubed = tSquared * t; 358 return (oneMinusTCubed * p0) + (3 * oneMinusTSquared * t * p1) 359 + (3 * oneMinusT * tSquared * p2) + (tCubed * p3); 360 } 361 362 static SkPoint cubicBezierCalculation(float t, const SkPoint* points) { 363 float x = cubicCoordinateCalculation(t, points[0].x(), points[1].x(), 364 points[2].x(), points[3].x()); 365 float y = cubicCoordinateCalculation(t, points[0].y(), points[1].y(), 366 points[2].y(), points[3].y()); 367 return SkPoint::Make(x, y); 368 } 369 370 static float quadraticCoordinateCalculation(float t, float p0, float p1, float p2) { 371 float oneMinusT = 1 - t; 372 return oneMinusT * ((oneMinusT * p0) + (t * p1)) + t * ((oneMinusT * p1) + (t * p2)); 373 } 374 375 static SkPoint quadraticBezierCalculation(float t, const SkPoint* points) { 376 float x = quadraticCoordinateCalculation(t, points[0].x(), points[1].x(), points[2].x()); 377 float y = quadraticCoordinateCalculation(t, points[0].y(), points[1].y(), points[2].y()); 378 return SkPoint::Make(x, y); 379 } 380 381 // Subdivide a section of the Bezier curve, set the mid-point and the mid-t value. 382 // Returns true if further subdivision is necessary as defined by errorSquared. 383 static bool subdividePoints(const SkPoint* points, bezierCalculation bezierFunction, 384 float t0, const SkPoint &p0, float t1, const SkPoint &p1, 385 float& midT, SkPoint &midPoint, float errorSquared) { 386 midT = (t1 + t0) / 2; 387 float midX = (p1.x() + p0.x()) / 2; 388 float midY = (p1.y() + p0.y()) / 2; 389 390 midPoint = (*bezierFunction)(midT, points); 391 float xError = midPoint.x() - midX; 392 float yError = midPoint.y() - midY; 393 float midErrorSquared = (xError * xError) + (yError * yError); 394 return midErrorSquared > errorSquared; 395 } 396 397 // Divides Bezier curves until linear interpolation is very close to accurate, using 398 // errorSquared as a metric. Cubic Bezier curves can have an inflection point that improperly 399 // short-circuit subdivision. If you imagine an S shape, the top and bottom points being the 400 // starting and end points, linear interpolation would mark the center where the curve places 401 // the point. It is clearly not the case that we can linearly interpolate at that point. 402 // doubleCheckDivision forces a second examination between subdivisions to ensure that linear 403 // interpolation works. 404 static void addBezier(const SkPoint* points, 405 bezierCalculation bezierFunction, std::vector<SkPoint>& segmentPoints, 406 std::vector<float>& lengths, float errorSquared, bool doubleCheckDivision) { 407 typedef std::map<float, SkPoint> PointMap; 408 PointMap tToPoint; 409 410 tToPoint[0] = (*bezierFunction)(0, points); 411 tToPoint[1] = (*bezierFunction)(1, points); 412 413 PointMap::iterator iter = tToPoint.begin(); 414 PointMap::iterator next = iter; 415 ++next; 416 while (next != tToPoint.end()) { 417 bool needsSubdivision = true; 418 SkPoint midPoint; 419 do { 420 float midT; 421 needsSubdivision = subdividePoints(points, bezierFunction, iter->first, 422 iter->second, next->first, next->second, midT, midPoint, errorSquared); 423 if (!needsSubdivision && doubleCheckDivision) { 424 SkPoint quarterPoint; 425 float quarterT; 426 needsSubdivision = subdividePoints(points, bezierFunction, iter->first, 427 iter->second, midT, midPoint, quarterT, quarterPoint, errorSquared); 428 if (needsSubdivision) { 429 // Found an inflection point. No need to double-check. 430 doubleCheckDivision = false; 431 } 432 } 433 if (needsSubdivision) { 434 next = tToPoint.insert(iter, PointMap::value_type(midT, midPoint)); 435 } 436 } while (needsSubdivision); 437 iter = next; 438 next++; 439 } 440 441 // Now that each division can use linear interpolation with less than the allowed error 442 for (iter = tToPoint.begin(); iter != tToPoint.end(); ++iter) { 443 addLine(segmentPoints, lengths, iter->second); 444 } 445 } 446 447 static void createVerbSegments(SkPath::Verb verb, const SkPoint* points, 448 std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, float errorSquared) { 449 switch (verb) { 450 case SkPath::kMove_Verb: 451 addMove(segmentPoints, lengths, points[0]); 452 break; 453 case SkPath::kClose_Verb: 454 addLine(segmentPoints, lengths, points[0]); 455 break; 456 case SkPath::kLine_Verb: 457 addLine(segmentPoints, lengths, points[1]); 458 break; 459 case SkPath::kQuad_Verb: 460 addBezier(points, quadraticBezierCalculation, segmentPoints, lengths, 461 errorSquared, false); 462 break; 463 case SkPath::kCubic_Verb: 464 addBezier(points, cubicBezierCalculation, segmentPoints, lengths, 465 errorSquared, true); 466 break; 467 default: 468 // Leave element as NULL, Conic sections are not supported. 469 break; 470 } 471 } 472 473 // Returns a float[] with each point along the path represented by 3 floats 474 // * fractional length along the path that the point resides 475 // * x coordinate 476 // * y coordinate 477 // Note that more than one point may have the same length along the path in 478 // the case of a move. 479 // NULL can be returned if the Path is empty. 480 static jfloatArray approximate(JNIEnv* env, jclass, jlong pathHandle, float acceptableError) 481 { 482 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 483 SkASSERT(path); 484 SkPath::Iter pathIter(*path, false); 485 SkPath::Verb verb; 486 SkPoint points[4]; 487 std::vector<SkPoint> segmentPoints; 488 std::vector<float> lengths; 489 float errorSquared = acceptableError * acceptableError; 490 491 while ((verb = pathIter.next(points)) != SkPath::kDone_Verb) { 492 createVerbSegments(verb, points, segmentPoints, lengths, errorSquared); 493 } 494 495 if (segmentPoints.empty()) { 496 return NULL; 497 } 498 499 size_t numPoints = segmentPoints.size(); 500 size_t approximationArraySize = numPoints * 3; 501 502 float* approximation = new float[approximationArraySize]; 503 float totalLength = lengths.back(); 504 505 int approximationIndex = 0; 506 for (size_t i = 0; i < numPoints; i++) { 507 const SkPoint& point = segmentPoints[i]; 508 approximation[approximationIndex++] = lengths[i] / totalLength; 509 approximation[approximationIndex++] = point.x(); 510 approximation[approximationIndex++] = point.y(); 511 } 512 513 jfloatArray result = env->NewFloatArray(approximationArraySize); 514 env->SetFloatArrayRegion(result, 0, approximationArraySize, approximation); 515 delete[] approximation; 516 return result; 517 } 518 519 static jlong trim(JNIEnv* env, jobject clazz, jlong inPathPtr, jlong outPathPtr, 520 jlong pathMeasurePtr, jfloat trimStart, jfloat trimEnd, jfloat trimOffset) { 521 SkPath* inPath = reinterpret_cast<SkPath*>(inPathPtr); 522 SkPath* outPath = reinterpret_cast<SkPath*>(outPathPtr); 523 SkPathMeasure* pathMeasure = reinterpret_cast<SkPathMeasure*>(pathMeasurePtr); 524 if (trimStart == 0 && trimEnd == 1) { 525 if (outPath != NULL) { 526 *outPath = *inPath; 527 } 528 return reinterpret_cast<jlong>(pathMeasure); 529 } 530 531 bool modifyPath = (outPath == NULL); 532 if (modifyPath) { 533 outPath = new SkPath(); 534 } else { 535 outPath->reset(); 536 } 537 if (pathMeasure == NULL) { 538 pathMeasure = new SkPathMeasure(*inPath, false); 539 } 540 float length = pathMeasure->getLength(); 541 float start = (trimStart + trimOffset) * length; 542 float end = (trimEnd + trimOffset) * length; 543 544 if (end > length && start <= length) { 545 pathMeasure->getSegment(start, length, outPath, true); 546 pathMeasure->getSegment(0, end - length, outPath, true); 547 } else { 548 if (start > length) { 549 start -= length; 550 end -= length; 551 } 552 pathMeasure->getSegment(start, end, outPath, true); 553 } 554 if (modifyPath) { 555 delete pathMeasure; 556 pathMeasure = NULL; 557 *inPath = *outPath; 558 delete outPath; 559 } 560 return reinterpret_cast<jlong>(pathMeasure); 561 } 562 563 static void destroyMeasure(JNIEnv* env, jobject clazz, jlong measure) { 564 delete reinterpret_cast<SkPathMeasure*>(measure); 565 } 566}; 567 568static JNINativeMethod methods[] = { 569 {"finalizer", "(J)V", (void*) SkPathGlue::finalizer}, 570 {"init1","()J", (void*) SkPathGlue::init1}, 571 {"init2","(J)J", (void*) SkPathGlue::init2}, 572 {"native_reset","(J)V", (void*) SkPathGlue::reset}, 573 {"native_rewind","(J)V", (void*) SkPathGlue::rewind}, 574 {"native_set","(JJ)V", (void*) SkPathGlue::assign}, 575 {"native_getFillType","(J)I", (void*) SkPathGlue::getFillType}, 576 {"native_setFillType","(JI)V", (void*) SkPathGlue::setFillType}, 577 {"native_isEmpty","(J)Z", (void*) SkPathGlue::isEmpty}, 578 {"native_isRect","(JLandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect}, 579 {"native_computeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds}, 580 {"native_incReserve","(JI)V", (void*) SkPathGlue::incReserve}, 581 {"native_moveTo","(JFF)V", (void*) SkPathGlue::moveTo__FF}, 582 {"native_rMoveTo","(JFF)V", (void*) SkPathGlue::rMoveTo}, 583 {"native_lineTo","(JFF)V", (void*) SkPathGlue::lineTo__FF}, 584 {"native_rLineTo","(JFF)V", (void*) SkPathGlue::rLineTo}, 585 {"native_quadTo","(JFFFF)V", (void*) SkPathGlue::quadTo__FFFF}, 586 {"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo}, 587 {"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF}, 588 {"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo}, 589 {"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo}, 590 {"native_close","(J)V", (void*) SkPathGlue::close}, 591 {"native_addRect","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addRect__RectFI}, 592 {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect__FFFFI}, 593 {"native_addOval","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addOval}, 594 {"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle}, 595 {"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc}, 596 {"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY}, 597 {"native_addRoundRect","(JLandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8}, 598 {"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF}, 599 {"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path}, 600 {"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix}, 601 {"native_offset","(JFFJ)V", (void*) SkPathGlue::offset__FFPath}, 602 {"native_offset","(JFF)V", (void*) SkPathGlue::offset__FF}, 603 {"native_setLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint}, 604 {"native_transform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath}, 605 {"native_transform","(JJ)V", (void*) SkPathGlue::transform__Matrix}, 606 {"native_op","(JJIJ)Z", (void*) SkPathGlue::op}, 607 {"native_approximate", "(JF)[F", (void*) SkPathGlue::approximate}, 608 {"native_destroyMeasure","(J)V", (void*) SkPathGlue::destroyMeasure}, 609 {"native_trim","(JJJFFF)J", (void*) SkPathGlue::trim}, 610}; 611 612int register_android_graphics_Path(JNIEnv* env) { 613 int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Path", methods, 614 sizeof(methods) / sizeof(methods[0])); 615 return result; 616} 617 618} 619