1 module skia.SKCanvas; 2 3 import skia.Exceptions; 4 import skia.SkiaApi; 5 import skia.SKObject; 6 import skia.SKTextBlob; 7 import skia.MathTypes; 8 import skia.Definitions; 9 import skia.SKPath; 10 import skia.SKBitmap; 11 import skia.SKPaint; 12 import skia.SKMatrix; 13 import skia.SKColor; 14 import skia.SKImage; 15 import skia.SKFont; 16 import skia.SKRegion; 17 import skia.SKData; 18 import skia.SKRoundRect; 19 import skia.SKPicture; 20 import skia.SKDrawable; 21 import skia.SKSurface; 22 import skia.SKVertices; 23 import skia.IDisposable; 24 import skia.SKColors; 25 26 import std.typecons; 27 28 import std.experimental.logger; 29 30 // TODO: carefully consider the `PeekPixels`, `ReadPixels` 31 32 class SKCanvas : SKObject 33 { 34 private enum PatchCornerCount = 4; 35 private enum PatchCubicsCount = 12; 36 37 this (void* handle, bool owns) 38 { 39 super(handle, owns); 40 } 41 42 this (SKBitmap bitmap) 43 { 44 this (null, true); 45 if (bitmap is null) 46 throw new ArgumentNullException (bitmap.stringof); 47 Handle = SkiaApi.sk_canvas_new_from_bitmap (cast(sk_bitmap_t*)bitmap.Handle); 48 } 49 50 // protected override void Dispose (bool disposing) 51 // { 52 // return super.Dispose (disposing); 53 // } 54 55 // override void Dispose() 56 // { 57 // return super.Dispose(); 58 // } 59 60 protected override void DisposeNative () 61 { 62 return SkiaApi.sk_canvas_destroy (cast(sk_canvas_t*)Handle); 63 } 64 65 void Discard () 66 { 67 return SkiaApi.sk_canvas_discard (cast(sk_canvas_t*)Handle); 68 } 69 70 // QuickReject 71 72 bool QuickReject (SKRect rect) 73 { 74 return SkiaApi.sk_canvas_quick_reject (cast(sk_canvas_t*)Handle, &rect); 75 } 76 77 bool QuickReject (SKPath path) 78 { 79 if (path is null) 80 throw new ArgumentNullException (path.stringof); 81 return path.IsEmpty || QuickReject (path.Bounds); 82 } 83 84 // Save* 85 86 int Save () 87 { 88 if (Handle is null) 89 throw new ObjectDisposedException ("SKCanvas"); 90 return SkiaApi.sk_canvas_save (cast(sk_canvas_t*)Handle); 91 } 92 93 int SaveLayer (SKRect limit, SKPaint paint) 94 { 95 return SkiaApi.sk_canvas_save_layer (cast(sk_canvas_t*)Handle, &limit, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 96 } 97 98 int SaveLayer (SKPaint paint) 99 { 100 return SkiaApi.sk_canvas_save_layer (cast(sk_canvas_t*)Handle, null, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 101 } 102 103 int SaveLayer () 104 { 105 return SaveLayer (null); 106 } 107 108 // DrawColor 109 110 void DrawColor (SKColor color, SKBlendMode mode = SKBlendMode.Src) 111 { 112 SkiaApi.sk_canvas_draw_color (cast(sk_canvas_t*)Handle, cast(uint)color, mode); 113 } 114 115 // DrawLine 116 117 void DrawLine (SKPoint p0, SKPoint p1, SKPaint paint) 118 { 119 DrawLine (p0.X, p0.Y, p1.X, p1.Y, paint); 120 } 121 122 void DrawLine (float x0, float y0, float x1, float y1, SKPaint paint) 123 { 124 if (paint is null) 125 throw new ArgumentNullException (paint.stringof); 126 SkiaApi.sk_canvas_draw_line (cast(sk_canvas_t*)Handle, x0, y0, x1, y1, cast(sk_paint_t*)paint.Handle); 127 } 128 129 // Clear 130 131 void Clear () 132 { 133 DrawColor (SKColors.Empty, SKBlendMode.Src); 134 } 135 136 void Clear (SKColor color) 137 { 138 DrawColor (color, SKBlendMode.Src); 139 } 140 141 // Restore* 142 143 void Restore () 144 { 145 SkiaApi.sk_canvas_restore (cast(sk_canvas_t*)Handle); 146 } 147 148 void RestoreToCount (int count) 149 { 150 SkiaApi.sk_canvas_restore_to_count (cast(sk_canvas_t*)Handle, count); 151 } 152 153 // Translate 154 155 void Translate (float dx, float dy) 156 { 157 SkiaApi.sk_canvas_translate (cast(sk_canvas_t*)Handle, dx, dy); 158 } 159 160 void Translate (SKPoint point) 161 { 162 SkiaApi.sk_canvas_translate (cast(sk_canvas_t*)Handle, point.X, point.Y); 163 } 164 165 // Scale 166 167 void Scale (float s) 168 { 169 SkiaApi.sk_canvas_scale (cast(sk_canvas_t*)Handle, s, s); 170 } 171 172 void Scale (float sx, float sy) 173 { 174 SkiaApi.sk_canvas_scale (cast(sk_canvas_t*)Handle, sx, sy); 175 } 176 177 void Scale (SKPoint size) 178 { 179 SkiaApi.sk_canvas_scale (cast(sk_canvas_t*)Handle, size.X, size.Y); 180 } 181 182 void Scale (float sx, float sy, float px, float py) 183 { 184 Translate (px, py); 185 Scale (sx, sy); 186 Translate (-px, -py); 187 } 188 189 // Rotate* 190 191 void RotateDegrees (float degrees) 192 { 193 SkiaApi.sk_canvas_rotate_degrees (cast(sk_canvas_t*)Handle, degrees); 194 } 195 196 void RotateRadians (float radians) 197 { 198 SkiaApi.sk_canvas_rotate_radians (cast(sk_canvas_t*)Handle, radians); 199 } 200 201 void RotateDegrees (float degrees, float px, float py) 202 { 203 Translate (px, py); 204 RotateDegrees (degrees); 205 Translate (-px, -py); 206 } 207 208 void RotateRadians (float radians, float px, float py) 209 { 210 Translate (px, py); 211 RotateRadians (radians); 212 Translate (-px, -py); 213 } 214 215 // Skew 216 217 void Skew (float sx, float sy) 218 { 219 SkiaApi.sk_canvas_skew (cast(sk_canvas_t*)Handle, sx, sy); 220 } 221 222 void Skew (SKPoint skew) 223 { 224 SkiaApi.sk_canvas_skew (cast(sk_canvas_t*)Handle, skew.X, skew.Y); 225 } 226 227 // Concat 228 229 void Concat (ref SKMatrix m) 230 { 231 SKMatrix* ptr = &m; 232 SkiaApi.sk_canvas_concat (cast(sk_canvas_t*)Handle, ptr); 233 } 234 235 // Clip* 236 237 void ClipRect (SKRect rect, SKClipOperation operation = SKClipOperation.Intersect, bool antialias = false) 238 { 239 SkiaApi.sk_canvas_clip_rect_with_operation (cast(sk_canvas_t*)Handle, &rect, operation, antialias); 240 } 241 242 void ClipRoundRect (SKRoundRect rect, SKClipOperation operation = SKClipOperation.Intersect, bool antialias = false) 243 { 244 if (rect is null) 245 throw new ArgumentNullException (rect.stringof); 246 247 SkiaApi.sk_canvas_clip_rrect_with_operation (cast(sk_canvas_t*)Handle, cast(sk_rrect_t*)rect.Handle, operation, antialias); 248 } 249 250 void ClipPath (SKPath path, SKClipOperation operation = SKClipOperation.Intersect, bool antialias = false) 251 { 252 if (path is null) 253 throw new ArgumentNullException (path.stringof); 254 255 SkiaApi.sk_canvas_clip_path_with_operation (cast(sk_canvas_t*)Handle,cast(sk_path_t*) path.Handle, operation, antialias); 256 } 257 258 void ClipRegion (SKRegion region, SKClipOperation operation = SKClipOperation.Intersect) 259 { 260 if (region is null) 261 throw new ArgumentNullException (region.stringof); 262 263 SkiaApi.sk_canvas_clip_region (cast(sk_canvas_t*)Handle, cast(sk_region_t*)region.Handle, operation); 264 } 265 266 SKRect LocalClipBounds() { 267 SKRect bounds; 268 GetLocalClipBounds (bounds); 269 return bounds; 270 } 271 272 SKRectI DeviceClipBounds() { 273 SKRectI bounds; 274 GetDeviceClipBounds (bounds); 275 return bounds; 276 } 277 278 bool IsClipEmpty() { return SkiaApi.sk_canvas_is_clip_empty (cast(sk_canvas_t*)Handle); } 279 280 bool IsClipRect() { return SkiaApi.sk_canvas_is_clip_rect (cast(sk_canvas_t*)Handle); } 281 282 bool GetLocalClipBounds (ref SKRect bounds) 283 { 284 SKRect* b = &bounds; 285 return SkiaApi.sk_canvas_get_local_clip_bounds (cast(sk_canvas_t*)Handle, b); 286 } 287 288 bool GetDeviceClipBounds (ref SKRectI bounds) 289 { 290 SKRectI* b = &bounds; 291 return SkiaApi.sk_canvas_get_device_clip_bounds (cast(sk_canvas_t*)Handle, b); 292 } 293 294 // DrawPaint 295 296 void DrawPaint (SKPaint paint) 297 { 298 if (paint is null) 299 throw new ArgumentNullException (paint.stringof); 300 SkiaApi.sk_canvas_draw_paint (cast(sk_canvas_t*)Handle, cast(sk_paint_t*)paint.Handle); 301 } 302 303 // DrawRegion 304 305 void DrawRegion (SKRegion region, SKPaint paint) 306 { 307 if (region is null) 308 throw new ArgumentNullException (region.stringof); 309 if (paint is null) 310 throw new ArgumentNullException (paint.stringof); 311 SkiaApi.sk_canvas_draw_region (cast(sk_canvas_t*)Handle, cast(sk_region_t*)region.Handle, cast(sk_paint_t*)paint.Handle); 312 } 313 314 // DrawRect 315 316 void DrawRect (float x, float y, float w, float h, SKPaint paint) 317 { 318 DrawRect (SKRect.Create (x, y, w, h), paint); 319 } 320 321 void DrawRect (SKRect rect, SKPaint paint) 322 { 323 if (paint is null) 324 throw new ArgumentNullException (paint.stringof); 325 SkiaApi.sk_canvas_draw_rect (cast(sk_canvas_t*)Handle, &rect, cast(sk_paint_t*)paint.Handle); 326 } 327 328 // DrawRoundRect 329 330 void DrawRoundRect (SKRoundRect rect, SKPaint paint) 331 { 332 if (rect is null) 333 throw new ArgumentNullException (rect.stringof); 334 if (paint is null) 335 throw new ArgumentNullException (paint.stringof); 336 SkiaApi.sk_canvas_draw_rrect (cast(sk_canvas_t*)Handle, cast(sk_rrect_t*)rect.Handle, cast(sk_paint_t*)paint.Handle); 337 } 338 339 void DrawRoundRect (float x, float y, float w, float h, float rx, float ry, SKPaint paint) 340 { 341 DrawRoundRect (SKRect.Create (x, y, w, h), rx, ry, paint); 342 } 343 344 void DrawRoundRect (SKRect rect, float rx, float ry, SKPaint paint) 345 { 346 if (paint is null) 347 throw new ArgumentNullException (paint.stringof); 348 SkiaApi.sk_canvas_draw_round_rect (cast(sk_canvas_t*)Handle, &rect, rx, ry, cast(sk_paint_t*)paint.Handle); 349 } 350 351 void DrawRoundRect (SKRect rect, SKSize r, SKPaint paint) 352 { 353 DrawRoundRect (rect, r.Width, r.Height, paint); 354 } 355 356 // DrawOval 357 358 void DrawOval (float cx, float cy, float rx, float ry, SKPaint paint) 359 { 360 DrawOval (SKRect (cx - rx, cy - ry, cx + rx, cy + ry), paint); 361 } 362 363 void DrawOval (SKPoint c, SKSize r, SKPaint paint) 364 { 365 DrawOval (c.X, c.Y, r.Width, r.Height, paint); 366 } 367 368 void DrawOval (SKRect rect, SKPaint paint) 369 { 370 if (paint is null) 371 throw new ArgumentNullException (paint.stringof); 372 SkiaApi.sk_canvas_draw_oval (cast(sk_canvas_t*)Handle, &rect, cast(sk_paint_t*)paint.Handle); 373 } 374 375 // DrawCircle 376 377 void DrawCircle (float cx, float cy, float radius, SKPaint paint) 378 { 379 if (paint is null) 380 throw new ArgumentNullException (paint.stringof); 381 SkiaApi.sk_canvas_draw_circle (cast(sk_canvas_t*)Handle, cx, cy, radius, cast(sk_paint_t*)paint.Handle); 382 } 383 384 void DrawCircle (SKPoint c, float radius, SKPaint paint) 385 { 386 DrawCircle (c.X, c.Y, radius, paint); 387 } 388 389 // DrawPath 390 391 void DrawPath (SKPath path, SKPaint paint) 392 { 393 if (paint is null) 394 throw new ArgumentNullException (paint.stringof); 395 if (path is null) 396 throw new ArgumentNullException (path.stringof); 397 SkiaApi.sk_canvas_draw_path (cast(sk_canvas_t*)Handle, cast(sk_path_t*)path.Handle, cast(sk_paint_t*)paint.Handle); 398 } 399 400 // DrawPoints 401 402 void DrawPoints (SKPointMode mode, SKPoint[] points, SKPaint paint) 403 { 404 if (paint is null) 405 throw new ArgumentNullException (paint.stringof); 406 if (points is null) 407 throw new ArgumentNullException (points.stringof); 408 SKPoint* p = points.ptr; 409 SkiaApi.sk_canvas_draw_points (cast(sk_canvas_t*)Handle, mode, cast(void*)points.length, p, cast(sk_paint_t*)paint.Handle); 410 } 411 412 // DrawPoint 413 414 void DrawPoint (SKPoint p, SKPaint paint) 415 { 416 DrawPoint (p.X, p.Y, paint); 417 } 418 419 void DrawPoint (float x, float y, SKPaint paint) 420 { 421 if (paint is null) 422 throw new ArgumentNullException (paint.stringof); 423 SkiaApi.sk_canvas_draw_point (cast(sk_canvas_t*)Handle, x, y, cast(sk_paint_t*)paint.Handle); 424 } 425 426 void DrawPoint (SKPoint p, SKColor color) 427 { 428 DrawPoint (p.X, p.Y, color); 429 } 430 431 void DrawPoint (float x, float y, SKColor color) 432 { 433 SKPaint paint = new SKPaint(); 434 scope(exit) { 435 paint.Dispose(); 436 } 437 438 paint.Color = color; 439 paint.BlendMode = SKBlendMode.Src; 440 441 DrawPoint (x, y, paint); 442 } 443 444 // DrawImage 445 446 void DrawImage (SKImage image, SKPoint p, SKPaint paint = null) 447 { 448 DrawImage (image, p.X, p.Y, paint); 449 } 450 451 void DrawImage (SKImage image, float x, float y, SKPaint paint = null) 452 { 453 if (image is null) 454 throw new ArgumentNullException (image.stringof); 455 SkiaApi.sk_canvas_draw_image (cast(sk_canvas_t*)Handle, cast(sk_image_t*)image.Handle, x, y, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 456 } 457 458 void DrawImage (SKImage image, SKRect dest, SKPaint paint = null) 459 { 460 if (image is null) 461 throw new ArgumentNullException (image.stringof); 462 SkiaApi.sk_canvas_draw_image_rect (cast(sk_canvas_t*)Handle, cast(sk_image_t*)image.Handle, null, &dest, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 463 } 464 465 void DrawImage (SKImage image, SKRect source, SKRect dest, SKPaint paint = null) 466 { 467 if (image is null) 468 throw new ArgumentNullException (image.stringof); 469 SkiaApi.sk_canvas_draw_image_rect (cast(sk_canvas_t*)Handle, cast(sk_image_t*)image.Handle, &source, &dest, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 470 } 471 472 // DrawPicture 473 474 void DrawPicture (SKPicture picture, float x, float y, SKPaint paint = null) 475 { 476 auto matrix = SKMatrix.CreateTranslation (x, y); 477 DrawPicture (picture, matrix, paint); 478 } 479 480 void DrawPicture (SKPicture picture, SKPoint p, SKPaint paint = null) 481 { 482 DrawPicture (picture, p.X, p.Y, paint); 483 } 484 485 void DrawPicture (SKPicture picture, ref SKMatrix matrix, SKPaint paint = null) 486 { 487 if (picture is null) 488 throw new ArgumentNullException (picture.stringof); 489 SKMatrix* m = &matrix; 490 SkiaApi.sk_canvas_draw_picture (cast(sk_canvas_t*)Handle, cast(sk_picture_t*)picture.Handle, m, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 491 } 492 493 void DrawPicture (SKPicture picture, SKPaint paint = null) 494 { 495 if (picture is null) 496 throw new ArgumentNullException (picture.stringof); 497 SkiaApi.sk_canvas_draw_picture (cast(sk_canvas_t*)Handle, cast(sk_picture_t*)picture.Handle, null, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 498 } 499 500 // DrawDrawable 501 502 void DrawDrawable (SKDrawable drawable, ref SKMatrix matrix) 503 { 504 if (drawable is null) 505 throw new ArgumentNullException (drawable.stringof); 506 SKMatrix* m = &matrix; 507 SkiaApi.sk_canvas_draw_drawable (cast(sk_canvas_t*)Handle, cast(sk_drawable_t*)drawable.Handle, m); 508 } 509 510 void DrawDrawable (SKDrawable drawable, float x, float y) 511 { 512 if (drawable is null) 513 throw new ArgumentNullException (drawable.stringof); 514 auto matrix = SKMatrix.CreateTranslation (x, y); 515 DrawDrawable (drawable, matrix); 516 } 517 518 void DrawDrawable (SKDrawable drawable, SKPoint p) 519 { 520 if (drawable is null) 521 throw new ArgumentNullException (drawable.stringof); 522 auto matrix = SKMatrix.CreateTranslation (p.X, p.Y); 523 DrawDrawable (drawable, matrix); 524 } 525 526 // DrawBitmap 527 528 void DrawBitmap (SKBitmap bitmap, SKPoint p, SKPaint paint = null) 529 { 530 DrawBitmap (bitmap, p.X, p.Y, paint); 531 } 532 533 void DrawBitmap (SKBitmap bitmap, float x, float y, SKPaint paint = null) 534 { 535 if (bitmap is null) 536 throw new ArgumentNullException (bitmap.stringof); 537 SkiaApi.sk_canvas_draw_bitmap (cast(sk_canvas_t*)Handle, cast(sk_bitmap_t*)bitmap.Handle, x, y, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 538 } 539 540 void DrawBitmap (SKBitmap bitmap, SKRect dest, SKPaint paint = null) 541 { 542 if (bitmap is null) 543 throw new ArgumentNullException (bitmap.stringof); 544 SkiaApi.sk_canvas_draw_bitmap_rect (cast(sk_canvas_t*)Handle, cast(sk_bitmap_t*)bitmap.Handle, null, &dest, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 545 } 546 547 void DrawBitmap (SKBitmap bitmap, SKRect source, SKRect dest, SKPaint paint = null) 548 { 549 if (bitmap is null) 550 throw new ArgumentNullException (bitmap.stringof); 551 SkiaApi.sk_canvas_draw_bitmap_rect (cast(sk_canvas_t*)Handle, cast(sk_bitmap_t*)bitmap.Handle, &source, &dest, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 552 } 553 554 // DrawSurface 555 556 void DrawSurface (SKSurface surface, SKPoint p, SKPaint paint = null) 557 { 558 DrawSurface (surface, p.X, p.Y, paint); 559 } 560 561 void DrawSurface (SKSurface surface, float x, float y, SKPaint paint = null) 562 { 563 if (surface is null) 564 throw new ArgumentNullException (surface.stringof); 565 566 surface.Draw (this, x, y, paint); 567 } 568 569 // DrawText (SKTextBlob) 570 571 void DrawText (SKTextBlob text, float x, float y, SKPaint paint) 572 { 573 if (text is null) 574 throw new ArgumentNullException (text.stringof); 575 if (paint is null) 576 throw new ArgumentNullException (paint.stringof); 577 578 SkiaApi.sk_canvas_draw_text_blob (cast(sk_canvas_t*)Handle, cast(sk_textblob_t*)text.Handle, x, y, cast(sk_paint_t*)paint.Handle); 579 } 580 581 // DrawText 582 583 void DrawText (string text, SKPoint p, SKPaint paint) 584 { 585 DrawText (text, p.X, p.Y, paint); 586 } 587 588 void DrawText (string text, float x, float y, SKPaint paint) 589 { 590 DrawText (text, x, y, paint.GetFont (), paint); 591 } 592 593 void DrawText (string text, float x, float y, SKFont font, SKPaint paint) 594 { 595 if (text is null) 596 throw new ArgumentNullException (text.stringof); 597 if (font is null) 598 throw new ArgumentNullException (font.stringof); 599 if (paint is null) 600 throw new ArgumentNullException (paint.stringof); 601 602 if (paint.TextAlign != SKTextAlign.Left) { 603 auto width = font.MeasureText (text); 604 if (paint.TextAlign == SKTextAlign.Center) 605 width *= 0.5f; 606 x -= width; 607 } 608 609 SKTextBlob blob = SKTextBlob.Create (text, font); 610 if (blob is null) 611 return; 612 613 scope(exit) { 614 blob.Dispose(); 615 } 616 617 DrawText (blob, x, y, paint); 618 } 619 620 void DrawText (byte[] text, SKPoint p, SKPaint paint) 621 { 622 DrawText (text, p.X, p.Y, paint); 623 } 624 625 void DrawText (byte[] text, float x, float y, SKPaint paint) 626 { 627 if (text is null) 628 throw new ArgumentNullException (text.stringof); 629 if (paint is null) 630 throw new ArgumentNullException (paint.stringof); 631 632 if (paint.TextAlign != SKTextAlign.Left) { 633 auto width = paint.MeasureText (text); 634 if (paint.TextAlign == SKTextAlign.Center) 635 width *= 0.5f; 636 x -= width; 637 } 638 639 SKTextBlob blob = SKTextBlob.Create (text, paint.TextEncoding, paint.GetFont ()); 640 if (blob is null) 641 return; 642 643 scope(exit) { 644 blob.Dispose(); 645 } 646 647 DrawText (blob, x, y, paint); 648 } 649 650 void DrawText (void* buffer, int length, SKPoint p, SKPaint paint) 651 { 652 DrawText (buffer, length, p.X, p.Y, paint); 653 } 654 655 void DrawText (void* buffer, int length, float x, float y, SKPaint paint) 656 { 657 if (buffer is null && length != 0) 658 throw new ArgumentNullException (buffer.stringof); 659 if (paint is null) 660 throw new ArgumentNullException (paint.stringof); 661 662 if (paint.TextAlign != SKTextAlign.Left) { 663 auto width = paint.MeasureText (buffer, length); 664 if (paint.TextAlign == SKTextAlign.Center) 665 width *= 0.5f; 666 x -= width; 667 } 668 669 SKTextBlob blob = SKTextBlob.Create (buffer, cast(int)length, paint.TextEncoding, paint.GetFont ()); 670 if (blob is null) 671 return; 672 673 scope(exit) { 674 blob.Dispose(); 675 } 676 677 DrawText (blob, x, y, paint); 678 } 679 680 // DrawPositionedText 681 682 void DrawPositionedText (string text, SKPoint[] points, SKPaint paint) 683 { 684 if (text is null) 685 throw new ArgumentNullException (text.stringof); 686 if (paint is null) 687 throw new ArgumentNullException (paint.stringof); 688 if (points is null) 689 throw new ArgumentNullException (points.stringof); 690 691 SKTextBlob blob = SKTextBlob.CreatePositioned (text, paint.GetFont (), points); 692 if (blob is null) 693 return; 694 695 scope(exit) { 696 blob.Dispose(); 697 } 698 699 DrawText (blob, 0, 0, paint); 700 } 701 702 void DrawPositionedText (byte[] text, SKPoint[] points, SKPaint paint) 703 { 704 if (text is null) 705 throw new ArgumentNullException (text.stringof); 706 if (paint is null) 707 throw new ArgumentNullException (paint.stringof); 708 if (points is null) 709 throw new ArgumentNullException (points.stringof); 710 711 SKTextBlob blob = SKTextBlob.CreatePositioned (text, paint.TextEncoding, paint.GetFont (), points); 712 if (blob is null) 713 return; 714 715 scope(exit) { 716 blob.Dispose(); 717 } 718 719 DrawText (blob, 0, 0, paint); 720 } 721 722 void DrawPositionedText (void* buffer, int length, SKPoint[] points, SKPaint paint) 723 { 724 if (buffer is null && length != 0) 725 throw new ArgumentNullException (buffer.stringof); 726 if (paint is null) 727 throw new ArgumentNullException (paint.stringof); 728 if (points is null) 729 throw new ArgumentNullException (points.stringof); 730 731 SKTextBlob blob = SKTextBlob.CreatePositioned (buffer, length, paint.TextEncoding, paint.GetFont (), points); 732 if (blob is null) 733 return; 734 735 scope(exit) { 736 blob.Dispose(); 737 } 738 739 DrawText (blob, 0, 0, paint); 740 } 741 742 // DrawTextOnPath 743 744 void DrawTextOnPath (string text, SKPath path, SKPoint offset, SKPaint paint) 745 { 746 DrawTextOnPath (text, path, offset, true, paint); 747 } 748 749 void DrawTextOnPath (string text, SKPath path, float hOffset, float vOffset, SKPaint paint) 750 { 751 DrawTextOnPath (text, path, SKPoint (hOffset, vOffset), true, paint); 752 } 753 754 void DrawTextOnPath (string text, SKPath path, SKPoint offset, bool warpGlyphs, SKPaint paint) 755 { 756 if (paint is null) 757 throw new ArgumentNullException (paint.stringof); 758 759 DrawTextOnPath (text, path, offset, warpGlyphs, paint.GetFont (), paint); 760 } 761 762 void DrawTextOnPath (string text, SKPath path, SKPoint offset, bool warpGlyphs, SKFont font, SKPaint paint) 763 { 764 if (text is null) 765 throw new ArgumentNullException (text.stringof); 766 if (path is null) 767 throw new ArgumentNullException (path.stringof); 768 if (font is null) 769 throw new ArgumentNullException (font.stringof); 770 if (paint is null) 771 throw new ArgumentNullException (paint.stringof); 772 773 if (warpGlyphs) { 774 auto textPath = font.GetTextPathOnPath (text, path, paint.TextAlign, offset); 775 scope(exit) { 776 textPath.Dispose(); 777 } 778 779 DrawPath (textPath, paint); 780 } else { 781 SKTextBlob blob = SKTextBlob.CreatePathPositioned (text, font, path, paint.TextAlign, offset); 782 if (blob !is null) { 783 scope(exit) { 784 blob.Dispose(); 785 } 786 DrawText (blob, 0, 0, paint); 787 } 788 } 789 } 790 791 void DrawTextOnPath (byte[] text, SKPath path, SKPoint offset, SKPaint paint) 792 { 793 DrawTextOnPath (text, path, offset.X, offset.Y, paint); 794 } 795 796 void DrawTextOnPath (byte[] text, SKPath path, float hOffset, float vOffset, SKPaint paint) 797 { 798 if (text is null) 799 throw new ArgumentNullException (text.stringof); 800 if (path is null) 801 throw new ArgumentNullException (path.stringof); 802 if (paint is null) 803 throw new ArgumentNullException (paint.stringof); 804 805 byte* t = text.ptr; 806 DrawTextOnPath (cast(void*)t, cast(int)text.length, path, hOffset, vOffset, paint); 807 } 808 809 void DrawTextOnPath (void* buffer, int length, SKPath path, SKPoint offset, SKPaint paint) 810 { 811 DrawTextOnPath (buffer, length, path, offset.X, offset.Y, paint); 812 } 813 814 void DrawTextOnPath (void* buffer, int length, SKPath path, float hOffset, float vOffset, SKPaint paint) 815 { 816 if (buffer is null && length != 0) 817 throw new ArgumentNullException (buffer.stringof); 818 if (path is null) 819 throw new ArgumentNullException (path.stringof); 820 if (paint is null) 821 throw new ArgumentNullException (paint.stringof); 822 823 auto font = paint.GetFont (); 824 825 auto textPath = font.GetTextPathOnPath (buffer, length, paint.TextEncoding, path, paint.TextAlign, SKPoint (hOffset, vOffset)); 826 scope(exit) { 827 textPath.Dispose(); 828 } 829 830 DrawPath (textPath, paint); 831 } 832 833 // Flush 834 835 void Flush () 836 { 837 SkiaApi.sk_canvas_flush (cast(sk_canvas_t*)Handle); 838 } 839 840 // Draw*Annotation 841 842 void DrawAnnotation (SKRect rect, string key, SKData value) 843 { 844 // auto bytes = StringUtilities.GetEncodedText (key, SKTextEncoding.Utf8, true); 845 // byte* b = bytes.ptr; 846 // SkiaApi.sk_canvas_draw_annotation (cast(sk_canvas_t*)Handle, &rect, b.stringof, cast(sk_data_t*)(value is null ? null : value.Handle)); 847 } 848 849 void DrawUrlAnnotation (SKRect rect, SKData value) 850 { 851 SkiaApi.sk_canvas_draw_url_annotation (cast(sk_canvas_t*)Handle, &rect, cast(sk_data_t*)(value is null ? null : value.Handle)); 852 } 853 854 SKData DrawUrlAnnotation (SKRect rect, string value) 855 { 856 auto data = SKData.FromCString (value); 857 DrawUrlAnnotation (rect, data); 858 return data; 859 } 860 861 void DrawNamedDestinationAnnotation (SKPoint point, SKData value) 862 { 863 SkiaApi.sk_canvas_draw_named_destination_annotation (cast(sk_canvas_t*)Handle, &point, cast(sk_data_t*)(value is null ? null : value.Handle)); 864 } 865 866 SKData DrawNamedDestinationAnnotation (SKPoint point, string value) 867 { 868 auto data = SKData.FromCString (value); 869 DrawNamedDestinationAnnotation (point, data); 870 return data; 871 } 872 873 void DrawLinkDestinationAnnotation (SKRect rect, SKData value) 874 { 875 SkiaApi.sk_canvas_draw_link_destination_annotation (cast(sk_canvas_t*)Handle, &rect, cast(sk_data_t*)(value is null ? null : value.Handle)); 876 } 877 878 SKData DrawLinkDestinationAnnotation (SKRect rect, string value) 879 { 880 auto data = SKData.FromCString (value); 881 DrawLinkDestinationAnnotation (rect, data); 882 return data; 883 } 884 885 // Draw*NinePatch 886 887 void DrawBitmapNinePatch (SKBitmap bitmap, SKRectI center, SKRect dst, SKPaint paint = null) 888 { 889 if (bitmap is null) 890 throw new ArgumentNullException (bitmap.stringof); 891 // the "center" rect must fit inside the bitmap "rect" 892 if (!SKRect.Create (cast(SKSize)bitmap.Info.Size).Contains (cast(SKRect)center)) 893 throw new ArgumentException ("Center rectangle must be contained inside the bitmap bounds.", center.stringof); 894 895 SkiaApi.sk_canvas_draw_bitmap_nine (cast(sk_canvas_t*)Handle, cast(sk_bitmap_t*)bitmap.Handle, ¢er, &dst, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 896 } 897 898 void DrawImageNinePatch (SKImage image, SKRectI center, SKRect dst, SKPaint paint = null) 899 { 900 if (image is null) 901 throw new ArgumentNullException (image.stringof); 902 // the "center" rect must fit inside the image "rect" 903 if (!SKRect.Create (image.Width(), image.Height()).Contains (cast(SKRect)center)) 904 throw new ArgumentException ("Center rectangle must be contained inside the image bounds.", center.stringof); 905 906 SkiaApi.sk_canvas_draw_image_nine (cast(sk_canvas_t*)Handle, cast(sk_image_t*)image.Handle, ¢er, &dst, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 907 } 908 909 // Draw*Lattice 910 911 void DrawBitmapLattice (SKBitmap bitmap, int[] xDivs, int[] yDivs, SKRect dst, SKPaint paint = null) 912 { 913 SKLattice lattice = SKLattice (); 914 lattice.XDivs = xDivs; 915 lattice.YDivs = yDivs; 916 DrawBitmapLattice (bitmap, lattice, dst, paint); 917 } 918 919 void DrawImageLattice (SKImage image, int[] xDivs, int[] yDivs, SKRect dst, SKPaint paint = null) 920 { 921 SKLattice lattice = SKLattice(); 922 lattice.XDivs = xDivs; 923 lattice.YDivs = yDivs; 924 DrawImageLattice (image, lattice, dst, paint); 925 } 926 927 void DrawBitmapLattice (SKBitmap bitmap, SKLattice lattice, SKRect dst, SKPaint paint = null) 928 { 929 if (bitmap is null) 930 throw new ArgumentNullException (bitmap.stringof); 931 if (lattice.XDivs is null) 932 throw new ArgumentNullException (lattice.XDivs.stringof); 933 if (lattice.YDivs is null) 934 throw new ArgumentNullException (lattice.YDivs.stringof); 935 936 int* x = lattice.XDivs.ptr; 937 int* y = lattice.YDivs.ptr; 938 SKLatticeRectType* r = lattice.RectTypes.ptr; 939 SKColor* c = lattice.Colors.ptr; 940 941 SKLatticeInternal nativeLattice = SKLatticeInternal(); 942 943 nativeLattice.fBounds = null; 944 nativeLattice.fRectTypes = r; 945 nativeLattice.fXCount = cast(int)lattice.XDivs.length; 946 nativeLattice.fXDivs = x; 947 nativeLattice.fYCount = cast(int)lattice.YDivs.length; 948 nativeLattice.fYDivs = y; 949 nativeLattice.fColors = cast(uint*)c; 950 951 Nullable!SKRectI nullableBounds = lattice.Bounds; 952 953 if (!nullableBounds.isNull) { 954 SKRectI bounds = nullableBounds.get(); 955 nativeLattice.fBounds = &bounds; 956 } 957 SkiaApi.sk_canvas_draw_bitmap_lattice (cast(sk_canvas_t*)Handle, cast(sk_bitmap_t*)bitmap.Handle, &nativeLattice, &dst, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 958 } 959 960 void DrawImageLattice (SKImage image, SKLattice lattice, SKRect dst, SKPaint paint = null) 961 { 962 if (image is null) 963 throw new ArgumentNullException (image.stringof); 964 if (lattice.XDivs is null) 965 throw new ArgumentNullException (lattice.XDivs.stringof); 966 if (lattice.YDivs is null) 967 throw new ArgumentNullException (lattice.YDivs.stringof); 968 969 int* x = lattice.XDivs.ptr; 970 int* y = lattice.YDivs.ptr; 971 SKLatticeRectType* r = lattice.RectTypes.ptr; 972 SKColor* c = lattice.Colors.ptr; 973 974 SKLatticeInternal nativeLattice = SKLatticeInternal(); 975 976 nativeLattice.fBounds = null; 977 nativeLattice.fRectTypes = r; 978 nativeLattice.fXCount = cast(int)lattice.XDivs.length; 979 nativeLattice.fXDivs = x; 980 nativeLattice.fYCount = cast(int)lattice.YDivs.length; 981 nativeLattice.fYDivs = y; 982 nativeLattice.fColors = cast(uint*)c; 983 984 Nullable!SKRectI nullableBounds = lattice.Bounds; 985 986 if (!nullableBounds.isNull) { 987 SKRectI bounds = nullableBounds.get(); 988 nativeLattice.fBounds = &bounds; 989 } 990 SkiaApi.sk_canvas_draw_image_lattice (cast(sk_canvas_t*)Handle, cast(sk_image_t*)image.Handle, &nativeLattice, &dst, cast(sk_paint_t*)(paint is null ? null : paint.Handle)); 991 } 992 993 // *Matrix 994 995 void ResetMatrix () 996 { 997 SkiaApi.sk_canvas_reset_matrix (cast(sk_canvas_t*)Handle); 998 } 999 1000 void SetMatrix (SKMatrix matrix) 1001 { 1002 SkiaApi.sk_canvas_set_matrix (cast(sk_canvas_t*)Handle, &matrix); 1003 } 1004 1005 SKMatrix TotalMatrix() { 1006 SKMatrix matrix; 1007 SkiaApi.sk_canvas_get_total_matrix (cast(sk_canvas_t*)Handle, &matrix); 1008 return matrix; 1009 } 1010 1011 // SaveCount 1012 1013 int SaveCount() { return SkiaApi.sk_canvas_get_save_count (cast(sk_canvas_t*)Handle); } 1014 1015 // DrawVertices 1016 1017 void DrawVertices (SKVertexMode vmode, SKPoint[] vertices, SKColor[] colors, SKPaint paint) 1018 { 1019 auto vert = SKVertices.CreateCopy (vmode, vertices, colors); 1020 DrawVertices (vert, SKBlendMode.Modulate, paint); 1021 } 1022 1023 void DrawVertices (SKVertexMode vmode, SKPoint[] vertices, SKPoint[] texs, SKColor[] colors, SKPaint paint) 1024 { 1025 auto vert = SKVertices.CreateCopy (vmode, vertices, texs, colors); 1026 DrawVertices (vert, SKBlendMode.Modulate, paint); 1027 } 1028 1029 void DrawVertices (SKVertexMode vmode, SKPoint[] vertices, SKPoint[] texs, SKColor[] colors, ushort[] indices, SKPaint paint) 1030 { 1031 auto vert = SKVertices.CreateCopy (vmode, vertices, texs, colors, indices); 1032 DrawVertices (vert, SKBlendMode.Modulate, paint); 1033 } 1034 1035 void DrawVertices (SKVertexMode vmode, SKPoint[] vertices, SKPoint[] texs, SKColor[] colors, SKBlendMode mode, ushort[] indices, SKPaint paint) 1036 { 1037 auto vert = SKVertices.CreateCopy (vmode, vertices, texs, colors, indices); 1038 DrawVertices (vert, mode, paint); 1039 } 1040 1041 void DrawVertices (SKVertices vertices, SKBlendMode mode, SKPaint paint) 1042 { 1043 if (vertices is null) 1044 throw new ArgumentNullException (vertices.stringof); 1045 if (paint is null) 1046 throw new ArgumentNullException (paint.stringof); 1047 SkiaApi.sk_canvas_draw_vertices (cast(sk_canvas_t*)Handle, cast(sk_vertices_t*)vertices.Handle, mode, cast(sk_paint_t*)paint.Handle); 1048 } 1049 1050 // DrawArc 1051 1052 void DrawArc (SKRect oval, float startAngle, float sweepAngle, bool useCenter, SKPaint paint) 1053 { 1054 if (paint is null) 1055 throw new ArgumentNullException (paint.stringof); 1056 SkiaApi.sk_canvas_draw_arc (cast(sk_canvas_t*)Handle, &oval, startAngle, sweepAngle, useCenter, cast(sk_paint_t*)paint.Handle); 1057 } 1058 1059 // DrawRoundRectDifference 1060 1061 void DrawRoundRectDifference (SKRoundRect outer, SKRoundRect inner, SKPaint paint) 1062 { 1063 if (outer is null) 1064 throw new ArgumentNullException (outer.stringof); 1065 if (inner is null) 1066 throw new ArgumentNullException (inner.stringof); 1067 if (paint is null) 1068 throw new ArgumentNullException (paint.stringof); 1069 1070 SkiaApi.sk_canvas_draw_drrect (cast(sk_canvas_t*)Handle, cast(sk_rrect_t*)outer.Handle, cast(sk_rrect_t*)inner.Handle, cast(sk_paint_t*)paint.Handle); 1071 } 1072 1073 // DrawAtlas 1074 1075 void DrawAtlas (SKImage atlas, SKRect[] sprites, SKRotationScaleMatrix[] transforms, SKPaint paint) 1076 { 1077 return DrawAtlas (atlas, sprites, transforms, null, SKBlendMode.Dst, null, paint); 1078 } 1079 1080 void DrawAtlas (SKImage atlas, SKRect[] sprites, SKRotationScaleMatrix[] transforms, SKColor[] colors, SKBlendMode mode, SKPaint paint) 1081 { 1082 return DrawAtlas (atlas, sprites, transforms, colors, mode, null, paint); 1083 } 1084 1085 void DrawAtlas (SKImage atlas, SKRect[] sprites, SKRotationScaleMatrix[] transforms, SKColor[] colors, SKBlendMode mode, SKRect cullRect, SKPaint paint) 1086 { 1087 return DrawAtlas (atlas, sprites, transforms, colors, mode, &cullRect, paint); 1088 } 1089 1090 private void DrawAtlas (SKImage atlas, SKRect[] sprites, SKRotationScaleMatrix[] transforms, SKColor[] colors, SKBlendMode mode, SKRect* cullRect, SKPaint paint) 1091 { 1092 if (atlas is null) 1093 throw new ArgumentNullException (atlas.stringof); 1094 if (sprites is null) 1095 throw new ArgumentNullException (sprites.stringof); 1096 if (transforms is null) 1097 throw new ArgumentNullException (transforms.stringof); 1098 1099 if (transforms.length != sprites.length) 1100 throw new ArgumentException ("The number of transforms must match the number of sprites.", transforms.stringof); 1101 if (colors !is null && colors.length != sprites.length) 1102 throw new ArgumentException ("The number of colors must match the number of sprites.", colors.stringof); 1103 1104 SKRect* s = sprites.ptr; 1105 SKRotationScaleMatrix* t = transforms.ptr; 1106 SKColor* c = colors.ptr; 1107 SkiaApi.sk_canvas_draw_atlas (cast(sk_canvas_t*)Handle, cast(sk_image_t*)atlas.Handle, t, s, cast(uint*)c, cast(int)transforms.length, mode,cullRect, cast(sk_paint_t*)paint.Handle); 1108 } 1109 1110 // DrawPatch 1111 1112 void DrawPatch (SKPoint[] cubics, SKColor[] colors, SKPoint[] texCoords, SKPaint paint) 1113 { 1114 return DrawPatch (cubics, colors, texCoords, SKBlendMode.Modulate, paint); 1115 } 1116 1117 void DrawPatch (SKPoint[] cubics, SKColor[] colors, SKPoint[] texCoords, SKBlendMode mode, SKPaint paint) 1118 { 1119 if (cubics is null) 1120 throw new ArgumentNullException (cubics.stringof); 1121 if (cubics.length != PatchCubicsCount) 1122 throw new ArgumentException ("Cubics must have a length of {PatchCubicsCount}."~cubics.stringof); 1123 1124 if (colors !is null && colors.length != PatchCornerCount) 1125 throw new ArgumentException ("Colors must have a length of {PatchCornerCount}."~colors.stringof); 1126 1127 if (texCoords !is null && texCoords.length != PatchCornerCount) 1128 throw new ArgumentException ("Texture coordinates must have a length of {PatchCornerCount}."~texCoords.stringof); 1129 1130 if (paint is null) 1131 throw new ArgumentNullException (paint.stringof); 1132 1133 SKPoint* cubes = cubics.ptr; 1134 SKColor* cols = colors.ptr; 1135 SKPoint* coords = texCoords.ptr; 1136 SkiaApi.sk_canvas_draw_patch (cast(sk_canvas_t*)Handle, cubes, cast(uint*)cols, coords, mode, cast(sk_paint_t*)paint.Handle); 1137 } 1138 1139 static SKCanvas GetObject (void* handle, bool owns = true, bool unrefExisting = true) 1140 { 1141 return GetOrAddObject!(SKCanvas)(handle, owns, unrefExisting, 1142 (h,o) { 1143 return new SKCanvas (h, o); 1144 }); 1145 } 1146 } 1147 1148 class SKAutoCanvasRestore : IDisposable 1149 { 1150 private SKCanvas canvas; 1151 private int saveCount; 1152 1153 this (SKCanvas canvas) 1154 { 1155 this (canvas, true); 1156 } 1157 1158 this (SKCanvas canvas, bool doSave) 1159 { 1160 this.canvas = canvas; 1161 this.saveCount = 0; 1162 1163 if (canvas !is null) { 1164 saveCount = canvas.SaveCount(); 1165 if (doSave) { 1166 canvas.Save (); 1167 } 1168 } 1169 } 1170 1171 void Dispose () 1172 { 1173 Restore (); 1174 } 1175 1176 /// <summary> 1177 /// Perform the restore now, instead of waiting for the Dispose. 1178 /// Will only do this once. 1179 /// </summary> 1180 void Restore () 1181 { 1182 if (canvas !is null) { 1183 canvas.RestoreToCount (saveCount); 1184 canvas = null; 1185 } 1186 } 1187 }