1#Topic Canvas 2#Alias Canvas_Reference ## 3 4#Class SkCanvas 5 6#Code 7#Populate 8## 9 10Canvas provides an interface for drawing, and how the drawing is clipped and transformed. 11Canvas contains a stack of Matrix and Clip values. 12 13Canvas and Paint together provide the state to draw into Surface or Device. 14Each Canvas draw call transforms the geometry of the object by the concatenation of all 15Matrix values in the stack. The transformed geometry is clipped by the intersection 16of all of Clip values in the stack. The Canvas draw calls use Paint to supply drawing 17state such as Color, Typeface, text size, stroke width, Shader and so on. 18 19To draw to a pixel-based destination, create Raster_Surface or GPU_Surface. 20Request Canvas from Surface to obtain the interface to draw. 21Canvas generated by Raster_Surface draws to memory visible to the CPU. 22Canvas generated by GPU_Surface uses Vulkan or OpenGL to draw to the GPU. 23 24To draw to a document, obtain Canvas from SVG_Canvas, Document_PDF, or Picture_Recorder. 25Document based Canvas and other Canvas subclasses reference Device describing the 26destination. 27 28Canvas can be constructed to draw to Bitmap without first creating Raster_Surface. 29This approach may be deprecated in the future. 30 31Canvas may be created directly when no Surface is required; some Canvas methods 32implicitly create Raster_Surface. 33 34# ------------------------------------------------------------------------------ 35 36#Method static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels, 37 size_t rowBytes, 38 const SkSurfaceProps* props = nullptr) 39#In Constructors 40#Line # creates from SkImageInfo and Pixel_Storage ## 41#Populate 42 43#Example 44 #Description 45 Allocates a three by three bitmap, clears it to white, and draws a black pixel 46 in the center. 47 ## 48void draw(SkCanvas* ) { 49 SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3); // device aligned, 32 bpp, Premultiplied 50 const size_t minRowBytes = info.minRowBytes(); // bytes used by one bitmap row 51 const size_t size = info.computeMinByteSize(); // bytes used by all rows 52 SkAutoTMalloc<SkPMColor> storage(size); // allocate storage for pixels 53 SkPMColor* pixels = storage.get(); // get pointer to allocated storage 54 // create a SkCanvas backed by a raster device, and delete it when the 55 // function goes out of scope. 56 std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, pixels, minRowBytes); 57 canvas->clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order 58 canvas->flush(); // ensure that pixels are cleared 59 SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary 60 SkPaint paint; // by default, draws black 61 canvas->drawPoint(1, 1, paint); // draw in the center 62 canvas->flush(); // ensure that point was drawn 63 for (int y = 0; y < info.height(); ++y) { 64 for (int x = 0; x < info.width(); ++x) { 65 SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); 66 } 67 SkDebugf("\n"); 68 } 69} 70 #StdOut 71 --- 72 -x- 73 --- 74 ## 75## 76 77#SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect 78 79## 80 81# ------------------------------------------------------------------------------ 82 83#Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels, 84 size_t rowBytes) 85#In Constructors 86#Line # creates from image data and Pixel_Storage ## 87#Populate 88 89#Example 90 #Description 91 Allocates a three by three bitmap, clears it to white, and draws a black pixel 92 in the center. 93 ## 94void draw(SkCanvas* ) { 95 const int width = 3; 96 const int height = 3; 97 SkPMColor pixels[height][width]; // allocate a 3 by 3 Premultiplied bitmap on the stack 98 // create a SkCanvas backed by a raster device, and delete it when the 99 // function goes out of scope. 100 std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirectN32( 101 width, 102 height, 103 pixels[0], // top-left of the bitmap 104 sizeof(pixels[0])); // byte width of the each row 105 // write a Premultiplied value for white into all pixels in the bitmap 106 canvas->clear(SK_ColorWHITE); 107 SkPMColor pmWhite = pixels[0][0]; // the Premultiplied format may vary 108 SkPaint paint; // by default, draws black 109 canvas->drawPoint(1, 1, paint); // draw in the center 110 canvas->flush(); // ensure that pixels is ready to be read 111 for (int y = 0; y < height; ++y) { 112 for (int x = 0; x < width; ++x) { 113 SkDebugf("%c", pixels[y][x] == pmWhite ? '-' : 'x'); 114 } 115 SkDebugf("\n"); 116 } 117} 118 #StdOut 119 --- 120 -x- 121 --- 122 ## 123## 124 125#SeeAlso MakeRasterDirect SkSurface::MakeRasterDirect SkImageInfo::MakeN32Premul 126 127## 128 129# ------------------------------------------------------------------------------ 130 131#Method SkCanvas() 132 133#Line # creates with no Surface, no dimensions ## 134#Populate 135 136#Example 137 138#Description 139Passes a placeholder to a function that requires one. 140## 141 142#Function 143static void check_for_rotated_ctm(const SkCanvas* canvas) { 144 const SkMatrix& matrix = canvas->getTotalMatrix(); 145 SkDebugf("rect stays rect is %s\n", matrix.rectStaysRect() ? "true" : "false"); 146} 147 148## 149void draw(SkCanvas* canvas) { 150 check_for_rotated_ctm(canvas); 151 canvas->rotate(30); 152 check_for_rotated_ctm(canvas); 153 154 SkCanvas defaultCanvas; 155 check_for_rotated_ctm(&defaultCanvas); 156} 157 158 #StdOut 159 rect stays rect is true 160 rect stays rect is false 161 rect stays rect is true 162 ## 163## 164 165#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas 166 167## 168 169# ------------------------------------------------------------------------------ 170 171#Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr) 172 173#Line # creates with no Surface, set dimensions, Surface_Properties ## 174#Populate 175 176#Example 177 SkCanvas canvas(10, 20); // 10 units wide, 20 units high 178 canvas.clipRect(SkRect::MakeXYWH(30, 40, 5, 10)); // clip is outside canvas' device 179 SkDebugf("canvas %s empty\n", canvas.getDeviceClipBounds().isEmpty() ? "is" : "is not"); 180 181 #StdOut 182 canvas is empty 183 ## 184## 185 186#SeeAlso MakeRasterDirect SkSurfaceProps SkPixelGeometry SkCreateColorSpaceXformCanvas 187 188## 189 190# ------------------------------------------------------------------------------ 191 192#Method explicit SkCanvas(const SkBitmap& bitmap) 193 194#Line # uses existing Bitmap ## 195#Populate 196 197#Example 198#Description 199The actual output depends on the installed fonts. 200## 201 SkBitmap bitmap; 202 // create a bitmap 5 wide and 11 high 203 bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11)); 204 SkCanvas canvas(bitmap); 205 canvas.clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order 206 SkPixmap pixmap; // provides guaranteed access to the drawn pixels 207 if (!canvas.peekPixels(&pixmap)) { 208 SkDebugf("peekPixels should never fail.\n"); 209 } 210 const SkPMColor* pixels = pixmap.addr32(); // points to top-left of bitmap 211 SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary 212 SkPaint paint; // by default, draws black, 12 point text 213 canvas.drawString("!", 1, 10, SkFont(), paint); // 1 char at baseline (1, 10) 214 for (int y = 0; y < bitmap.height(); ++y) { 215 for (int x = 0; x < bitmap.width(); ++x) { 216 SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); 217 } 218 SkDebugf("\n"); 219 } 220## 221 222#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas 223 224## 225 226# ------------------------------------------------------------------------------ 227 228#Method SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) 229 230#Line # uses existing Bitmap and Surface_Properties ## 231#Populate 232 233#Example 234#Description 235The actual output depends on the installed fonts. 236## 237 SkBitmap bitmap; 238 // create a bitmap 5 wide and 11 high 239 bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11)); 240 SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); 241 canvas.clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order 242 SkPixmap pixmap; // provides guaranteed access to the drawn pixels 243 if (!canvas.peekPixels(&pixmap)) { 244 SkDebugf("peekPixels should never fail.\n"); 245 } 246 const SkPMColor* pixels = pixmap.addr32(); // points to top-left of bitmap 247 SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary 248 SkPaint paint; // by default, draws black, 12 point text 249 canvas.drawString("!", 1, 10, SkFont(), paint); // 1 char at baseline (1, 10) 250 for (int y = 0; y < bitmap.height(); ++y) { 251 for (int x = 0; x < bitmap.width(); ++x) { 252 SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); 253 } 254 SkDebugf("\n"); 255 } 256## 257 258#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas 259 260## 261 262# ------------------------------------------------------------------------------ 263 264#Method virtual ~SkCanvas() 265 266#Line # draws saved Layers, frees resources ## 267#Populate 268 269#Example 270#Description 271Canvas Layer draws into bitmap. saveLayerAlpha sets up an additional 272drawing surface that blends with the bitmap. When Layer goes out of 273scope, Layer destructor is called. The saved Layer is restored, drawing 274transparent letters. 275## 276void draw(SkCanvas* canvas) { 277 SkBitmap bitmap; 278 bitmap.allocPixels(SkImageInfo::MakeN32Premul(200, 200)); 279 { 280 SkCanvas offscreen(bitmap); 281 SkPaint paint; 282 SkFont font(nullptr, 100); 283 offscreen.drawString("ABC", 20, 160, font, paint); 284 SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192); 285 offscreen.saveLayerAlpha(&layerBounds, 128); 286 offscreen.clear(SK_ColorWHITE); 287 offscreen.drawString("DEF", 20, 160, font, paint); 288 } 289 canvas->drawBitmap(bitmap, 0, 0, nullptr); 290} 291## 292 293#SeeAlso State_Stack 294 295## 296 297# ------------------------------------------------------------------------------ 298#Subtopic Property 299#Line # metrics and attributes ## 300## 301 302#Method SkImageInfo imageInfo() const 303#In Property 304#Line # returns Image_Info for Canvas ## 305#Populate 306 307#Example 308 SkCanvas emptyCanvas; 309 SkImageInfo canvasInfo = emptyCanvas.imageInfo(); 310 SkImageInfo emptyInfo; 311 SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!'); 312 313 #StdOut 314 emptyInfo == canvasInfo 315 ## 316## 317 318#SeeAlso SkImageInfo MakeRasterDirect makeSurface 319 320## 321 322# ------------------------------------------------------------------------------ 323 324#Method bool getProps(SkSurfaceProps* props) const 325#In Property 326#Line # copies Surface_Properties if available ## 327#Populate 328 329#Example 330 SkBitmap bitmap; 331 SkCanvas canvas(bitmap, SkSurfaceProps(0, kRGB_V_SkPixelGeometry)); 332 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); 333 SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry())); 334 if (!canvas.getProps(&surfaceProps)) { 335 SkDebugf("getProps failed unexpectedly.\n"); 336 } 337 SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry())); 338 339 #StdOut 340 isRGB:0 341 isRGB:1 342 #StdOut ## 343## 344 345#SeeAlso SkSurfaceProps makeSurface 346 347## 348 349# ------------------------------------------------------------------------------ 350#Subtopic Utility 351#Line # rarely called management functions ## 352## 353 354#Method void flush() 355#In Utility 356#Line # triggers execution of all pending draw operations ## 357#Populate 358 359#NoExample 360## 361 362#SeeAlso peekPixels SkSurface::flush GrContext::flush GrContext::abandonContext 363 364## 365 366# ------------------------------------------------------------------------------ 367 368#Method virtual SkISize getBaseLayerSize() const 369#In Property 370#Line # returns size of base Layer in global coordinates ## 371#Populate 372 373#Example 374 SkBitmap bitmap; 375 bitmap.allocPixels(SkImageInfo::MakeN32Premul(20, 30)); 376 SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); 377 canvas.clipRect(SkRect::MakeWH(10, 40)); 378 SkIRect clipDeviceBounds = canvas.getDeviceClipBounds(); 379 if (clipDeviceBounds.isEmpty()) { 380 SkDebugf("Empty clip bounds is unexpected!\n"); 381 } 382 SkDebugf("clip=%d,%d\n", clipDeviceBounds.width(), clipDeviceBounds.height()); 383 SkISize baseLayerSize = canvas.getBaseLayerSize(); 384 SkDebugf("size=%d,%d\n", baseLayerSize.width(), baseLayerSize.height()); 385 386 #StdOut 387 clip=10,30 388 size=20,30 389 ## 390## 391 392#ToDo is this the same as the width and height of surface? ## 393 394#SeeAlso getDeviceClipBounds 395 396## 397 398# ------------------------------------------------------------------------------ 399 400#Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr) 401#In Constructors 402#Line # creates Surface matching SkImageInfo and SkSurfaceProps ## 403#Populate 404 405#Example 406 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(5, 6); 407 SkCanvas* smallCanvas = surface->getCanvas(); 408 SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(3, 4); 409 sk_sp<SkSurface> compatible = smallCanvas->makeSurface(imageInfo); 410 SkDebugf("compatible %c= nullptr\n", compatible == nullptr ? '=' : '!'); 411 SkDebugf("size = %d, %d\n", compatible->width(), compatible->height()); 412 413 #StdOut 414 compatible != nullptr 415 size = 3, 4 416 ## 417## 418 419#SeeAlso SkSurface SkSurface::makeSurface SkImageInfo SkSurfaceProps 420 421## 422 423# ------------------------------------------------------------------------------ 424 425#Method virtual GrContext* getGrContext() 426#In Property 427#Line # returns GPU_Context of the GPU_Surface ## 428#Populate 429 430#Example 431void draw(SkCanvas* canvas) { 432 if (canvas->getGrContext()) { 433 canvas->clear(SK_ColorRED); 434 } else { 435 canvas->clear(SK_ColorBLUE); 436 } 437} 438## 439 440#ToDo fiddle should show both CPU and GPU out ## 441 442#SeeAlso GrContext 443 444## 445 446# ------------------------------------------------------------------------------ 447 448#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr) 449#In Utility 450#In Property 451#Line # returns writable pixel access if available ## 452#Populate 453 454#Example 455void draw(SkCanvas* canvas) { 456 if (canvas->accessTopLayerPixels(nullptr, nullptr)) { 457 canvas->clear(SK_ColorRED); 458 } else { 459 canvas->clear(SK_ColorBLUE); 460 } 461} 462## 463 464#Example 465#Description 466Draws "ABC" on the device. Then draws "DEF" in Layer, and reads 467Layer to add a large dotted "DEF". Finally blends Layer with the 468device. 469 470The Layer and blended result appear on the CPU and GPU but the large dotted 471"DEF" appear only on the CPU. 472## 473void draw(SkCanvas* canvas) { 474 SkPaint paint; 475 SkFont font(nullptr, 100); 476 canvas->drawString("ABC", 20, 160, font, paint); 477 SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192); 478 canvas->saveLayerAlpha(&layerBounds, 128); 479 canvas->clear(SK_ColorWHITE); 480 canvas->drawString("DEF", 20, 160, font, paint); 481 SkImageInfo imageInfo; 482 size_t rowBytes; 483 SkIPoint origin; 484 uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin); 485 if (access) { 486 int h = imageInfo.height(); 487 int v = imageInfo.width(); 488 int rowWords = rowBytes / sizeof(uint32_t); 489 for (int y = 0; y < h; ++y) { 490 int newY = (y - h / 2) * 2 + h / 2; 491 if (newY < 0 || newY >= h) { 492 continue; 493 } 494 for (int x = 0; x < v; ++x) { 495 int newX = (x - v / 2) * 2 + v / 2; 496 if (newX < 0 || newX >= v) { 497 continue; 498 } 499 if (access[y * rowWords + x] == SK_ColorBLACK) { 500 access[newY * rowWords + newX] = SK_ColorGRAY; 501 } 502 } 503 } 504 505 } 506 canvas->restore(); 507} 508## 509 510#ToDo there are no callers of this that I can find. Deprecate? ## 511#ToDo fiddle should show both CPU and GPU out ## 512 513#SeeAlso SkImageInfo SkPixmap 514 515## 516 517# ------------------------------------------------------------------------------ 518 519#Method SkRasterHandleAllocator::Handle accessTopRasterHandle() const 520#In Utility 521#In Property 522#Line # returns context that tracks Clip and Matrix ## 523#Populate 524 525#Example 526#Description 527#ToDo ## 528## 529#Function 530 static void DeleteCallback(void*, void* context) { 531 delete (char*) context; 532 } 533 534 class CustomAllocator : public SkRasterHandleAllocator { 535 public: 536 bool allocHandle(const SkImageInfo& info, Rec* rec) override { 537 char* context = new char[4]{'s', 'k', 'i', 'a'}; 538 rec->fReleaseProc = DeleteCallback; 539 rec->fReleaseCtx = context; 540 rec->fHandle = context; 541 rec->fPixels = context; 542 rec->fRowBytes = 4; 543 return true; 544 } 545 546 void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override { 547 // apply canvas matrix and clip to custom environment 548 } 549 }; 550 551## 552 void draw(SkCanvas* canvas) { 553 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 554 std::unique_ptr<SkCanvas> c2 = 555 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<CustomAllocator>( 556 new CustomAllocator()), info); 557 char* context = (char*) c2->accessTopRasterHandle(); 558 SkDebugf("context = %.4s\n", context); 559 560 } 561 #StdOut 562 context = skia 563 ## 564 #ToDo skstd::make_unique could not be used because def is private -- note to fix in c++14? ## 565## 566 567#SeeAlso SkRasterHandleAllocator 568 569## 570 571# ------------------------------------------------------------------------------ 572#Subtopic Pixels 573#Line # read and write pixel values ## 574## 575 576#Method bool peekPixels(SkPixmap* pixmap) 577#In Pixels 578#Line # returns if Canvas has direct access to its pixels ## 579#Populate 580 581#Example 582 SkPixmap pixmap; 583 if (canvas->peekPixels(&pixmap)) { 584 SkDebugf("width=%d height=%d\n", pixmap.bounds().width(), pixmap.bounds().height()); 585 } 586 #StdOut 587 width=256 height=256 588 ## 589## 590 591#SeeAlso readPixels SkBitmap::peekPixels SkImage::peekPixels SkSurface::peekPixels 592 593## 594 595# ------------------------------------------------------------------------------ 596 597#Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 598 int srcX, int srcY) 599#In Pixels 600#Line # copies and converts rectangle of pixels from Canvas ## 601 602Copies Rect of pixels from Canvas into dstPixels. Matrix and Clip are 603ignored. 604 605Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 606Destination Rect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). 607Copies each readable pixel intersecting both rectangles, without scaling, 608converting to dstInfo.colorType() and dstInfo.alphaType() if required. 609 610Pixels are readable when Device is raster, or backed by a GPU. 611Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 612returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility 613class like SkDebugCanvas. 614 615The destination pixel storage must be allocated by the caller. 616 617Pixel values are converted only if Color_Type and Alpha_Type 618do not match. Only pixels within both source and destination rectangles 619are copied. dstPixels contents outside Rect intersection are unchanged. 620 621Pass negative values for srcX or srcY to offset pixels across or down destination. 622 623Does not copy, and returns false if: 624 625#List 626# Source and destination rectangles do not intersect. ## 627# Canvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). ## 628# Canvas pixels are not readable; for instance, Canvas is document-based. ## 629# dstRowBytes is too small to contain one row of pixels. ## 630## 631 632#Param dstInfo width, height, Color_Type, and Alpha_Type of dstPixels ## 633#Param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger ## 634#Param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger ## 635#Param srcX offset into readable pixels on x-axis; may be negative ## 636#Param srcY offset into readable pixels on y-axis; may be negative ## 637 638#Return true if pixels were copied ## 639 640#Example 641#Width 64 642#Height 64 643#Description 644 A black circle drawn on a blue background provides an image to copy. 645 readPixels copies one quarter of the canvas into each of the four corners. 646 The copied quarter circles overdraw the original circle. 647## 648 canvas->clear(SK_ColorBLUE); 649 SkPaint paint; 650 canvas->drawCircle(32, 32, 28, paint); 651 SkImageInfo info = SkImageInfo::Make(64, 64, kBGRA_8888_SkColorType, kPremul_SkAlphaType); 652 sk_sp<SkData> data(SkData::MakeUninitialized(info.minRowBytes() * info.height())); 653 sk_bzero(data->writable_data(), info.minRowBytes() * info.height()); 654 for (int x : { 32, -32 } ) { 655 for (int y : { 32, -32 } ) { 656 canvas->readPixels(info, data->writable_data(), info.minRowBytes(), x, y); 657 } 658 } 659 sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, info.minRowBytes()); 660 canvas->drawImage(image, 0, 0); 661## 662 663#Example 664#Description 665 Canvas returned by Raster_Surface has Premultiplied pixel values. 666 clear() takes Unpremultiplied input with Color_Alpha equal 0x80 667 and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha 668 to generate Premultiplied value 0x802B5580. readPixels converts pixel back 669 to Unpremultiplied value 0x8056A9FF, introducing error. 670## 671 canvas->clear(0x8055aaff); 672 for (SkAlphaType alphaType : { kPremul_SkAlphaType, kUnpremul_SkAlphaType } ) { 673 uint32_t pixel = 0; 674 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, alphaType); 675 if (canvas->readPixels(info, &pixel, 4, 0, 0)) { 676 SkDebugf("pixel = %08x\n", pixel); 677 } 678 } 679 680 #StdOut 681 pixel = 802b5580 682 pixel = 8056a9ff 683 ## 684## 685 686#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels 687 688## 689 690# ------------------------------------------------------------------------------ 691 692#Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY) 693 694Copies Rect of pixels from Canvas into pixmap. Matrix and Clip are 695ignored. 696 697Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 698Destination Rect corners are (0, 0) and (pixmap.width(), pixmap.height()). 699Copies each readable pixel intersecting both rectangles, without scaling, 700converting to pixmap.colorType() and pixmap.alphaType() if required. 701 702Pixels are readable when Device is raster, or backed by a GPU. 703Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 704returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility 705class like SkDebugCanvas. 706 707Caller must allocate pixel storage in pixmap if needed. 708 709Pixel values are converted only if Color_Type and Alpha_Type 710do not match. Only pixels within both source and destination Rects 711are copied. pixmap pixels contents outside Rect intersection are unchanged. 712 713Pass negative values for srcX or srcY to offset pixels across or down pixmap. 714 715Does not copy, and returns false if: 716 717#List 718# Source and destination rectangles do not intersect. ## 719# Canvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). ## 720# Canvas pixels are not readable; for instance, Canvas is document-based. ## 721# Pixmap pixels could not be allocated. ## 722# pixmap.rowBytes() is too small to contain one row of pixels. ## 723## 724 725#Param pixmap storage for pixels copied from Canvas ## 726#Param srcX offset into readable pixels on x-axis; may be negative ## 727#Param srcY offset into readable pixels on y-axis; may be negative ## 728 729#Return true if pixels were copied ## 730 731#Example 732 #Description 733 clear() takes Unpremultiplied input with Color_Alpha equal 0x80 734 and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha 735 to generate Premultiplied value 0x802B5580. 736 ## 737 void draw(SkCanvas* canvas) { 738 canvas->clear(0x8055aaff); 739 uint32_t pixels[1] = { 0 }; 740 SkPixmap pixmap(SkImageInfo::MakeN32Premul(1, 1), pixels, 4); 741 canvas->readPixels(pixmap, 0, 0); 742 SkDebugf("pixel = %08x\n", pixels[0]); 743 } 744 #StdOut 745 pixel = 802b5580 746 ## 747## 748 749#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels 750 751## 752 753# ------------------------------------------------------------------------------ 754 755#Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY) 756 757Copies Rect of pixels from Canvas into bitmap. Matrix and Clip are 758ignored. 759 760Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 761Destination Rect corners are (0, 0) and (bitmap.width(), bitmap.height()). 762Copies each readable pixel intersecting both rectangles, without scaling, 763converting to bitmap.colorType() and bitmap.alphaType() if required. 764 765Pixels are readable when Device is raster, or backed by a GPU. 766Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 767returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility 768class like SkDebugCanvas. 769 770Caller must allocate pixel storage in bitmap if needed. 771 772Bitmap values are converted only if Color_Type and Alpha_Type 773do not match. Only pixels within both source and destination rectangles 774are copied. Bitmap pixels outside Rect intersection are unchanged. 775 776Pass negative values for srcX or srcY to offset pixels across or down bitmap. 777 778Does not copy, and returns false if: 779 780#List 781# Source and destination rectangles do not intersect. ## 782# Canvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). ## 783# Canvas pixels are not readable; for instance, Canvas is document-based. ## 784# bitmap pixels could not be allocated. ## 785# bitmap.rowBytes() is too small to contain one row of pixels. ## 786## 787 788#Param bitmap storage for pixels copied from Canvas ## 789#Param srcX offset into readable pixels on x-axis; may be negative ## 790#Param srcY offset into readable pixels on y-axis; may be negative ## 791 792#Return true if pixels were copied ## 793 794#Example 795 #Description 796 clear() takes Unpremultiplied input with Color_Alpha equal 0x80 797 and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha 798 to generate Premultiplied value 0x802B5580. 799 ## 800void draw(SkCanvas* canvas) { 801 canvas->clear(0x8055aaff); 802 SkBitmap bitmap; 803 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1)); 804 canvas->readPixels(bitmap, 0, 0); 805 SkDebugf("pixel = %08x\n", bitmap.getAddr32(0, 0)[0]); 806} 807 #StdOut 808 pixel = 802b5580 809 ## 810## 811 812#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels 813 814## 815 816# ------------------------------------------------------------------------------ 817 818#Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) 819#In Pixels 820#Line # copies and converts rectangle of pixels to Canvas ## 821Copies Rect from pixels to Canvas. Matrix and Clip are ignored. 822Source Rect corners are (0, 0) and (info.width(), info.height()). 823Destination Rect corners are (x, y) and 824(imageInfo().width(), imageInfo().height()). 825 826Copies each readable pixel intersecting both rectangles, without scaling, 827converting to imageInfo().colorType() and imageInfo().alphaType() if required. 828 829Pixels are writable when Device is raster, or backed by a GPU. 830Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, 831returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility 832class like SkDebugCanvas. 833 834Pixel values are converted only if Color_Type and Alpha_Type 835do not match. Only pixels within both source and destination rectangles 836are copied. Canvas pixels outside Rect intersection are unchanged. 837 838Pass negative values for x or y to offset pixels to the left or 839above Canvas pixels. 840 841Does not copy, and returns false if: 842 843#List 844# Source and destination rectangles do not intersect. ## 845# pixels could not be converted to Canvas imageInfo().colorType() or 846 imageInfo().alphaType(). ## 847# Canvas pixels are not writable; for instance, Canvas is document-based. ## 848# rowBytes is too small to contain one row of pixels. ## 849## 850 851#Param info width, height, Color_Type, and Alpha_Type of pixels ## 852#Param pixels pixels to copy, of size info.height() times rowBytes, or larger ## 853#Param rowBytes size of one row of pixels; info.width() times pixel size, or larger ## 854#Param x offset into Canvas writable pixels on x-axis; may be negative ## 855#Param y offset into Canvas writable pixels on y-axis; may be negative ## 856 857#Return true if pixels were written to Canvas ## 858 859#Example 860 SkImageInfo imageInfo = SkImageInfo::MakeN32(256, 1, kPremul_SkAlphaType); 861 for (int y = 0; y < 256; ++y) { 862 uint32_t pixels[256]; 863 for (int x = 0; x < 256; ++x) { 864 pixels[x] = SkColorSetARGB(x, x + y, x, x - y); 865 } 866 canvas->writePixels(imageInfo, &pixels, sizeof(pixels), 0, y); 867 } 868## 869 870#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels 871 872## 873 874# ------------------------------------------------------------------------------ 875 876#Method bool writePixels(const SkBitmap& bitmap, int x, int y) 877 878Copies Rect from pixels to Canvas. Matrix and Clip are ignored. 879Source Rect corners are (0, 0) and (bitmap.width(), bitmap.height()). 880 881Destination Rect corners are (x, y) and 882(imageInfo().width(), imageInfo().height()). 883 884Copies each readable pixel intersecting both rectangles, without scaling, 885converting to imageInfo().colorType() and imageInfo().alphaType() if required. 886 887Pixels are writable when Device is raster, or backed by a GPU. 888Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, 889returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility 890class like SkDebugCanvas. 891 892Pixel values are converted only if Color_Type and Alpha_Type 893do not match. Only pixels within both source and destination rectangles 894are copied. Canvas pixels outside Rect intersection are unchanged. 895 896Pass negative values for x or y to offset pixels to the left or 897above Canvas pixels. 898 899Does not copy, and returns false if: 900 901#List 902# Source and destination rectangles do not intersect. ## 903# bitmap does not have allocated pixels. ## 904# bitmap pixels could not be converted to Canvas imageInfo().colorType() or 905 imageInfo().alphaType(). ## 906# Canvas pixels are not writable; for instance, Canvas is document based. ## 907# bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ## 908## 909 910#Param bitmap contains pixels copied to Canvas ## 911#Param x offset into Canvas writable pixels in x; may be negative ## 912#Param y offset into Canvas writable pixels in y; may be negative ## 913 914#Return true if pixels were written to Canvas ## 915 916#Example 917void draw(SkCanvas* canvas) { 918 SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(2, 2); 919 SkBitmap bitmap; 920 bitmap.setInfo(imageInfo); 921 uint32_t pixels[4]; 922 bitmap.setPixels(pixels); 923 for (int y = 0; y < 256; y += 2) { 924 for (int x = 0; x < 256; x += 2) { 925 pixels[0] = SkColorSetRGB(x, y, x | y); 926 pixels[1] = SkColorSetRGB(x ^ y, y, x); 927 pixels[2] = SkColorSetRGB(x, x & y, y); 928 pixels[3] = SkColorSetRGB(~x, ~y, x); 929 canvas->writePixels(bitmap, x, y); 930 } 931 } 932} 933## 934 935#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels 936 937## 938 939# ------------------------------------------------------------------------------ 940#Subtopic State_Stack 941#Line # stack of state for hierarchical drawing ## 942 943Canvas maintains a stack of state that allows hierarchical drawing, commonly used 944to implement windows and views. The initial state has an identity matrix and and 945an infinite clip. Even with a wide-open clip, drawing is constrained by the 946bounds of the Canvas Surface or Device. 947 948Canvas savable state consists of Clip and Matrix. 949Clip describes the area that may be drawn to. 950Matrix transforms the geometry. 951 952save(), saveLayer, and saveLayerAlpha 953save state and return the depth of the stack. 954 955restore(), restoreToCount, and ~SkCanvas() revert state to its value when saved. 956 957Each state on the stack intersects Clip with the previous Clip, 958and concatenates Matrix with the previous Matrix. 959The intersected Clip makes the drawing area the same or smaller; 960the concatenated Matrix may move the origin and potentially scale or rotate 961the coordinate space. 962 963Canvas does not require balancing the state stack but it is a good idea 964to do so. Calling save() without restore() will eventually cause Skia to fail; 965mismatched save() and restore() create hard to find bugs. 966 967It is not possible to use state to draw outside of the clip defined by the 968previous state. 969 970#Example 971#Description 972Draw to ever smaller clips; then restore drawing to full canvas. 973Note that the second clipRect is not permitted to enlarge Clip. 974## 975#Height 160 976void draw(SkCanvas* canvas) { 977 SkPaint paint; 978 canvas->save(); // records stack depth to restore 979 canvas->clipRect(SkRect::MakeWH(100, 100)); // constrains drawing to clip 980 canvas->clear(SK_ColorRED); // draws to limit of clip 981 canvas->save(); // records stack depth to restore 982 canvas->clipRect(SkRect::MakeWH(50, 150)); // Rect below 100 is ignored 983 canvas->clear(SK_ColorBLUE); // draws to smaller clip 984 canvas->restore(); // enlarges clip 985 canvas->drawLine(20, 20, 150, 150, paint); // line below 100 is not drawn 986 canvas->restore(); // enlarges clip 987 canvas->drawLine(150, 20, 50, 120, paint); // line below 100 is drawn 988} 989## 990 991Each Clip uses the current Matrix for its coordinates. 992 993#Example 994#Description 995While clipRect is given the same rectangle twice, Matrix makes the second 996clipRect draw at half the size of the first. 997## 998#Height 128 999void draw(SkCanvas* canvas) { 1000 canvas->clipRect(SkRect::MakeWH(100, 100)); 1001 canvas->clear(SK_ColorRED); 1002 canvas->scale(.5, .5); 1003 canvas->clipRect(SkRect::MakeWH(100, 100)); 1004 canvas->clear(SK_ColorBLUE); 1005} 1006## 1007 1008#SeeAlso save saveLayer saveLayerAlpha restore() restoreToCount 1009 1010#Method int save() 1011 1012#In State_Stack 1013#Line # saves Clip and Matrix on stack ## 1014#Populate 1015 1016#Example 1017#Description 1018The black square is translated 50 pixels down and to the right. 1019Restoring Canvas state removes translate() from Canvas stack; 1020the red square is not translated, and is drawn at the origin. 1021## 1022#Height 100 1023void draw(SkCanvas* canvas) { 1024 SkPaint paint; 1025 SkRect rect = { 0, 0, 25, 25 }; 1026 canvas->drawRect(rect, paint); 1027 canvas->save(); 1028 canvas->translate(50, 50); 1029 canvas->drawRect(rect, paint); 1030 canvas->restore(); 1031 paint.setColor(SK_ColorRED); 1032 canvas->drawRect(rect, paint); 1033} 1034## 1035 1036#SeeAlso saveLayer saveLayerAlpha restore restoreToCount 1037 1038## 1039 1040# ------------------------------------------------------------------------------ 1041 1042#Method void restore() 1043 1044#In State_Stack 1045#Line # restores changes to Clip and Matrix, pops save stack ## 1046#Populate 1047 1048#Example 1049void draw(SkCanvas* canvas) { 1050 SkCanvas simple; 1051 SkDebugf("depth = %d\n", simple.getSaveCount()); 1052 simple.restore(); 1053 SkDebugf("depth = %d\n", simple.getSaveCount()); 1054} 1055## 1056 1057#SeeAlso save saveLayer saveLayerAlpha restoreToCount 1058 1059## 1060 1061# ------------------------------------------------------------------------------ 1062 1063#Method int getSaveCount() const 1064 1065#In State_Stack 1066#Line # returns depth of stack containing Clip and Matrix ## 1067#Populate 1068 1069#Example 1070void draw(SkCanvas* canvas) { 1071 SkCanvas simple; 1072 SkDebugf("depth = %d\n", simple.getSaveCount()); 1073 simple.save(); 1074 SkDebugf("depth = %d\n", simple.getSaveCount()); 1075 simple.restore(); 1076 SkDebugf("depth = %d\n", simple.getSaveCount()); 1077} 1078#StdOut 1079depth = 1 1080depth = 2 1081depth = 1 1082## 1083## 1084 1085#SeeAlso save restore restoreToCount 1086 1087## 1088 1089# ------------------------------------------------------------------------------ 1090 1091#Method void restoreToCount(int saveCount) 1092 1093#In State_Stack 1094#Line # restores changes to Clip and Matrix to given depth ## 1095#Populate 1096 1097#Example 1098void draw(SkCanvas* canvas) { 1099 SkDebugf("depth = %d\n", canvas->getSaveCount()); 1100 canvas->save(); 1101 canvas->save(); 1102 SkDebugf("depth = %d\n", canvas->getSaveCount()); 1103 canvas->restoreToCount(0); 1104 SkDebugf("depth = %d\n", canvas->getSaveCount()); 1105} 1106#StdOut 1107depth = 1 1108depth = 3 1109depth = 1 1110## 1111## 1112 1113#SeeAlso restore getSaveCount save 1114 1115## 1116 1117#Subtopic State_Stack ## 1118 1119# ------------------------------------------------------------------------------ 1120 1121#Subtopic Layer 1122#Substitute layer 1123#Alias Layers 1124#Substitute layers 1125## 1126#Line # temporary Bitmap to draw into ## 1127 1128Layer allocates a temporary Bitmap to draw into. When the drawing is 1129complete, the Bitmap is drawn into the Canvas. 1130 1131Layer is saved in a stack along with other saved state. When state with a Layer 1132is restored, the Bitmap is drawn into the previous Layer. 1133 1134Layer may be initialized with the contents of the previous Layer. When Layer is 1135restored, its Bitmap can be modified by Paint passed to Layer to apply 1136Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode. 1137 1138#Method int saveLayer(const SkRect* bounds, const SkPaint* paint) 1139 1140#In Layer 1141#Line # saves Clip and Matrix on stack; creates Layer ## 1142#Populate 1143 1144#Example 1145#Description 1146Rectangles are blurred by Image_Filter when restore() draws Layer to main 1147Canvas. 1148## 1149#Height 128 1150#Function 1151###$ 1152#include "SkBlurImageFilter.h" 1153$$$# 1154## 1155 1156void draw(SkCanvas* canvas) { 1157 SkPaint paint, blur; 1158 blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr)); 1159 canvas->saveLayer(nullptr, &blur); 1160 SkRect rect = { 25, 25, 50, 50}; 1161 canvas->drawRect(rect, paint); 1162 canvas->translate(50, 50); 1163 paint.setColor(SK_ColorRED); 1164 canvas->drawRect(rect, paint); 1165 canvas->restore(); 1166} 1167## 1168 1169#SeeAlso save restore saveLayer saveLayerAlpha SaveLayerRec 1170 1171## 1172 1173#Method int saveLayer(const SkRect& bounds, const SkPaint* paint) 1174 1175#In Layer 1176#Populate 1177 1178#Example 1179#Description 1180Rectangles are blurred by Image_Filter when restore() draws Layer to main Canvas. 1181The red rectangle is clipped; it does not fully fit on Layer. 1182Image_Filter blurs past edge of Layer so red rectangle is blurred on all sides. 1183## 1184#Height 128 1185#Function 1186###$ 1187#include "SkBlurImageFilter.h" 1188$$$# 1189## 1190 1191void draw(SkCanvas* canvas) { 1192 SkPaint paint, blur; 1193 blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr)); 1194 canvas->saveLayer(SkRect::MakeWH(90, 90), &blur); 1195 SkRect rect = { 25, 25, 50, 50}; 1196 canvas->drawRect(rect, paint); 1197 canvas->translate(50, 50); 1198 paint.setColor(SK_ColorRED); 1199 canvas->drawRect(rect, paint); 1200 canvas->restore(); 1201} 1202## 1203 1204#SeeAlso save restore saveLayerAlpha SaveLayerRec 1205 1206## 1207 1208#Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) 1209 1210#In Layer 1211#Line # saves Clip and Matrix on stack; creates Layer; sets opacity ## 1212#Populate 1213 1214#Example 1215 SkPaint paint; 1216 paint.setColor(SK_ColorRED); 1217 canvas->drawCircle(50, 50, 50, paint); 1218 canvas->saveLayerAlpha(nullptr, 128); 1219 paint.setColor(SK_ColorBLUE); 1220 canvas->drawCircle(100, 50, 50, paint); 1221 paint.setColor(SK_ColorGREEN); 1222 paint.setAlpha(128); 1223 canvas->drawCircle(75, 90, 50, paint); 1224 canvas->restore(); 1225## 1226 1227#SeeAlso save restore saveLayer SaveLayerRec 1228 1229## 1230 1231#Enum SaveLayerFlagsSet 1232#Line # sets SaveLayerRec options ## 1233#Code 1234#Populate 1235## 1236 1237 1238#Typedef uint32_t SaveLayerFlags 1239#Line # options for SaveLayerRec ## 1240## 1241 1242SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, 1243defining how Layer allocated by saveLayer operates. It may be set to zero or 1244kInitWithPrevious_SaveLayerFlag. 1245 1246#Const kInitWithPrevious_SaveLayerFlag 4 1247#Line # initializes with previous contents ## 1248 Initializes Layer with the contents of the previous Layer. 1249## 1250 1251#Example 1252#Height 160 1253#Description 1254Canvas Layer captures red and blue circles scaled up by four. 1255scalePaint blends Layer back with transparency. 1256## 1257void draw(SkCanvas* canvas) { 1258 SkPaint redPaint, bluePaint, scalePaint; 1259 redPaint.setColor(SK_ColorRED); 1260 canvas->drawCircle(21, 21, 8, redPaint); 1261 bluePaint.setColor(SK_ColorBLUE); 1262 canvas->drawCircle(31, 21, 8, bluePaint); 1263 SkMatrix matrix; 1264 matrix.setScale(4, 4); 1265 scalePaint.setAlpha(0x40); 1266 scalePaint.setImageFilter( 1267 SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr)); 1268 SkCanvas::SaveLayerRec saveLayerRec(nullptr, &scalePaint, 1269 SkCanvas::kInitWithPrevious_SaveLayerFlag); 1270 canvas->saveLayer(saveLayerRec); 1271 canvas->restore(); 1272} 1273## 1274 1275#SeeAlso save restore saveLayer saveLayerAlpha SaveLayerRec 1276 1277#Enum ## 1278 1279#Subtopic SaveLayerRec 1280#Line # contains the state used to create the Layer ## 1281 1282#Struct SaveLayerRec 1283#Line # contains the state used to create the Layer ## 1284 1285#Code 1286#Populate 1287## 1288 1289SaveLayerRec contains the state used to create the Layer. 1290 1291#Member const SkRect* fBounds 1292#Line # hints at Layer size limit ## 1293 fBounds is used as a hint to limit the size of Layer; may be nullptr. 1294 fBounds suggests but does not define Layer size. To clip drawing to 1295 a specific rectangle, use clipRect. 1296## 1297 1298#Member const SkPaint* fPaint 1299#Line # modifies overlay ## 1300 fPaint modifies how Layer overlays the prior Layer; may be nullptr. 1301 Color_Alpha, Blend_Mode, Color_Filter, Draw_Looper, Image_Filter, and 1302 Mask_Filter affect Layer draw. 1303## 1304 1305#Member const SkImageFilter* fBackdrop 1306#Line # applies Image_Filter to prior Layer ## 1307 If not null, this triggers the same initialization behavior as setting kInitWithPrevious_SaveLayerFlag 1308 on fSaveLayerFlags: the current layer is copied into the new layer, rather than initializing the 1309 new layer with transparent-black. This is then filtered by fBackdrop (respecting the current clip). 1310## 1311 1312#Member const SkImage* fClipMask 1313#Line # clips Layer with Mask_Alpha ## 1314 restore() clips Layer by the Color_Alpha channel of fClipMask when 1315 Layer is copied to Device. fClipMask may be nullptr. . 1316## 1317 1318#Member const SkMatrix* fClipMatrix 1319#Line # transforms Mask_Alpha used to clip ## 1320 fClipMatrix transforms fClipMask before it clips Layer. If 1321 fClipMask describes a translucent gradient, it may be scaled and rotated 1322 without introducing artifacts. fClipMatrix may be nullptr. 1323## 1324 1325#Member SaveLayerFlags fSaveLayerFlags 1326#Line # creates with prior Layer contents ## 1327 fSaveLayerFlags are used to create Layer without transparency, 1328 and to create Layer with the contents of the previous Layer. 1329## 1330 1331#Example 1332#Height 160 1333#Description 1334Canvas Layer captures a red Anti_Aliased circle and a blue Aliased circle scaled 1335up by four. After drawing another red circle without scaling on top, the Layer is 1336transferred to the main canvas. 1337## 1338void draw(SkCanvas* canvas) { 1339 SkPaint redPaint, bluePaint; 1340 redPaint.setAntiAlias(true); 1341 redPaint.setColor(SK_ColorRED); 1342 canvas->drawCircle(21, 21, 8, redPaint); 1343 bluePaint.setColor(SK_ColorBLUE); 1344 canvas->drawCircle(31, 21, 8, bluePaint); 1345 SkMatrix matrix; 1346 matrix.setScale(4, 4); 1347 auto scaler = SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr); 1348 SkCanvas::SaveLayerRec saveLayerRec(nullptr, nullptr, scaler.get(), 0); 1349 canvas->saveLayer(saveLayerRec); 1350 canvas->drawCircle(125, 85, 8, redPaint); 1351 canvas->restore(); 1352} 1353## 1354 1355#Subtopic Constructors 1356## 1357 1358#Method SaveLayerRec() 1359#Line # constructs SaveLayerRec ## 1360#Populate 1361 1362#Example 1363 SkCanvas::SaveLayerRec rec1; 1364 rec1.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag; 1365 SkCanvas::SaveLayerRec rec2(nullptr, nullptr, SkCanvas::kInitWithPrevious_SaveLayerFlag); 1366 SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds 1367 && rec1.fPaint == rec2.fPaint 1368 && rec1.fBackdrop == rec2.fBackdrop 1369 && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); 1370 #StdOut 1371 rec1 == rec2 1372 ## 1373## 1374 1375#SeeAlso save restore saveLayer saveLayerAlpha 1376 1377## 1378 1379#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) 1380#Populate 1381 1382#Example 1383 SkCanvas::SaveLayerRec rec1; 1384 SkCanvas::SaveLayerRec rec2(nullptr, nullptr); 1385 SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds 1386 && rec1.fPaint == rec2.fPaint 1387 && rec1.fBackdrop == rec2.fBackdrop 1388 && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); 1389 #StdOut 1390 rec1 == rec2 1391 ## 1392## 1393 1394#SeeAlso save restore saveLayer saveLayerAlpha 1395 1396## 1397 1398#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, 1399 SaveLayerFlags saveLayerFlags) 1400#Populate 1401 1402#Example 1403 SkCanvas::SaveLayerRec rec1; 1404 SkCanvas::SaveLayerRec rec2(nullptr, nullptr, nullptr, 0); 1405 SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds 1406 && rec1.fPaint == rec2.fPaint 1407 && rec1.fBackdrop == rec2.fBackdrop 1408 && rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!'); 1409 #StdOut 1410 rec1 == rec2 1411 ## 1412## 1413 1414#SeeAlso save restore saveLayer saveLayerAlpha 1415 1416## 1417 1418#Struct ## 1419 1420#Subtopic ## 1421 1422#Method int saveLayer(const SaveLayerRec& layerRec) 1423 1424#In Layer 1425#Populate 1426 1427#Example 1428#Description 1429The example draws an image, and saves it into a Layer with kInitWithPrevious_SaveLayerFlag. 1430Next it punches a hole in Layer and restore with SkBlendMode::kPlus. 1431Where Layer was cleared, the original image will draw unchanged. 1432Outside of the circle the mandrill is brightened. 1433## 1434 #Image 3 1435 // sk_sp<SkImage> image = GetResourceAsImage("images/mandrill_256.png"); 1436 canvas->drawImage(image, 0, 0, nullptr); 1437 SkCanvas::SaveLayerRec rec; 1438 SkPaint paint; 1439 paint.setBlendMode(SkBlendMode::kPlus); 1440 rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag; 1441 rec.fPaint = &paint; 1442 canvas->saveLayer(rec); 1443 paint.setBlendMode(SkBlendMode::kClear); 1444 canvas->drawCircle(128, 128, 96, paint); 1445 canvas->restore(); 1446## 1447 1448#ToDo above example needs to replace GetResourceAsImage with way to select image in fiddle ## 1449 1450#SeeAlso save restore saveLayer saveLayerAlpha 1451 1452## 1453 1454#Subtopic Layer ## 1455 1456# ------------------------------------------------------------------------------ 1457#Subtopic Matrix 1458#Line # coordinate transformation ## 1459 1460#Method void translate(SkScalar dx, SkScalar dy) 1461 1462#In Matrix 1463#Line # translates Matrix ## 1464#Populate 1465 1466#Example 1467#Height 128 1468#Description 1469scale() followed by translate() produces different results from translate() followed 1470by scale(). 1471 1472The blue stroke follows translate of (50, 50); a black 1473fill follows scale of (2, 1/2.f). After restoring the clip, which resets 1474Matrix, a red frame follows the same scale of (2, 1/2.f); a gray fill 1475follows translate of (50, 50). 1476## 1477void draw(SkCanvas* canvas) { 1478 SkPaint filledPaint; 1479 SkPaint outlinePaint; 1480 outlinePaint.setStyle(SkPaint::kStroke_Style); 1481 outlinePaint.setColor(SK_ColorBLUE); 1482 canvas->save(); 1483 canvas->translate(50, 50); 1484 canvas->drawCircle(28, 28, 15, outlinePaint); // blue center: (50+28, 50+28) 1485 canvas->scale(2, 1/2.f); 1486 canvas->drawCircle(28, 28, 15, filledPaint); // black center: (50+(28*2), 50+(28/2)) 1487 canvas->restore(); 1488 filledPaint.setColor(SK_ColorGRAY); 1489 outlinePaint.setColor(SK_ColorRED); 1490 canvas->scale(2, 1/2.f); 1491 canvas->drawCircle(28, 28, 15, outlinePaint); // red center: (28*2, 28/2) 1492 canvas->translate(50, 50); 1493 canvas->drawCircle(28, 28, 15, filledPaint); // gray center: ((50+28)*2, (50+28)/2) 1494} 1495## 1496 1497#SeeAlso concat() scale() skew() rotate() setMatrix 1498 1499## 1500 1501# ------------------------------------------------------------------------------ 1502 1503#Method void scale(SkScalar sx, SkScalar sy) 1504 1505#In Matrix 1506#Line # scales Matrix ## 1507#Populate 1508 1509#Example 1510#Height 160 1511void draw(SkCanvas* canvas) { 1512 SkPaint paint; 1513 SkRect rect = { 10, 20, 60, 120 }; 1514 canvas->translate(20, 20); 1515 canvas->drawRect(rect, paint); 1516 canvas->scale(2, .5f); 1517 paint.setColor(SK_ColorGRAY); 1518 canvas->drawRect(rect, paint); 1519} 1520## 1521 1522#SeeAlso concat() translate() skew() rotate() setMatrix 1523 1524## 1525 1526# ------------------------------------------------------------------------------ 1527 1528#Method void rotate(SkScalar degrees) 1529 1530#In Matrix 1531#Line # rotates Matrix ## 1532#Populate 1533 1534#Example 1535#Description 1536Draw clock hands at time 5:10. The hour hand and minute hand point up and 1537are rotated clockwise. 1538## 1539void draw(SkCanvas* canvas) { 1540 SkPaint paint; 1541 paint.setStyle(SkPaint::kStroke_Style); 1542 canvas->translate(128, 128); 1543 canvas->drawCircle(0, 0, 60, paint); 1544 canvas->save(); 1545 canvas->rotate(10 * 360 / 60); // 10 minutes of 60 scaled to 360 degrees 1546 canvas->drawLine(0, 0, 0, -50, paint); 1547 canvas->restore(); 1548 canvas->rotate((5 + 10.f/60) * 360 / 12); // 5 and 10/60 hours of 12 scaled to 360 degrees 1549 canvas->drawLine(0, 0, 0, -30, paint); 1550} 1551## 1552 1553#SeeAlso concat() translate() skew() scale() setMatrix 1554 1555## 1556 1557# ------------------------------------------------------------------------------ 1558 1559#Method void rotate(SkScalar degrees, SkScalar px, SkScalar py) 1560 1561#In Matrix 1562#Populate 1563 1564#Example 1565#Height 192 1566void draw(SkCanvas* canvas) { 1567 SkPaint paint; 1568 SkFont font(nullptr, 96); 1569 canvas->drawString("A1", 130, 100, font, paint); 1570 canvas->rotate(180, 130, 100); 1571 canvas->drawString("A1", 130, 100, font, paint); 1572} 1573## 1574 1575#SeeAlso concat() translate() skew() scale() setMatrix 1576 1577## 1578 1579# ------------------------------------------------------------------------------ 1580 1581#Method void skew(SkScalar sx, SkScalar sy) 1582 1583#In Matrix 1584#Line # skews Matrix ## 1585#Populate 1586 1587#Example 1588 #Description 1589 Black text mimics an oblique text style by using a negative skew on x-axis 1590 that shifts the geometry to the right as the y-axis values decrease. 1591 Red text uses a positive skew on y-axis to shift the geometry down 1592 as the x-axis values increase. 1593 Blue text combines sx and sy skew to rotate and scale. 1594 ## 1595 SkPaint paint; 1596 SkFont font(nullptr, 128); 1597 canvas->translate(30, 130); 1598 canvas->save(); 1599 canvas->skew(-.5, 0); 1600 canvas->drawString("A1", 0, 0, font, paint); 1601 canvas->restore(); 1602 canvas->save(); 1603 canvas->skew(0, .5); 1604 paint.setColor(SK_ColorRED); 1605 canvas->drawString("A1", 0, 0, font, paint); 1606 canvas->restore(); 1607 canvas->skew(-.5, .5); 1608 paint.setColor(SK_ColorBLUE); 1609 canvas->drawString("A1", 0, 0, font, paint); 1610## 1611 1612#SeeAlso concat() translate() rotate() scale() setMatrix 1613 1614## 1615 1616# ------------------------------------------------------------------------------ 1617 1618#Method void concat(const SkMatrix& matrix) 1619 1620#In Matrix 1621#Line # multiplies Matrix by Matrix ## 1622#Populate 1623 1624#Example 1625void draw(SkCanvas* canvas) { 1626 SkPaint paint; 1627 SkFont font(nullptr, 80); 1628 font.setScaleX(.3); 1629 SkMatrix matrix; 1630 SkRect rect[2] = {{ 10, 20, 90, 110 }, { 40, 130, 140, 180 }}; 1631 matrix.setRectToRect(rect[0], rect[1], SkMatrix::kFill_ScaleToFit); 1632 canvas->drawRect(rect[0], paint); 1633 canvas->drawRect(rect[1], paint); 1634 paint.setColor(SK_ColorWHITE); 1635 canvas->drawString("Here", rect[0].fLeft + 10, rect[0].fBottom - 10, font, paint); 1636 canvas->concat(matrix); 1637 canvas->drawString("There", rect[0].fLeft + 10, rect[0].fBottom - 10, font, paint); 1638} 1639## 1640 1641#SeeAlso translate() rotate() scale() skew() setMatrix 1642 1643## 1644 1645# ------------------------------------------------------------------------------ 1646 1647#Method void setMatrix(const SkMatrix& matrix) 1648 1649#In Matrix 1650#Line # sets Matrix ## 1651#Populate 1652 1653#Example 1654#Height 128 1655void draw(SkCanvas* canvas) { 1656 SkPaint paint; 1657 SkFont font; 1658 canvas->scale(4, 6); 1659 canvas->drawString("truth", 2, 10, font, paint); 1660 SkMatrix matrix; 1661 matrix.setScale(2.8f, 6); 1662 canvas->setMatrix(matrix); 1663 canvas->drawString("consequences", 2, 20, font, paint); 1664} 1665## 1666 1667#SeeAlso resetMatrix concat() translate() rotate() scale() skew() 1668 1669## 1670 1671# ------------------------------------------------------------------------------ 1672 1673#Method void resetMatrix() 1674 1675#In Matrix 1676#Line # resets Matrix to identity ## 1677#Populate 1678 1679#Example 1680#Height 128 1681void draw(SkCanvas* canvas) { 1682 SkPaint paint; 1683 SkFont font; 1684 canvas->scale(4, 6); 1685 canvas->drawString("truth", 2, 10, font, paint); 1686 canvas->resetMatrix(); 1687 canvas->scale(2.8f, 6); 1688 canvas->drawString("consequences", 2, 20, font, paint); 1689} 1690## 1691 1692#SeeAlso setMatrix concat() translate() rotate() scale() skew() 1693 1694## 1695 1696# ------------------------------------------------------------------------------ 1697 1698#Method const SkMatrix& getTotalMatrix() const 1699 1700#In Matrix 1701#Line # returns Matrix ## 1702#Populate 1703 1704#Example 1705 SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false"); 1706 #StdOut 1707 isIdentity true 1708 ## 1709## 1710 1711#SeeAlso setMatrix resetMatrix concat() 1712 1713## 1714 1715#Subtopic Matrix ## 1716 1717# ------------------------------------------------------------------------------ 1718#Subtopic Clip 1719#Line # stack of clipping Paths ## 1720 1721Clip is built from a stack of clipping paths. Each Path in the 1722stack can be constructed from one or more Path_Contour elements. The 1723Path_Contour may be composed of any number of Path_Verb segments. Each 1724Path_Contour forms a closed area; Path_Fill_Type defines the area enclosed 1725by Path_Contour. 1726 1727Clip stack of Path elements successfully restrict the Path area. Each 1728Path is transformed by Matrix, then intersected with or subtracted from the 1729prior Clip to form the replacement Clip. Use SkClipOp::kDifference 1730to subtract Path from Clip; use SkClipOp::kIntersect to intersect Path 1731with Clip. 1732 1733A clipping Path may be Anti_Aliased; if Path, after transformation, is 1734composed of horizontal and vertical lines, clearing Anti_Alias allows whole pixels 1735to either be inside or outside the clip. The fastest drawing has a Aliased, 1736rectangular clip. 1737 1738If clipping Path has Anti_Alias set, clip may partially clip a pixel, requiring 1739that drawing blend partially with the destination along the edge. A rotated 1740rectangular Anti_Aliased clip looks smoother but draws slower. 1741 1742Clip can combine with Rect and Round_Rect primitives; like 1743Path, these are transformed by Matrix before they are combined with Clip. 1744 1745Clip can combine with Region. Region is assumed to be in Device coordinates 1746and is unaffected by Matrix. 1747 1748#Example 1749#Height 90 1750 #Description 1751 Draw a red circle with an Aliased clip and an Anti_Aliased clip. 1752 Use an image filter to zoom into the pixels drawn. 1753 The edge of the Aliased clip fully draws pixels in the red circle. 1754 The edge of the Anti_Aliased clip partially draws pixels in the red circle. 1755 ## 1756 SkPaint redPaint, scalePaint; 1757 redPaint.setAntiAlias(true); 1758 redPaint.setColor(SK_ColorRED); 1759 canvas->save(); 1760 for (bool antialias : { false, true } ) { 1761 canvas->save(); 1762 canvas->clipRect(SkRect::MakeWH(19.5f, 11.5f), antialias); 1763 canvas->drawCircle(17, 11, 8, redPaint); 1764 canvas->restore(); 1765 canvas->translate(16, 0); 1766 } 1767 canvas->restore(); 1768 SkMatrix matrix; 1769 matrix.setScale(6, 6); 1770 scalePaint.setImageFilter( 1771 SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr)); 1772 SkCanvas::SaveLayerRec saveLayerRec( 1773 nullptr, &scalePaint, SkCanvas::kInitWithPrevious_SaveLayerFlag); 1774 canvas->saveLayer(saveLayerRec); 1775 canvas->restore(); 1776## 1777 1778#Method void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias) 1779 1780#In Clip 1781#Line # combines Clip with Rect ## 1782#Populate 1783 1784#Example 1785#Height 128 1786void draw(SkCanvas* canvas) { 1787 canvas->rotate(10); 1788 SkPaint paint; 1789 paint.setAntiAlias(true); 1790 for (auto alias: { false, true } ) { 1791 canvas->save(); 1792 canvas->clipRect(SkRect::MakeWH(90, 80), SkClipOp::kIntersect, alias); 1793 canvas->drawCircle(100, 60, 60, paint); 1794 canvas->restore(); 1795 canvas->translate(80, 0); 1796 } 1797} 1798## 1799 1800#SeeAlso clipRRect clipPath clipRegion 1801 1802## 1803 1804#Method void clipRect(const SkRect& rect, SkClipOp op) 1805 1806#In Clip 1807#Populate 1808 1809#Example 1810#Height 192 1811#Width 280 1812void draw(SkCanvas* canvas) { 1813 SkPaint paint; 1814 for (SkClipOp op: { SkClipOp::kIntersect, SkClipOp::kDifference } ) { 1815 canvas->save(); 1816 canvas->clipRect(SkRect::MakeWH(90, 120), op, false); 1817 canvas->drawCircle(100, 100, 60, paint); 1818 canvas->restore(); 1819 canvas->translate(80, 0); 1820 } 1821} 1822## 1823 1824#SeeAlso clipRRect clipPath clipRegion 1825 1826## 1827 1828#Method void clipRect(const SkRect& rect, bool doAntiAlias = false) 1829 1830#In Clip 1831#Populate 1832 1833#Example 1834#Height 133 1835 #Description 1836 A circle drawn in pieces looks uniform when drawn Aliased. 1837 The same circle pieces blend with pixels more than once when Anti_Aliased, 1838 visible as a thin pair of lines through the right circle. 1839 ## 1840void draw(SkCanvas* canvas) { 1841 canvas->clear(SK_ColorWHITE); 1842 SkPaint paint; 1843 paint.setAntiAlias(true); 1844 paint.setColor(0x8055aaff); 1845 SkRect clipRect = { 0, 0, 87.4f, 87.4f }; 1846 for (auto alias: { false, true } ) { 1847 canvas->save(); 1848 canvas->clipRect(clipRect, SkClipOp::kIntersect, alias); 1849 canvas->drawCircle(67, 67, 60, paint); 1850 canvas->restore(); 1851 canvas->save(); 1852 canvas->clipRect(clipRect, SkClipOp::kDifference, alias); 1853 canvas->drawCircle(67, 67, 60, paint); 1854 canvas->restore(); 1855 canvas->translate(120, 0); 1856 } 1857} 1858## 1859 1860#SeeAlso clipRRect clipPath clipRegion 1861 1862## 1863 1864#Method void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias) 1865 1866#In Clip 1867#Line # combines Clip with Round_Rect ## 1868#Populate 1869 1870#Example 1871#Height 128 1872void draw(SkCanvas* canvas) { 1873 canvas->clear(SK_ColorWHITE); 1874 SkPaint paint; 1875 paint.setAntiAlias(true); 1876 paint.setColor(0x8055aaff); 1877 SkRRect oval; 1878 oval.setOval({10, 20, 90, 100}); 1879 canvas->clipRRect(oval, SkClipOp::kIntersect, true); 1880 canvas->drawCircle(70, 100, 60, paint); 1881} 1882## 1883 1884#SeeAlso clipRect clipPath clipRegion 1885 1886## 1887 1888#Method void clipRRect(const SkRRect& rrect, SkClipOp op) 1889 1890#In Clip 1891#Populate 1892 1893#Example 1894#Height 128 1895void draw(SkCanvas* canvas) { 1896 SkPaint paint; 1897 paint.setColor(0x8055aaff); 1898 auto oval = SkRRect::MakeOval({10, 20, 90, 100}); 1899 canvas->clipRRect(oval, SkClipOp::kIntersect); 1900 canvas->drawCircle(70, 100, 60, paint); 1901} 1902## 1903 1904#SeeAlso clipRect clipPath clipRegion 1905 1906## 1907 1908#Method void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) 1909 1910#In Clip 1911#Populate 1912 1913#Example 1914#Height 128 1915void draw(SkCanvas* canvas) { 1916 SkPaint paint; 1917 paint.setAntiAlias(true); 1918 auto oval = SkRRect::MakeRectXY({10, 20, 90, 100}, 9, 13); 1919 canvas->clipRRect(oval, true); 1920 canvas->drawCircle(70, 100, 60, paint); 1921} 1922## 1923 1924#SeeAlso clipRect clipPath clipRegion 1925 1926## 1927 1928#Method void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias) 1929 1930#In Clip 1931#Line # combines Clip with Path ## 1932#Populate 1933 1934#Example 1935#Description 1936Top figure uses SkPath::kInverseWinding_FillType and SkClipOp::kDifference; 1937area outside clip is subtracted from circle. 1938 1939Bottom figure uses SkPath::kWinding_FillType and SkClipOp::kIntersect; 1940area inside clip is intersected with circle. 1941## 1942void draw(SkCanvas* canvas) { 1943 SkPaint paint; 1944 paint.setAntiAlias(true); 1945 SkPath path; 1946 path.addRect({20, 30, 100, 110}); 1947 path.setFillType(SkPath::kInverseWinding_FillType); 1948 canvas->save(); 1949 canvas->clipPath(path, SkClipOp::kDifference, false); 1950 canvas->drawCircle(70, 100, 60, paint); 1951 canvas->restore(); 1952 canvas->translate(100, 100); 1953 path.setFillType(SkPath::kWinding_FillType); 1954 canvas->clipPath(path, SkClipOp::kIntersect, false); 1955 canvas->drawCircle(70, 100, 60, paint); 1956} 1957## 1958 1959#SeeAlso clipRect clipRRect clipRegion 1960 1961## 1962 1963#Method void clipPath(const SkPath& path, SkClipOp op) 1964 1965#In Clip 1966#Populate 1967 1968#Example 1969#Description 1970Overlapping Rects form a clip. When clip Path_Fill_Type is set to 1971SkPath::kWinding_FillType, the overlap is included. Set to 1972SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole. 1973## 1974void draw(SkCanvas* canvas) { 1975 SkPaint paint; 1976 paint.setAntiAlias(true); 1977 SkPath path; 1978 path.addRect({20, 15, 100, 95}); 1979 path.addRect({50, 65, 130, 135}); 1980 path.setFillType(SkPath::kWinding_FillType); 1981 canvas->save(); 1982 canvas->clipPath(path, SkClipOp::kIntersect); 1983 canvas->drawCircle(70, 85, 60, paint); 1984 canvas->restore(); 1985 canvas->translate(100, 100); 1986 path.setFillType(SkPath::kEvenOdd_FillType); 1987 canvas->clipPath(path, SkClipOp::kIntersect); 1988 canvas->drawCircle(70, 85, 60, paint); 1989} 1990## 1991 1992#SeeAlso clipRect clipRRect clipRegion 1993 1994## 1995 1996#Method void clipPath(const SkPath& path, bool doAntiAlias = false) 1997 1998#In Clip 1999#Populate 2000 2001#Example 2002#Height 212 2003#Description 2004Clip loops over itself covering its center twice. When clip Path_Fill_Type 2005is set to SkPath::kWinding_FillType, the overlap is included. Set to 2006SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole. 2007## 2008void draw(SkCanvas* canvas) { 2009 SkPaint paint; 2010 paint.setAntiAlias(true); 2011 SkPath path; 2012 SkPoint poly[] = {{20, 20}, { 80, 20}, { 80, 80}, {40, 80}, 2013 {40, 40}, {100, 40}, {100, 100}, {20, 100}}; 2014 path.addPoly(poly, SK_ARRAY_COUNT(poly), true); 2015 path.setFillType(SkPath::kWinding_FillType); 2016 canvas->save(); 2017 canvas->clipPath(path, SkClipOp::kIntersect); 2018 canvas->drawCircle(50, 50, 45, paint); 2019 canvas->restore(); 2020 canvas->translate(100, 100); 2021 path.setFillType(SkPath::kEvenOdd_FillType); 2022 canvas->clipPath(path, SkClipOp::kIntersect); 2023 canvas->drawCircle(50, 50, 45, paint); 2024} 2025## 2026 2027#SeeAlso clipRect clipRRect clipRegion 2028 2029## 2030 2031# ------------------------------------------------------------------------------ 2032 2033#Method void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect) 2034 2035#In Clip 2036#Line # combines Clip with Region ## 2037#Populate 2038 2039#Example 2040#Description 2041 region is unaffected by canvas rotation; iRect is affected by canvas rotation. 2042 Both clips are Aliased; this is not noticeable on Region clip because it 2043 aligns to pixel boundaries. 2044## 2045void draw(SkCanvas* canvas) { 2046 SkPaint paint; 2047 paint.setAntiAlias(true); 2048 SkIRect iRect = {30, 40, 120, 130 }; 2049 SkRegion region(iRect); 2050 canvas->rotate(10); 2051 canvas->save(); 2052 canvas->clipRegion(region, SkClipOp::kIntersect); 2053 canvas->drawCircle(50, 50, 45, paint); 2054 canvas->restore(); 2055 canvas->translate(100, 100); 2056 canvas->clipRect(SkRect::Make(iRect), SkClipOp::kIntersect); 2057 canvas->drawCircle(50, 50, 45, paint); 2058} 2059## 2060 2061#SeeAlso clipRect clipRRect clipPath 2062 2063## 2064 2065#Method bool quickReject(const SkRect& rect) const 2066 2067#In Clip 2068#Line # returns if Rect is outside Clip ## 2069#Populate 2070 2071#Example 2072void draw(SkCanvas* canvas) { 2073 SkRect testRect = {30, 30, 120, 129 }; 2074 SkRect clipRect = {30, 130, 120, 230 }; 2075 canvas->save(); 2076 canvas->clipRect(clipRect); 2077 SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false"); 2078 canvas->restore(); 2079 canvas->rotate(10); 2080 canvas->clipRect(clipRect); 2081 SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false"); 2082} 2083 #StdOut 2084 quickReject true 2085 quickReject false 2086 ## 2087## 2088 2089#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing 2090 2091## 2092 2093#Method bool quickReject(const SkPath& path) const 2094 2095#In Clip 2096#Populate 2097 2098#Example 2099void draw(SkCanvas* canvas) { 2100 SkPoint testPoints[] = {{30, 30}, {120, 30}, {120, 129} }; 2101 SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} }; 2102 SkPath testPath, clipPath; 2103 testPath.addPoly(testPoints, SK_ARRAY_COUNT(testPoints), true); 2104 clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true); 2105 canvas->save(); 2106 canvas->clipPath(clipPath); 2107 SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false"); 2108 canvas->restore(); 2109 canvas->rotate(10); 2110 canvas->clipPath(clipPath); 2111 SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false"); 2112 #StdOut 2113 quickReject true 2114 quickReject false 2115 ## 2116} 2117## 2118 2119#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing 2120 2121## 2122 2123#Method SkRect getLocalClipBounds() const 2124 2125#In Clip 2126#Line # returns Clip bounds in source coordinates ## 2127#Populate 2128 2129#Example 2130 #Description 2131 Initial bounds is device bounds outset by 1 on all sides. 2132 Clipped bounds is clipPath bounds outset by 1 on all sides. 2133 Scaling the canvas by two on both axes scales the local bounds by 1/2 2134 on both axes. 2135 ## 2136 SkCanvas local(256, 256); 2137 canvas = &local; 2138 SkRect bounds = canvas->getLocalClipBounds(); 2139 SkDebugf("left:%g top:%g right:%g bottom:%g\n", 2140 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2141 SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} }; 2142 SkPath clipPath; 2143 clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true); 2144 canvas->clipPath(clipPath); 2145 bounds = canvas->getLocalClipBounds(); 2146 SkDebugf("left:%g top:%g right:%g bottom:%g\n", 2147 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2148 canvas->scale(2, 2); 2149 bounds = canvas->getLocalClipBounds(); 2150 SkDebugf("left:%g top:%g right:%g bottom:%g\n", 2151 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2152 #StdOut 2153 left:-1 top:-1 right:257 bottom:257 2154 left:29 top:129 right:121 bottom:231 2155 left:14.5 top:64.5 right:60.5 bottom:115.5 2156 ## 2157## 2158 2159# local canvas in example works around bug in fiddle ## 2160#Bug 6524 2161#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject 2162 2163## 2164 2165#Method bool getLocalClipBounds(SkRect* bounds) const 2166 2167#In Clip 2168#Populate 2169 2170#Example 2171 void draw(SkCanvas* canvas) { 2172 SkCanvas local(256, 256); 2173 canvas = &local; 2174 SkRect bounds; 2175 SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds) 2176 ? "false" : "true"); 2177 SkPath path; 2178 canvas->clipPath(path); 2179 SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds) 2180 ? "false" : "true"); 2181 } 2182 #StdOut 2183 local bounds empty = false 2184 local bounds empty = true 2185 ## 2186## 2187 2188# local canvas in example works around bug in fiddle ## 2189#Bug 6524 2190#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject 2191 2192## 2193 2194#Method SkIRect getDeviceClipBounds() const 2195 2196#In Clip 2197#Line # returns IRect bounds of Clip ## 2198#Populate 2199 2200#Example 2201void draw(SkCanvas* canvas) { 2202 #Description 2203 Initial bounds is device bounds, not outset. 2204 Clipped bounds is clipPath bounds, not outset. 2205 Scaling the canvas by 1/2 on both axes scales the device bounds by 1/2 2206 on both axes. 2207 ## 2208 SkCanvas device(256, 256); 2209 canvas = &device; 2210 SkIRect bounds = canvas->getDeviceClipBounds(); 2211 SkDebugf("left:%d top:%d right:%d bottom:%d\n", 2212 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2213 SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} }; 2214 SkPath clipPath; 2215 clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true); 2216 canvas->save(); 2217 canvas->clipPath(clipPath); 2218 bounds = canvas->getDeviceClipBounds(); 2219 SkDebugf("left:%d top:%d right:%d bottom:%d\n", 2220 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2221 canvas->restore(); 2222 canvas->scale(1.f/2, 1.f/2); 2223 canvas->clipPath(clipPath); 2224 bounds = canvas->getDeviceClipBounds(); 2225 SkDebugf("left:%d top:%d right:%d bottom:%d\n", 2226 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 2227 #StdOut 2228 left:0 top:0 right:256 bottom:256 2229 left:30 top:130 right:120 bottom:230 2230 left:15 top:65 right:60 bottom:115 2231 ## 2232} 2233## 2234 2235#ToDo some confusion on why with an identity Matrix local and device are different ## 2236#SeeAlso getLocalClipBounds getBaseLayerSize quickReject 2237 2238# device canvas in example works around bug in fiddle ## 2239#Bug 6524 2240 2241## 2242 2243#Method bool getDeviceClipBounds(SkIRect* bounds) const 2244 2245#In Clip 2246#Populate 2247 2248#Example 2249 void draw(SkCanvas* canvas) { 2250 SkIRect bounds; 2251 SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds) 2252 ? "false" : "true"); 2253 SkPath path; 2254 canvas->clipPath(path); 2255 SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds) 2256 ? "false" : "true"); 2257 } 2258 #StdOut 2259 device bounds empty = false 2260 device bounds empty = true 2261 ## 2262## 2263 2264#SeeAlso getLocalClipBounds getBaseLayerSize quickReject 2265 2266## 2267 2268#Subtopic Clip ## 2269 2270# ------------------------------------------------------------------------------ 2271#Subtopic Draw 2272#Line # draws into Canvas ## 2273## 2274 2275#Method void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver) 2276#In Draw 2277#Line # fills Clip with Color and Blend_Mode ## 2278#Populate 2279 2280#Example 2281 canvas->drawColor(SK_ColorRED); 2282 canvas->clipRect(SkRect::MakeWH(150, 150)); 2283 canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00), SkBlendMode::kPlus); 2284 canvas->clipRect(SkRect::MakeWH(75, 75)); 2285 canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF), SkBlendMode::kPlus); 2286## 2287 2288#SeeAlso clear SkBitmap::erase drawPaint 2289 2290## 2291 2292# ------------------------------------------------------------------------------ 2293 2294#Method void clear(SkColor color) 2295#In Draw 2296#Line # fills Clip with Color ## 2297#Populate 2298 2299#Example 2300void draw(SkCanvas* canvas) { 2301 canvas->save(); 2302 canvas->clipRect(SkRect::MakeWH(256, 128)); 2303 canvas->clear(SkColorSetARGB(0x80, 0xFF, 0x00, 0x00)); 2304 canvas->restore(); 2305 canvas->save(); 2306 canvas->clipRect(SkRect::MakeWH(150, 192)); 2307 canvas->clear(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00)); 2308 canvas->restore(); 2309 canvas->clipRect(SkRect::MakeWH(75, 256)); 2310 canvas->clear(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF)); 2311} 2312## 2313 2314#SeeAlso drawColor SkBitmap::erase drawPaint 2315 2316## 2317 2318# ------------------------------------------------------------------------------ 2319 2320#Method void discard() 2321#In Utility 2322#Line # makes Canvas contents undefined ## 2323#Populate 2324 2325#NoExample 2326## 2327 2328#SeeAlso flush() GrContext::abandonContext 2329 2330## 2331 2332# ------------------------------------------------------------------------------ 2333 2334#Method void drawPaint(const SkPaint& paint) 2335#In Draw 2336#Line # fills Clip with Paint ## 2337#Populate 2338 2339#Example 2340void draw(SkCanvas* canvas) { 2341 SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE }; 2342 SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 }; 2343 SkPaint paint; 2344 paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, SK_ARRAY_COUNT(colors))); 2345 canvas->drawPaint(paint); 2346} 2347## 2348 2349#SeeAlso clear drawColor SkBitmap::erase 2350 2351## 2352 2353# ------------------------------------------------------------------------------ 2354 2355#Enum PointMode 2356#Line # sets drawPoints options ## 2357 2358#Code 2359#Populate 2360## 2361 2362Selects if an array of points are drawn as discrete points, as lines, or as 2363an open polygon. 2364 2365#Const kPoints_PointMode 0 2366#Line # draw each point separately ## 2367## 2368 2369#Const kLines_PointMode 1 2370#Line # draw each pair of points as a line segment ## 2371## 2372 2373#Const kPolygon_PointMode 2 2374#Line # draw the array of points as a open polygon ## 2375## 2376 2377#Example 2378 #Description 2379 The upper left corner shows three squares when drawn as points. 2380 The upper right corner shows one line; when drawn as lines, two points are required per line. 2381 The lower right corner shows two lines; when draw as polygon, no miter is drawn at the corner. 2382 The lower left corner shows two lines with a miter when path contains polygon. 2383 ## 2384void draw(SkCanvas* canvas) { 2385 SkPaint paint; 2386 paint.setStyle(SkPaint::kStroke_Style); 2387 paint.setStrokeWidth(10); 2388 SkPoint points[] = {{64, 32}, {96, 96}, {32, 96}}; 2389 canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, points, paint); 2390 canvas->translate(128, 0); 2391 canvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint); 2392 canvas->translate(0, 128); 2393 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, paint); 2394 SkPath path; 2395 path.addPoly(points, 3, false); 2396 canvas->translate(-128, 0); 2397 canvas->drawPath(path, paint); 2398} 2399## 2400 2401#SeeAlso drawLine drawPoint drawPath 2402 2403## 2404 2405# ------------------------------------------------------------------------------ 2406 2407#Method void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) 2408#In Draw 2409#Line # draws array as points, lines, polygon ## 2410#Populate 2411 2412#Example 2413#Height 200 2414 #Description 2415 #List 2416 # The first column draws points. ## 2417 # The second column draws points as lines. ## 2418 # The third column draws points as a polygon. ## 2419 # The fourth column draws points as a polygonal path. ## 2420 # The first row uses a round cap and round join. ## 2421 # The second row uses a square cap and a miter join. ## 2422 # The third row uses a butt cap and a bevel join. ## 2423 ## 2424 The transparent color makes multiple line draws visible; 2425 the path is drawn all at once. 2426 ## 2427void draw(SkCanvas* canvas) { 2428 SkPaint paint; 2429 paint.setAntiAlias(true); 2430 paint.setStyle(SkPaint::kStroke_Style); 2431 paint.setStrokeWidth(10); 2432 paint.setColor(0x80349a45); 2433 const SkPoint points[] = {{32, 16}, {48, 48}, {16, 32}}; 2434 const SkPaint::Join join[] = { SkPaint::kRound_Join, 2435 SkPaint::kMiter_Join, 2436 SkPaint::kBevel_Join }; 2437 int joinIndex = 0; 2438 SkPath path; 2439 path.addPoly(points, 3, false); 2440 for (const auto cap : { SkPaint::kRound_Cap, SkPaint::kSquare_Cap, SkPaint::kButt_Cap } ) { 2441 paint.setStrokeCap(cap); 2442 paint.setStrokeJoin(join[joinIndex++]); 2443 for (const auto mode : { SkCanvas::kPoints_PointMode, 2444 SkCanvas::kLines_PointMode, 2445 SkCanvas::kPolygon_PointMode } ) { 2446 canvas->drawPoints(mode, 3, points, paint); 2447 canvas->translate(64, 0); 2448 } 2449 canvas->drawPath(path, paint); 2450 canvas->translate(-192, 64); 2451 } 2452} 2453## 2454 2455#SeeAlso drawLine drawPoint drawPath 2456 2457## 2458 2459# ------------------------------------------------------------------------------ 2460 2461#Method void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) 2462#In Draw 2463#Line # draws point at (x, y) position ## 2464#Populate 2465 2466#Example 2467void draw(SkCanvas* canvas) { 2468 SkPaint paint; 2469 paint.setAntiAlias(true); 2470 paint.setColor(0x80349a45); 2471 paint.setStyle(SkPaint::kStroke_Style); 2472 paint.setStrokeWidth(100); 2473 paint.setStrokeCap(SkPaint::kRound_Cap); 2474 canvas->scale(1, 1.2f); 2475 canvas->drawPoint(64, 96, paint); 2476 canvas->scale(.6f, .8f); 2477 paint.setColor(SK_ColorWHITE); 2478 canvas->drawPoint(106, 120, paint); 2479} 2480## 2481 2482#SeeAlso drawPoints drawCircle drawRect drawLine drawPath 2483 2484## 2485 2486#Method void drawPoint(SkPoint p, const SkPaint& paint) 2487#Populate 2488 2489#Example 2490void draw(SkCanvas* canvas) { 2491 SkPaint paint; 2492 paint.setAntiAlias(true); 2493 paint.setColor(0x80349a45); 2494 paint.setStyle(SkPaint::kStroke_Style); 2495 paint.setStrokeWidth(100); 2496 paint.setStrokeCap(SkPaint::kSquare_Cap); 2497 canvas->scale(1, 1.2f); 2498 canvas->drawPoint({64, 96}, paint); 2499 canvas->scale(.6f, .8f); 2500 paint.setColor(SK_ColorWHITE); 2501 canvas->drawPoint(106, 120, paint); 2502} 2503## 2504 2505#SeeAlso drawPoints drawCircle drawRect drawLine drawPath 2506 2507## 2508 2509# ------------------------------------------------------------------------------ 2510 2511#Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) 2512#In Draw 2513#Line # draws line segment between two points ## 2514#Populate 2515 2516#Example 2517 SkPaint paint; 2518 paint.setAntiAlias(true); 2519 paint.setColor(0xFF9a67be); 2520 paint.setStrokeWidth(20); 2521 canvas->skew(1, 0); 2522 canvas->drawLine(32, 96, 32, 160, paint); 2523 canvas->skew(-2, 0); 2524 canvas->drawLine(288, 96, 288, 160, paint); 2525## 2526 2527#SeeAlso drawPoint drawCircle drawRect drawPath 2528 2529## 2530 2531#Method void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) 2532#Populate 2533 2534#Example 2535 SkPaint paint; 2536 paint.setAntiAlias(true); 2537 paint.setColor(0xFF9a67be); 2538 paint.setStrokeWidth(20); 2539 canvas->skew(1, 0); 2540 canvas->drawLine({32, 96}, {32, 160}, paint); 2541 canvas->skew(-2, 0); 2542 canvas->drawLine({288, 96}, {288, 160}, paint); 2543## 2544 2545#SeeAlso drawPoint drawCircle drawRect drawPath 2546 2547## 2548 2549# ------------------------------------------------------------------------------ 2550 2551#Method void drawRect(const SkRect& rect, const SkPaint& paint) 2552#In Draw 2553#Line # draws Rect using Clip, Matrix, and Paint ## 2554#Populate 2555 2556#Example 2557void draw(SkCanvas* canvas) { 2558 SkPoint rectPts[] = { {64, 48}, {192, 160} }; 2559 SkPaint paint; 2560 paint.setAntiAlias(true); 2561 paint.setStyle(SkPaint::kStroke_Style); 2562 paint.setStrokeWidth(20); 2563 paint.setStrokeJoin(SkPaint::kRound_Join); 2564 SkMatrix rotator; 2565 rotator.setRotate(30, 128, 128); 2566 for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) { 2567 paint.setColor(color); 2568 SkRect rect; 2569 rect.set(rectPts[0], rectPts[1]); 2570 canvas->drawRect(rect, paint); 2571 rotator.mapPoints(rectPts, 2); 2572 } 2573} 2574## 2575 2576#SeeAlso drawIRect drawRRect drawRoundRect drawRegion drawPath drawLine 2577 2578## 2579 2580# ------------------------------------------------------------------------------ 2581 2582#Method void drawIRect(const SkIRect& rect, const SkPaint& paint) 2583#In Draw 2584#Line # draws IRect using Clip, Matrix, and Paint ## 2585#Populate 2586 2587#Example 2588 SkIRect rect = { 64, 48, 192, 160 }; 2589 SkPaint paint; 2590 paint.setAntiAlias(true); 2591 paint.setStyle(SkPaint::kStroke_Style); 2592 paint.setStrokeWidth(20); 2593 paint.setStrokeJoin(SkPaint::kRound_Join); 2594 for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) { 2595 paint.setColor(color); 2596 canvas->drawIRect(rect, paint); 2597 canvas->rotate(30, 128, 128); 2598 } 2599## 2600 2601#SeeAlso drawRect drawRRect drawRoundRect drawRegion drawPath drawLine 2602 2603## 2604 2605# ------------------------------------------------------------------------------ 2606 2607#Method void drawRegion(const SkRegion& region, const SkPaint& paint) 2608#In Draw 2609#Line # draws Region using Clip, Matrix, and Paint ## 2610#Populate 2611 2612#Example 2613void draw(SkCanvas* canvas) { 2614 SkRegion region; 2615 region.op( 10, 10, 50, 50, SkRegion::kUnion_Op); 2616 region.op( 10, 50, 90, 90, SkRegion::kUnion_Op); 2617 SkPaint paint; 2618 paint.setAntiAlias(true); 2619 paint.setStyle(SkPaint::kStroke_Style); 2620 paint.setStrokeWidth(20); 2621 paint.setStrokeJoin(SkPaint::kRound_Join); 2622 canvas->drawRegion(region, paint); 2623} 2624## 2625 2626#SeeAlso drawRect drawIRect drawPath 2627 2628## 2629 2630# ------------------------------------------------------------------------------ 2631 2632#Method void drawOval(const SkRect& oval, const SkPaint& paint) 2633#In Draw 2634#Line # draws Oval using Clip, Matrix, and Paint ## 2635#Populate 2636 2637#Example 2638void draw(SkCanvas* canvas) { 2639 canvas->clear(0xFF3f5f9f); 2640 SkColor kColor1 = SkColorSetARGB(0xff, 0xff, 0x7f, 0); 2641 SkColor g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) }; 2642 SkPoint g1Points[] = { { 0, 0 }, { 0, 100 } }; 2643 SkScalar pos[] = { 0.2f, 1.0f }; 2644 SkRect bounds = SkRect::MakeWH(80, 70); 2645 SkPaint paint; 2646 paint.setAntiAlias(true); 2647 paint.setShader(SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors), 2648 SkShader::kClamp_TileMode)); 2649 canvas->drawOval(bounds , paint); 2650} 2651## 2652 2653#SeeAlso drawCircle drawPoint drawPath drawRRect drawRoundRect 2654 2655## 2656 2657# ------------------------------------------------------------------------------ 2658 2659#Method void drawRRect(const SkRRect& rrect, const SkPaint& paint) 2660#In Draw 2661#Line # draws Round_Rect using Clip, Matrix, and Paint ## 2662#Populate 2663 2664#Example 2665void draw(SkCanvas* canvas) { 2666 SkPaint paint; 2667 paint.setAntiAlias(true); 2668 SkRect outer = {30, 40, 210, 220}; 2669 SkRect radii = {30, 50, 70, 90 }; 2670 SkRRect rRect; 2671 rRect.setNinePatch(outer, radii.fLeft, radii.fTop, radii.fRight, radii.fBottom); 2672 canvas->drawRRect(rRect, paint); 2673 paint.setColor(SK_ColorWHITE); 2674 canvas->drawLine(outer.fLeft + radii.fLeft, outer.fTop, 2675 outer.fLeft + radii.fLeft, outer.fBottom, paint); 2676 canvas->drawLine(outer.fRight - radii.fRight, outer.fTop, 2677 outer.fRight - radii.fRight, outer.fBottom, paint); 2678 canvas->drawLine(outer.fLeft, outer.fTop + radii.fTop, 2679 outer.fRight, outer.fTop + radii.fTop, paint); 2680 canvas->drawLine(outer.fLeft, outer.fBottom - radii.fBottom, 2681 outer.fRight, outer.fBottom - radii.fBottom, paint); 2682} 2683## 2684 2685#SeeAlso drawRect drawRoundRect drawDRRect drawCircle drawOval drawPath 2686 2687## 2688 2689# ------------------------------------------------------------------------------ 2690 2691#Method void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) 2692#In Draw 2693#Line # draws double Round_Rect stroked or filled ## 2694#Populate 2695 2696#Example 2697void draw(SkCanvas* canvas) { 2698 SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200}); 2699 SkRRect inner = SkRRect::MakeOval({60, 70, 170, 160}); 2700 SkPaint paint; 2701 canvas->drawDRRect(outer, inner, paint); 2702} 2703## 2704 2705#Example 2706#Description 2707 Outer Rect has no corner radii, but stroke join is rounded. 2708 Inner Round_Rect has corner radii; outset stroke increases radii of corners. 2709 Stroke join does not affect inner Round_Rect since it has no sharp corners. 2710## 2711void draw(SkCanvas* canvas) { 2712 SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200}); 2713 SkRRect inner = SkRRect::MakeRectXY({60, 70, 170, 160}, 10, 10); 2714 SkPaint paint; 2715 paint.setAntiAlias(true); 2716 paint.setStyle(SkPaint::kStroke_Style); 2717 paint.setStrokeWidth(20); 2718 paint.setStrokeJoin(SkPaint::kRound_Join); 2719 canvas->drawDRRect(outer, inner, paint); 2720 paint.setStrokeWidth(1); 2721 paint.setColor(SK_ColorWHITE); 2722 canvas->drawDRRect(outer, inner, paint); 2723} 2724## 2725 2726#SeeAlso drawRect drawRoundRect drawRRect drawCircle drawOval drawPath 2727 2728## 2729 2730# ------------------------------------------------------------------------------ 2731 2732#Method void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) 2733#In Draw 2734#Line # draws Circle using Clip, Matrix, and Paint ## 2735#Populate 2736 2737#Example 2738 void draw(SkCanvas* canvas) { 2739 SkPaint paint; 2740 paint.setAntiAlias(true); 2741 canvas->drawCircle(128, 128, 90, paint); 2742 paint.setColor(SK_ColorWHITE); 2743 canvas->drawCircle(86, 86, 20, paint); 2744 canvas->drawCircle(160, 76, 20, paint); 2745 canvas->drawCircle(140, 150, 35, paint); 2746 } 2747## 2748 2749#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine 2750 2751## 2752 2753#Method void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) 2754#Populate 2755 2756#Example 2757 void draw(SkCanvas* canvas) { 2758 SkPaint paint; 2759 paint.setAntiAlias(true); 2760 canvas->drawCircle(128, 128, 90, paint); 2761 paint.setColor(SK_ColorWHITE); 2762 canvas->drawCircle({86, 86}, 20, paint); 2763 canvas->drawCircle({160, 76}, 20, paint); 2764 canvas->drawCircle({140, 150}, 35, paint); 2765 } 2766## 2767 2768#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine 2769 2770## 2771 2772# ------------------------------------------------------------------------------ 2773 2774#Method void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 2775 bool useCenter, const SkPaint& paint) 2776#In Draw 2777#Line # draws Arc using Clip, Matrix, and Paint ## 2778#Populate 2779 2780#Example 2781 void draw(SkCanvas* canvas) { 2782 SkPaint paint; 2783 paint.setAntiAlias(true); 2784 SkRect oval = { 4, 4, 60, 60}; 2785 for (auto useCenter : { false, true } ) { 2786 for (auto style : { SkPaint::kFill_Style, SkPaint::kStroke_Style } ) { 2787 paint.setStyle(style); 2788 for (auto degrees : { 45, 90, 180, 360} ) { 2789 canvas->drawArc(oval, 0, degrees , useCenter, paint); 2790 canvas->translate(64, 0); 2791 } 2792 canvas->translate(-256, 64); 2793 } 2794 } 2795 } 2796## 2797 2798#Example 2799#Height 64 2800 void draw(SkCanvas* canvas) { 2801 SkPaint paint; 2802 paint.setAntiAlias(true); 2803 paint.setStyle(SkPaint::kStroke_Style); 2804 paint.setStrokeWidth(4); 2805 SkRect oval = { 4, 4, 60, 60}; 2806 float intervals[] = { 5, 5 }; 2807 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f)); 2808 for (auto degrees : { 270, 360, 540, 720 } ) { 2809 canvas->drawArc(oval, 0, degrees, false, paint); 2810 canvas->translate(64, 0); 2811 } 2812 } 2813## 2814 2815#SeeAlso SkPath::arcTo drawCircle drawOval drawPath 2816 2817## 2818 2819# ------------------------------------------------------------------------------ 2820 2821#Method void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint) 2822#In Draw 2823#Line # draws Round_Rect using Clip, Matrix, and Paint ## 2824#Populate 2825 2826#Example 2827#Description 2828 Top row has a zero radius a generates a rectangle. 2829 Second row radii sum to less than sides. 2830 Third row radii sum equals sides. 2831 Fourth row radii sum exceeds sides; radii are scaled to fit. 2832## 2833 void draw(SkCanvas* canvas) { 2834 SkVector radii[] = { {0, 20}, {10, 10}, {10, 20}, {10, 40} }; 2835 SkPaint paint; 2836 paint.setStrokeWidth(15); 2837 paint.setStrokeJoin(SkPaint::kRound_Join); 2838 paint.setAntiAlias(true); 2839 for (auto style : { SkPaint::kStroke_Style, SkPaint::kFill_Style } ) { 2840 paint.setStyle(style ); 2841 for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) { 2842 canvas->drawRoundRect({10, 10, 60, 40}, radii[i].fX, radii[i].fY, paint); 2843 canvas->translate(0, 60); 2844 } 2845 canvas->translate(80, -240); 2846 } 2847 } 2848## 2849 2850#SeeAlso drawRRect drawRect drawDRRect drawPath drawCircle drawOval drawPoint 2851 2852## 2853 2854# ------------------------------------------------------------------------------ 2855 2856#Method void drawPath(const SkPath& path, const SkPaint& paint) 2857#In Draw 2858#Line # draws Path using Clip, Matrix, and Paint ## 2859#Populate 2860 2861#Example 2862#Description 2863 Top rows draw stroked path with combinations of joins and caps. The open contour 2864 is affected by caps; the closed contour is affected by joins. 2865 Bottom row draws fill the same for open and closed contour. 2866 First bottom column shows winding fills overlap. 2867 Second bottom column shows even odd fills exclude overlap. 2868 Third bottom column shows inverse winding fills area outside both contours. 2869## 2870void draw(SkCanvas* canvas) { 2871 SkPath path; 2872 path.moveTo(20, 20); 2873 path.quadTo(60, 20, 60, 60); 2874 path.close(); 2875 path.moveTo(60, 20); 2876 path.quadTo(60, 60, 20, 60); 2877 SkPaint paint; 2878 paint.setStrokeWidth(10); 2879 paint.setAntiAlias(true); 2880 paint.setStyle(SkPaint::kStroke_Style); 2881 for (auto join: { SkPaint::kBevel_Join, SkPaint::kRound_Join, SkPaint::kMiter_Join } ) { 2882 paint.setStrokeJoin(join); 2883 for (auto cap: { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap } ) { 2884 paint.setStrokeCap(cap); 2885 canvas->drawPath(path, paint); 2886 canvas->translate(80, 0); 2887 } 2888 canvas->translate(-240, 60); 2889 } 2890 paint.setStyle(SkPaint::kFill_Style); 2891 for (auto fill : { SkPath::kWinding_FillType, 2892 SkPath::kEvenOdd_FillType, 2893 SkPath::kInverseWinding_FillType } ) { 2894 path.setFillType(fill); 2895 canvas->save(); 2896 canvas->clipRect({0, 10, 80, 70}); 2897 canvas->drawPath(path, paint); 2898 canvas->restore(); 2899 canvas->translate(80, 0); 2900 } 2901} 2902## 2903 2904#SeeAlso SkPath drawLine drawArc drawRect drawPoints 2905 2906## 2907 2908# ------------------------------------------------------------------------------ 2909#Subtopic Draw_Image 2910#Line # draws Image to Canvas ## 2911 2912drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or 2913a smart pointer as a convenience. The pairs of calls are otherwise identical. 2914 2915#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr) 2916#In Draw_Image 2917#In Draw 2918#Line # draws Image at (x, y) position ## 2919#Populate 2920 2921#Example 2922#Height 64 2923#Image 4 2924void draw(SkCanvas* canvas) { 2925 // sk_sp<SkImage> image; 2926 SkImage* imagePtr = image.get(); 2927 canvas->drawImage(imagePtr, 0, 0); 2928 SkPaint paint; 2929 canvas->drawImage(imagePtr, 80, 0, &paint); 2930 paint.setAlpha(0x80); 2931 canvas->drawImage(imagePtr, 160, 0, &paint); 2932} 2933## 2934 2935#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter 2936 2937## 2938 2939# ------------------------------------------------------------------------------ 2940 2941#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, 2942 const SkPaint* paint = nullptr) 2943#Populate 2944 2945#Example 2946#Height 64 2947#Image 4 2948void draw(SkCanvas* canvas) { 2949 // sk_sp<SkImage> image; 2950 canvas->drawImage(image, 0, 0); 2951 SkPaint paint; 2952 canvas->drawImage(image, 80, 0, &paint); 2953 paint.setAlpha(0x80); 2954 canvas->drawImage(image, 160, 0, &paint); 2955} 2956## 2957 2958#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter 2959 2960## 2961 2962# ------------------------------------------------------------------------------ 2963 2964#Enum SrcRectConstraint 2965#Line # sets drawImageRect options ## 2966 2967#Code 2968#Populate 2969## 2970 2971SrcRectConstraint controls the behavior at the edge of source Rect, 2972provided to drawImageRect, trading off speed for precision. 2973 2974Image_Filter in Paint may sample multiple pixels in the image. Source Rect 2975restricts the bounds of pixels that may be read. Image_Filter may slow down if 2976it cannot read outside the bounds, when sampling near the edge of source Rect. 2977SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels 2978outside source Rect. 2979 2980#Const kStrict_SrcRectConstraint 0 2981#Line # sample only inside bounds; slower ## 2982 Requires Image_Filter to respect source Rect, 2983 sampling only inside of its bounds, possibly with a performance penalty. 2984## 2985 2986#Const kFast_SrcRectConstraint 1 2987#Line # sample outside bounds; faster ## 2988 Permits Image_Filter to sample outside of source Rect 2989 by half the width of Image_Filter, permitting it to run faster but with 2990 error at the image edges. 2991## 2992 2993#Example 2994#Height 64 2995#Description 2996 redBorder contains a black and white checkerboard bordered by red. 2997 redBorder is drawn scaled by 16 on the left. 2998 The middle and right bitmaps are filtered checkerboards. 2999 Drawing the checkerboard with kStrict_SrcRectConstraint shows only a blur of black and white. 3000 Drawing the checkerboard with kFast_SrcRectConstraint allows red to bleed in the corners. 3001## 3002void draw(SkCanvas* canvas) { 3003 SkBitmap redBorder; 3004 redBorder.allocPixels(SkImageInfo::MakeN32Premul(4, 4)); 3005 SkCanvas checkRed(redBorder); 3006 checkRed.clear(SK_ColorRED); 3007 uint32_t checkers[][2] = { { SK_ColorBLACK, SK_ColorWHITE }, 3008 { SK_ColorWHITE, SK_ColorBLACK } }; 3009 checkRed.writePixels( 3010 SkImageInfo::MakeN32Premul(2, 2), (void*) checkers, sizeof(checkers[0]), 1, 1); 3011 canvas->scale(16, 16); 3012 canvas->drawBitmap(redBorder, 0, 0, nullptr); 3013 canvas->resetMatrix(); 3014 sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder); 3015 SkPaint lowPaint; 3016 lowPaint.setFilterQuality(kLow_SkFilterQuality); 3017 for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint, 3018 SkCanvas::kFast_SrcRectConstraint } ) { 3019 canvas->translate(80, 0); 3020 canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3), 3021 SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint); 3022 } 3023} 3024## 3025 3026#SeeAlso drawImageRect drawImage SkPaint::setImageFilter 3027 3028## 3029 3030# ------------------------------------------------------------------------------ 3031 3032#Method void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, 3033 const SkPaint* paint, 3034 SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3035#In Draw_Image 3036#In Draw 3037#Line # draws Image, source Rect to destination Rect ## 3038#Populate 3039 3040#Example 3041#Height 64 3042#Description 3043 The left bitmap draws with Paint default kNone_SkFilterQuality, and stays within 3044 its bounds; there is no bleeding with kFast_SrcRectConstraint. 3045 the middle and right bitmaps draw with kLow_SkFilterQuality; with 3046 kStrict_SrcRectConstraint, the filter remains within the checkerboard, and 3047 with kFast_SrcRectConstraint red bleeds on the edges. 3048## 3049void draw(SkCanvas* canvas) { 3050 uint32_t pixels[][4] = { 3051 { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 }, 3052 { 0xFFFF0000, 0xFF000000, 0xFFFFFFFF, 0xFFFF0000 }, 3053 { 0xFFFF0000, 0xFFFFFFFF, 0xFF000000, 0xFFFF0000 }, 3054 { 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 } }; 3055 SkBitmap redBorder; 3056 redBorder.installPixels(SkImageInfo::MakeN32Premul(4, 4), 3057 (void*) pixels, sizeof(pixels[0])); 3058 sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder); 3059 SkPaint lowPaint; 3060 for (auto constraint : { 3061 SkCanvas::kFast_SrcRectConstraint, 3062 SkCanvas::kStrict_SrcRectConstraint, 3063 SkCanvas::kFast_SrcRectConstraint } ) { 3064 canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3), 3065 SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint); 3066 lowPaint.setFilterQuality(kLow_SkFilterQuality); 3067 canvas->translate(80, 0); 3068 } 3069} 3070## 3071 3072#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3073 3074## 3075 3076# ------------------------------------------------------------------------------ 3077 3078#Method void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, 3079 const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3080#In Draw_Image 3081#In Draw 3082#Populate 3083 3084#Example 3085#Image 4 3086void draw(SkCanvas* canvas) { 3087 // sk_sp<SkImage> image; 3088 for (auto i : { 1, 2, 4, 8 } ) { 3089 canvas->drawImageRect(image.get(), SkIRect::MakeLTRB(0, 0, 100, 100), 3090 SkRect::MakeXYWH(i * 20, i * 20, i * 20, i * 20), nullptr); 3091 } 3092} 3093## 3094 3095#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3096 3097## 3098 3099# ------------------------------------------------------------------------------ 3100 3101#Method void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) 3102#In Draw_Image 3103#In Draw 3104#Populate 3105 3106#Example 3107#Image 4 3108void draw(SkCanvas* canvas) { 3109 // sk_sp<SkImage> image; 3110 for (auto i : { 20, 40, 80, 160 } ) { 3111 canvas->drawImageRect(image.get(), SkRect::MakeXYWH(i, i, i, i), nullptr); 3112 } 3113} 3114## 3115 3116#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3117 3118## 3119 3120# ------------------------------------------------------------------------------ 3121 3122#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst, 3123 const SkPaint* paint, 3124 SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3125#In Draw_Image 3126#In Draw 3127#Populate 3128 3129#Example 3130#Height 64 3131#Description 3132 Canvas scales and translates; transformation from src to dst also scales. 3133 The two matrices are concatenated to create the final transformation. 3134## 3135void draw(SkCanvas* canvas) { 3136 uint32_t pixels[][2] = { { SK_ColorBLACK, SK_ColorWHITE }, 3137 { SK_ColorWHITE, SK_ColorBLACK } }; 3138 SkBitmap bitmap; 3139 bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 3140 (void*) pixels, sizeof(pixels[0])); 3141 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3142 SkPaint paint; 3143 canvas->scale(4, 4); 3144 for (auto alpha : { 50, 100, 150, 255 } ) { 3145 paint.setAlpha(alpha); 3146 canvas->drawImageRect(image, SkRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint); 3147 canvas->translate(8, 0); 3148 } 3149} 3150## 3151 3152#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3153 3154## 3155 3156# ------------------------------------------------------------------------------ 3157 3158#Method void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst, 3159 const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3160#In Draw_Image 3161#In Draw 3162#Populate 3163 3164#Example 3165#Height 64 3166void draw(SkCanvas* canvas) { 3167 uint32_t pixels[][2] = { { 0x00000000, 0x55555555}, 3168 { 0xAAAAAAAA, 0xFFFFFFFF} }; 3169 SkBitmap bitmap; 3170 bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 3171 (void*) pixels, sizeof(pixels[0])); 3172 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3173 SkPaint paint; 3174 canvas->scale(4, 4); 3175 for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) { 3176 paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus)); 3177 canvas->drawImageRect(image, SkIRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint); 3178 canvas->translate(8, 0); 3179 } 3180} 3181## 3182 3183#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3184 3185## 3186 3187# ------------------------------------------------------------------------------ 3188 3189#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint) 3190#In Draw_Image 3191#In Draw 3192#Populate 3193 3194#Example 3195#Height 64 3196void draw(SkCanvas* canvas) { 3197 uint32_t pixels[][2] = { { 0x00000000, 0x55550000}, 3198 { 0xAAAA0000, 0xFFFF0000} }; 3199 SkBitmap bitmap; 3200 bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 3201 (void*) pixels, sizeof(pixels[0])); 3202 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3203 SkPaint paint; 3204 canvas->scale(4, 4); 3205 for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) { 3206 paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus)); 3207 canvas->drawImageRect(image, SkRect::MakeWH(8, 8), &paint); 3208 canvas->translate(8, 0); 3209 } 3210} 3211## 3212 3213#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine 3214 3215## 3216 3217# ------------------------------------------------------------------------------ 3218 3219#Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 3220 const SkPaint* paint = nullptr) 3221#In Draw_Image 3222#In Draw 3223#Line # draws Nine_Patch Image ## 3224 3225Draws Image image stretched proportionally to fit into Rect dst. 3226IRect center divides the image into nine sections: four sides, four corners, and 3227the center. Corners are unmodified or scaled down proportionately if their sides 3228are larger than dst; center and four sides are scaled to fit remaining space, if any. 3229 3230Additionally transform draw using Clip, Matrix, and optional Paint paint. 3231 3232#paint_as_used_by_draw_lattice_or_draw_nine(image)# 3233 3234If generated mask extends beyond image bounds, replicate image edge colors, just 3235as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set 3236replicates the image edge color when it samples outside of its bounds. 3237 3238#Param image Image containing pixels, dimensions, and format ## 3239#Param center IRect edge of image corners and sides ## 3240#Param dst destination Rect of image to draw to ## 3241#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, 3242 and so on; or nullptr 3243## 3244 3245#Example 3246#Height 128 3247#Description 3248 The leftmost image is smaller than center; only corners are drawn, all scaled to fit. 3249 The second image equals the size of center; only corners are drawn without scaling. 3250 The remaining images are larger than center. All corners draw without scaling. 3251 The sides and center are scaled if needed to take up the remaining space. 3252## 3253void draw(SkCanvas* canvas) { 3254 SkIRect center = { 20, 10, 50, 40 }; 3255 SkBitmap bitmap; 3256 bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); 3257 SkCanvas bitCanvas(bitmap); 3258 SkPaint paint; 3259 SkColor gray = 0xFF000000; 3260 int left = 0; 3261 for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) { 3262 int top = 0; 3263 for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) { 3264 paint.setColor(gray); 3265 bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint); 3266 gray += 0x001f1f1f; 3267 top = bottom; 3268 } 3269 left = right; 3270 } 3271 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3272 SkImage* imagePtr = image.get(); 3273 for (auto dest: { 20, 30, 40, 60, 90 } ) { 3274 canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr); 3275 canvas->translate(dest + 4, 0); 3276 } 3277} 3278## 3279 3280#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect 3281 3282## 3283 3284# ------------------------------------------------------------------------------ 3285 3286#Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst, 3287 const SkPaint* paint = nullptr) 3288#In Draw_Image 3289#In Draw 3290Draws Image image stretched proportionally to fit into Rect dst. 3291IRect center divides the image into nine sections: four sides, four corners, and 3292the center. Corners are not scaled, or scaled down proportionately if their sides 3293are larger than dst; center and four sides are scaled to fit remaining space, if any. 3294 3295Additionally transform draw using Clip, Matrix, and optional Paint paint. 3296 3297#paint_as_used_by_draw_lattice_or_draw_nine(image)# 3298 3299If generated mask extends beyond image bounds, replicate image edge colors, just 3300as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set 3301replicates the image edge color when it samples outside of its bounds. 3302 3303#Param image Image containing pixels, dimensions, and format ## 3304#Param center IRect edge of image corners and sides ## 3305#Param dst destination Rect of image to draw to ## 3306#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, 3307 and so on; or nullptr 3308## 3309 3310#Example 3311#Height 128 3312#Description 3313 The two leftmost images has four corners and sides to the left and right of center. 3314 The leftmost image scales the width of corners proportionately to fit. 3315 The third and fourth image corners are not scaled; the sides and center are scaled to 3316 fill the remaining space. 3317 The rightmost image has four corners scaled vertically to fit, and uses sides above 3318 and below center to fill the remaining space. 3319## 3320void draw(SkCanvas* canvas) { 3321 SkIRect center = { 20, 10, 50, 40 }; 3322 SkBitmap bitmap; 3323 bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); 3324 SkCanvas bitCanvas(bitmap); 3325 SkPaint paint; 3326 SkColor gray = 0xFF000000; 3327 int left = 0; 3328 for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) { 3329 int top = 0; 3330 for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) { 3331 paint.setColor(gray); 3332 bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint); 3333 gray += 0x001f1f1f; 3334 top = bottom; 3335 } 3336 left = right; 3337 } 3338 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3339 for (auto dest: { 20, 30, 40, 60, 90 } ) { 3340 canvas->drawImageNine(image, center, SkRect::MakeWH(dest, 110 - dest), nullptr); 3341 canvas->translate(dest + 4, 0); 3342 } 3343} 3344## 3345 3346#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect 3347 3348## 3349 3350# ------------------------------------------------------------------------------ 3351 3352#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 3353 const SkPaint* paint = nullptr) 3354#In Draw_Image 3355#In Draw 3356#Line # draws Bitmap at (x, y) position ## 3357#Populate 3358 3359#Example 3360#Height 64 3361void draw(SkCanvas* canvas) { 3362 uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00}, 3363 { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}, 3364 { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}, 3365 { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF}, 3366 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 3367 { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00}, 3368 { 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00}, 3369 { 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF} }; 3370 SkBitmap bitmap; 3371 bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 3372 (void*) pixels, sizeof(pixels[0])); 3373 SkPaint paint; 3374 canvas->scale(4, 4); 3375 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) { 3376 paint.setColor(color); 3377 canvas->drawBitmap(bitmap, 0, 0, &paint); 3378 canvas->translate(12, 0); 3379 } 3380} 3381## 3382 3383#SeeAlso drawImage drawBitmapLattice drawBitmapNine drawBitmapRect SkBitmap::readPixels SkBitmap::writePixels 3384 3385## 3386 3387# ------------------------------------------------------------------------------ 3388 3389#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst, 3390 const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3391#In Draw_Image 3392#In Draw 3393#Line # draws Bitmap, source Rect to destination Rect ## 3394#Populate 3395 3396#Example 3397#Height 64 3398void draw(SkCanvas* canvas) { 3399 uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00}, 3400 { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}, 3401 { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}, 3402 { 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF}, 3403 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 3404 { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00}, 3405 { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, 3406 { 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00} }; 3407 SkBitmap bitmap; 3408 bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 3409 (void*) pixels, sizeof(pixels[0])); 3410 SkPaint paint; 3411 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, 6)); 3412 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) { 3413 paint.setColor(color); 3414 canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint); 3415 canvas->translate(48, 0); 3416 } 3417} 3418## 3419 3420#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine 3421 3422## 3423 3424# ------------------------------------------------------------------------------ 3425 3426#Method void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst, 3427 const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3428#In Draw_Image 3429#In Draw 3430#Populate 3431 3432#Example 3433#Height 64 3434void draw(SkCanvas* canvas) { 3435 uint8_t pixels[][8] = { { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}, 3436 { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, 3437 { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF}, 3438 { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF}, 3439 { 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF}, 3440 { 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF}, 3441 { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, 3442 { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00} }; 3443 SkBitmap bitmap; 3444 bitmap.installPixels(SkImageInfo::MakeA8(8, 8), 3445 (void*) pixels, sizeof(pixels[0])); 3446 SkPaint paint; 3447 paint.setFilterQuality(kHigh_SkFilterQuality); 3448 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00, 0xFF7f007f} ) { 3449 paint.setColor(color); 3450 canvas->drawBitmapRect(bitmap, SkIRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint); 3451 canvas->translate(48.25f, 0); 3452 } 3453} 3454## 3455 3456#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine 3457 3458## 3459 3460# ------------------------------------------------------------------------------ 3461 3462#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint, 3463 SrcRectConstraint constraint = kStrict_SrcRectConstraint) 3464#In Draw_Image 3465#In Draw 3466#Populate 3467 3468#Example 3469#Height 64 3470void draw(SkCanvas* canvas) { 3471 uint32_t pixels[][2] = { { 0x00000000, 0x55550000}, 3472 { 0xAAAA0000, 0xFFFF0000} }; 3473 SkBitmap bitmap; 3474 bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2), 3475 (void*) pixels, sizeof(pixels[0])); 3476 SkPaint paint; 3477 canvas->scale(4, 4); 3478 for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) { 3479 paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus)); 3480 canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), &paint); 3481 canvas->translate(8, 0); 3482 } 3483} 3484## 3485 3486#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine 3487 3488## 3489 3490# ------------------------------------------------------------------------------ 3491 3492#PhraseDef paint_as_used_by_draw_lattice_or_draw_nine(bitmap_or_image) 3493If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter, 3494Blend_Mode, and Draw_Looper. If #bitmap_or_image# is kAlpha_8_SkColorType, apply Shader. 3495If paint contains Mask_Filter, generate mask from #bitmap_or_image# bounds. If paint 3496Filter_Quality set to kNone_SkFilterQuality, disable pixel filtering. For all 3497other values of paint Filter_Quality, use kLow_SkFilterQuality to filter pixels. 3498Any SkMaskFilter on paint is ignored as is paint Anti_Aliasing state. 3499## 3500 3501#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, 3502 const SkPaint* paint = nullptr) 3503#In Draw_Image 3504#In Draw 3505#Line # draws Nine_Patch Bitmap ## 3506 3507Draws Bitmap bitmap stretched proportionally to fit into Rect dst. 3508IRect center divides the bitmap into nine sections: four sides, four corners, 3509and the center. Corners are not scaled, or scaled down proportionately if their 3510sides are larger than dst; center and four sides are scaled to fit remaining 3511space, if any. 3512 3513Additionally transform draw using Clip, Matrix, and optional Paint paint. 3514 3515#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)# 3516 3517If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, 3518just as Shader made from SkShader::MakeBitmapShader with 3519SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples 3520outside of its bounds. 3521 3522#Param bitmap Bitmap containing pixels, dimensions, and format ## 3523#Param center IRect edge of image corners and sides ## 3524#Param dst destination Rect of image to draw to ## 3525#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, 3526 and so on; or nullptr 3527## 3528 3529#Example 3530#Height 128 3531#Description 3532 The two leftmost bitmap draws has four corners and sides to the left and right of center. 3533 The leftmost bitmap draw scales the width of corners proportionately to fit. 3534 The third and fourth draw corners are not scaled; the sides and center are scaled to 3535 fill the remaining space. 3536 The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above 3537 and below center to fill the remaining space. 3538## 3539void draw(SkCanvas* canvas) { 3540 SkIRect center = { 20, 10, 50, 40 }; 3541 SkBitmap bitmap; 3542 bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); 3543 SkCanvas bitCanvas(bitmap); 3544 SkPaint paint; 3545 SkColor gray = 0xFF000000; 3546 int left = 0; 3547 for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) { 3548 int top = 0; 3549 for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) { 3550 paint.setColor(gray); 3551 bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint); 3552 gray += 0x001f1f1f; 3553 top = bottom; 3554 } 3555 left = right; 3556 } 3557 for (auto dest: { 20, 30, 40, 60, 90 } ) { 3558 canvas->drawBitmapNine(bitmap, center, SkRect::MakeWH(dest, 110 - dest), nullptr); 3559 canvas->translate(dest + 4, 0); 3560 } 3561} 3562## 3563 3564#SeeAlso drawImageNine drawBitmap drawBitmapLattice drawBitmapRect 3565 3566## 3567 3568# ------------------------------------------------------------------------------ 3569#Subtopic Lattice 3570#Line # divides Bitmap or Image into a rectangular grid ## 3571 3572#Struct Lattice 3573#Line # divides Bitmap or Image into a rectangular grid ## 3574 3575#Code 3576#Populate 3577## 3578 3579Lattice divides Bitmap or Image into a rectangular grid. 3580Grid entries on even columns and even rows are fixed; these entries are 3581always drawn at their original size if the destination is large enough. 3582If the destination side is too small to hold the fixed entries, all fixed 3583entries are proportionately scaled down to fit. 3584The grid entries not on even columns and rows are scaled to fit the 3585remaining space, if any. 3586 3587 #Enum RectType 3588 #Line # optional setting per rectangular grid entry ## 3589 #Code 3590 #Populate 3591 ## 3592 3593 Optional setting per rectangular grid entry to make it transparent, 3594 or to fill the grid entry with a color. 3595 3596 #Const kDefault 0 3597 #Line # draws Bitmap into lattice rectangle ## 3598 ## 3599 3600 #Const kTransparent 1 3601 #Line # skips lattice rectangle by making it transparent ## 3602 ## 3603 3604 #Const kFixedColor 2 3605 #Line # draws one of fColors into lattice rectangle ## 3606 ## 3607 ## 3608 3609#Subtopic Members 3610## 3611 3612 #Member const int* fXDivs 3613 #Line # x-axis values dividing bitmap ## 3614 Array of x-axis values that divide the bitmap vertically. 3615 Array entries must be unique, increasing, greater than or equal to 3616 fBounds left edge, and less than fBounds right edge. 3617 Set the first element to fBounds left to collapse the left column of 3618 fixed grid entries. 3619 ## 3620 3621 #Member const int* fYDivs 3622 #Line # y-axis values dividing bitmap ## 3623 Array of y-axis values that divide the bitmap horizontally. 3624 Array entries must be unique, increasing, greater than or equal to 3625 fBounds top edge, and less than fBounds bottom edge. 3626 Set the first element to fBounds top to collapse the top row of fixed 3627 grid entries. 3628 ## 3629 3630 #Member const RectType* fRectTypes 3631 #Line # array of fill types ## 3632 Optional array of fill types, one per rectangular grid entry: 3633 array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##. 3634 3635 Each RectType is one of: kDefault, kTransparent, kFixedColor. 3636 3637 Array entries correspond to the rectangular grid entries, ascending 3638 left to right and then top to bottom. 3639 ## 3640 3641 #Member int fXCount 3642 #Line # number of x-coordinates ## 3643 Number of entries in fXDivs array; one less than the number of 3644 horizontal divisions. 3645 ## 3646 3647 #Member int fYCount 3648 #Line # number of y-coordinates ## 3649 Number of entries in fYDivs array; one less than the number of vertical 3650 divisions. 3651 ## 3652 3653 #Member const SkIRect* fBounds 3654 #Line # source bounds to draw from ## 3655 Optional subset IRect source to draw from. 3656 If nullptr, source bounds is dimensions of Bitmap or Image. 3657 ## 3658 3659 #Member const SkColor* fColors 3660 #Line # array of colors ## 3661 Optional array of colors, one per rectangular grid entry. 3662 Array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##. 3663 3664 Array entries correspond to the rectangular grid entries, ascending 3665 left to right, then top to bottom. 3666 ## 3667 3668#Struct Lattice ## 3669 3670#Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, 3671 const SkPaint* paint = nullptr) 3672#In Draw_Image 3673#In Draw 3674#Line # draws proportionally stretched Bitmap ## 3675 3676Draws Bitmap bitmap stretched proportionally to fit into Rect dst. 3677 3678Lattice lattice divides bitmap into a rectangular grid. 3679Each intersection of an even-numbered row and column is fixed; like the corners 3680of drawBitmapNine, fixed lattice elements never scale larger than their initial 3681size and shrink proportionately when all fixed elements exceed the bitmap 3682dimension. All other grid elements scale to fill the available space, if any. 3683 3684Additionally transform draw using Clip, Matrix, and optional Paint paint. 3685 3686#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)# 3687 3688If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, 3689just as Shader made from SkShader::MakeBitmapShader with 3690SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples 3691outside of its bounds. 3692 3693#Param bitmap Bitmap containing pixels, dimensions, and format ## 3694#Param lattice division of bitmap into fixed and variable rectangles ## 3695#Param dst destination Rect of image to draw to ## 3696#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, 3697 and so on; or nullptr 3698## 3699 3700#Example 3701#Height 128 3702#Description 3703 The two leftmost bitmap draws has four corners and sides to the left and right of center. 3704 The leftmost bitmap draw scales the width of corners proportionately to fit. 3705 The third and fourth draw corners are not scaled; the sides are scaled to 3706 fill the remaining space; the center is transparent. 3707 The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above 3708 and below center to fill the remaining space. 3709## 3710void draw(SkCanvas* canvas) { 3711 SkIRect center = { 20, 10, 50, 40 }; 3712 SkBitmap bitmap; 3713 bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); 3714 SkCanvas bitCanvas(bitmap); 3715 SkPaint paint; 3716 SkColor gray = 0xFF000000; 3717 int left = 0; 3718 for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) { 3719 int top = 0; 3720 for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) { 3721 paint.setColor(gray); 3722 bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint); 3723 gray += 0x001f1f1f; 3724 top = bottom; 3725 } 3726 left = right; 3727 } 3728 const int xDivs[] = { center.fLeft, center.fRight }; 3729 const int yDivs[] = { center.fTop, center.fBottom }; 3730 SkCanvas::Lattice::RectType fillTypes[3][3]; 3731 memset(fillTypes, 0, sizeof(fillTypes)); 3732 fillTypes[1][1] = SkCanvas::Lattice::kTransparent; 3733 SkColor dummy[9]; // temporary pending bug fix 3734 SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs), 3735 SK_ARRAY_COUNT(yDivs), nullptr, dummy }; 3736 for (auto dest: { 20, 30, 40, 60, 90 } ) { 3737 canvas->drawBitmapLattice(bitmap, lattice, SkRect::MakeWH(dest, 110 - dest), nullptr); 3738 canvas->translate(dest + 4, 0); 3739 } 3740} 3741## 3742 3743#SeeAlso drawImageLattice drawBitmap drawBitmapNine Lattice 3744 3745## 3746 3747# ------------------------------------------------------------------------------ 3748 3749#Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 3750 const SkPaint* paint = nullptr) 3751#In Draw_Image 3752#In Draw 3753#Line # draws proportionally stretched Image ## 3754 3755Draws Image image stretched proportionally to fit into Rect dst. 3756 3757Lattice lattice divides image into a rectangular grid. 3758Each intersection of an even-numbered row and column is fixed; like the corners 3759of drawBitmapNine, fixed lattice elements never scale larger than their initial 3760size and shrink proportionately when all fixed elements exceed the bitmap 3761dimension. All other grid elements scale to fill the available space, if any. 3762 3763Additionally transform draw using Clip, Matrix, and optional Paint paint. 3764 3765#paint_as_used_by_draw_lattice_or_draw_nine(image)# 3766 3767If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, 3768just as Shader made from SkShader::MakeBitmapShader with 3769SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples 3770outside of its bounds. 3771 3772#Param image Image containing pixels, dimensions, and format ## 3773#Param lattice division of bitmap into fixed and variable rectangles ## 3774#Param dst destination Rect of image to draw to ## 3775#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter, 3776 and so on; or nullptr 3777## 3778 3779#Example 3780#Height 128 3781#Description 3782 The leftmost image is smaller than center; only corners are drawn, all scaled to fit. 3783 The second image equals the size of center; only corners are drawn without scaling. 3784 The remaining images are larger than center. All corners draw without scaling. The sides 3785 are scaled if needed to take up the remaining space; the center is transparent. 3786## 3787void draw(SkCanvas* canvas) { 3788 SkIRect center = { 20, 10, 50, 40 }; 3789 SkBitmap bitmap; 3790 bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); 3791 SkCanvas bitCanvas(bitmap); 3792 SkPaint paint; 3793 SkColor gray = 0xFF000000; 3794 int left = 0; 3795 for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) { 3796 int top = 0; 3797 for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) { 3798 paint.setColor(gray); 3799 bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint); 3800 gray += 0x001f1f1f; 3801 top = bottom; 3802 } 3803 left = right; 3804 } 3805 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 3806 SkImage* imagePtr = image.get(); 3807 for (auto dest: { 20, 30, 40, 60, 90 } ) { 3808 canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr); 3809 canvas->translate(dest + 4, 0); 3810 } 3811} 3812## 3813 3814#SeeAlso drawBitmapLattice drawImage drawImageNine Lattice 3815 3816## 3817 3818#Subtopic Lattice ## 3819 3820#Subtopic Draw_Image ## 3821 3822# ------------------------------------------------------------------------------ 3823#Subtopic Draw_Text 3824#Line # draws text into Canvas ## 3825## 3826 3827#Method void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, 3828 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) 3829#In Draw_Text 3830#In Draw 3831#Line # draws text at (x, y), using font advance ## 3832#Populate 3833 3834#Example 3835#Height 200 3836#Description 3837The same text is drawn varying Paint_Text_Size and varying 3838Matrix. 3839## 3840void draw(SkCanvas* canvas) { 3841 SkPaint paint; 3842 SkFont font; 3843 float textSizes[] = { 12, 18, 24, 36 }; 3844 for (auto size: textSizes ) { 3845 font.setSize(size); 3846 canvas->drawSimpleText("Aa", 2, kUTF8_SkTextEncoding, 10, 20, font, paint); 3847 canvas->translate(0, size * 2); 3848 } 3849 font.setSize(12); 3850 float yPos = 20; 3851 for (auto size: textSizes ) { 3852 float scale = size / 12.f; 3853 canvas->resetMatrix(); 3854 canvas->translate(100, 0); 3855 canvas->scale(scale, scale); 3856 canvas->drawSimpleText("Aa", 2, kUTF8_SkTextEncoding, 3857 10 / scale, yPos / scale, font, paint); 3858 yPos += size * 2; 3859 } 3860} 3861## 3862 3863#SeeAlso drawString drawTextBlob 3864 3865## 3866 3867# ------------------------------------------------------------------------------ 3868 3869#Method void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) 3870#In Draw_Text 3871#In Draw 3872#Line # draws text with arrays of positions and Paint ## 3873Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint. 3874 3875blob contains Glyphs, their positions, and paint attributes specific to text: 3876#font_metrics#. 3877 3878Paint_Text_Encoding must be set to kGlyphID_SkTextEncoding. 3879 3880Elements of paint: Anti_Alias, Blend_Mode, Color including Color_Alpha, 3881Color_Filter, Paint_Dither, Draw_Looper, Mask_Filter, Path_Effect, Shader, and 3882Paint_Style; apply to blob. If Paint contains SkPaint::kStroke_Style: 3883Paint_Miter_Limit, Paint_Stroke_Cap, Paint_Stroke_Join, and Paint_Stroke_Width; 3884apply to Path created from blob. 3885 3886#Param blob Glyphs, positions, and their paints' text size, typeface, and so on ## 3887#Param x horizontal offset applied to blob ## 3888#Param y vertical offset applied to blob ## 3889#Param paint blend, color, stroking, and so on, used to draw ## 3890 3891#Example 3892#Height 120 3893void draw(SkCanvas* canvas) { 3894 SkTextBlobBuilder textBlobBuilder; 3895 const char bunny[] = "/(^x^)\\"; 3896 const int len = sizeof(bunny) - 1; 3897 uint16_t glyphs[len]; 3898 SkFont font; 3899 font.textToGlyphs(bunny, len, SkTextEncoding::kUTF8, glyphs, len); 3900 int runs[] = { 3, 1, 3 }; 3901 SkPoint textPos = { 20, 100 }; 3902 int glyphIndex = 0; 3903 for (auto runLen : runs) { 3904 font.setSize(1 == runLen ? 20 : 50); 3905 const SkTextBlobBuilder::RunBuffer& run = 3906 textBlobBuilder.allocRun(font, runLen, textPos.fX, textPos.fY); 3907 memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen); 3908 font.setSize(1 == runLen ? 20 : 50); 3909 textPos.fX += font.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, 3910 SkTextEncoding::kGlyphID); 3911 glyphIndex += runLen; 3912 } 3913 sk_sp<const SkTextBlob> blob = textBlobBuilder.make(); 3914 canvas->drawTextBlob(blob.get(), 0, 0, SkPaint()); 3915} 3916## 3917 3918#SeeAlso drawText 3919 3920## 3921 3922# ------------------------------------------------------------------------------ 3923 3924#Method void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint) 3925 3926Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint. 3927 3928blob contains Glyphs, their positions, and paint attributes specific to text: 3929#font_metrics#. 3930 3931Paint_Text_Encoding must be set to kGlyphID_SkTextEncoding. 3932 3933Elements of paint: Path_Effect, Mask_Filter, Shader, Color_Filter, 3934Image_Filter, and Draw_Looper; apply to blob. 3935 3936#Param blob Glyphs, positions, and their paints' text size, typeface, and so on ## 3937#Param x horizontal offset applied to blob ## 3938#Param y vertical offset applied to blob ## 3939#Param paint blend, color, stroking, and so on, used to draw ## 3940 3941#Example 3942#Height 120 3943#Description 3944Paint attributes related to text, like text size, have no effect on paint passed to drawTextBlob. 3945## 3946 void draw(SkCanvas* canvas) { 3947 SkTextBlobBuilder textBlobBuilder; 3948 SkFont font; 3949 font.setSize(50); 3950 const SkTextBlobBuilder::RunBuffer& run = 3951 textBlobBuilder.allocRun(font, 1, 20, 100); 3952 run.glyphs[0] = 20; 3953 sk_sp<const SkTextBlob> blob = textBlobBuilder.make(); 3954 SkPaint paint; 3955 paint.setColor(SK_ColorBLUE); 3956 canvas->drawTextBlob(blob.get(), 0, 0, paint); 3957 } 3958## 3959 3960#SeeAlso drawText 3961 3962## 3963 3964# ------------------------------------------------------------------------------ 3965 3966#Method void drawPicture(const SkPicture* picture) 3967#In Draw 3968#Line # draws Picture using Clip and Matrix ## 3969#Populate 3970 3971#Example 3972void draw(SkCanvas* canvas) { 3973 SkPictureRecorder recorder; 3974 SkCanvas* recordingCanvas = recorder.beginRecording(50, 50); 3975 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) { 3976 SkPaint paint; 3977 paint.setColor(color); 3978 recordingCanvas->drawRect({10, 10, 30, 40}, paint); 3979 recordingCanvas->translate(10, 10); 3980 recordingCanvas->scale(1.2f, 1.4f); 3981 } 3982 sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture(); 3983 canvas->drawPicture(playback); 3984 canvas->scale(2, 2); 3985 canvas->translate(50, 0); 3986 canvas->drawPicture(playback); 3987} 3988## 3989 3990#SeeAlso drawDrawable SkPicture SkPicture::playback 3991 3992## 3993 3994# ------------------------------------------------------------------------------ 3995 3996#Method void drawPicture(const sk_sp<SkPicture>& picture) 3997#Populate 3998 3999#Example 4000void draw(SkCanvas* canvas) { 4001 SkPictureRecorder recorder; 4002 SkCanvas* recordingCanvas = recorder.beginRecording(50, 50); 4003 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) { 4004 SkPaint paint; 4005 paint.setColor(color); 4006 recordingCanvas->drawRect({10, 10, 30, 40}, paint); 4007 recordingCanvas->translate(10, 10); 4008 recordingCanvas->scale(1.2f, 1.4f); 4009 } 4010 sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture(); 4011 canvas->drawPicture(playback); 4012 canvas->scale(2, 2); 4013 canvas->translate(50, 0); 4014 canvas->drawPicture(playback); 4015} 4016## 4017 4018#SeeAlso drawDrawable SkPicture SkPicture::playback 4019 4020## 4021 4022# ------------------------------------------------------------------------------ 4023 4024#Method void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) 4025#Populate 4026 4027#Example 4028void draw(SkCanvas* canvas) { 4029 SkPaint paint; 4030 SkPictureRecorder recorder; 4031 SkCanvas* recordingCanvas = recorder.beginRecording(50, 50); 4032 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) { 4033 paint.setColor(color); 4034 recordingCanvas->drawRect({10, 10, 30, 40}, paint); 4035 recordingCanvas->translate(10, 10); 4036 recordingCanvas->scale(1.2f, 1.4f); 4037 } 4038 sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture(); 4039 const SkPicture* playbackPtr = playback.get(); 4040 SkMatrix matrix; 4041 matrix.reset(); 4042 for (auto alpha : { 70, 140, 210 } ) { 4043 paint.setAlpha(alpha); 4044 canvas->drawPicture(playbackPtr, &matrix, &paint); 4045 matrix.preTranslate(70, 70); 4046 } 4047} 4048## 4049 4050#SeeAlso drawDrawable SkPicture SkPicture::playback 4051 4052## 4053 4054# ------------------------------------------------------------------------------ 4055 4056#Method void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint) 4057#Populate 4058 4059#Example 4060void draw(SkCanvas* canvas) { 4061 SkPaint paint; 4062 SkPictureRecorder recorder; 4063 SkCanvas* recordingCanvas = recorder.beginRecording(50, 50); 4064 for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) { 4065 paint.setColor(color); 4066 recordingCanvas->drawRect({10, 10, 30, 40}, paint); 4067 recordingCanvas->translate(10, 10); 4068 recordingCanvas->scale(1.2f, 1.4f); 4069 } 4070 sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture(); 4071 SkMatrix matrix; 4072 matrix.reset(); 4073 for (auto alpha : { 70, 140, 210 } ) { 4074 paint.setAlpha(alpha); 4075 canvas->drawPicture(playback, &matrix, &paint); 4076 matrix.preTranslate(70, 70); 4077 } 4078} 4079## 4080 4081#SeeAlso drawDrawable SkPicture SkPicture::playback 4082 4083## 4084 4085# ------------------------------------------------------------------------------ 4086 4087#Method void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) 4088#In Draw 4089#Line # draws Vertices, a triangle mesh ## 4090#Populate 4091 4092#Example 4093void draw(SkCanvas* canvas) { 4094 SkPaint paint; 4095 SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; 4096 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN }; 4097 auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4098 SK_ARRAY_COUNT(points), points, nullptr, colors); 4099 canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, paint); 4100} 4101## 4102 4103#SeeAlso drawPatch drawPicture 4104 4105## 4106 4107# ------------------------------------------------------------------------------ 4108 4109#Method void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint) 4110#Populate 4111 4112#Example 4113void draw(SkCanvas* canvas) { 4114 SkPaint paint; 4115 SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; 4116 SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } }; 4117 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN }; 4118 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4, 4119 SkShader::kClamp_TileMode)); 4120 auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4121 SK_ARRAY_COUNT(points), points, texs, colors); 4122 canvas->drawVertices(vertices, SkBlendMode::kDarken, paint); 4123} 4124## 4125 4126#SeeAlso drawPatch drawPicture 4127 4128## 4129 4130# ------------------------------------------------------------------------------ 4131 4132#Method void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], 4133 int boneCount, SkBlendMode mode, const SkPaint& paint) 4134#Populate 4135 4136#NoExample 4137void draw(SkCanvas* canvas) { 4138 SkPaint paint; 4139 SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; 4140 SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } }; 4141 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN }; 4142 SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 }, 4143 { 1, 0, 0, 0 }, 4144 { 2, 0, 0, 0 }, 4145 { 3, 0, 0, 0 } }; 4146 SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f }, 4147 { 1.0f, 0.0f, 0.0f, 0.0f }, 4148 { 1.0f, 0.0f, 0.0f, 0.0f }, 4149 { 1.0f, 0.0f, 0.0f, 0.0f } }; 4150 SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}, 4151 {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }}, 4152 {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }}, 4153 {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} }; 4154 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4, 4155 SkShader::kClamp_TileMode)); 4156 auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4157 SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights); 4158 canvas->drawVertices(vertices.get(), bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint); 4159} 4160## 4161 4162#SeeAlso drawPatch drawPicture 4163 4164## 4165 4166# ------------------------------------------------------------------------------ 4167 4168#Method void drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[], 4169 int boneCount, SkBlendMode mode, const SkPaint& paint) 4170#Populate 4171 4172#NoExample 4173void draw(SkCanvas* canvas) { 4174 SkPaint paint; 4175 SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } }; 4176 SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } }; 4177 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN }; 4178 SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 }, 4179 { 1, 0, 0, 0 }, 4180 { 2, 0, 0, 0 }, 4181 { 3, 0, 0, 0 } }; 4182 SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f }, 4183 { 1.0f, 0.0f, 0.0f, 0.0f }, 4184 { 1.0f, 0.0f, 0.0f, 0.0f }, 4185 { 1.0f, 0.0f, 0.0f, 0.0f } }; 4186 SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }}, 4187 {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }}, 4188 {{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }}, 4189 {{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} }; 4190 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4, 4191 SkShader::kClamp_TileMode)); 4192 auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4193 SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights); 4194 canvas->drawVertices(vertices, bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint); 4195} 4196## 4197 4198#SeeAlso drawPatch drawPicture 4199 4200## 4201 4202# ------------------------------------------------------------------------------ 4203 4204#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], 4205 const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint) 4206#In Draw 4207#Line # draws Coons_Patch ## 4208#Populate 4209 4210#Example 4211#Image 5 4212void draw(SkCanvas* canvas) { 4213 // SkBitmap source = cmbkygk; 4214 SkPaint paint; 4215 paint.setFilterQuality(kLow_SkFilterQuality); 4216 paint.setAntiAlias(true); 4217 SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 }, 4218 /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 }, 4219 /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 }, 4220 /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ }; 4221 SkColor colors[] = { 0xbfff0000, 0xbf0000ff, 0xbfff00ff, 0xbf00ffff }; 4222 SkPoint texCoords[] = { { -30, -30 }, { 162, -30}, { 162, 162}, { -30, 162} }; 4223 paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode, 4224 SkShader::kClamp_TileMode, nullptr)); 4225 canvas->scale(15, 15); 4226 for (auto blend : { SkBlendMode::kSrcOver, SkBlendMode::kModulate, SkBlendMode::kXor } ) { 4227 canvas->drawPatch(cubics, colors, texCoords, blend, paint); 4228 canvas->translate(4, 4); 4229 } 4230} 4231## 4232 4233#ToDo can patch use image filter? ## 4234#SeeAlso drawVertices drawPicture 4235 4236## 4237 4238# ------------------------------------------------------------------------------ 4239 4240#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4], 4241 const SkPoint texCoords[4], const SkPaint& paint) 4242#Populate 4243 4244#Example 4245void draw(SkCanvas* canvas) { 4246 SkPaint paint; 4247 paint.setAntiAlias(true); 4248 SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 }, 4249 /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 }, 4250 /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 }, 4251 /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ }; 4252 SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN }; 4253 canvas->scale(30, 30); 4254 canvas->drawPatch(cubics, colors, nullptr, paint); 4255 SkPoint text[] = { {3,0.9f}, {4,2.5f}, {5,0.9f}, {7.5f,3.2f}, {5.5f,4.2f}, 4256 {7.5f,5.2f}, {5,7.5f}, {4,5.9f}, {3,7.5f}, {0.5f,5.2f}, {2.5f,4.2f}, 4257 {0.5f,3.2f} }; 4258 4259 SkFont font(nullptr, 18.f / 30); 4260 for (int i = 0; i< 10; ++i) { 4261 char digit = '0' + i; 4262 canvas->drawSimpleText(&digit, kUTF8_SkTextEncoding, 1, text[i].fX, text[i].fY, font, paint); 4263 } 4264 canvas->drawString("10", text[10].fX, text[10].fY, font, paint); 4265 canvas->drawString("11", text[11].fX, text[11].fY, font, paint); 4266 paint.setStyle(SkPaint::kStroke_Style); 4267 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 12, cubics, paint); 4268 canvas->drawLine(cubics[11].fX, cubics[11].fY, cubics[0].fX, cubics[0].fY, paint); 4269} 4270## 4271 4272#Example 4273#Image 6 4274void draw(SkCanvas* canvas) { 4275 // SkBitmap source = checkerboard; 4276 SkPaint paint; 4277 paint.setFilterQuality(kLow_SkFilterQuality); 4278 paint.setAntiAlias(true); 4279 SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 }, 4280 /* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 }, 4281 /* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 }, 4282 /* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ }; 4283 SkPoint texCoords[] = { { 0, 0 }, { 0, 62}, { 62, 62}, { 62, 0 } }; 4284 paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode, 4285 SkShader::kClamp_TileMode, nullptr)); 4286 canvas->scale(30, 30); 4287 canvas->drawPatch(cubics, nullptr, texCoords, paint); 4288} 4289## 4290 4291#ToDo can patch use image filter? ## 4292#SeeAlso drawVertices drawPicture 4293 4294## 4295 4296# ------------------------------------------------------------------------------ 4297 4298#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 4299 const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, 4300 const SkPaint* paint) 4301#In Draw 4302#Line # draws sprites using Clip, Matrix, and Paint ## 4303#Populate 4304 4305#Example 4306#Image 3 4307void draw(SkCanvas* canvas) { 4308 // SkBitmap source = mandrill; 4309 SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } }; 4310 SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } }; 4311 SkColor colors[] = { 0x7f55aa00, 0x7f3333bf }; 4312 const SkImage* imagePtr = image.get(); 4313 canvas->drawAtlas(imagePtr, xforms, tex, colors, 2, SkBlendMode::kSrcOver, nullptr, nullptr); 4314} 4315## 4316 4317#SeeAlso drawBitmap drawImage 4318 4319## 4320 4321# ------------------------------------------------------------------------------ 4322 4323#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[], 4324 const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, 4325 const SkPaint* paint) 4326#Populate 4327 4328#Example 4329#Image 3 4330void draw(SkCanvas* canvas) { 4331 // SkBitmap source = mandrill; 4332 SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } }; 4333 SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } }; 4334 SkColor colors[] = { 0x7f55aa00, 0x7f3333bf }; 4335 SkPaint paint; 4336 paint.setAlpha(127); 4337 canvas->drawAtlas(image, xforms, tex, colors, 2, SkBlendMode::kPlus, nullptr, &paint); 4338} 4339## 4340 4341#ToDo bug in example on cpu side, gpu looks ok ## 4342 4343#SeeAlso drawBitmap drawImage 4344 4345## 4346 4347# ------------------------------------------------------------------------------ 4348 4349#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count, 4350 const SkRect* cullRect, const SkPaint* paint) 4351#Populate 4352 4353#Example 4354#Image 3 4355void draw(SkCanvas* canvas) { 4356 // sk_sp<SkImage> image = mandrill; 4357 SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } }; 4358 SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } }; 4359 const SkImage* imagePtr = image.get(); 4360 canvas->drawAtlas(imagePtr, xforms, tex, 2, nullptr, nullptr); 4361} 4362## 4363 4364#SeeAlso drawBitmap drawImage 4365 4366## 4367 4368# ------------------------------------------------------------------------------ 4369 4370#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[], 4371 int count, const SkRect* cullRect, const SkPaint* paint) 4372#Populate 4373 4374#Example 4375#Image 3 4376void draw(SkCanvas* canvas) { 4377 // sk_sp<SkImage> image = mandrill; 4378 SkRSXform xforms[] = { { 1, 0, 0, 0 }, {0, 1, 300, 100 } }; 4379 SkRect tex[] = { { 0, 0, 200, 200 }, { 200, 0, 400, 200 } }; 4380 canvas->drawAtlas(image, xforms, tex, 2, nullptr, nullptr); 4381} 4382## 4383 4384#SeeAlso drawBitmap drawImage 4385 4386## 4387 4388# ------------------------------------------------------------------------------ 4389 4390#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr) 4391#In Draw 4392#Line # draws Drawable, encapsulated drawing commands ## 4393#Populate 4394 4395#Example 4396#Height 100 4397#Function 4398struct MyDrawable : public SkDrawable { 4399 SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); } 4400 4401 void onDraw(SkCanvas* canvas) override { 4402 SkPath path; 4403 path.conicTo(10, 90, 50, 90, 0.9f); 4404 SkPaint paint; 4405 paint.setColor(SK_ColorBLUE); 4406 canvas->drawRect(path.getBounds(), paint); 4407 paint.setAntiAlias(true); 4408 paint.setColor(SK_ColorWHITE); 4409 canvas->drawPath(path, paint); 4410 } 4411}; 4412 4413#Function ## 4414void draw(SkCanvas* canvas) { 4415 sk_sp<SkDrawable> drawable(new MyDrawable); 4416 SkMatrix matrix; 4417 matrix.setTranslate(10, 10); 4418 canvas->drawDrawable(drawable.get(), &matrix); 4419} 4420## 4421 4422#SeeAlso SkDrawable drawPicture 4423 4424## 4425 4426# ------------------------------------------------------------------------------ 4427 4428#Method void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y) 4429#Populate 4430 4431#Example 4432#Height 100 4433#Function 4434struct MyDrawable : public SkDrawable { 4435 SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); } 4436 4437 void onDraw(SkCanvas* canvas) override { 4438 SkPath path; 4439 path.conicTo(10, 90, 50, 90, 0.9f); 4440 SkPaint paint; 4441 paint.setColor(SK_ColorBLUE); 4442 canvas->drawRect(path.getBounds(), paint); 4443 paint.setAntiAlias(true); 4444 paint.setColor(SK_ColorWHITE); 4445 canvas->drawPath(path, paint); 4446 } 4447}; 4448 4449#Function ## 4450void draw(SkCanvas* canvas) { 4451 sk_sp<SkDrawable> drawable(new MyDrawable); 4452 canvas->drawDrawable(drawable.get(), 10, 10); 4453} 4454## 4455 4456#SeeAlso SkDrawable drawPicture 4457 4458## 4459 4460# ------------------------------------------------------------------------------ 4461 4462#Method void drawAnnotation(const SkRect& rect, const char key[], SkData* value) 4463#In Draw 4464#In Utility 4465#Line # associates a Rect with a key-value pair ## 4466#Populate 4467 4468#Example 4469 #Height 1 4470 const char text[] = "Click this link!"; 4471 SkRect bounds; 4472 SkPaint paint; 4473 SkFont font(nullptr, 40); 4474 (void)font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 4475 const char url[] = "https://www.google.com/"; 4476 sk_sp<SkData> urlData(SkData::MakeWithCString(url)); 4477 canvas->drawAnnotation(bounds, "url_key", urlData.get()); 4478## 4479 4480#SeeAlso SkPicture SkDocument 4481 4482## 4483 4484# ------------------------------------------------------------------------------ 4485 4486#Method void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value) 4487#Populate 4488 4489#Example 4490#Height 1 4491 const char text[] = "Click this link!"; 4492 SkRect bounds; 4493 SkPaint paint; 4494 SkFont font(nullptr, 40); 4495 (void)font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 4496 const char url[] = "https://www.google.com/"; 4497 sk_sp<SkData> urlData(SkData::MakeWithCString(url)); 4498 canvas->drawAnnotation(bounds, "url_key", urlData.get()); 4499## 4500 4501#SeeAlso SkPicture SkDocument 4502 4503## 4504 4505# ------------------------------------------------------------------------------ 4506 4507#Method virtual bool isClipEmpty() const 4508#In Property 4509#Line # returns if Clip is empty ## 4510#Populate 4511 4512#Example 4513 void draw(SkCanvas* canvas) { 4514 SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not"); 4515 SkPath path; 4516 canvas->clipPath(path); 4517 SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not"); 4518 } 4519 #StdOut 4520 clip is not empty 4521 clip is empty 4522 ## 4523## 4524 4525#SeeAlso isClipRect getLocalClipBounds getDeviceClipBounds 4526 4527## 4528 4529# ------------------------------------------------------------------------------ 4530 4531#Method virtual bool isClipRect() const 4532#In Property 4533#Line # returns if Clip is Rect and not empty ## 4534#Populate 4535 4536#Example 4537 void draw(SkCanvas* canvas) { 4538 SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not"); 4539 canvas->clipRect({0, 0, 0, 0}); 4540 SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not"); 4541 } 4542 #StdOut 4543 clip is rect 4544 clip is not rect 4545 ## 4546## 4547 4548#SeeAlso isClipEmpty getLocalClipBounds getDeviceClipBounds 4549 4550## 4551 4552#Class SkCanvas ## 4553 4554#Topic Canvas ## 4555