Path.cpp revision c96c7b2e54965e30c8fb82295f1ca9f891ebd5e7
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, SkPath* obj) { 40#ifdef USE_OPENGL_RENDERER 41 if (android::uirenderer::Caches::hasInstance()) { 42 android::uirenderer::Caches::getInstance().resourceCache.destructor(obj); 43 return; 44 } 45#endif 46 delete obj; 47 } 48 49 static SkPath* init1(JNIEnv* env, jobject clazz) { 50 return new SkPath(); 51 } 52 53 static SkPath* init2(JNIEnv* env, jobject clazz, SkPath* val) { 54 return new SkPath(*val); 55 } 56 57 static void reset(JNIEnv* env, jobject clazz, SkPath* obj) { 58 obj->reset(); 59 } 60 61 static void rewind(JNIEnv* env, jobject clazz, SkPath* obj) { 62 obj->rewind(); 63 } 64 65 static void assign(JNIEnv* env, jobject clazz, SkPath* dst, const SkPath* src) { 66 *dst = *src; 67 } 68 69 static jint getFillType(JNIEnv* env, jobject clazz, SkPath* obj) { 70 return obj->getFillType(); 71 } 72 73 static void setFillType(JNIEnv* env, jobject clazz, SkPath* path, SkPath::FillType ft) { 74 path->setFillType(ft); 75 } 76 77 static jboolean isEmpty(JNIEnv* env, jobject clazz, SkPath* obj) { 78 return obj->isEmpty(); 79 } 80 81 static jboolean isRect(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect) { 82 SkRect rect_; 83 jboolean result = obj->isRect(&rect_); 84 GraphicsJNI::rect_to_jrectf(rect_, env, rect); 85 return result; 86 } 87 88 static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds) { 89 const SkRect& bounds_ = obj->getBounds(); 90 GraphicsJNI::rect_to_jrectf(bounds_, env, bounds); 91 } 92 93 static void incReserve(JNIEnv* env, jobject clazz, SkPath* obj, jint extraPtCount) { 94 obj->incReserve(extraPtCount); 95 } 96 97 static void moveTo__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y) { 98 SkScalar x_ = SkFloatToScalar(x); 99 SkScalar y_ = SkFloatToScalar(y); 100 obj->moveTo(x_, y_); 101 } 102 103 static void rMoveTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) { 104 SkScalar dx_ = SkFloatToScalar(dx); 105 SkScalar dy_ = SkFloatToScalar(dy); 106 obj->rMoveTo(dx_, dy_); 107 } 108 109 static void lineTo__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y) { 110 SkScalar x_ = SkFloatToScalar(x); 111 SkScalar y_ = SkFloatToScalar(y); 112 obj->lineTo(x_, y_); 113 } 114 115 static void rLineTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) { 116 SkScalar dx_ = SkFloatToScalar(dx); 117 SkScalar dy_ = SkFloatToScalar(dy); 118 obj->rLineTo(dx_, dy_); 119 } 120 121 static void quadTo__FFFF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2) { 122 SkScalar x1_ = SkFloatToScalar(x1); 123 SkScalar y1_ = SkFloatToScalar(y1); 124 SkScalar x2_ = SkFloatToScalar(x2); 125 SkScalar y2_ = SkFloatToScalar(y2); 126 obj->quadTo(x1_, y1_, x2_, y2_); 127 } 128 129 static void rQuadTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) { 130 SkScalar dx1_ = SkFloatToScalar(dx1); 131 SkScalar dy1_ = SkFloatToScalar(dy1); 132 SkScalar dx2_ = SkFloatToScalar(dx2); 133 SkScalar dy2_ = SkFloatToScalar(dy2); 134 obj->rQuadTo(dx1_, dy1_, dx2_, dy2_); 135 } 136 137 static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { 138 SkScalar x1_ = SkFloatToScalar(x1); 139 SkScalar y1_ = SkFloatToScalar(y1); 140 SkScalar x2_ = SkFloatToScalar(x2); 141 SkScalar y2_ = SkFloatToScalar(y2); 142 SkScalar x3_ = SkFloatToScalar(x3); 143 SkScalar y3_ = SkFloatToScalar(y3); 144 obj->cubicTo(x1_, y1_, x2_, y2_, x3_, y3_); 145 } 146 147 static void rCubicTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { 148 SkScalar x1_ = SkFloatToScalar(x1); 149 SkScalar y1_ = SkFloatToScalar(y1); 150 SkScalar x2_ = SkFloatToScalar(x2); 151 SkScalar y2_ = SkFloatToScalar(y2); 152 SkScalar x3_ = SkFloatToScalar(x3); 153 SkScalar y3_ = SkFloatToScalar(y3); 154 obj->rCubicTo(x1_, y1_, x2_, y2_, x3_, y3_); 155 } 156 157 static void arcTo(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) { 158 SkRect oval_; 159 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 160 SkScalar startAngle_ = SkFloatToScalar(startAngle); 161 SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle); 162 obj->arcTo(oval_, startAngle_, sweepAngle_, forceMoveTo); 163 } 164 165 static void close(JNIEnv* env, jobject clazz, SkPath* obj) { 166 obj->close(); 167 } 168 169 static void addRect__RectFI(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect, SkPath::Direction dir) { 170 SkRect rect_; 171 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 172 obj->addRect(rect_, dir); 173 } 174 175 static void addRect__FFFFI(JNIEnv* env, jobject clazz, SkPath* obj, jfloat left, jfloat top, jfloat right, jfloat bottom, SkPath::Direction dir) { 176 SkScalar left_ = SkFloatToScalar(left); 177 SkScalar top_ = SkFloatToScalar(top); 178 SkScalar right_ = SkFloatToScalar(right); 179 SkScalar bottom_ = SkFloatToScalar(bottom); 180 obj->addRect(left_, top_, right_, bottom_, dir); 181 } 182 183 static void addOval(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, SkPath::Direction dir) { 184 SkRect oval_; 185 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 186 obj->addOval(oval_, dir); 187 } 188 189 static void addCircle(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y, jfloat radius, SkPath::Direction dir) { 190 SkScalar x_ = SkFloatToScalar(x); 191 SkScalar y_ = SkFloatToScalar(y); 192 SkScalar radius_ = SkFloatToScalar(radius); 193 obj->addCircle(x_, y_, radius_, dir); 194 } 195 196 static void addArc(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, jfloat startAngle, jfloat sweepAngle) { 197 SkRect oval_; 198 GraphicsJNI::jrectf_to_rect(env, oval, &oval_); 199 SkScalar startAngle_ = SkFloatToScalar(startAngle); 200 SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle); 201 obj->addArc(oval_, startAngle_, sweepAngle_); 202 } 203 204 static void addRoundRectXY(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect, 205 jfloat rx, jfloat ry, SkPath::Direction dir) { 206 SkRect rect_; 207 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 208 SkScalar rx_ = SkFloatToScalar(rx); 209 SkScalar ry_ = SkFloatToScalar(ry); 210 obj->addRoundRect(rect_, rx_, ry_, dir); 211 } 212 213 static void addRoundRect8(JNIEnv* env, jobject, SkPath* obj, jobject rect, 214 jfloatArray array, SkPath::Direction dir) { 215 SkRect rect_; 216 GraphicsJNI::jrectf_to_rect(env, rect, &rect_); 217 AutoJavaFloatArray afa(env, array, 8); 218 const float* src = afa.ptr(); 219 SkScalar dst[8]; 220 221 for (int i = 0; i < 8; i++) { 222 dst[i] = SkFloatToScalar(src[i]); 223 } 224 obj->addRoundRect(rect_, dst, dir); 225 } 226 227 static void addPath__PathFF(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src, jfloat dx, jfloat dy) { 228 SkScalar dx_ = SkFloatToScalar(dx); 229 SkScalar dy_ = SkFloatToScalar(dy); 230 obj->addPath(*src, dx_, dy_); 231 } 232 233 static void addPath__Path(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src) { 234 obj->addPath(*src); 235 } 236 237 static void addPath__PathMatrix(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src, SkMatrix* matrix) { 238 obj->addPath(*src, *matrix); 239 } 240 241 static void offset__FFPath(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy, SkPath* dst) { 242 SkScalar dx_ = SkFloatToScalar(dx); 243 SkScalar dy_ = SkFloatToScalar(dy); 244 obj->offset(dx_, dy_, dst); 245 } 246 247 static void offset__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) { 248 SkScalar dx_ = SkFloatToScalar(dx); 249 SkScalar dy_ = SkFloatToScalar(dy); 250 obj->offset(dx_, dy_); 251 } 252 253 static void setLastPoint(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) { 254 SkScalar dx_ = SkFloatToScalar(dx); 255 SkScalar dy_ = SkFloatToScalar(dy); 256 obj->setLastPt(dx_, dy_); 257 } 258 259 static void transform__MatrixPath(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix, SkPath* dst) { 260 obj->transform(*matrix, dst); 261 } 262 263 static void transform__Matrix(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix) { 264 obj->transform(*matrix); 265 } 266 267 static jboolean op(JNIEnv* env, jobject clazz, SkPath* p1, SkPath* p2, SkPathOp op, SkPath* r) { 268 return Op(*p1, *p2, op, r); 269 } 270 271 272 typedef SkPoint (*bezierCalculation)(float t, const SkPoint* points); 273 274 static void addMove(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, 275 const SkPoint& point) { 276 float length = 0; 277 if (!lengths.empty()) { 278 length = lengths.back(); 279 } 280 segmentPoints.push_back(point); 281 lengths.push_back(length); 282 } 283 284 static void addLine(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, 285 const SkPoint& toPoint) { 286 if (segmentPoints.empty()) { 287 segmentPoints.push_back(SkPoint::Make(0, 0)); 288 lengths.push_back(0); 289 } else if (segmentPoints.back() == toPoint) { 290 return; // Empty line 291 } 292 float length = lengths.back() + SkPoint::Distance(segmentPoints.back(), toPoint); 293 segmentPoints.push_back(toPoint); 294 lengths.push_back(length); 295 } 296 297 static float cubicCoordinateCalculation(float t, float p0, float p1, float p2, float p3) { 298 float oneMinusT = 1 - t; 299 float oneMinusTSquared = oneMinusT * oneMinusT; 300 float oneMinusTCubed = oneMinusTSquared * oneMinusT; 301 float tSquared = t * t; 302 float tCubed = tSquared * t; 303 return (oneMinusTCubed * p0) + (3 * oneMinusTSquared * t * p1) 304 + (3 * oneMinusT * tSquared * p2) + (tCubed * p3); 305 } 306 307 static SkPoint cubicBezierCalculation(float t, const SkPoint* points) { 308 float x = cubicCoordinateCalculation(t, points[0].x(), points[1].x(), 309 points[2].x(), points[3].x()); 310 float y = cubicCoordinateCalculation(t, points[0].y(), points[1].y(), 311 points[2].y(), points[3].y()); 312 return SkPoint::Make(x, y); 313 } 314 315 static float quadraticCoordinateCalculation(float t, float p0, float p1, float p2) { 316 float oneMinusT = 1 - t; 317 return oneMinusT * ((oneMinusT * p0) + (t * p1)) + t * ((oneMinusT * p1) + (t * p2)); 318 } 319 320 static SkPoint quadraticBezierCalculation(float t, const SkPoint* points) { 321 float x = quadraticCoordinateCalculation(t, points[0].x(), points[1].x(), points[2].x()); 322 float y = quadraticCoordinateCalculation(t, points[0].y(), points[1].y(), points[2].y()); 323 return SkPoint::Make(x, y); 324 } 325 326 // Subdivide a section of the Bezier curve, set the mid-point and the mid-t value. 327 // Returns true if further subdivision is necessary as defined by errorSquared. 328 static bool subdividePoints(const SkPoint* points, bezierCalculation bezierFunction, 329 float t0, const SkPoint &p0, float t1, const SkPoint &p1, 330 float& midT, SkPoint &midPoint, float errorSquared) { 331 midT = (t1 + t0) / 2; 332 float midX = (p1.x() + p0.x()) / 2; 333 float midY = (p1.y() + p0.y()) / 2; 334 335 midPoint = (*bezierFunction)(midT, points); 336 float xError = midPoint.x() - midX; 337 float yError = midPoint.y() - midY; 338 float midErrorSquared = (xError * xError) + (yError * yError); 339 return midErrorSquared > errorSquared; 340 } 341 342 // Divides Bezier curves until linear interpolation is very close to accurate, using 343 // errorSquared as a metric. Cubic Bezier curves can have an inflection point that improperly 344 // short-circuit subdivision. If you imagine an S shape, the top and bottom points being the 345 // starting and end points, linear interpolation would mark the center where the curve places 346 // the point. It is clearly not the case that we can linearly interpolate at that point. 347 // doubleCheckDivision forces a second examination between subdivisions to ensure that linear 348 // interpolation works. 349 static void addBezier(const SkPoint* points, 350 bezierCalculation bezierFunction, std::vector<SkPoint>& segmentPoints, 351 std::vector<float>& lengths, float errorSquared, bool doubleCheckDivision) { 352 typedef std::map<float, SkPoint> PointMap; 353 PointMap tToPoint; 354 355 tToPoint[0] = (*bezierFunction)(0, points); 356 tToPoint[1] = (*bezierFunction)(1, points); 357 358 PointMap::iterator iter = tToPoint.begin(); 359 PointMap::iterator next = iter; 360 ++next; 361 while (next != tToPoint.end()) { 362 bool needsSubdivision = true; 363 SkPoint midPoint; 364 do { 365 float midT; 366 needsSubdivision = subdividePoints(points, bezierFunction, iter->first, 367 iter->second, next->first, next->second, midT, midPoint, errorSquared); 368 if (!needsSubdivision && doubleCheckDivision) { 369 SkPoint quarterPoint; 370 float quarterT; 371 needsSubdivision = subdividePoints(points, bezierFunction, iter->first, 372 iter->second, midT, midPoint, quarterT, quarterPoint, errorSquared); 373 if (needsSubdivision) { 374 // Found an inflection point. No need to double-check. 375 doubleCheckDivision = false; 376 } 377 } 378 if (needsSubdivision) { 379 next = tToPoint.insert(iter, PointMap::value_type(midT, midPoint)); 380 } 381 } while (needsSubdivision); 382 iter = next; 383 next++; 384 } 385 386 // Now that each division can use linear interpolation with less than the allowed error 387 for (iter = tToPoint.begin(); iter != tToPoint.end(); ++iter) { 388 addLine(segmentPoints, lengths, iter->second); 389 } 390 } 391 392 static void createVerbSegments(SkPath::Verb verb, const SkPoint* points, 393 std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, float errorSquared) { 394 switch (verb) { 395 case SkPath::kMove_Verb: 396 addMove(segmentPoints, lengths, points[0]); 397 break; 398 case SkPath::kClose_Verb: 399 case SkPath::kLine_Verb: 400 addLine(segmentPoints, lengths, points[1]); 401 break; 402 case SkPath::kQuad_Verb: 403 addBezier(points, quadraticBezierCalculation, segmentPoints, lengths, 404 errorSquared, false); 405 break; 406 case SkPath::kCubic_Verb: 407 addBezier(points, cubicBezierCalculation, segmentPoints, lengths, 408 errorSquared, true); 409 break; 410 default: 411 // Leave element as NULL, Conic sections are not supported. 412 break; 413 } 414 } 415 416 // Returns a float[] with each point along the path represented by 3 floats 417 // * fractional length along the path that the point resides 418 // * x coordinate 419 // * y coordinate 420 // Note that more than one point may have the same length along the path in 421 // the case of a move. 422 // NULL can be returned if the Path is empty. 423 static jfloatArray approximate(JNIEnv* env, jclass, SkPath* path, float acceptableError) 424 { 425 SkASSERT(path); 426 SkPath::Iter pathIter(*path, false); 427 SkPath::Verb verb; 428 SkPoint points[4]; 429 std::vector<SkPoint> segmentPoints; 430 std::vector<float> lengths; 431 float errorSquared = acceptableError * acceptableError; 432 433 while ((verb = pathIter.next(points)) != SkPath::kDone_Verb) { 434 createVerbSegments(verb, points, segmentPoints, lengths, errorSquared); 435 } 436 437 if (segmentPoints.empty()) { 438 return NULL; 439 } 440 441 size_t numPoints = segmentPoints.size(); 442 size_t approximationArraySize = numPoints * 3; 443 444 float* approximation = new float[approximationArraySize]; 445 float totalLength = lengths.back(); 446 447 int approximationIndex = 0; 448 for (int i = 0; i < numPoints; i++) { 449 const SkPoint& point = segmentPoints[i]; 450 approximation[approximationIndex++] = lengths[i] / totalLength; 451 approximation[approximationIndex++] = point.x(); 452 approximation[approximationIndex++] = point.y(); 453 } 454 455 jfloatArray result = env->NewFloatArray(approximationArraySize); 456 env->SetFloatArrayRegion(result, 0, approximationArraySize, approximation); 457 delete[] approximation; 458 return result; 459 } 460}; 461 462static JNINativeMethod methods[] = { 463 {"finalizer", "(I)V", (void*) SkPathGlue::finalizer}, 464 {"init1","()I", (void*) SkPathGlue::init1}, 465 {"init2","(I)I", (void*) SkPathGlue::init2}, 466 {"native_reset","(I)V", (void*) SkPathGlue::reset}, 467 {"native_rewind","(I)V", (void*) SkPathGlue::rewind}, 468 {"native_set","(II)V", (void*) SkPathGlue::assign}, 469 {"native_getFillType","(I)I", (void*) SkPathGlue::getFillType}, 470 {"native_setFillType","(II)V", (void*) SkPathGlue::setFillType}, 471 {"native_isEmpty","(I)Z", (void*) SkPathGlue::isEmpty}, 472 {"native_isRect","(ILandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect}, 473 {"native_computeBounds","(ILandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds}, 474 {"native_incReserve","(II)V", (void*) SkPathGlue::incReserve}, 475 {"native_moveTo","(IFF)V", (void*) SkPathGlue::moveTo__FF}, 476 {"native_rMoveTo","(IFF)V", (void*) SkPathGlue::rMoveTo}, 477 {"native_lineTo","(IFF)V", (void*) SkPathGlue::lineTo__FF}, 478 {"native_rLineTo","(IFF)V", (void*) SkPathGlue::rLineTo}, 479 {"native_quadTo","(IFFFF)V", (void*) SkPathGlue::quadTo__FFFF}, 480 {"native_rQuadTo","(IFFFF)V", (void*) SkPathGlue::rQuadTo}, 481 {"native_cubicTo","(IFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF}, 482 {"native_rCubicTo","(IFFFFFF)V", (void*) SkPathGlue::rCubicTo}, 483 {"native_arcTo","(ILandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo}, 484 {"native_close","(I)V", (void*) SkPathGlue::close}, 485 {"native_addRect","(ILandroid/graphics/RectF;I)V", (void*) SkPathGlue::addRect__RectFI}, 486 {"native_addRect","(IFFFFI)V", (void*) SkPathGlue::addRect__FFFFI}, 487 {"native_addOval","(ILandroid/graphics/RectF;I)V", (void*) SkPathGlue::addOval}, 488 {"native_addCircle","(IFFFI)V", (void*) SkPathGlue::addCircle}, 489 {"native_addArc","(ILandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc}, 490 {"native_addRoundRect","(ILandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY}, 491 {"native_addRoundRect","(ILandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8}, 492 {"native_addPath","(IIFF)V", (void*) SkPathGlue::addPath__PathFF}, 493 {"native_addPath","(II)V", (void*) SkPathGlue::addPath__Path}, 494 {"native_addPath","(III)V", (void*) SkPathGlue::addPath__PathMatrix}, 495 {"native_offset","(IFFI)V", (void*) SkPathGlue::offset__FFPath}, 496 {"native_offset","(IFF)V", (void*) SkPathGlue::offset__FF}, 497 {"native_setLastPoint","(IFF)V", (void*) SkPathGlue::setLastPoint}, 498 {"native_transform","(III)V", (void*) SkPathGlue::transform__MatrixPath}, 499 {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix}, 500 {"native_op","(IIII)Z", (void*) SkPathGlue::op}, 501 {"native_approximate", "(IF)[F", (void*) SkPathGlue::approximate}, 502}; 503 504int register_android_graphics_Path(JNIEnv* env) { 505 int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Path", methods, 506 sizeof(methods) / sizeof(methods[0])); 507 return result; 508} 509 510} 511