1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "sk_canvas.h" 9 #include "sk_data.h" 10 #include "sk_image.h" 11 #include "sk_paint.h" 12 #include "sk_path.h" 13 #include "sk_surface.h" 14 #include "sk_types_priv.h" 15 16 #include "SkCanvas.h" 17 #include "SkData.h" 18 #include "SkImage.h" 19 #include "SkMaskFilter.h" 20 #include "SkMatrix.h" 21 #include "SkPaint.h" 22 #include "SkPath.h" 23 #include "SkPictureRecorder.h" 24 #include "SkSurface.h" 25 26 const struct { 27 sk_colortype_t fC; 28 SkColorType fSK; 29 } gColorTypeMap[] = { 30 { UNKNOWN_SK_COLORTYPE, kUnknown_SkColorType }, 31 { RGBA_8888_SK_COLORTYPE, kRGBA_8888_SkColorType }, 32 { BGRA_8888_SK_COLORTYPE, kBGRA_8888_SkColorType }, 33 { ALPHA_8_SK_COLORTYPE, kAlpha_8_SkColorType }, 34 }; 35 36 const struct { 37 sk_alphatype_t fC; 38 SkAlphaType fSK; 39 } gAlphaTypeMap[] = { 40 { OPAQUE_SK_ALPHATYPE, kOpaque_SkAlphaType }, 41 { PREMUL_SK_ALPHATYPE, kPremul_SkAlphaType }, 42 { UNPREMUL_SK_ALPHATYPE, kUnpremul_SkAlphaType }, 43 }; 44 45 static bool from_c_colortype(sk_colortype_t cCT, SkColorType* skCT) { 46 for (size_t i = 0; i < SK_ARRAY_COUNT(gColorTypeMap); ++i) { 47 if (gColorTypeMap[i].fC == cCT) { 48 if (skCT) { 49 *skCT = gColorTypeMap[i].fSK; 50 } 51 return true; 52 } 53 } 54 return false; 55 } 56 57 static bool to_c_colortype(SkColorType skCT, sk_colortype_t* cCT) { 58 for (size_t i = 0; i < SK_ARRAY_COUNT(gColorTypeMap); ++i) { 59 if (gColorTypeMap[i].fSK == skCT) { 60 if (cCT) { 61 *cCT = gColorTypeMap[i].fC; 62 } 63 return true; 64 } 65 } 66 return false; 67 } 68 69 static bool from_c_alphatype(sk_alphatype_t cAT, SkAlphaType* skAT) { 70 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlphaTypeMap); ++i) { 71 if (gAlphaTypeMap[i].fC == cAT) { 72 if (skAT) { 73 *skAT = gAlphaTypeMap[i].fSK; 74 } 75 return true; 76 } 77 } 78 return false; 79 } 80 81 static bool from_c_info(const sk_imageinfo_t& cinfo, SkImageInfo* info) { 82 SkColorType ct; 83 SkAlphaType at; 84 85 if (!from_c_colortype(cinfo.colorType, &ct)) { 86 // optionally report error to client? 87 return false; 88 } 89 if (!from_c_alphatype(cinfo.alphaType, &at)) { 90 // optionally report error to client? 91 return false; 92 } 93 if (info) { 94 *info = SkImageInfo::Make(cinfo.width, cinfo.height, ct, at); 95 } 96 return true; 97 } 98 99 static void from_c_matrix(const sk_matrix_t* cmatrix, SkMatrix* matrix) { 100 matrix->setAll(cmatrix->mat[0], cmatrix->mat[1], cmatrix->mat[2], 101 cmatrix->mat[3], cmatrix->mat[4], cmatrix->mat[5], 102 cmatrix->mat[6], cmatrix->mat[7], cmatrix->mat[8]); 103 } 104 105 const struct { 106 sk_path_direction_t fC; 107 SkPath::Direction fSk; 108 } gPathDirMap[] = { 109 { CW_SK_PATH_DIRECTION, SkPath::kCW_Direction }, 110 { CCW_SK_PATH_DIRECTION, SkPath::kCCW_Direction }, 111 }; 112 113 static bool from_c_path_direction(sk_path_direction_t cdir, SkPath::Direction* dir) { 114 for (size_t i = 0; i < SK_ARRAY_COUNT(gPathDirMap); ++i) { 115 if (gPathDirMap[i].fC == cdir) { 116 if (dir) { 117 *dir = gPathDirMap[i].fSk; 118 } 119 return true; 120 } 121 } 122 return false; 123 } 124 125 static SkData* AsData(const sk_data_t* cdata) { 126 return reinterpret_cast<SkData*>(const_cast<sk_data_t*>(cdata)); 127 } 128 129 static sk_data_t* ToData(SkData* data) { 130 return reinterpret_cast<sk_data_t*>(data); 131 } 132 133 static sk_rect_t ToRect(const SkRect& rect) { 134 return reinterpret_cast<const sk_rect_t&>(rect); 135 } 136 137 static const SkRect& AsRect(const sk_rect_t& crect) { 138 return reinterpret_cast<const SkRect&>(crect); 139 } 140 141 static const SkRect* AsRect(const sk_rect_t* crect) { 142 return reinterpret_cast<const SkRect*>(crect); 143 } 144 145 static const SkPath& AsPath(const sk_path_t& cpath) { 146 return reinterpret_cast<const SkPath&>(cpath); 147 } 148 149 static SkPath* as_path(sk_path_t* cpath) { 150 return reinterpret_cast<SkPath*>(cpath); 151 } 152 153 static const SkImage* AsImage(const sk_image_t* cimage) { 154 return reinterpret_cast<const SkImage*>(cimage); 155 } 156 157 static sk_image_t* ToImage(SkImage* cimage) { 158 return reinterpret_cast<sk_image_t*>(cimage); 159 } 160 161 static sk_canvas_t* ToCanvas(SkCanvas* canvas) { 162 return reinterpret_cast<sk_canvas_t*>(canvas); 163 } 164 165 static SkCanvas* AsCanvas(sk_canvas_t* ccanvas) { 166 return reinterpret_cast<SkCanvas*>(ccanvas); 167 } 168 169 static SkPictureRecorder* AsPictureRecorder(sk_picture_recorder_t* crec) { 170 return reinterpret_cast<SkPictureRecorder*>(crec); 171 } 172 173 static sk_picture_recorder_t* ToPictureRecorder(SkPictureRecorder* rec) { 174 return reinterpret_cast<sk_picture_recorder_t*>(rec); 175 } 176 177 static const SkPicture* AsPicture(const sk_picture_t* cpic) { 178 return reinterpret_cast<const SkPicture*>(cpic); 179 } 180 181 static SkPicture* AsPicture(sk_picture_t* cpic) { 182 return reinterpret_cast<SkPicture*>(cpic); 183 } 184 185 static sk_picture_t* ToPicture(SkPicture* pic) { 186 return reinterpret_cast<sk_picture_t*>(pic); 187 } 188 189 /////////////////////////////////////////////////////////////////////////////////////////// 190 191 sk_colortype_t sk_colortype_get_default_8888() { 192 sk_colortype_t ct; 193 if (!to_c_colortype(kN32_SkColorType, &ct)) { 194 ct = UNKNOWN_SK_COLORTYPE; 195 } 196 return ct; 197 } 198 199 /////////////////////////////////////////////////////////////////////////////////////////// 200 201 sk_image_t* sk_image_new_raster_copy(const sk_imageinfo_t* cinfo, const void* pixels, 202 size_t rowBytes) { 203 SkImageInfo info; 204 if (!from_c_info(*cinfo, &info)) { 205 return NULL; 206 } 207 return (sk_image_t*)SkImage::NewRasterCopy(info, pixels, rowBytes); 208 } 209 210 sk_image_t* sk_image_new_from_data(const sk_data_t* cdata) { 211 return ToImage(SkImage::NewFromData(AsData(cdata))); 212 } 213 214 sk_data_t* sk_image_encode(const sk_image_t* cimage) { 215 return ToData(AsImage(cimage)->encode()); 216 } 217 218 void sk_image_ref(const sk_image_t* cimage) { 219 AsImage(cimage)->ref(); 220 } 221 222 void sk_image_unref(const sk_image_t* cimage) { 223 AsImage(cimage)->unref(); 224 } 225 226 int sk_image_get_width(const sk_image_t* cimage) { 227 return AsImage(cimage)->width(); 228 } 229 230 int sk_image_get_height(const sk_image_t* cimage) { 231 return AsImage(cimage)->height(); 232 } 233 234 uint32_t sk_image_get_unique_id(const sk_image_t* cimage) { 235 return AsImage(cimage)->uniqueID(); 236 } 237 238 /////////////////////////////////////////////////////////////////////////////////////////// 239 240 sk_path_t* sk_path_new() { 241 return (sk_path_t*)SkNEW(SkPath); 242 } 243 244 void sk_path_delete(sk_path_t* cpath) { 245 SkDELETE(as_path(cpath)); 246 } 247 248 void sk_path_move_to(sk_path_t* cpath, float x, float y) { 249 as_path(cpath)->moveTo(x, y); 250 } 251 252 void sk_path_line_to(sk_path_t* cpath, float x, float y) { 253 as_path(cpath)->lineTo(x, y); 254 } 255 256 void sk_path_quad_to(sk_path_t* cpath, float x0, float y0, float x1, float y1) { 257 as_path(cpath)->quadTo(x0, y0, x1, y1); 258 } 259 260 void sk_path_conic_to(sk_path_t* cpath, float x0, float y0, float x1, float y1, float w) { 261 as_path(cpath)->conicTo(x0, y0, x1, y1, w); 262 } 263 264 void sk_path_cubic_to(sk_path_t* cpath, float x0, float y0, float x1, float y1, float x2, float y2) { 265 as_path(cpath)->cubicTo(x0, y0, x1, y1, x2, y2); 266 } 267 268 void sk_path_close(sk_path_t* cpath) { 269 as_path(cpath)->close(); 270 } 271 272 void sk_path_add_rect(sk_path_t* cpath, const sk_rect_t* crect, sk_path_direction_t cdir) { 273 SkPath::Direction dir; 274 if (!from_c_path_direction(cdir, &dir)) { 275 return; 276 } 277 as_path(cpath)->addRect(AsRect(*crect), dir); 278 } 279 280 void sk_path_add_oval(sk_path_t* cpath, const sk_rect_t* crect, sk_path_direction_t cdir) { 281 SkPath::Direction dir; 282 if (!from_c_path_direction(cdir, &dir)) { 283 return; 284 } 285 as_path(cpath)->addOval(AsRect(*crect), dir); 286 } 287 288 bool sk_path_get_bounds(const sk_path_t* cpath, sk_rect_t* crect) { 289 const SkPath& path = AsPath(*cpath); 290 291 if (path.isEmpty()) { 292 if (crect) { 293 *crect = ToRect(SkRect::MakeEmpty()); 294 } 295 return false; 296 } 297 298 if (crect) { 299 *crect = ToRect(path.getBounds()); 300 } 301 return true; 302 } 303 304 /////////////////////////////////////////////////////////////////////////////////////////// 305 306 void sk_canvas_save(sk_canvas_t* ccanvas) { 307 AsCanvas(ccanvas)->save(); 308 } 309 310 void sk_canvas_save_layer(sk_canvas_t* ccanvas, const sk_rect_t* crect, const sk_paint_t* cpaint) { 311 AsCanvas(ccanvas)->drawRect(AsRect(*crect), AsPaint(*cpaint)); 312 } 313 314 void sk_canvas_restore(sk_canvas_t* ccanvas) { 315 AsCanvas(ccanvas)->restore(); 316 } 317 318 void sk_canvas_translate(sk_canvas_t* ccanvas, float dx, float dy) { 319 AsCanvas(ccanvas)->translate(dx, dy); 320 } 321 322 void sk_canvas_scale(sk_canvas_t* ccanvas, float sx, float sy) { 323 AsCanvas(ccanvas)->scale(sx, sy); 324 } 325 326 void sk_canvas_rotate_degress(sk_canvas_t* ccanvas, float degrees) { 327 AsCanvas(ccanvas)->rotate(degrees); 328 } 329 330 void sk_canvas_rotate_radians(sk_canvas_t* ccanvas, float radians) { 331 AsCanvas(ccanvas)->rotate(SkRadiansToDegrees(radians)); 332 } 333 334 void sk_canvas_skew(sk_canvas_t* ccanvas, float sx, float sy) { 335 AsCanvas(ccanvas)->skew(sx, sy); 336 } 337 338 void sk_canvas_concat(sk_canvas_t* ccanvas, const sk_matrix_t* cmatrix) { 339 SkASSERT(cmatrix); 340 SkMatrix matrix; 341 from_c_matrix(cmatrix, &matrix); 342 AsCanvas(ccanvas)->concat(matrix); 343 } 344 345 void sk_canvas_clip_rect(sk_canvas_t* ccanvas, const sk_rect_t* crect) { 346 AsCanvas(ccanvas)->clipRect(AsRect(*crect)); 347 } 348 349 void sk_canvas_clip_path(sk_canvas_t* ccanvas, const sk_path_t* cpath) { 350 AsCanvas(ccanvas)->clipPath(AsPath(*cpath)); 351 } 352 353 void sk_canvas_draw_paint(sk_canvas_t* ccanvas, const sk_paint_t* cpaint) { 354 AsCanvas(ccanvas)->drawPaint(AsPaint(*cpaint)); 355 } 356 357 void sk_canvas_draw_rect(sk_canvas_t* ccanvas, const sk_rect_t* crect, const sk_paint_t* cpaint) { 358 AsCanvas(ccanvas)->drawRect(AsRect(*crect), AsPaint(*cpaint)); 359 } 360 361 void sk_canvas_draw_oval(sk_canvas_t* ccanvas, const sk_rect_t* crect, const sk_paint_t* cpaint) { 362 AsCanvas(ccanvas)->drawOval(AsRect(*crect), AsPaint(*cpaint)); 363 } 364 365 void sk_canvas_draw_path(sk_canvas_t* ccanvas, const sk_path_t* cpath, const sk_paint_t* cpaint) { 366 AsCanvas(ccanvas)->drawPath(AsPath(*cpath), AsPaint(*cpaint)); 367 } 368 369 void sk_canvas_draw_image(sk_canvas_t* ccanvas, const sk_image_t* cimage, float x, float y, 370 const sk_paint_t* cpaint) { 371 AsCanvas(ccanvas)->drawImage(AsImage(cimage), x, y, AsPaint(cpaint)); 372 } 373 374 void sk_canvas_draw_image_rect(sk_canvas_t* ccanvas, const sk_image_t* cimage, 375 const sk_rect_t* csrcR, const sk_rect_t* cdstR, 376 const sk_paint_t* cpaint) { 377 AsCanvas(ccanvas)->drawImageRect(AsImage(cimage), AsRect(csrcR), AsRect(*cdstR), AsPaint(cpaint)); 378 } 379 380 void sk_canvas_draw_picture(sk_canvas_t* ccanvas, const sk_picture_t* cpicture, 381 const sk_matrix_t* cmatrix, const sk_paint_t* cpaint) { 382 const SkMatrix* matrixPtr = NULL; 383 SkMatrix matrix; 384 if (cmatrix) { 385 from_c_matrix(cmatrix, &matrix); 386 matrixPtr = &matrix; 387 } 388 AsCanvas(ccanvas)->drawPicture(AsPicture(cpicture), matrixPtr, AsPaint(cpaint)); 389 } 390 391 /////////////////////////////////////////////////////////////////////////////////////////// 392 393 sk_surface_t* sk_surface_new_raster(const sk_imageinfo_t* cinfo) { 394 SkImageInfo info; 395 if (!from_c_info(*cinfo, &info)) { 396 return NULL; 397 } 398 return (sk_surface_t*)SkSurface::NewRaster(info); 399 } 400 401 sk_surface_t* sk_surface_new_raster_direct(const sk_imageinfo_t* cinfo, void* pixels, 402 size_t rowBytes) { 403 SkImageInfo info; 404 if (!from_c_info(*cinfo, &info)) { 405 return NULL; 406 } 407 return (sk_surface_t*)SkSurface::NewRasterDirect(info, pixels, rowBytes); 408 } 409 410 void sk_surface_unref(sk_surface_t* csurf) { 411 SkSafeUnref((SkSurface*)csurf); 412 } 413 414 sk_canvas_t* sk_surface_get_canvas(sk_surface_t* csurf) { 415 SkSurface* surf = (SkSurface*)csurf; 416 return (sk_canvas_t*)surf->getCanvas(); 417 } 418 419 sk_image_t* sk_surface_new_image_snapshot(sk_surface_t* csurf) { 420 SkSurface* surf = (SkSurface*)csurf; 421 return (sk_image_t*)surf->newImageSnapshot(); 422 } 423 424 /////////////////////////////////////////////////////////////////////////////////////////// 425 426 sk_picture_recorder_t* sk_picture_recorder_new() { 427 return ToPictureRecorder(new SkPictureRecorder); 428 } 429 430 void sk_picture_recorder_delete(sk_picture_recorder_t* crec) { 431 delete AsPictureRecorder(crec); 432 } 433 434 sk_canvas_t* sk_picture_recorder_begin_recording(sk_picture_recorder_t* crec, 435 const sk_rect_t* cbounds) { 436 return ToCanvas(AsPictureRecorder(crec)->beginRecording(AsRect(*cbounds))); 437 } 438 439 sk_picture_t* sk_picture_recorder_end_recording(sk_picture_recorder_t* crec) { 440 return ToPicture(AsPictureRecorder(crec)->endRecording()); 441 } 442 443 void sk_picture_ref(sk_picture_t* cpic) { 444 SkSafeRef(AsPicture(cpic)); 445 } 446 447 void sk_picture_unref(sk_picture_t* cpic) { 448 SkSafeUnref(AsPicture(cpic)); 449 } 450 451 uint32_t sk_picture_get_unique_id(sk_picture_t* cpic) { 452 return AsPicture(cpic)->uniqueID(); 453 } 454 455 sk_rect_t sk_picture_get_bounds(sk_picture_t* cpic) { 456 return ToRect(AsPicture(cpic)->cullRect()); 457 } 458 459 /////////////////////////////////////////////////////////////////////////////////////////// 460 461 #include "../../include/effects/SkGradientShader.h" 462 #include "sk_shader.h" 463 464 const struct { 465 sk_shader_tilemode_t fC; 466 SkShader::TileMode fSK; 467 } gTileModeMap[] = { 468 { CLAMP_SK_SHADER_TILEMODE, SkShader::kClamp_TileMode }, 469 { REPEAT_SK_SHADER_TILEMODE, SkShader::kRepeat_TileMode }, 470 { MIRROR_SK_SHADER_TILEMODE, SkShader::kMirror_TileMode }, 471 }; 472 473 static bool from_c_tilemode(sk_shader_tilemode_t cMode, SkShader::TileMode* skMode) { 474 for (size_t i = 0; i < SK_ARRAY_COUNT(gTileModeMap); ++i) { 475 if (cMode == gTileModeMap[i].fC) { 476 if (skMode) { 477 *skMode = gTileModeMap[i].fSK; 478 } 479 return true; 480 } 481 } 482 return false; 483 } 484 485 void sk_shader_ref(sk_shader_t* cshader) { 486 SkSafeRef(AsShader(cshader)); 487 } 488 489 void sk_shader_unref(sk_shader_t* cshader) { 490 SkSafeUnref(AsShader(cshader)); 491 } 492 493 sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t pts[2], 494 const sk_color_t colors[], 495 const float colorPos[], 496 int colorCount, 497 sk_shader_tilemode_t cmode, 498 const sk_matrix_t* cmatrix) { 499 SkShader::TileMode mode; 500 if (!from_c_tilemode(cmode, &mode)) { 501 return NULL; 502 } 503 SkMatrix matrix; 504 if (cmatrix) { 505 from_c_matrix(cmatrix, &matrix); 506 } else { 507 matrix.setIdentity(); 508 } 509 SkShader* s = SkGradientShader::CreateLinear(reinterpret_cast<const SkPoint*>(pts), 510 reinterpret_cast<const SkColor*>(colors), 511 colorPos, colorCount, mode, 0, &matrix); 512 return (sk_shader_t*)s; 513 } 514 515 /////////////////////////////////////////////////////////////////////////////////////////// 516 517 #include "../../include/effects/SkBlurMaskFilter.h" 518 #include "sk_maskfilter.h" 519 520 const struct { 521 sk_blurstyle_t fC; 522 SkBlurStyle fSk; 523 } gBlurStylePairs[] = { 524 { NORMAL_SK_BLUR_STYLE, kNormal_SkBlurStyle }, 525 { SOLID_SK_BLUR_STYLE, kSolid_SkBlurStyle }, 526 { OUTER_SK_BLUR_STYLE, kOuter_SkBlurStyle }, 527 { INNER_SK_BLUR_STYLE, kInner_SkBlurStyle }, 528 }; 529 530 static bool find_blurstyle(sk_blurstyle_t csrc, SkBlurStyle* dst) { 531 for (size_t i = 0; i < SK_ARRAY_COUNT(gBlurStylePairs); ++i) { 532 if (gBlurStylePairs[i].fC == csrc) { 533 if (dst) { 534 *dst = gBlurStylePairs[i].fSk; 535 } 536 return true; 537 } 538 } 539 return false; 540 } 541 542 void sk_maskfilter_ref(sk_maskfilter_t* cfilter) { 543 SkSafeRef(AsMaskFilter(cfilter)); 544 } 545 546 void sk_maskfilter_unref(sk_maskfilter_t* cfilter) { 547 SkSafeUnref(AsMaskFilter(cfilter)); 548 } 549 550 sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t cstyle, float sigma) { 551 SkBlurStyle style; 552 if (!find_blurstyle(cstyle, &style)) { 553 return NULL; 554 } 555 return ToMaskFilter(SkBlurMaskFilter::Create(style, sigma)); 556 } 557 558 /////////////////////////////////////////////////////////////////////////////////////////// 559 560 sk_data_t* sk_data_new_with_copy(const void* src, size_t length) { 561 return ToData(SkData::NewWithCopy(src, length)); 562 } 563 564 sk_data_t* sk_data_new_from_malloc(const void* memory, size_t length) { 565 return ToData(SkData::NewFromMalloc(memory, length)); 566 } 567 568 sk_data_t* sk_data_new_subset(const sk_data_t* csrc, size_t offset, size_t length) { 569 return ToData(SkData::NewSubset(AsData(csrc), offset, length)); 570 } 571 572 void sk_data_ref(const sk_data_t* cdata) { 573 SkSafeRef(AsData(cdata)); 574 } 575 576 void sk_data_unref(const sk_data_t* cdata) { 577 SkSafeUnref(AsData(cdata)); 578 } 579 580 size_t sk_data_get_size(const sk_data_t* cdata) { 581 return AsData(cdata)->size(); 582 } 583 584 const void* sk_data_get_data(const sk_data_t* cdata) { 585 return AsData(cdata)->data(); 586 } 587 588 /////////////////////////////////////////////////////////////////////////////////////////// 589 /////////////////////////////////////////////////////////////////////////////////////////// 590 591 void sk_test_capi(SkCanvas* canvas) { 592 sk_imageinfo_t cinfo; 593 cinfo.width = 100; 594 cinfo.height = 100; 595 cinfo.colorType = (sk_colortype_t)kN32_SkColorType; 596 cinfo.alphaType = (sk_alphatype_t)kPremul_SkAlphaType; 597 598 sk_surface_t* csurface = sk_surface_new_raster(&cinfo); 599 sk_canvas_t* ccanvas = sk_surface_get_canvas(csurface); 600 601 sk_paint_t* cpaint = sk_paint_new(); 602 sk_paint_set_antialias(cpaint, true); 603 sk_paint_set_color(cpaint, 0xFFFF0000); 604 605 sk_rect_t cr = { 5, 5, 95, 95 }; 606 sk_canvas_draw_oval(ccanvas, &cr, cpaint); 607 608 cr.left += 25; 609 cr.top += 25; 610 cr.right -= 25; 611 cr.bottom -= 25; 612 sk_paint_set_color(cpaint, 0xFF00FF00); 613 sk_canvas_draw_rect(ccanvas, &cr, cpaint); 614 615 sk_path_t* cpath = sk_path_new(); 616 sk_path_move_to(cpath, 50, 50); 617 sk_path_line_to(cpath, 100, 100); 618 sk_path_line_to(cpath, 50, 100); 619 sk_path_close(cpath); 620 621 sk_canvas_draw_path(ccanvas, cpath, cpaint); 622 623 sk_image_t* cimage = sk_surface_new_image_snapshot(csurface); 624 625 // HERE WE CROSS THE C..C++ boundary 626 canvas->drawImage((const SkImage*)cimage, 20, 20, NULL); 627 628 sk_path_delete(cpath); 629 sk_paint_delete(cpaint); 630 sk_image_unref(cimage); 631 sk_surface_unref(csurface); 632 } 633