1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkCanvas_DEFINED 9 #define SkCanvas_DEFINED 10 11 #include "include/core/SkBlendMode.h" 12 #include "include/core/SkClipOp.h" 13 #include "include/core/SkColor.h" 14 #include "include/core/SkFontTypes.h" 15 #include "include/core/SkImageFilter.h" 16 #include "include/core/SkImageInfo.h" 17 #include "include/core/SkM44.h" 18 #include "include/core/SkMatrix.h" 19 #include "include/core/SkPaint.h" 20 #include "include/core/SkPoint.h" 21 #include "include/core/SkRasterHandleAllocator.h" 22 #include "include/core/SkRect.h" 23 #include "include/core/SkRefCnt.h" 24 #include "include/core/SkSamplingOptions.h" 25 #include "include/core/SkScalar.h" 26 #include "include/core/SkSize.h" 27 #include "include/core/SkString.h" 28 #include "include/core/SkSurfaceProps.h" 29 #include "include/core/SkTypes.h" 30 #include "include/private/base/SkCPUTypes.h" 31 #include "include/private/base/SkDeque.h" 32 33 #include <cstdint> 34 #include <cstring> 35 #include <memory> 36 #include <optional> 37 38 #ifndef SK_SUPPORT_LEGACY_GETTOTALMATRIX 39 #define SK_SUPPORT_LEGACY_GETTOTALMATRIX 40 #endif 41 42 namespace sktext { 43 class GlyphRunBuilder; 44 class GlyphRunList; 45 } 46 47 class AutoLayerForImageFilter; 48 class GrRecordingContext; 49 50 class SkBaseDevice; 51 class SkBitmap; 52 class SkBlender; 53 class SkData; 54 class SkDrawable; 55 class SkFont; 56 class SkImage; 57 class SkMesh; 58 class SkPaintFilterCanvas; 59 class SkPath; 60 class SkPicture; 61 class SkPixmap; 62 class SkRRect; 63 class SkRegion; 64 class SkShader; 65 class SkSpecialImage; 66 class SkSurface; 67 class SkSurface_Base; 68 class SkTextBlob; 69 class SkVertices; 70 struct SkDrawShadowRec; 71 struct SkRSXform; 72 73 namespace skgpu::graphite { class Recorder; } 74 namespace sktext::gpu { class Slug; } 75 namespace SkRecords { class Draw; } 76 77 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_GANESH) 78 class GrBackendRenderTarget; 79 #endif 80 81 // TODO: 82 // This is not ideal but Chrome is depending on a forward decl of GrSlug here. 83 // It should be removed once Chrome has migrated to sktext::gpu::Slug. 84 using GrSlug = sktext::gpu::Slug; 85 86 /** \class SkCanvas 87 SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed. 88 SkCanvas contains a stack of SkMatrix and clip values. 89 90 SkCanvas and SkPaint together provide the state to draw into SkSurface or SkBaseDevice. 91 Each SkCanvas draw call transforms the geometry of the object by the concatenation of all 92 SkMatrix values in the stack. The transformed geometry is clipped by the intersection 93 of all of clip values in the stack. The SkCanvas draw calls use SkPaint to supply drawing 94 state such as color, SkTypeface, text size, stroke width, SkShader and so on. 95 96 To draw to a pixel-based destination, create raster surface or GPU surface. 97 Request SkCanvas from SkSurface to obtain the interface to draw. 98 SkCanvas generated by raster surface draws to memory visible to the CPU. 99 SkCanvas generated by GPU surface uses Vulkan or OpenGL to draw to the GPU. 100 101 To draw to a document, obtain SkCanvas from SVG canvas, document PDF, or SkPictureRecorder. 102 SkDocument based SkCanvas and other SkCanvas subclasses reference SkBaseDevice describing the 103 destination. 104 105 SkCanvas can be constructed to draw to SkBitmap without first creating raster surface. 106 This approach may be deprecated in the future. 107 */ 108 class SK_API SkCanvas { 109 public: 110 111 /** Allocates raster SkCanvas that will draw directly into pixels. 112 113 SkCanvas is returned if all parameters are valid. 114 Valid parameters include: 115 info dimensions are zero or positive; 116 info contains SkColorType and SkAlphaType supported by raster surface; 117 pixels is not nullptr; 118 rowBytes is zero or large enough to contain info width pixels of SkColorType. 119 120 Pass zero for rowBytes to compute rowBytes from info width and size of pixel. 121 If rowBytes is greater than zero, it must be equal to or greater than 122 info width times bytes required for SkColorType. 123 124 Pixel buffer size should be info height times computed rowBytes. 125 Pixels are not initialized. 126 To access pixels after drawing, call flush() or peekPixels(). 127 128 @param info width, height, SkColorType, SkAlphaType, SkColorSpace, of raster surface; 129 width, or height, or both, may be zero 130 @param pixels pointer to destination pixels buffer 131 @param rowBytes interval from one SkSurface row to the next, or zero 132 @param props LCD striping orientation and setting for device independent fonts; 133 may be nullptr 134 @return SkCanvas if all parameters are valid; otherwise, nullptr 135 */ 136 static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels, 137 size_t rowBytes, 138 const SkSurfaceProps* props = nullptr); 139 140 /** Allocates raster SkCanvas specified by inline image specification. Subsequent SkCanvas 141 calls draw into pixels. 142 SkColorType is set to kN32_SkColorType. 143 SkAlphaType is set to kPremul_SkAlphaType. 144 To access pixels after drawing, call flush() or peekPixels(). 145 146 SkCanvas is returned if all parameters are valid. 147 Valid parameters include: 148 width and height are zero or positive; 149 pixels is not nullptr; 150 rowBytes is zero or large enough to contain width pixels of kN32_SkColorType. 151 152 Pass zero for rowBytes to compute rowBytes from width and size of pixel. 153 If rowBytes is greater than zero, it must be equal to or greater than 154 width times bytes required for SkColorType. 155 156 Pixel buffer size should be height times rowBytes. 157 158 @param width pixel column count on raster surface created; must be zero or greater 159 @param height pixel row count on raster surface created; must be zero or greater 160 @param pixels pointer to destination pixels buffer; buffer size should be height 161 times rowBytes 162 @param rowBytes interval from one SkSurface row to the next, or zero 163 @return SkCanvas if all parameters are valid; otherwise, nullptr 164 */ MakeRasterDirectN32(int width,int height,SkPMColor * pixels,size_t rowBytes)165 static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels, 166 size_t rowBytes) { 167 return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); 168 } 169 170 /** Creates an empty SkCanvas with no backing device or pixels, with 171 a width and height of zero. 172 173 @return empty SkCanvas 174 175 example: https://fiddle.skia.org/c/@Canvas_empty_constructor 176 */ 177 SkCanvas(); 178 179 /** Creates SkCanvas of the specified dimensions without a SkSurface. 180 Used by subclasses with custom implementations for draw member functions. 181 182 If props equals nullptr, SkSurfaceProps are created with 183 SkSurfaceProps::InitType settings, which choose the pixel striping 184 direction and order. Since a platform may dynamically change its direction when 185 the device is rotated, and since a platform may have multiple monitors with 186 different characteristics, it is best not to rely on this legacy behavior. 187 188 @param width zero or greater 189 @param height zero or greater 190 @param props LCD striping orientation and setting for device independent fonts; 191 may be nullptr 192 @return SkCanvas placeholder with dimensions 193 194 example: https://fiddle.skia.org/c/@Canvas_int_int_const_SkSurfaceProps_star 195 */ 196 SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr); 197 198 /** Private. For internal use only. 199 */ 200 explicit SkCanvas(sk_sp<SkBaseDevice> device); 201 202 /** Constructs a canvas that draws into bitmap. 203 Sets kUnknown_SkPixelGeometry in constructed SkSurface. 204 205 SkBitmap is copied so that subsequently editing bitmap will not affect 206 constructed SkCanvas. 207 208 May be deprecated in the future. 209 210 @param bitmap width, height, SkColorType, SkAlphaType, and pixel 211 storage of raster surface 212 @return SkCanvas that can be used to draw into bitmap 213 214 example: https://fiddle.skia.org/c/@Canvas_copy_const_SkBitmap 215 */ 216 explicit SkCanvas(const SkBitmap& bitmap); 217 218 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 219 /** Private. 220 */ 221 enum class ColorBehavior { 222 kLegacy, //!< placeholder 223 }; 224 225 /** Private. For use by Android framework only. 226 227 @param bitmap specifies a bitmap for the canvas to draw into 228 @param behavior specializes this constructor; value is unused 229 @return SkCanvas that can be used to draw into bitmap 230 */ 231 SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior); 232 #endif 233 234 /** Constructs a canvas that draws into bitmap. 235 Use props to match the device characteristics, like LCD striping. 236 237 bitmap is copied so that subsequently editing bitmap will not affect 238 constructed SkCanvas. 239 240 @param bitmap width, height, SkColorType, SkAlphaType, 241 and pixel storage of raster surface 242 @param props order and orientation of RGB striping; and whether to use 243 device independent fonts 244 @return SkCanvas that can be used to draw into bitmap 245 246 example: https://fiddle.skia.org/c/@Canvas_const_SkBitmap_const_SkSurfaceProps 247 */ 248 SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props); 249 250 /** Draws saved layers, if any. 251 Frees up resources used by SkCanvas. 252 253 example: https://fiddle.skia.org/c/@Canvas_destructor 254 */ 255 virtual ~SkCanvas(); 256 257 /** Returns SkImageInfo for SkCanvas. If SkCanvas is not associated with raster surface or 258 GPU surface, returned SkColorType is set to kUnknown_SkColorType. 259 260 @return dimensions and SkColorType of SkCanvas 261 262 example: https://fiddle.skia.org/c/@Canvas_imageInfo 263 */ 264 SkImageInfo imageInfo() const; 265 266 /** Copies SkSurfaceProps, if SkCanvas is associated with raster surface or 267 GPU surface, and returns true. Otherwise, returns false and leave props unchanged. 268 269 @param props storage for writable SkSurfaceProps 270 @return true if SkSurfaceProps was copied 271 272 DEPRECATED: Replace usage with getBaseProps() or getTopProps() 273 274 example: https://fiddle.skia.org/c/@Canvas_getProps 275 */ 276 bool getProps(SkSurfaceProps* props) const; 277 278 /** Returns the SkSurfaceProps associated with the canvas (i.e., at the base of the layer 279 stack). 280 281 @return base SkSurfaceProps 282 */ 283 SkSurfaceProps getBaseProps() const; 284 285 /** Returns the SkSurfaceProps associated with the canvas that are currently active (i.e., at 286 the top of the layer stack). This can differ from getBaseProps depending on the flags 287 passed to saveLayer (see SaveLayerFlagsSet). 288 289 @return SkSurfaceProps active in the current/top layer 290 */ 291 SkSurfaceProps getTopProps() const; 292 293 /** Triggers the immediate execution of all pending draw operations. 294 If SkCanvas is associated with GPU surface, resolves all pending GPU operations. 295 If SkCanvas is associated with raster surface, has no effect; raster draw 296 operations are never deferred. 297 298 DEPRECATED: Replace usage with GrDirectContext::flush() 299 */ 300 void flush(); 301 302 /** Gets the size of the base or root layer in global canvas coordinates. The 303 origin of the base layer is always (0,0). The area available for drawing may be 304 smaller (due to clipping or saveLayer). 305 306 @return integral width and height of base layer 307 308 example: https://fiddle.skia.org/c/@Canvas_getBaseLayerSize 309 */ 310 virtual SkISize getBaseLayerSize() const; 311 312 /** Creates SkSurface matching info and props, and associates it with SkCanvas. 313 Returns nullptr if no match found. 314 315 If props is nullptr, matches SkSurfaceProps in SkCanvas. If props is nullptr and SkCanvas 316 does not have SkSurfaceProps, creates SkSurface with default SkSurfaceProps. 317 318 @param info width, height, SkColorType, SkAlphaType, and SkColorSpace 319 @param props SkSurfaceProps to match; may be nullptr to match SkCanvas 320 @return SkSurface matching info and props, or nullptr if no match is available 321 322 example: https://fiddle.skia.org/c/@Canvas_makeSurface 323 */ 324 sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr); 325 326 /** Returns GPU context of the GPU surface associated with SkCanvas. 327 328 @return GPU context, if available; nullptr otherwise 329 330 example: https://fiddle.skia.org/c/@Canvas_recordingContext 331 */ 332 virtual GrRecordingContext* recordingContext(); 333 334 /** Returns Recorder for the GPU surface associated with SkCanvas. 335 336 @return Recorder, if available; nullptr otherwise 337 */ 338 virtual skgpu::graphite::Recorder* recorder(); 339 340 /** Sometimes a canvas is owned by a surface. If it is, getSurface() will return a bare 341 * pointer to that surface, else this will return nullptr. 342 */ 343 SkSurface* getSurface() const; 344 345 /** Returns the pixel base address, SkImageInfo, rowBytes, and origin if the pixels 346 can be read directly. The returned address is only valid 347 while SkCanvas is in scope and unchanged. Any SkCanvas call or SkSurface call 348 may invalidate the returned address and other returned values. 349 350 If pixels are inaccessible, info, rowBytes, and origin are unchanged. 351 352 @param info storage for writable pixels' SkImageInfo; may be nullptr 353 @param rowBytes storage for writable pixels' row bytes; may be nullptr 354 @param origin storage for SkCanvas top layer origin, its top-left corner; 355 may be nullptr 356 @return address of pixels, or nullptr if inaccessible 357 358 example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_a 359 example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_b 360 */ 361 void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr); 362 363 /** Returns custom context that tracks the SkMatrix and clip. 364 365 Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed 366 by the host platform user interface. The custom context returned is generated by 367 SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for 368 the drawing destination. 369 370 @return context of custom allocation 371 372 example: https://fiddle.skia.org/c/@Canvas_accessTopRasterHandle 373 */ 374 SkRasterHandleAllocator::Handle accessTopRasterHandle() const; 375 376 /** Returns true if SkCanvas has direct access to its pixels. 377 378 Pixels are readable when SkBaseDevice is raster. Pixels are not readable when SkCanvas 379 is returned from GPU surface, returned by SkDocument::beginPage, returned by 380 SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility class 381 like DebugCanvas. 382 383 pixmap is valid only while SkCanvas is in scope and unchanged. Any 384 SkCanvas or SkSurface call may invalidate the pixmap values. 385 386 @param pixmap storage for pixel state if pixels are readable; otherwise, ignored 387 @return true if SkCanvas has direct access to pixels 388 389 example: https://fiddle.skia.org/c/@Canvas_peekPixels 390 */ 391 bool peekPixels(SkPixmap* pixmap); 392 393 /** Copies SkRect of pixels from SkCanvas into dstPixels. SkMatrix and clip are 394 ignored. 395 396 Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 397 Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). 398 Copies each readable pixel intersecting both rectangles, without scaling, 399 converting to dstInfo.colorType() and dstInfo.alphaType() if required. 400 401 Pixels are readable when SkBaseDevice is raster, or backed by a GPU. 402 Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 403 returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility 404 class like DebugCanvas. 405 406 The destination pixel storage must be allocated by the caller. 407 408 Pixel values are converted only if SkColorType and SkAlphaType 409 do not match. Only pixels within both source and destination rectangles 410 are copied. dstPixels contents outside SkRect intersection are unchanged. 411 412 Pass negative values for srcX or srcY to offset pixels across or down destination. 413 414 Does not copy, and returns false if: 415 - Source and destination rectangles do not intersect. 416 - SkCanvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). 417 - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. 418 - dstRowBytes is too small to contain one row of pixels. 419 420 @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels 421 @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger 422 @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger 423 @param srcX offset into readable pixels on x-axis; may be negative 424 @param srcY offset into readable pixels on y-axis; may be negative 425 @return true if pixels were copied 426 */ 427 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 428 int srcX, int srcY); 429 430 /** Copies SkRect of pixels from SkCanvas into pixmap. SkMatrix and clip are 431 ignored. 432 433 Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 434 Destination SkRect corners are (0, 0) and (pixmap.width(), pixmap.height()). 435 Copies each readable pixel intersecting both rectangles, without scaling, 436 converting to pixmap.colorType() and pixmap.alphaType() if required. 437 438 Pixels are readable when SkBaseDevice is raster, or backed by a GPU. 439 Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 440 returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility 441 class like DebugCanvas. 442 443 Caller must allocate pixel storage in pixmap if needed. 444 445 Pixel values are converted only if SkColorType and SkAlphaType 446 do not match. Only pixels within both source and destination SkRect 447 are copied. pixmap pixels contents outside SkRect intersection are unchanged. 448 449 Pass negative values for srcX or srcY to offset pixels across or down pixmap. 450 451 Does not copy, and returns false if: 452 - Source and destination rectangles do not intersect. 453 - SkCanvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). 454 - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. 455 - SkPixmap pixels could not be allocated. 456 - pixmap.rowBytes() is too small to contain one row of pixels. 457 458 @param pixmap storage for pixels copied from SkCanvas 459 @param srcX offset into readable pixels on x-axis; may be negative 460 @param srcY offset into readable pixels on y-axis; may be negative 461 @return true if pixels were copied 462 463 example: https://fiddle.skia.org/c/@Canvas_readPixels_2 464 */ 465 bool readPixels(const SkPixmap& pixmap, int srcX, int srcY); 466 467 /** Copies SkRect of pixels from SkCanvas into bitmap. SkMatrix and clip are 468 ignored. 469 470 Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). 471 Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). 472 Copies each readable pixel intersecting both rectangles, without scaling, 473 converting to bitmap.colorType() and bitmap.alphaType() if required. 474 475 Pixels are readable when SkBaseDevice is raster, or backed by a GPU. 476 Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, 477 returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility 478 class like DebugCanvas. 479 480 Caller must allocate pixel storage in bitmap if needed. 481 482 SkBitmap values are converted only if SkColorType and SkAlphaType 483 do not match. Only pixels within both source and destination rectangles 484 are copied. SkBitmap pixels outside SkRect intersection are unchanged. 485 486 Pass negative values for srcX or srcY to offset pixels across or down bitmap. 487 488 Does not copy, and returns false if: 489 - Source and destination rectangles do not intersect. 490 - SkCanvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). 491 - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. 492 - bitmap pixels could not be allocated. 493 - bitmap.rowBytes() is too small to contain one row of pixels. 494 495 @param bitmap storage for pixels copied from SkCanvas 496 @param srcX offset into readable pixels on x-axis; may be negative 497 @param srcY offset into readable pixels on y-axis; may be negative 498 @return true if pixels were copied 499 500 example: https://fiddle.skia.org/c/@Canvas_readPixels_3 501 */ 502 bool readPixels(const SkBitmap& bitmap, int srcX, int srcY); 503 504 /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. 505 Source SkRect corners are (0, 0) and (info.width(), info.height()). 506 Destination SkRect corners are (x, y) and 507 (imageInfo().width(), imageInfo().height()). 508 509 Copies each readable pixel intersecting both rectangles, without scaling, 510 converting to imageInfo().colorType() and imageInfo().alphaType() if required. 511 512 Pixels are writable when SkBaseDevice is raster, or backed by a GPU. 513 Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, 514 returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility 515 class like DebugCanvas. 516 517 Pixel values are converted only if SkColorType and SkAlphaType 518 do not match. Only pixels within both source and destination rectangles 519 are copied. SkCanvas pixels outside SkRect intersection are unchanged. 520 521 Pass negative values for x or y to offset pixels to the left or 522 above SkCanvas pixels. 523 524 Does not copy, and returns false if: 525 - Source and destination rectangles do not intersect. 526 - pixels could not be converted to SkCanvas imageInfo().colorType() or 527 imageInfo().alphaType(). 528 - SkCanvas pixels are not writable; for instance, SkCanvas is document-based. 529 - rowBytes is too small to contain one row of pixels. 530 531 @param info width, height, SkColorType, and SkAlphaType of pixels 532 @param pixels pixels to copy, of size info.height() times rowBytes, or larger 533 @param rowBytes size of one row of pixels; info.width() times pixel size, or larger 534 @param x offset into SkCanvas writable pixels on x-axis; may be negative 535 @param y offset into SkCanvas writable pixels on y-axis; may be negative 536 @return true if pixels were written to SkCanvas 537 538 example: https://fiddle.skia.org/c/@Canvas_writePixels 539 */ 540 bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y); 541 542 /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. 543 Source SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). 544 545 Destination SkRect corners are (x, y) and 546 (imageInfo().width(), imageInfo().height()). 547 548 Copies each readable pixel intersecting both rectangles, without scaling, 549 converting to imageInfo().colorType() and imageInfo().alphaType() if required. 550 551 Pixels are writable when SkBaseDevice is raster, or backed by a GPU. 552 Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, 553 returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility 554 class like DebugCanvas. 555 556 Pixel values are converted only if SkColorType and SkAlphaType 557 do not match. Only pixels within both source and destination rectangles 558 are copied. SkCanvas pixels outside SkRect intersection are unchanged. 559 560 Pass negative values for x or y to offset pixels to the left or 561 above SkCanvas pixels. 562 563 Does not copy, and returns false if: 564 - Source and destination rectangles do not intersect. 565 - bitmap does not have allocated pixels. 566 - bitmap pixels could not be converted to SkCanvas imageInfo().colorType() or 567 imageInfo().alphaType(). 568 - SkCanvas pixels are not writable; for instance, SkCanvas is document based. 569 - bitmap pixels are inaccessible; for instance, bitmap wraps a texture. 570 571 @param bitmap contains pixels copied to SkCanvas 572 @param x offset into SkCanvas writable pixels on x-axis; may be negative 573 @param y offset into SkCanvas writable pixels on y-axis; may be negative 574 @return true if pixels were written to SkCanvas 575 576 example: https://fiddle.skia.org/c/@Canvas_writePixels_2 577 example: https://fiddle.skia.org/c/@State_Stack_a 578 example: https://fiddle.skia.org/c/@State_Stack_b 579 */ 580 bool writePixels(const SkBitmap& bitmap, int x, int y); 581 582 /** Saves SkMatrix and clip. 583 Calling restore() discards changes to SkMatrix and clip, 584 restoring the SkMatrix and clip to their state when save() was called. 585 586 SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix(), 587 and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), clipPath(), clipRegion(). 588 589 Saved SkCanvas state is put on a stack; multiple calls to save() should be balance 590 by an equal number of calls to restore(). 591 592 Call restoreToCount() with result to restore this and subsequent saves. 593 594 @return depth of saved stack 595 596 example: https://fiddle.skia.org/c/@Canvas_save 597 */ 598 int save(); 599 600 /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. 601 Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. 602 603 SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), 604 setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), 605 clipPath(), clipRegion(). 606 607 SkRect bounds suggests but does not define the SkSurface size. To clip drawing to 608 a specific rectangle, use clipRect(). 609 610 Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and 611 SkBlendMode when restore() is called. 612 613 Call restoreToCount() with returned value to restore this and subsequent saves. 614 615 @param bounds hint to limit the size of the layer; may be nullptr 616 @param paint graphics state for layer; may be nullptr 617 @return depth of saved stack 618 619 example: https://fiddle.skia.org/c/@Canvas_saveLayer 620 example: https://fiddle.skia.org/c/@Canvas_saveLayer_4 621 */ 622 int saveLayer(const SkRect* bounds, const SkPaint* paint); 623 624 /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. 625 Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. 626 627 SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), 628 setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), 629 clipPath(), clipRegion(). 630 631 SkRect bounds suggests but does not define the layer size. To clip drawing to 632 a specific rectangle, use clipRect(). 633 634 Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and 635 SkBlendMode when restore() is called. 636 637 Call restoreToCount() with returned value to restore this and subsequent saves. 638 639 @param bounds hint to limit the size of layer; may be nullptr 640 @param paint graphics state for layer; may be nullptr 641 @return depth of saved stack 642 */ saveLayer(const SkRect & bounds,const SkPaint * paint)643 int saveLayer(const SkRect& bounds, const SkPaint* paint) { 644 return this->saveLayer(&bounds, paint); 645 } 646 647 /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. 648 649 Calling restore() discards changes to SkMatrix and clip, 650 and blends layer with alpha opacity onto prior layer. 651 652 SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), 653 setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), 654 clipPath(), clipRegion(). 655 656 SkRect bounds suggests but does not define layer size. To clip drawing to 657 a specific rectangle, use clipRect(). 658 659 alpha of zero is fully transparent, 1.0f is fully opaque. 660 661 Call restoreToCount() with returned value to restore this and subsequent saves. 662 663 @param bounds hint to limit the size of layer; may be nullptr 664 @param alpha opacity of layer 665 @return depth of saved stack 666 667 example: https://fiddle.skia.org/c/@Canvas_saveLayerAlpha 668 */ 669 int saveLayerAlphaf(const SkRect* bounds, float alpha); 670 // Helper that accepts an int between 0 and 255, and divides it by 255.0 saveLayerAlpha(const SkRect * bounds,U8CPU alpha)671 int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { 672 return this->saveLayerAlphaf(bounds, alpha * (1.0f / 255)); 673 } 674 675 /** \enum SkCanvas::SaveLayerFlagsSet 676 SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, 677 defining how layer allocated by saveLayer() operates. It may be set to zero, 678 kPreserveLCDText_SaveLayerFlag, kInitWithPrevious_SaveLayerFlag, or both flags. 679 */ 680 enum SaveLayerFlagsSet { 681 kPreserveLCDText_SaveLayerFlag = 1 << 1, 682 kInitWithPrevious_SaveLayerFlag = 1 << 2, //!< initializes with previous contents 683 // instead of matching previous layer's colortype, use F16 684 kF16ColorType = 1 << 4, 685 }; 686 687 typedef uint32_t SaveLayerFlags; 688 689 /** \struct SkCanvas::SaveLayerRec 690 SaveLayerRec contains the state used to create the layer. 691 */ 692 struct SaveLayerRec { 693 /** Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags. 694 695 @return empty SaveLayerRec 696 */ SaveLayerRecSaveLayerRec697 SaveLayerRec() {} 698 699 /** Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. 700 701 @param bounds layer dimensions; may be nullptr 702 @param paint applied to layer when overlaying prior layer; may be nullptr 703 @param saveLayerFlags SaveLayerRec options to modify layer 704 @return SaveLayerRec with empty fBackdrop 705 */ 706 SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) 707 : SaveLayerRec(bounds, paint, nullptr, 1.f, saveLayerFlags) {} 708 709 /** Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. 710 711 @param bounds layer dimensions; may be nullptr 712 @param paint applied to layer when overlaying prior layer; 713 may be nullptr 714 @param backdrop If not null, this causes the current layer to be filtered by 715 backdrop, and then drawn into the new layer 716 (respecting the current clip). 717 If null, the new layer is initialized with transparent-black. 718 @param saveLayerFlags SaveLayerRec options to modify layer 719 @return SaveLayerRec fully specified 720 */ SaveLayerRecSaveLayerRec721 SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, 722 SaveLayerFlags saveLayerFlags) 723 : SaveLayerRec(bounds, paint, backdrop, 1.f, saveLayerFlags) {} 724 725 /** hints at layer size limit */ 726 const SkRect* fBounds = nullptr; 727 728 /** modifies overlay */ 729 const SkPaint* fPaint = nullptr; 730 731 /** 732 * If not null, this triggers the same initialization behavior as setting 733 * kInitWithPrevious_SaveLayerFlag on fSaveLayerFlags: the current layer is copied into 734 * the new layer, rather than initializing the new layer with transparent-black. 735 * This is then filtered by fBackdrop (respecting the current clip). 736 */ 737 const SkImageFilter* fBackdrop = nullptr; 738 739 /** preserves LCD text, creates with prior layer contents */ 740 SaveLayerFlags fSaveLayerFlags = 0; 741 742 private: 743 friend class SkCanvas; 744 friend class SkCanvasPriv; 745 SaveLayerRecSaveLayerRec746 SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, 747 SkScalar backdropScale, SaveLayerFlags saveLayerFlags) 748 : fBounds(bounds) 749 , fPaint(paint) 750 , fBackdrop(backdrop) 751 , fSaveLayerFlags(saveLayerFlags) 752 , fExperimentalBackdropScale(backdropScale) {} 753 754 // Relative scale factor that the image content used to initialize the layer when the 755 // kInitFromPrevious flag or a backdrop filter is used. 756 SkScalar fExperimentalBackdropScale = 1.f; 757 }; 758 759 /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. 760 761 Calling restore() discards changes to SkMatrix and clip, 762 and blends SkSurface with alpha opacity onto the prior layer. 763 764 SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), 765 setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), 766 clipPath(), clipRegion(). 767 768 SaveLayerRec contains the state used to create the layer. 769 770 Call restoreToCount() with returned value to restore this and subsequent saves. 771 772 @param layerRec layer state 773 @return depth of save state stack before this call was made. 774 775 example: https://fiddle.skia.org/c/@Canvas_saveLayer_3 776 */ 777 int saveLayer(const SaveLayerRec& layerRec); 778 779 /** Removes changes to SkMatrix and clip since SkCanvas state was 780 last saved. The state is removed from the stack. 781 782 Does nothing if the stack is empty. 783 784 example: https://fiddle.skia.org/c/@AutoCanvasRestore_restore 785 786 example: https://fiddle.skia.org/c/@Canvas_restore 787 */ 788 void restore(); 789 790 /** Returns the number of saved states, each containing: SkMatrix and clip. 791 Equals the number of save() calls less the number of restore() calls plus one. 792 The save count of a new canvas is one. 793 794 @return depth of save state stack 795 796 example: https://fiddle.skia.org/c/@Canvas_getSaveCount 797 */ 798 int getSaveCount() const; 799 800 /** Restores state to SkMatrix and clip values when save(), saveLayer(), 801 saveLayerPreserveLCDTextRequests(), or saveLayerAlpha() returned saveCount. 802 803 Does nothing if saveCount is greater than state stack count. 804 Restores state to initial values if saveCount is less than or equal to one. 805 806 @param saveCount depth of state stack to restore 807 808 example: https://fiddle.skia.org/c/@Canvas_restoreToCount 809 */ 810 void restoreToCount(int saveCount); 811 812 /** Translates SkMatrix by dx along the x-axis and dy along the y-axis. 813 814 Mathematically, replaces SkMatrix with a translation matrix 815 premultiplied with SkMatrix. 816 817 This has the effect of moving the drawing by (dx, dy) before transforming 818 the result with SkMatrix. 819 820 @param dx distance to translate on x-axis 821 @param dy distance to translate on y-axis 822 823 example: https://fiddle.skia.org/c/@Canvas_translate 824 */ 825 void translate(SkScalar dx, SkScalar dy); 826 827 /** Scales SkMatrix by sx on the x-axis and sy on the y-axis. 828 829 Mathematically, replaces SkMatrix with a scale matrix 830 premultiplied with SkMatrix. 831 832 This has the effect of scaling the drawing by (sx, sy) before transforming 833 the result with SkMatrix. 834 835 @param sx amount to scale on x-axis 836 @param sy amount to scale on y-axis 837 838 example: https://fiddle.skia.org/c/@Canvas_scale 839 */ 840 void scale(SkScalar sx, SkScalar sy); 841 842 /** Rotates SkMatrix by degrees. Positive degrees rotates clockwise. 843 844 Mathematically, replaces SkMatrix with a rotation matrix 845 premultiplied with SkMatrix. 846 847 This has the effect of rotating the drawing by degrees before transforming 848 the result with SkMatrix. 849 850 @param degrees amount to rotate, in degrees 851 852 example: https://fiddle.skia.org/c/@Canvas_rotate 853 */ 854 void rotate(SkScalar degrees); 855 856 /** Rotates SkMatrix by degrees about a point at (px, py). Positive degrees rotates 857 clockwise. 858 859 Mathematically, constructs a rotation matrix; premultiplies the rotation matrix by 860 a translation matrix; then replaces SkMatrix with the resulting matrix 861 premultiplied with SkMatrix. 862 863 This has the effect of rotating the drawing about a given point before 864 transforming the result with SkMatrix. 865 866 @param degrees amount to rotate, in degrees 867 @param px x-axis value of the point to rotate about 868 @param py y-axis value of the point to rotate about 869 870 example: https://fiddle.skia.org/c/@Canvas_rotate_2 871 */ 872 void rotate(SkScalar degrees, SkScalar px, SkScalar py); 873 874 /** Skews SkMatrix by sx on the x-axis and sy on the y-axis. A positive value of sx 875 skews the drawing right as y-axis values increase; a positive value of sy skews 876 the drawing down as x-axis values increase. 877 878 Mathematically, replaces SkMatrix with a skew matrix premultiplied with SkMatrix. 879 880 This has the effect of skewing the drawing by (sx, sy) before transforming 881 the result with SkMatrix. 882 883 @param sx amount to skew on x-axis 884 @param sy amount to skew on y-axis 885 886 example: https://fiddle.skia.org/c/@Canvas_skew 887 */ 888 void skew(SkScalar sx, SkScalar sy); 889 890 /** Replaces SkMatrix with matrix premultiplied with existing SkMatrix. 891 892 This has the effect of transforming the drawn geometry by matrix, before 893 transforming the result with existing SkMatrix. 894 895 @param matrix matrix to premultiply with existing SkMatrix 896 897 example: https://fiddle.skia.org/c/@Canvas_concat 898 */ 899 void concat(const SkMatrix& matrix); 900 void concat(const SkM44&); 901 902 /** Replaces SkMatrix with matrix. 903 Unlike concat(), any prior matrix state is overwritten. 904 905 @param matrix matrix to copy, replacing existing SkMatrix 906 907 example: https://fiddle.skia.org/c/@Canvas_setMatrix 908 */ 909 void setMatrix(const SkM44& matrix); 910 911 // DEPRECATED -- use SkM44 version 912 void setMatrix(const SkMatrix& matrix); 913 914 /** Sets SkMatrix to the identity matrix. 915 Any prior matrix state is overwritten. 916 917 example: https://fiddle.skia.org/c/@Canvas_resetMatrix 918 */ 919 void resetMatrix(); 920 921 /** Replaces clip with the intersection or difference of clip and rect, 922 with an aliased or anti-aliased clip edge. rect is transformed by SkMatrix 923 before it is combined with clip. 924 925 @param rect SkRect to combine with clip 926 @param op SkClipOp to apply to clip 927 @param doAntiAlias true if clip is to be anti-aliased 928 929 example: https://fiddle.skia.org/c/@Canvas_clipRect 930 */ 931 void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias); 932 933 /** Replaces clip with the intersection or difference of clip and rect. 934 Resulting clip is aliased; pixels are fully contained by the clip. 935 rect is transformed by SkMatrix before it is combined with clip. 936 937 @param rect SkRect to combine with clip 938 @param op SkClipOp to apply to clip 939 */ clipRect(const SkRect & rect,SkClipOp op)940 void clipRect(const SkRect& rect, SkClipOp op) { 941 this->clipRect(rect, op, false); 942 } 943 944 /** Replaces clip with the intersection of clip and rect. 945 Resulting clip is aliased; pixels are fully contained by the clip. 946 rect is transformed by SkMatrix 947 before it is combined with clip. 948 949 @param rect SkRect to combine with clip 950 @param doAntiAlias true if clip is to be anti-aliased 951 */ 952 void clipRect(const SkRect& rect, bool doAntiAlias = false) { 953 this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias); 954 } 955 956 void clipIRect(const SkIRect& irect, SkClipOp op = SkClipOp::kIntersect) { 957 this->clipRect(SkRect::Make(irect), op, false); 958 } 959 960 /** Sets the maximum clip rectangle, which can be set by clipRect(), clipRRect() and 961 clipPath() and intersect the current clip with the specified rect. 962 The maximum clip affects only future clipping operations; it is not retroactive. 963 The clip restriction is not recorded in pictures. 964 965 Pass an empty rect to disable maximum clip. 966 This private API is for use by Android framework only. 967 968 DEPRECATED: Replace usage with SkAndroidFrameworkUtils::replaceClip() 969 970 @param rect maximum allowed clip in device coordinates 971 */ 972 void androidFramework_setDeviceClipRestriction(const SkIRect& rect); 973 974 /** Replaces clip with the intersection or difference of clip and rrect, 975 with an aliased or anti-aliased clip edge. 976 rrect is transformed by SkMatrix 977 before it is combined with clip. 978 979 @param rrect SkRRect to combine with clip 980 @param op SkClipOp to apply to clip 981 @param doAntiAlias true if clip is to be anti-aliased 982 983 example: https://fiddle.skia.org/c/@Canvas_clipRRect 984 */ 985 void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias); 986 987 /** Replaces clip with the intersection or difference of clip and rrect. 988 Resulting clip is aliased; pixels are fully contained by the clip. 989 rrect is transformed by SkMatrix before it is combined with clip. 990 991 @param rrect SkRRect to combine with clip 992 @param op SkClipOp to apply to clip 993 */ clipRRect(const SkRRect & rrect,SkClipOp op)994 void clipRRect(const SkRRect& rrect, SkClipOp op) { 995 this->clipRRect(rrect, op, false); 996 } 997 998 /** Replaces clip with the intersection of clip and rrect, 999 with an aliased or anti-aliased clip edge. 1000 rrect is transformed by SkMatrix before it is combined with clip. 1001 1002 @param rrect SkRRect to combine with clip 1003 @param doAntiAlias true if clip is to be anti-aliased 1004 */ 1005 void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { 1006 this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias); 1007 } 1008 1009 /** Replaces clip with the intersection or difference of clip and path, 1010 with an aliased or anti-aliased clip edge. SkPath::FillType determines if path 1011 describes the area inside or outside its contours; and if path contour overlaps 1012 itself or another path contour, whether the overlaps form part of the area. 1013 path is transformed by SkMatrix before it is combined with clip. 1014 1015 @param path SkPath to combine with clip 1016 @param op SkClipOp to apply to clip 1017 @param doAntiAlias true if clip is to be anti-aliased 1018 1019 example: https://fiddle.skia.org/c/@Canvas_clipPath 1020 */ 1021 void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias); 1022 1023 /** Replaces clip with the intersection or difference of clip and path. 1024 Resulting clip is aliased; pixels are fully contained by the clip. 1025 SkPath::FillType determines if path 1026 describes the area inside or outside its contours; and if path contour overlaps 1027 itself or another path contour, whether the overlaps form part of the area. 1028 path is transformed by SkMatrix 1029 before it is combined with clip. 1030 1031 @param path SkPath to combine with clip 1032 @param op SkClipOp to apply to clip 1033 */ clipPath(const SkPath & path,SkClipOp op)1034 void clipPath(const SkPath& path, SkClipOp op) { 1035 this->clipPath(path, op, false); 1036 } 1037 1038 /** Replaces clip with the intersection of clip and path. 1039 Resulting clip is aliased; pixels are fully contained by the clip. 1040 SkPath::FillType determines if path 1041 describes the area inside or outside its contours; and if path contour overlaps 1042 itself or another path contour, whether the overlaps form part of the area. 1043 path is transformed by SkMatrix before it is combined with clip. 1044 1045 @param path SkPath to combine with clip 1046 @param doAntiAlias true if clip is to be anti-aliased 1047 */ 1048 void clipPath(const SkPath& path, bool doAntiAlias = false) { 1049 this->clipPath(path, SkClipOp::kIntersect, doAntiAlias); 1050 } 1051 1052 void clipShader(sk_sp<SkShader>, SkClipOp = SkClipOp::kIntersect); 1053 1054 /** Replaces clip with the intersection or difference of clip and SkRegion deviceRgn. 1055 Resulting clip is aliased; pixels are fully contained by the clip. 1056 deviceRgn is unaffected by SkMatrix. 1057 1058 @param deviceRgn SkRegion to combine with clip 1059 @param op SkClipOp to apply to clip 1060 1061 example: https://fiddle.skia.org/c/@Canvas_clipRegion 1062 */ 1063 void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect); 1064 1065 /** Returns true if SkRect rect, transformed by SkMatrix, can be quickly determined to be 1066 outside of clip. May return false even though rect is outside of clip. 1067 1068 Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. 1069 1070 @param rect SkRect to compare with clip 1071 @return true if rect, transformed by SkMatrix, does not intersect clip 1072 1073 example: https://fiddle.skia.org/c/@Canvas_quickReject 1074 */ 1075 bool quickReject(const SkRect& rect) const; 1076 1077 /** Returns true if path, transformed by SkMatrix, can be quickly determined to be 1078 outside of clip. May return false even though path is outside of clip. 1079 1080 Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. 1081 1082 @param path SkPath to compare with clip 1083 @return true if path, transformed by SkMatrix, does not intersect clip 1084 1085 example: https://fiddle.skia.org/c/@Canvas_quickReject_2 1086 */ 1087 bool quickReject(const SkPath& path) const; 1088 1089 /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, 1090 return SkRect::MakeEmpty, where all SkRect sides equal zero. 1091 1092 SkRect returned is outset by one to account for partial pixel coverage if clip 1093 is anti-aliased. 1094 1095 @return bounds of clip in local coordinates 1096 1097 example: https://fiddle.skia.org/c/@Canvas_getLocalClipBounds 1098 */ 1099 SkRect getLocalClipBounds() const; 1100 1101 /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, 1102 return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. 1103 1104 bounds is outset by one to account for partial pixel coverage if clip 1105 is anti-aliased. 1106 1107 @param bounds SkRect of clip in local coordinates 1108 @return true if clip bounds is not empty 1109 */ getLocalClipBounds(SkRect * bounds)1110 bool getLocalClipBounds(SkRect* bounds) const { 1111 *bounds = this->getLocalClipBounds(); 1112 return !bounds->isEmpty(); 1113 } 1114 1115 /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, 1116 return SkRect::MakeEmpty, where all SkRect sides equal zero. 1117 1118 Unlike getLocalClipBounds(), returned SkIRect is not outset. 1119 1120 @return bounds of clip in SkBaseDevice coordinates 1121 1122 example: https://fiddle.skia.org/c/@Canvas_getDeviceClipBounds 1123 */ 1124 SkIRect getDeviceClipBounds() const; 1125 1126 /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, 1127 return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. 1128 1129 Unlike getLocalClipBounds(), bounds is not outset. 1130 1131 @param bounds SkRect of clip in device coordinates 1132 @return true if clip bounds is not empty 1133 */ getDeviceClipBounds(SkIRect * bounds)1134 bool getDeviceClipBounds(SkIRect* bounds) const { 1135 *bounds = this->getDeviceClipBounds(); 1136 return !bounds->isEmpty(); 1137 } 1138 1139 /** Fills clip with color color. 1140 mode determines how ARGB is combined with destination. 1141 1142 @param color unpremultiplied ARGB 1143 @param mode SkBlendMode used to combine source color and destination 1144 1145 example: https://fiddle.skia.org/c/@Canvas_drawColor 1146 */ 1147 void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver) { 1148 this->drawColor(SkColor4f::FromColor(color), mode); 1149 } 1150 1151 /** Fills clip with color color. 1152 mode determines how ARGB is combined with destination. 1153 1154 @param color SkColor4f representing unpremultiplied color. 1155 @param mode SkBlendMode used to combine source color and destination 1156 */ 1157 void drawColor(const SkColor4f& color, SkBlendMode mode = SkBlendMode::kSrcOver); 1158 1159 /** Fills clip with color color using SkBlendMode::kSrc. 1160 This has the effect of replacing all pixels contained by clip with color. 1161 1162 @param color unpremultiplied ARGB 1163 */ clear(SkColor color)1164 void clear(SkColor color) { 1165 this->clear(SkColor4f::FromColor(color)); 1166 } 1167 1168 /** Fills clip with color color using SkBlendMode::kSrc. 1169 This has the effect of replacing all pixels contained by clip with color. 1170 1171 @param color SkColor4f representing unpremultiplied color. 1172 */ clear(const SkColor4f & color)1173 void clear(const SkColor4f& color) { 1174 this->drawColor(color, SkBlendMode::kSrc); 1175 } 1176 1177 /** Makes SkCanvas contents undefined. Subsequent calls that read SkCanvas pixels, 1178 such as drawing with SkBlendMode, return undefined results. discard() does 1179 not change clip or SkMatrix. 1180 1181 discard() may do nothing, depending on the implementation of SkSurface or SkBaseDevice 1182 that created SkCanvas. 1183 1184 discard() allows optimized performance on subsequent draws by removing 1185 cached data associated with SkSurface or SkBaseDevice. 1186 It is not necessary to call discard() once done with SkCanvas; 1187 any cached data is deleted when owning SkSurface or SkBaseDevice is deleted. 1188 */ discard()1189 void discard() { this->onDiscard(); } 1190 1191 /** Fills clip with SkPaint paint. SkPaint components, SkShader, 1192 SkColorFilter, SkImageFilter, and SkBlendMode affect drawing; 1193 SkMaskFilter and SkPathEffect in paint are ignored. 1194 1195 @param paint graphics state used to fill SkCanvas 1196 1197 example: https://fiddle.skia.org/c/@Canvas_drawPaint 1198 */ 1199 void drawPaint(const SkPaint& paint); 1200 1201 /** \enum SkCanvas::PointMode 1202 Selects if an array of points are drawn as discrete points, as lines, or as 1203 an open polygon. 1204 */ 1205 enum PointMode { 1206 kPoints_PointMode, //!< draw each point separately 1207 kLines_PointMode, //!< draw each pair of points as a line segment 1208 kPolygon_PointMode, //!< draw the array of points as a open polygon 1209 }; 1210 1211 /** Draws pts using clip, SkMatrix and SkPaint paint. 1212 count is the number of points; if count is less than one, has no effect. 1213 mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode. 1214 1215 If mode is kPoints_PointMode, the shape of point drawn depends on paint 1216 SkPaint::Cap. If paint is set to SkPaint::kRound_Cap, each point draws a 1217 circle of diameter SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap 1218 or SkPaint::kButt_Cap, each point draws a square of width and height 1219 SkPaint stroke width. 1220 1221 If mode is kLines_PointMode, each pair of points draws a line segment. 1222 One line is drawn for every two points; each point is used once. If count is odd, 1223 the final point is ignored. 1224 1225 If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment. 1226 count minus one lines are drawn; the first and last point are used once. 1227 1228 Each line segment respects paint SkPaint::Cap and SkPaint stroke width. 1229 SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. 1230 1231 Always draws each element one at a time; is not affected by 1232 SkPaint::Join, and unlike drawPath(), does not create a mask from all points 1233 and lines before drawing. 1234 1235 @param mode whether pts draws points or lines 1236 @param count number of points in the array 1237 @param pts array of points to draw 1238 @param paint stroke, blend, color, and so on, used to draw 1239 1240 example: https://fiddle.skia.org/c/@Canvas_drawPoints 1241 */ 1242 void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint); 1243 1244 /** Draws point at (x, y) using clip, SkMatrix and SkPaint paint. 1245 1246 The shape of point drawn depends on paint SkPaint::Cap. 1247 If paint is set to SkPaint::kRound_Cap, draw a circle of diameter 1248 SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, 1249 draw a square of width and height SkPaint stroke width. 1250 SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. 1251 1252 @param x left edge of circle or square 1253 @param y top edge of circle or square 1254 @param paint stroke, blend, color, and so on, used to draw 1255 1256 example: https://fiddle.skia.org/c/@Canvas_drawPoint 1257 */ 1258 void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); 1259 1260 /** Draws point p using clip, SkMatrix and SkPaint paint. 1261 1262 The shape of point drawn depends on paint SkPaint::Cap. 1263 If paint is set to SkPaint::kRound_Cap, draw a circle of diameter 1264 SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, 1265 draw a square of width and height SkPaint stroke width. 1266 SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. 1267 1268 @param p top-left edge of circle or square 1269 @param paint stroke, blend, color, and so on, used to draw 1270 */ drawPoint(SkPoint p,const SkPaint & paint)1271 void drawPoint(SkPoint p, const SkPaint& paint) { 1272 this->drawPoint(p.x(), p.y(), paint); 1273 } 1274 1275 /** Draws line segment from (x0, y0) to (x1, y1) using clip, SkMatrix, and SkPaint paint. 1276 In paint: SkPaint stroke width describes the line thickness; 1277 SkPaint::Cap draws the end rounded or square; 1278 SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. 1279 1280 @param x0 start of line segment on x-axis 1281 @param y0 start of line segment on y-axis 1282 @param x1 end of line segment on x-axis 1283 @param y1 end of line segment on y-axis 1284 @param paint stroke, blend, color, and so on, used to draw 1285 1286 example: https://fiddle.skia.org/c/@Canvas_drawLine 1287 */ 1288 void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint); 1289 1290 /** Draws line segment from p0 to p1 using clip, SkMatrix, and SkPaint paint. 1291 In paint: SkPaint stroke width describes the line thickness; 1292 SkPaint::Cap draws the end rounded or square; 1293 SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. 1294 1295 @param p0 start of line segment 1296 @param p1 end of line segment 1297 @param paint stroke, blend, color, and so on, used to draw 1298 */ drawLine(SkPoint p0,SkPoint p1,const SkPaint & paint)1299 void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) { 1300 this->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint); 1301 } 1302 1303 /** Draws SkRect rect using clip, SkMatrix, and SkPaint paint. 1304 In paint: SkPaint::Style determines if rectangle is stroked or filled; 1305 if stroked, SkPaint stroke width describes the line thickness, and 1306 SkPaint::Join draws the corners rounded or square. 1307 1308 @param rect rectangle to draw 1309 @param paint stroke or fill, blend, color, and so on, used to draw 1310 1311 example: https://fiddle.skia.org/c/@Canvas_drawRect 1312 */ 1313 void drawRect(const SkRect& rect, const SkPaint& paint); 1314 1315 /** Draws SkIRect rect using clip, SkMatrix, and SkPaint paint. 1316 In paint: SkPaint::Style determines if rectangle is stroked or filled; 1317 if stroked, SkPaint stroke width describes the line thickness, and 1318 SkPaint::Join draws the corners rounded or square. 1319 1320 @param rect rectangle to draw 1321 @param paint stroke or fill, blend, color, and so on, used to draw 1322 */ drawIRect(const SkIRect & rect,const SkPaint & paint)1323 void drawIRect(const SkIRect& rect, const SkPaint& paint) { 1324 SkRect r; 1325 r.set(rect); // promotes the ints to scalars 1326 this->drawRect(r, paint); 1327 } 1328 1329 /** Draws SkRegion region using clip, SkMatrix, and SkPaint paint. 1330 In paint: SkPaint::Style determines if rectangle is stroked or filled; 1331 if stroked, SkPaint stroke width describes the line thickness, and 1332 SkPaint::Join draws the corners rounded or square. 1333 1334 @param region region to draw 1335 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1336 1337 example: https://fiddle.skia.org/c/@Canvas_drawRegion 1338 */ 1339 void drawRegion(const SkRegion& region, const SkPaint& paint); 1340 1341 /** Draws oval oval using clip, SkMatrix, and SkPaint. 1342 In paint: SkPaint::Style determines if oval is stroked or filled; 1343 if stroked, SkPaint stroke width describes the line thickness. 1344 1345 @param oval SkRect bounds of oval 1346 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1347 1348 example: https://fiddle.skia.org/c/@Canvas_drawOval 1349 */ 1350 void drawOval(const SkRect& oval, const SkPaint& paint); 1351 1352 /** Draws SkRRect rrect using clip, SkMatrix, and SkPaint paint. 1353 In paint: SkPaint::Style determines if rrect is stroked or filled; 1354 if stroked, SkPaint stroke width describes the line thickness. 1355 1356 rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or 1357 may have any combination of positive non-square radii for the four corners. 1358 1359 @param rrect SkRRect with up to eight corner radii to draw 1360 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1361 1362 example: https://fiddle.skia.org/c/@Canvas_drawRRect 1363 */ 1364 void drawRRect(const SkRRect& rrect, const SkPaint& paint); 1365 1366 /** Draws SkRRect outer and inner 1367 using clip, SkMatrix, and SkPaint paint. 1368 outer must contain inner or the drawing is undefined. 1369 In paint: SkPaint::Style determines if SkRRect is stroked or filled; 1370 if stroked, SkPaint stroke width describes the line thickness. 1371 If stroked and SkRRect corner has zero length radii, SkPaint::Join can 1372 draw corners rounded or square. 1373 1374 GPU-backed platforms optimize drawing when both outer and inner are 1375 concave and outer contains inner. These platforms may not be able to draw 1376 SkPath built with identical data as fast. 1377 1378 @param outer SkRRect outer bounds to draw 1379 @param inner SkRRect inner bounds to draw 1380 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1381 1382 example: https://fiddle.skia.org/c/@Canvas_drawDRRect_a 1383 example: https://fiddle.skia.org/c/@Canvas_drawDRRect_b 1384 */ 1385 void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); 1386 1387 /** Draws circle at (cx, cy) with radius using clip, SkMatrix, and SkPaint paint. 1388 If radius is zero or less, nothing is drawn. 1389 In paint: SkPaint::Style determines if circle is stroked or filled; 1390 if stroked, SkPaint stroke width describes the line thickness. 1391 1392 @param cx circle center on the x-axis 1393 @param cy circle center on the y-axis 1394 @param radius half the diameter of circle 1395 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1396 1397 example: https://fiddle.skia.org/c/@Canvas_drawCircle 1398 */ 1399 void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint); 1400 1401 /** Draws circle at center with radius using clip, SkMatrix, and SkPaint paint. 1402 If radius is zero or less, nothing is drawn. 1403 In paint: SkPaint::Style determines if circle is stroked or filled; 1404 if stroked, SkPaint stroke width describes the line thickness. 1405 1406 @param center circle center 1407 @param radius half the diameter of circle 1408 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1409 */ drawCircle(SkPoint center,SkScalar radius,const SkPaint & paint)1410 void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) { 1411 this->drawCircle(center.x(), center.y(), radius, paint); 1412 } 1413 1414 /** Draws arc using clip, SkMatrix, and SkPaint paint. 1415 1416 Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus 1417 sweepAngle. startAngle and sweepAngle are in degrees. 1418 1419 startAngle of zero places start point at the right middle edge of oval. 1420 A positive sweepAngle places arc end point clockwise from start point; 1421 a negative sweepAngle places arc end point counterclockwise from start point. 1422 sweepAngle may exceed 360 degrees, a full circle. 1423 If useCenter is true, draw a wedge that includes lines from oval 1424 center to arc end points. If useCenter is false, draw arc between end points. 1425 1426 If SkRect oval is empty or sweepAngle is zero, nothing is drawn. 1427 1428 @param oval SkRect bounds of oval containing arc to draw 1429 @param startAngle angle in degrees where arc begins 1430 @param sweepAngle sweep angle in degrees; positive is clockwise 1431 @param useCenter if true, include the center of the oval 1432 @param paint SkPaint stroke or fill, blend, color, and so on, used to draw 1433 */ 1434 void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 1435 bool useCenter, const SkPaint& paint); 1436 1437 /** Draws SkRRect bounded by SkRect rect, with corner radii (rx, ry) using clip, 1438 SkMatrix, and SkPaint paint. 1439 1440 In paint: SkPaint::Style determines if SkRRect is stroked or filled; 1441 if stroked, SkPaint stroke width describes the line thickness. 1442 If rx or ry are less than zero, they are treated as if they are zero. 1443 If rx plus ry exceeds rect width or rect height, radii are scaled down to fit. 1444 If rx and ry are zero, SkRRect is drawn as SkRect and if stroked is affected by 1445 SkPaint::Join. 1446 1447 @param rect SkRect bounds of SkRRect to draw 1448 @param rx axis length on x-axis of oval describing rounded corners 1449 @param ry axis length on y-axis of oval describing rounded corners 1450 @param paint stroke, blend, color, and so on, used to draw 1451 1452 example: https://fiddle.skia.org/c/@Canvas_drawRoundRect 1453 */ 1454 void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint); 1455 1456 /** Draws SkPath path using clip, SkMatrix, and SkPaint paint. 1457 SkPath contains an array of path contour, each of which may be open or closed. 1458 1459 In paint: SkPaint::Style determines if SkRRect is stroked or filled: 1460 if filled, SkPath::FillType determines whether path contour describes inside or 1461 outside of fill; if stroked, SkPaint stroke width describes the line thickness, 1462 SkPaint::Cap describes line ends, and SkPaint::Join describes how 1463 corners are drawn. 1464 1465 @param path SkPath to draw 1466 @param paint stroke, blend, color, and so on, used to draw 1467 1468 example: https://fiddle.skia.org/c/@Canvas_drawPath 1469 */ 1470 void drawPath(const SkPath& path, const SkPaint& paint); 1471 drawImage(const SkImage * image,SkScalar left,SkScalar top)1472 void drawImage(const SkImage* image, SkScalar left, SkScalar top) { 1473 this->drawImage(image, left, top, SkSamplingOptions(), nullptr); 1474 } drawImage(const sk_sp<SkImage> & image,SkScalar left,SkScalar top)1475 void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top) { 1476 this->drawImage(image.get(), left, top, SkSamplingOptions(), nullptr); 1477 } 1478 1479 /** \enum SkCanvas::SrcRectConstraint 1480 SrcRectConstraint controls the behavior at the edge of source SkRect, 1481 provided to drawImageRect() when there is any filtering. If kStrict is set, 1482 then extra code is used to ensure it never samples outside of the src-rect. 1483 kStrict_SrcRectConstraint disables the use of mipmaps and anisotropic filtering. 1484 */ 1485 enum SrcRectConstraint { 1486 kStrict_SrcRectConstraint, //!< sample only inside bounds; slower 1487 kFast_SrcRectConstraint, //!< sample outside bounds; faster 1488 }; 1489 1490 void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkSamplingOptions&, 1491 const SkPaint* = nullptr); 1492 void drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y, 1493 const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { 1494 this->drawImage(image.get(), x, y, sampling, paint); 1495 } 1496 void drawImageRect(const SkImage*, const SkRect& src, const SkRect& dst, 1497 const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); 1498 void drawImageRect(const SkImage*, const SkRect& dst, const SkSamplingOptions&, 1499 const SkPaint* = nullptr); drawImageRect(const sk_sp<SkImage> & image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)1500 void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst, 1501 const SkSamplingOptions& sampling, const SkPaint* paint, 1502 SrcRectConstraint constraint) { 1503 this->drawImageRect(image.get(), src, dst, sampling, paint, constraint); 1504 } 1505 void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, 1506 const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { 1507 this->drawImageRect(image.get(), dst, sampling, paint); 1508 } 1509 1510 /** Draws SkImage image stretched proportionally to fit into SkRect dst. 1511 SkIRect center divides the image into nine sections: four sides, four corners, and 1512 the center. Corners are unmodified or scaled down proportionately if their sides 1513 are larger than dst; center and four sides are scaled to fit remaining space, if any. 1514 1515 Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. 1516 1517 If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and 1518 SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. 1519 If paint contains SkMaskFilter, generate mask from image bounds. 1520 Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. 1521 1522 If generated mask extends beyond image bounds, replicate image edge colors, just 1523 as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set 1524 replicates the image edge color when it samples outside of its bounds. 1525 1526 @param image SkImage containing pixels, dimensions, and format 1527 @param center SkIRect edge of image corners and sides 1528 @param dst destination SkRect of image to draw to 1529 @param filter what technique to use when sampling the image 1530 @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, 1531 and so on; or nullptr 1532 */ 1533 void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 1534 SkFilterMode filter, const SkPaint* paint = nullptr); 1535 1536 /** \struct SkCanvas::Lattice 1537 SkCanvas::Lattice divides SkBitmap or SkImage into a rectangular grid. 1538 Grid entries on even columns and even rows are fixed; these entries are 1539 always drawn at their original size if the destination is large enough. 1540 If the destination side is too small to hold the fixed entries, all fixed 1541 entries are proportionately scaled down to fit. 1542 The grid entries not on even columns and rows are scaled to fit the 1543 remaining space, if any. 1544 */ 1545 struct Lattice { 1546 1547 /** \enum SkCanvas::Lattice::RectType 1548 Optional setting per rectangular grid entry to make it transparent, 1549 or to fill the grid entry with a color. 1550 */ 1551 enum RectType : uint8_t { 1552 kDefault = 0, //!< draws SkBitmap into lattice rectangle 1553 kTransparent, //!< skips lattice rectangle by making it transparent 1554 kFixedColor, //!< draws one of fColors into lattice rectangle 1555 }; 1556 1557 const int* fXDivs; //!< x-axis values dividing bitmap 1558 const int* fYDivs; //!< y-axis values dividing bitmap 1559 const RectType* fRectTypes; //!< array of fill types 1560 int fXCount; //!< number of x-coordinates 1561 int fYCount; //!< number of y-coordinates 1562 const SkIRect* fBounds; //!< source bounds to draw from 1563 const SkColor* fColors; //!< array of colors 1564 }; 1565 1566 /** Draws SkImage image stretched proportionally to fit into SkRect dst. 1567 1568 SkCanvas::Lattice lattice divides image into a rectangular grid. 1569 Each intersection of an even-numbered row and column is fixed; 1570 fixed lattice elements never scale larger than their initial 1571 size and shrink proportionately when all fixed elements exceed the bitmap 1572 dimension. All other grid elements scale to fill the available space, if any. 1573 1574 Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. 1575 1576 If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and 1577 SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. 1578 If paint contains SkMaskFilter, generate mask from image bounds. 1579 Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. 1580 1581 If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, 1582 just as SkShader made from SkShader::MakeBitmapShader with 1583 SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples 1584 outside of its bounds. 1585 1586 @param image SkImage containing pixels, dimensions, and format 1587 @param lattice division of bitmap into fixed and variable rectangles 1588 @param dst destination SkRect of image to draw to 1589 @param filter what technique to use when sampling the image 1590 @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, 1591 and so on; or nullptr 1592 */ 1593 void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 1594 SkFilterMode filter, const SkPaint* paint = nullptr); drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst)1595 void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst) { 1596 this->drawImageLattice(image, lattice, dst, SkFilterMode::kNearest, nullptr); 1597 } 1598 1599 /** 1600 * Experimental. Controls anti-aliasing of each edge of images in an image-set. 1601 */ 1602 enum QuadAAFlags : unsigned { 1603 kLeft_QuadAAFlag = 0b0001, 1604 kTop_QuadAAFlag = 0b0010, 1605 kRight_QuadAAFlag = 0b0100, 1606 kBottom_QuadAAFlag = 0b1000, 1607 1608 kNone_QuadAAFlags = 0b0000, 1609 kAll_QuadAAFlags = 0b1111, 1610 }; 1611 1612 /** This is used by the experimental API below. */ 1613 struct SK_API ImageSetEntry { 1614 ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, const SkRect& dstRect, 1615 int matrixIndex, float alpha, unsigned aaFlags, bool hasClip); 1616 1617 ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, const SkRect& dstRect, 1618 float alpha, unsigned aaFlags); 1619 1620 ImageSetEntry(); 1621 ~ImageSetEntry(); 1622 ImageSetEntry(const ImageSetEntry&); 1623 ImageSetEntry& operator=(const ImageSetEntry&); 1624 1625 sk_sp<const SkImage> fImage; 1626 SkRect fSrcRect; 1627 SkRect fDstRect; 1628 int fMatrixIndex = -1; // Index into the preViewMatrices arg, or < 0 1629 float fAlpha = 1.f; 1630 unsigned fAAFlags = kNone_QuadAAFlags; // QuadAAFlags 1631 bool fHasClip = false; // True to use next 4 points in dstClip arg as quad 1632 }; 1633 1634 /** 1635 * This is an experimental API for the SkiaRenderer Chromium project, and its API will surely 1636 * evolve if it is not removed outright. 1637 * 1638 * This behaves very similarly to drawRect() combined with a clipPath() formed by clip 1639 * quadrilateral. 'rect' and 'clip' are in the same coordinate space. If 'clip' is null, then it 1640 * is as if the rectangle was not clipped (or, alternatively, clipped to itself). If not null, 1641 * then it must provide 4 points. 1642 * 1643 * In addition to combining the draw and clipping into one operation, this function adds the 1644 * additional capability of controlling each of the rectangle's edges anti-aliasing 1645 * independently. The edges of the clip will respect the per-edge AA flags. It is required that 1646 * 'clip' be contained inside 'rect'. In terms of mapping to edge labels, the 'clip' points 1647 * should be ordered top-left, top-right, bottom-right, bottom-left so that the edge between [0] 1648 * and [1] is "top", [1] and [2] is "right", [2] and [3] is "bottom", and [3] and [0] is "left". 1649 * This ordering matches SkRect::toQuad(). 1650 * 1651 * This API only draws solid color, filled rectangles so it does not accept a full SkPaint. 1652 */ 1653 void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, 1654 const SkColor4f& color, SkBlendMode mode); experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,SkColor color,SkBlendMode mode)1655 void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, 1656 SkColor color, SkBlendMode mode) { 1657 this->experimental_DrawEdgeAAQuad(rect, clip, aaFlags, SkColor4f::FromColor(color), mode); 1658 } 1659 1660 /** 1661 * This is an bulk variant of experimental_DrawEdgeAAQuad() that renders 'cnt' textured quads. 1662 * For each entry, 'fDstRect' is rendered with its clip (determined by entry's 'fHasClip' and 1663 * the current index in 'dstClip'). The entry's fImage is applied to the destination rectangle 1664 * by sampling from 'fSrcRect' sub-image. The corners of 'fSrcRect' map to the corners of 1665 * 'fDstRect', just like in drawImageRect(), and they will be properly interpolated when 1666 * applying a clip. 1667 * 1668 * Like experimental_DrawEdgeAAQuad(), each entry can specify edge AA flags that apply to both 1669 * the destination rect and its clip. 1670 * 1671 * If provided, the 'dstClips' array must have length equal 4 * the number of entries with 1672 * fHasClip true. If 'dstClips' is null, every entry must have 'fHasClip' set to false. The 1673 * destination clip coordinates will be read consecutively with the image set entries, advancing 1674 * by 4 points every time an entry with fHasClip is passed. 1675 * 1676 * This entry point supports per-entry manipulations to the canvas's current matrix. If an 1677 * entry provides 'fMatrixIndex' >= 0, it will be drawn as if the canvas's CTM was 1678 * canvas->getTotalMatrix() * preViewMatrices[fMatrixIndex]. If 'fMatrixIndex' is less than 0, 1679 * the pre-view matrix transform is implicitly the identity, so it will be drawn using just the 1680 * current canvas matrix. The pre-view matrix modifies the canvas's view matrix, it does not 1681 * affect the local coordinates of each entry. 1682 * 1683 * An optional paint may be provided, which supports the same subset of features usable with 1684 * drawImageRect (i.e. assumed to be filled and no path effects). When a paint is provided, the 1685 * image set is drawn as if each image used the applied paint independently, so each is affected 1686 * by the image, color, and/or mask filter. 1687 */ 1688 void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, 1689 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 1690 const SkSamplingOptions&, const SkPaint* paint = nullptr, 1691 SrcRectConstraint constraint = kStrict_SrcRectConstraint); 1692 1693 /** Draws text, with origin at (x, y), using clip, SkMatrix, SkFont font, 1694 and SkPaint paint. 1695 1696 When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or 1697 SkTextEncoding::kUTF32, this function uses the default 1698 character-to-glyph mapping from the SkTypeface in font. It does not 1699 perform typeface fallback for characters not found in the SkTypeface. 1700 It does not perform kerning or other complex shaping; glyphs are 1701 positioned based on their default advances. 1702 1703 Text meaning depends on SkTextEncoding. 1704 1705 Text size is affected by SkMatrix and SkFont text size. Default text 1706 size is 12 point. 1707 1708 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1709 SkColorFilter, and SkImageFilter; apply to text. By 1710 default, draws filled black glyphs. 1711 1712 @param text character code points or glyphs drawn 1713 @param byteLength byte length of text array 1714 @param encoding text encoding used in the text array 1715 @param x start of text on x-axis 1716 @param y start of text on y-axis 1717 @param font typeface, text size and so, used to describe the text 1718 @param paint blend, color, and so on, used to draw 1719 */ 1720 void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, 1721 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint); 1722 1723 /** Draws null terminated string, with origin at (x, y), using clip, SkMatrix, 1724 SkFont font, and SkPaint paint. 1725 1726 This function uses the default character-to-glyph mapping from the 1727 SkTypeface in font. It does not perform typeface fallback for 1728 characters not found in the SkTypeface. It does not perform kerning; 1729 glyphs are positioned based on their default advances. 1730 1731 String str is encoded as UTF-8. 1732 1733 Text size is affected by SkMatrix and font text size. Default text 1734 size is 12 point. 1735 1736 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1737 SkColorFilter, and SkImageFilter; apply to text. By 1738 default, draws filled black glyphs. 1739 1740 @param str character code points drawn, 1741 ending with a char value of zero 1742 @param x start of string on x-axis 1743 @param y start of string on y-axis 1744 @param font typeface, text size and so, used to describe the text 1745 @param paint blend, color, and so on, used to draw 1746 */ drawString(const char str[],SkScalar x,SkScalar y,const SkFont & font,const SkPaint & paint)1747 void drawString(const char str[], SkScalar x, SkScalar y, const SkFont& font, 1748 const SkPaint& paint) { 1749 this->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint); 1750 } 1751 1752 /** Draws SkString, with origin at (x, y), using clip, SkMatrix, SkFont font, 1753 and SkPaint paint. 1754 1755 This function uses the default character-to-glyph mapping from the 1756 SkTypeface in font. It does not perform typeface fallback for 1757 characters not found in the SkTypeface. It does not perform kerning; 1758 glyphs are positioned based on their default advances. 1759 1760 SkString str is encoded as UTF-8. 1761 1762 Text size is affected by SkMatrix and SkFont text size. Default text 1763 size is 12 point. 1764 1765 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1766 SkColorFilter, and SkImageFilter; apply to text. By 1767 default, draws filled black glyphs. 1768 1769 @param str character code points drawn, 1770 ending with a char value of zero 1771 @param x start of string on x-axis 1772 @param y start of string on y-axis 1773 @param font typeface, text size and so, used to describe the text 1774 @param paint blend, color, and so on, used to draw 1775 */ drawString(const SkString & str,SkScalar x,SkScalar y,const SkFont & font,const SkPaint & paint)1776 void drawString(const SkString& str, SkScalar x, SkScalar y, const SkFont& font, 1777 const SkPaint& paint) { 1778 this->drawSimpleText(str.c_str(), str.size(), SkTextEncoding::kUTF8, x, y, font, paint); 1779 } 1780 1781 /** Draws count glyphs, at positions relative to origin styled with font and paint with 1782 supporting utf8 and cluster information. 1783 1784 This function draw glyphs at the given positions relative to the given origin. 1785 It does not perform typeface fallback for glyphs not found in the SkTypeface in font. 1786 1787 The drawing obeys the current transform matrix and clipping. 1788 1789 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1790 SkColorFilter, and SkImageFilter; apply to text. By 1791 default, draws filled black glyphs. 1792 1793 @param count number of glyphs to draw 1794 @param glyphs the array of glyphIDs to draw 1795 @param positions where to draw each glyph relative to origin 1796 @param clusters array of size count of cluster information 1797 @param textByteCount size of the utf8text 1798 @param utf8text utf8text supporting information for the glyphs 1799 @param origin the origin of all the positions 1800 @param font typeface, text size and so, used to describe the text 1801 @param paint blend, color, and so on, used to draw 1802 */ 1803 void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], 1804 const uint32_t clusters[], int textByteCount, const char utf8text[], 1805 SkPoint origin, const SkFont& font, const SkPaint& paint); 1806 1807 /** Draws count glyphs, at positions relative to origin styled with font and paint. 1808 1809 This function draw glyphs at the given positions relative to the given origin. 1810 It does not perform typeface fallback for glyphs not found in the SkTypeface in font. 1811 1812 The drawing obeys the current transform matrix and clipping. 1813 1814 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1815 SkColorFilter, and SkImageFilter; apply to text. By 1816 default, draws filled black glyphs. 1817 1818 @param count number of glyphs to draw 1819 @param glyphs the array of glyphIDs to draw 1820 @param positions where to draw each glyph relative to origin 1821 @param origin the origin of all the positions 1822 @param font typeface, text size and so, used to describe the text 1823 @param paint blend, color, and so on, used to draw 1824 */ 1825 void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], 1826 SkPoint origin, const SkFont& font, const SkPaint& paint); 1827 1828 /** Draws count glyphs, at positions relative to origin styled with font and paint. 1829 1830 This function draw glyphs using the given scaling and rotations. They are positioned 1831 relative to the given origin. It does not perform typeface fallback for glyphs not found 1832 in the SkTypeface in font. 1833 1834 The drawing obeys the current transform matrix and clipping. 1835 1836 All elements of paint: SkPathEffect, SkMaskFilter, SkShader, 1837 SkColorFilter, and SkImageFilter; apply to text. By 1838 default, draws filled black glyphs. 1839 1840 @param count number of glyphs to draw 1841 @param glyphs the array of glyphIDs to draw 1842 @param xforms where to draw and orient each glyph 1843 @param origin the origin of all the positions 1844 @param font typeface, text size and so, used to describe the text 1845 @param paint blend, color, and so on, used to draw 1846 */ 1847 void drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], 1848 SkPoint origin, const SkFont& font, const SkPaint& paint); 1849 1850 /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. 1851 1852 blob contains glyphs, their positions, and paint attributes specific to text: 1853 SkTypeface, SkPaint text size, SkPaint text scale x, 1854 SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, 1855 SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, 1856 and SkPaint subpixel text. 1857 1858 SkTextEncoding must be set to SkTextEncoding::kGlyphID. 1859 1860 Elements of paint: anti-alias, SkBlendMode, color including alpha, 1861 SkColorFilter, SkPaint dither, SkMaskFilter, SkPathEffect, SkShader, and 1862 SkPaint::Style; apply to blob. If SkPaint contains SkPaint::kStroke_Style: 1863 SkPaint miter limit, SkPaint::Cap, SkPaint::Join, and SkPaint stroke width; 1864 apply to SkPath created from blob. 1865 1866 @param blob glyphs, positions, and their paints' text size, typeface, and so on 1867 @param x horizontal offset applied to blob 1868 @param y vertical offset applied to blob 1869 @param paint blend, color, stroking, and so on, used to draw 1870 1871 example: https://fiddle.skia.org/c/@Canvas_drawTextBlob 1872 */ 1873 void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); 1874 1875 /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. 1876 1877 blob contains glyphs, their positions, and paint attributes specific to text: 1878 SkTypeface, SkPaint text size, SkPaint text scale x, 1879 SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, 1880 SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, 1881 and SkPaint subpixel text. 1882 1883 SkTextEncoding must be set to SkTextEncoding::kGlyphID. 1884 1885 Elements of paint: SkPathEffect, SkMaskFilter, SkShader, SkColorFilter, 1886 and SkImageFilter; apply to blob. 1887 1888 @param blob glyphs, positions, and their paints' text size, typeface, and so on 1889 @param x horizontal offset applied to blob 1890 @param y vertical offset applied to blob 1891 @param paint blend, color, stroking, and so on, used to draw 1892 */ drawTextBlob(const sk_sp<SkTextBlob> & blob,SkScalar x,SkScalar y,const SkPaint & paint)1893 void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint) { 1894 this->drawTextBlob(blob.get(), x, y, paint); 1895 } 1896 1897 /** Draws SkPicture picture, using clip and SkMatrix. 1898 Clip and SkMatrix are unchanged by picture contents, as if 1899 save() was called before and restore() was called after drawPicture(). 1900 1901 SkPicture records a series of draw commands for later playback. 1902 1903 @param picture recorded drawing commands to play 1904 */ drawPicture(const SkPicture * picture)1905 void drawPicture(const SkPicture* picture) { 1906 this->drawPicture(picture, nullptr, nullptr); 1907 } 1908 1909 /** Draws SkPicture picture, using clip and SkMatrix. 1910 Clip and SkMatrix are unchanged by picture contents, as if 1911 save() was called before and restore() was called after drawPicture(). 1912 1913 SkPicture records a series of draw commands for later playback. 1914 1915 @param picture recorded drawing commands to play 1916 */ drawPicture(const sk_sp<SkPicture> & picture)1917 void drawPicture(const sk_sp<SkPicture>& picture) { 1918 this->drawPicture(picture.get()); 1919 } 1920 1921 /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with 1922 SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, 1923 SkImageFilter, and SkBlendMode, if provided. 1924 1925 If paint is non-null, then the picture is always drawn into a temporary layer before 1926 actually landing on the canvas. Note that drawing into a layer can also change its 1927 appearance if there are any non-associative blendModes inside any of the pictures elements. 1928 1929 @param picture recorded drawing commands to play 1930 @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr 1931 @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr 1932 1933 example: https://fiddle.skia.org/c/@Canvas_drawPicture_3 1934 */ 1935 void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint); 1936 1937 /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with 1938 SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, 1939 SkImageFilter, and SkBlendMode, if provided. 1940 1941 If paint is non-null, then the picture is always drawn into a temporary layer before 1942 actually landing on the canvas. Note that drawing into a layer can also change its 1943 appearance if there are any non-associative blendModes inside any of the pictures elements. 1944 1945 @param picture recorded drawing commands to play 1946 @param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr 1947 @param paint SkPaint to apply transparency, filtering, and so on; may be nullptr 1948 */ drawPicture(const sk_sp<SkPicture> & picture,const SkMatrix * matrix,const SkPaint * paint)1949 void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, 1950 const SkPaint* paint) { 1951 this->drawPicture(picture.get(), matrix, paint); 1952 } 1953 1954 /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. 1955 If paint contains an SkShader and vertices does not contain texCoords, the shader 1956 is mapped using the vertices' positions. 1957 1958 SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines 1959 - the SkShader if SkPaint contains SkShader 1960 - or the opaque SkPaint color if SkPaint does not contain SkShader 1961 as the src of the blend and the interpolated vertex colors as the dst. 1962 1963 SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. 1964 1965 @param vertices triangle mesh to draw 1966 @param mode combines vertices' colors with SkShader if present or SkPaint opaque color 1967 if not. Ignored if the vertices do not contain color. 1968 @param paint specifies the SkShader, used as SkVertices texture, and SkColorFilter. 1969 1970 example: https://fiddle.skia.org/c/@Canvas_drawVertices 1971 */ 1972 void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint); 1973 1974 /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. 1975 If paint contains an SkShader and vertices does not contain texCoords, the shader 1976 is mapped using the vertices' positions. 1977 1978 SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines 1979 - the SkShader if SkPaint contains SkShader 1980 - or the opaque SkPaint color if SkPaint does not contain SkShader 1981 as the src of the blend and the interpolated vertex colors as the dst. 1982 1983 SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. 1984 1985 @param vertices triangle mesh to draw 1986 @param mode combines vertices' colors with SkShader if present or SkPaint opaque color 1987 if not. Ignored if the vertices do not contain color. 1988 @param paint specifies the SkShader, used as SkVertices texture, may be nullptr 1989 1990 example: https://fiddle.skia.org/c/@Canvas_drawVertices_2 1991 */ 1992 void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint); 1993 1994 #if defined(SK_ENABLE_SKSL) 1995 /** 1996 Experimental, under active development, and subject to change without notice. 1997 1998 Draws a mesh using a user-defined specification (see SkMeshSpecification). 1999 2000 SkBlender is ignored if SkMesh's specification does not output fragment shader color. 2001 Otherwise, it combines 2002 - the SkShader if SkPaint contains SkShader 2003 - or the opaque SkPaint color if SkPaint does not contain SkShader 2004 as the src of the blend and the mesh's fragment color as the dst. 2005 2006 SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. 2007 2008 @param mesh the mesh vertices and compatible specification. 2009 @param blender combines vertices colors with SkShader if present or SkPaint opaque color 2010 if not. Ignored if the custom mesh does not output color. Defaults to 2011 SkBlendMode::kModulate if nullptr. 2012 @param paint specifies the SkShader, used as SkVertices texture, may be nullptr 2013 */ 2014 void drawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint); 2015 #endif 2016 2017 /** Draws a Coons patch: the interpolation of four cubics with shared corners, 2018 associating a color, and optionally a texture SkPoint, with each corner. 2019 2020 SkPoint array cubics specifies four SkPath cubic starting at the top-left corner, 2021 in clockwise order, sharing every fourth point. The last SkPath cubic ends at the 2022 first point. 2023 2024 Color array color associates colors with corners in top-left, top-right, 2025 bottom-right, bottom-left order. 2026 2027 If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to 2028 corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is 2029 nullptr, SkShader is mapped using positions (derived from cubics). 2030 2031 SkBlendMode is ignored if colors is null. Otherwise, it combines 2032 - the SkShader if SkPaint contains SkShader 2033 - or the opaque SkPaint color if SkPaint does not contain SkShader 2034 as the src of the blend and the interpolated patch colors as the dst. 2035 2036 SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. 2037 2038 @param cubics SkPath cubic array, sharing common points 2039 @param colors color array, one for each corner 2040 @param texCoords SkPoint array of texture coordinates, mapping SkShader to corners; 2041 may be nullptr 2042 @param mode combines patch's colors with SkShader if present or SkPaint opaque color 2043 if not. Ignored if colors is null. 2044 @param paint SkShader, SkColorFilter, SkBlendMode, used to draw 2045 */ 2046 void drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2047 const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); 2048 2049 /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. 2050 paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode 2051 to draw, if present. For each entry in the array, SkRect tex locates sprite in 2052 atlas, and SkRSXform xform transforms it into destination space. 2053 2054 SkMaskFilter and SkPathEffect on paint are ignored. 2055 2056 xform, tex, and colors if present, must contain count entries. 2057 Optional colors are applied for each sprite using SkBlendMode mode, treating 2058 sprite as source and colors as destination. 2059 Optional cullRect is a conservative bounds of all transformed sprites. 2060 If cullRect is outside of clip, canvas can skip drawing. 2061 2062 If atlas is nullptr, this draws nothing. 2063 2064 @param atlas SkImage containing sprites 2065 @param xform SkRSXform mappings for sprites in atlas 2066 @param tex SkRect locations of sprites in atlas 2067 @param colors one per sprite, blended with sprite using SkBlendMode; may be nullptr 2068 @param count number of sprites to draw 2069 @param mode SkBlendMode combining colors and sprites 2070 @param sampling SkSamplingOptions used when sampling from the atlas image 2071 @param cullRect bounds of transformed sprites for efficient clipping; may be nullptr 2072 @param paint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr 2073 */ 2074 void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 2075 const SkColor colors[], int count, SkBlendMode mode, 2076 const SkSamplingOptions& sampling, const SkRect* cullRect, const SkPaint* paint); 2077 2078 /** Draws SkDrawable drawable using clip and SkMatrix, concatenated with 2079 optional matrix. 2080 2081 If SkCanvas has an asynchronous implementation, as is the case 2082 when it is recording into SkPicture, then drawable will be referenced, 2083 so that SkDrawable::draw() can be called when the operation is finalized. To force 2084 immediate drawing, call SkDrawable::draw() instead. 2085 2086 @param drawable custom struct encapsulating drawing commands 2087 @param matrix transformation applied to drawing; may be nullptr 2088 2089 example: https://fiddle.skia.org/c/@Canvas_drawDrawable 2090 */ 2091 void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr); 2092 2093 /** Draws SkDrawable drawable using clip and SkMatrix, offset by (x, y). 2094 2095 If SkCanvas has an asynchronous implementation, as is the case 2096 when it is recording into SkPicture, then drawable will be referenced, 2097 so that SkDrawable::draw() can be called when the operation is finalized. To force 2098 immediate drawing, call SkDrawable::draw() instead. 2099 2100 @param drawable custom struct encapsulating drawing commands 2101 @param x offset into SkCanvas writable pixels on x-axis 2102 @param y offset into SkCanvas writable pixels on y-axis 2103 2104 example: https://fiddle.skia.org/c/@Canvas_drawDrawable_2 2105 */ 2106 void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y); 2107 2108 /** Associates SkRect on SkCanvas with an annotation; a key-value pair, where the key is 2109 a null-terminated UTF-8 string, and optional value is stored as SkData. 2110 2111 Only some canvas implementations, such as recording to SkPicture, or drawing to 2112 document PDF, use annotations. 2113 2114 @param rect SkRect extent of canvas to annotate 2115 @param key string used for lookup 2116 @param value data holding value stored in annotation 2117 2118 example: https://fiddle.skia.org/c/@Canvas_drawAnnotation_2 2119 */ 2120 void drawAnnotation(const SkRect& rect, const char key[], SkData* value); 2121 2122 /** Associates SkRect on SkCanvas when an annotation; a key-value pair, where the key is 2123 a null-terminated UTF-8 string, and optional value is stored as SkData. 2124 2125 Only some canvas implementations, such as recording to SkPicture, or drawing to 2126 document PDF, use annotations. 2127 2128 @param rect SkRect extent of canvas to annotate 2129 @param key string used for lookup 2130 @param value data holding value stored in annotation 2131 */ drawAnnotation(const SkRect & rect,const char key[],const sk_sp<SkData> & value)2132 void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value) { 2133 this->drawAnnotation(rect, key, value.get()); 2134 } 2135 2136 /** Returns true if clip is empty; that is, nothing will draw. 2137 2138 May do work when called; it should not be called 2139 more often than needed. However, once called, subsequent calls perform no 2140 work until clip changes. 2141 2142 @return true if clip is empty 2143 2144 example: https://fiddle.skia.org/c/@Canvas_isClipEmpty 2145 */ 2146 virtual bool isClipEmpty() const; 2147 2148 /** Returns true if clip is SkRect and not empty. 2149 Returns false if the clip is empty, or if it is not SkRect. 2150 2151 @return true if clip is SkRect and not empty 2152 2153 example: https://fiddle.skia.org/c/@Canvas_isClipRect 2154 */ 2155 virtual bool isClipRect() const; 2156 2157 /** Returns the current transform from local coordinates to the 'device', which for most 2158 * purposes means pixels. 2159 * 2160 * @return transformation from local coordinates to device / pixels. 2161 */ 2162 SkM44 getLocalToDevice() const; 2163 2164 /** 2165 * Throws away the 3rd row and column in the matrix, so be warned. 2166 */ getLocalToDeviceAs3x3()2167 SkMatrix getLocalToDeviceAs3x3() const { 2168 return this->getLocalToDevice().asM33(); 2169 } 2170 2171 #ifdef SK_SUPPORT_LEGACY_GETTOTALMATRIX 2172 /** DEPRECATED 2173 * Legacy version of getLocalToDevice(), which strips away any Z information, and 2174 * just returns a 3x3 version. 2175 * 2176 * @return 3x3 version of getLocalToDevice() 2177 * 2178 * example: https://fiddle.skia.org/c/@Canvas_getTotalMatrix 2179 * example: https://fiddle.skia.org/c/@Clip 2180 */ 2181 SkMatrix getTotalMatrix() const; 2182 #endif 2183 2184 /////////////////////////////////////////////////////////////////////////// 2185 2186 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(SK_GANESH) 2187 // These methods exist to support WebView in Android Framework. 2188 SkIRect topLayerBounds() const; 2189 GrBackendRenderTarget topLayerBackendRenderTarget() const; 2190 #endif 2191 2192 /** 2193 * Returns the global clip as a region. If the clip contains AA, then only the bounds 2194 * of the clip may be returned. 2195 */ 2196 void temporary_internal_getRgnClip(SkRegion* region); 2197 2198 void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&); 2199 2200 2201 protected: 2202 // default impl defers to getDevice()->newSurface(info) 2203 virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props); 2204 2205 // default impl defers to its device 2206 virtual bool onPeekPixels(SkPixmap* pixmap); 2207 virtual bool onAccessTopLayerPixels(SkPixmap* pixmap); 2208 virtual SkImageInfo onImageInfo() const; 2209 virtual bool onGetProps(SkSurfaceProps* props, bool top) const; 2210 virtual void onFlush(); 2211 2212 // Subclass save/restore notifiers. 2213 // Overriders should call the corresponding INHERITED method up the inheritance chain. 2214 // getSaveLayerStrategy()'s return value may suppress full layer allocation. 2215 enum SaveLayerStrategy { 2216 kFullLayer_SaveLayerStrategy, 2217 kNoLayer_SaveLayerStrategy, 2218 }; 2219 willSave()2220 virtual void willSave() {} 2221 // Overriders should call the corresponding INHERITED method up the inheritance chain. getSaveLayerStrategy(const SaveLayerRec &)2222 virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& ) { 2223 return kFullLayer_SaveLayerStrategy; 2224 } 2225 2226 // returns true if we should actually perform the saveBehind, or false if we should just save. onDoSaveBehind(const SkRect *)2227 virtual bool onDoSaveBehind(const SkRect*) { return true; } willRestore()2228 virtual void willRestore() {} didRestore()2229 virtual void didRestore() {} 2230 didConcat44(const SkM44 &)2231 virtual void didConcat44(const SkM44&) {} didSetM44(const SkM44 &)2232 virtual void didSetM44(const SkM44&) {} didTranslate(SkScalar,SkScalar)2233 virtual void didTranslate(SkScalar, SkScalar) {} didScale(SkScalar,SkScalar)2234 virtual void didScale(SkScalar, SkScalar) {} 2235 2236 // NOTE: If you are adding a new onDraw virtual to SkCanvas, PLEASE add an override to 2237 // SkCanvasVirtualEnforcer (in SkCanvasVirtualEnforcer.h). This ensures that subclasses using 2238 // that mechanism will be required to implement the new function. 2239 virtual void onDrawPaint(const SkPaint& paint); 2240 virtual void onDrawBehind(const SkPaint& paint); 2241 virtual void onDrawRect(const SkRect& rect, const SkPaint& paint); 2242 virtual void onDrawRRect(const SkRRect& rrect, const SkPaint& paint); 2243 virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); 2244 virtual void onDrawOval(const SkRect& rect, const SkPaint& paint); 2245 virtual void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, 2246 bool useCenter, const SkPaint& paint); 2247 virtual void onDrawPath(const SkPath& path, const SkPaint& paint); 2248 virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint); 2249 2250 virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2251 const SkPaint& paint); 2252 2253 virtual void onDrawGlyphRunList(const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); 2254 2255 virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2256 const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); 2257 virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], 2258 const SkPaint& paint); 2259 2260 virtual void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, 2261 const SkPaint*); 2262 virtual void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst, 2263 const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); 2264 virtual void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect& dst, 2265 SkFilterMode, const SkPaint*); 2266 virtual void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect src[], 2267 const SkColor[], int count, SkBlendMode, const SkSamplingOptions&, 2268 const SkRect* cull, const SkPaint*); 2269 virtual void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, 2270 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 2271 const SkSamplingOptions&, const SkPaint*, 2272 SrcRectConstraint); 2273 2274 virtual void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, 2275 const SkPaint& paint); 2276 #ifdef SK_ENABLE_SKSL 2277 virtual void onDrawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&); 2278 #endif 2279 virtual void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value); 2280 virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&); 2281 2282 virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix); 2283 virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2284 const SkPaint* paint); 2285 2286 virtual void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, 2287 const SkColor4f& color, SkBlendMode mode); 2288 2289 enum ClipEdgeStyle { 2290 kHard_ClipEdgeStyle, 2291 kSoft_ClipEdgeStyle 2292 }; 2293 2294 virtual void onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle); 2295 virtual void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle); 2296 virtual void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle); 2297 virtual void onClipShader(sk_sp<SkShader>, SkClipOp); 2298 virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp op); 2299 virtual void onResetClip(); 2300 2301 virtual void onDiscard(); 2302 2303 #if (defined(SK_GANESH) || defined(SK_GRAPHITE)) 2304 /** Experimental 2305 */ 2306 virtual sk_sp<sktext::gpu::Slug> onConvertGlyphRunListToSlug( 2307 const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); 2308 2309 /** Experimental 2310 */ 2311 virtual void onDrawSlug(const sktext::gpu::Slug* slug); 2312 #endif 2313 2314 private: 2315 2316 enum ShaderOverrideOpacity { 2317 kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) 2318 kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque 2319 kNotOpaque_ShaderOverrideOpacity, //!< the overriding shader may not be opaque 2320 }; 2321 2322 // notify our surface (if we have one) that we are about to draw, so it 2323 // can perform copy-on-write or invalidate any cached images 2324 // returns false if the copy failed 2325 bool SK_WARN_UNUSED_RESULT predrawNotify(bool willOverwritesEntireSurface = false); 2326 bool SK_WARN_UNUSED_RESULT predrawNotify(const SkRect*, const SkPaint*, ShaderOverrideOpacity); 2327 2328 enum class CheckForOverwrite : bool { 2329 kNo = false, 2330 kYes = true 2331 }; 2332 // call the appropriate predrawNotify and create a layer if needed. 2333 std::optional<AutoLayerForImageFilter> aboutToDraw( 2334 SkCanvas* canvas, 2335 const SkPaint& paint, 2336 const SkRect* rawBounds = nullptr, 2337 CheckForOverwrite = CheckForOverwrite::kNo, 2338 ShaderOverrideOpacity = kNone_ShaderOverrideOpacity); 2339 2340 // The bottom-most device in the stack, only changed by init(). Image properties and the final 2341 // canvas pixels are determined by this device. baseDevice()2342 SkBaseDevice* baseDevice() const { 2343 SkASSERT(fBaseDevice); 2344 return fBaseDevice.get(); 2345 } 2346 2347 // The top-most device in the stack, will change within saveLayer()'s. All drawing and clipping 2348 // operations should route to this device. 2349 SkBaseDevice* topDevice() const; 2350 2351 // Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing, 2352 // clip, and matrix commands. There is a layer per call to saveLayer() using the 2353 // kFullLayer_SaveLayerStrategy. 2354 struct Layer { 2355 sk_sp<SkBaseDevice> fDevice; 2356 sk_sp<SkImageFilter> fImageFilter; // applied to layer *before* being drawn by paint 2357 SkPaint fPaint; 2358 bool fDiscard; 2359 2360 Layer(sk_sp<SkBaseDevice> device, sk_sp<SkImageFilter> imageFilter, const SkPaint& paint); 2361 }; 2362 2363 // Encapsulate state needed to restore from saveBehind() 2364 struct BackImage { 2365 // Out of line to avoid including SkSpecialImage.h 2366 BackImage(sk_sp<SkSpecialImage>, SkIPoint); 2367 BackImage(const BackImage&); 2368 BackImage(BackImage&&); 2369 BackImage& operator=(const BackImage&); 2370 ~BackImage(); 2371 2372 sk_sp<SkSpecialImage> fImage; 2373 SkIPoint fLoc; 2374 }; 2375 2376 class MCRec { 2377 public: 2378 // If not null, this MCRec corresponds with the saveLayer() record that made the layer. 2379 // The base "layer" is not stored here, since it is stored inline in SkCanvas and has no 2380 // restoration behavior. 2381 std::unique_ptr<Layer> fLayer; 2382 2383 // This points to the device of the top-most layer (which may be lower in the stack), or 2384 // to the canvas's fBaseDevice. The MCRec does not own the device. 2385 SkBaseDevice* fDevice; 2386 2387 std::unique_ptr<BackImage> fBackImage; 2388 SkM44 fMatrix; 2389 int fDeferredSaveCount = 0; 2390 2391 MCRec(SkBaseDevice* device); 2392 MCRec(const MCRec* prev); 2393 ~MCRec(); 2394 2395 void newLayer(sk_sp<SkBaseDevice> layerDevice, 2396 sk_sp<SkImageFilter> filter, 2397 const SkPaint& restorePaint); 2398 2399 void reset(SkBaseDevice* device); 2400 }; 2401 2402 // the first N recs that can fit here mean we won't call malloc 2403 static constexpr int kMCRecSize = 96; // most recent measurement 2404 static constexpr int kMCRecCount = 32; // common depth for save/restores 2405 2406 intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)]; 2407 2408 SkDeque fMCStack; 2409 // points to top of stack 2410 MCRec* fMCRec; 2411 2412 // Installed via init() 2413 sk_sp<SkBaseDevice> fBaseDevice; 2414 const SkSurfaceProps fProps; 2415 2416 int fSaveCount; // value returned by getSaveCount() 2417 2418 std::unique_ptr<SkRasterHandleAllocator> fAllocator; 2419 2420 SkSurface_Base* fSurfaceBase; getSurfaceBase()2421 SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } setSurfaceBase(SkSurface_Base * sb)2422 void setSurfaceBase(SkSurface_Base* sb) { 2423 fSurfaceBase = sb; 2424 } 2425 friend class SkSurface_Base; 2426 friend class SkSurface_Gpu; 2427 2428 SkIRect fClipRestrictionRect = SkIRect::MakeEmpty(); 2429 int fClipRestrictionSaveCount = -1; 2430 2431 void doSave(); 2432 void checkForDeferredSave(); 2433 void internalSetMatrix(const SkM44&); 2434 2435 friend class SkAndroidFrameworkUtils; 2436 friend class SkCanvasPriv; // needs to expose android functions for testing outside android 2437 friend class AutoLayerForImageFilter; 2438 friend class SkSurface_Raster; // needs getDevice() 2439 friend class SkNoDrawCanvas; // needs resetForNextPicture() 2440 friend class SkNWayCanvas; 2441 friend class SkPictureRecord; // predrawNotify (why does it need it? <reed>) 2442 friend class SkOverdrawCanvas; 2443 friend class SkRasterHandleAllocator; 2444 friend class SkRecords::Draw; 2445 template <typename Key> 2446 friend class SkTestCanvas; 2447 2448 protected: 2449 // For use by SkNoDrawCanvas (via SkCanvasVirtualEnforcer, which can't be a friend) 2450 SkCanvas(const SkIRect& bounds); 2451 private: 2452 SkCanvas(const SkBitmap&, std::unique_ptr<SkRasterHandleAllocator>, 2453 SkRasterHandleAllocator::Handle, const SkSurfaceProps* props); 2454 2455 SkCanvas(SkCanvas&&) = delete; 2456 SkCanvas(const SkCanvas&) = delete; 2457 SkCanvas& operator=(SkCanvas&&) = delete; 2458 SkCanvas& operator=(const SkCanvas&) = delete; 2459 2460 #if (defined(SK_GANESH) || defined(SK_GRAPHITE)) 2461 friend class sktext::gpu::Slug; 2462 /** Experimental 2463 * Convert a SkTextBlob to a sktext::gpu::Slug using the current canvas state. 2464 */ 2465 sk_sp<sktext::gpu::Slug> convertBlobToSlug(const SkTextBlob& blob, SkPoint origin, 2466 const SkPaint& paint); 2467 2468 /** Experimental 2469 * Draw an sktext::gpu::Slug given the current canvas state. 2470 */ 2471 void drawSlug(const sktext::gpu::Slug* slug); 2472 #endif 2473 2474 /** Experimental 2475 * Saves the specified subset of the current pixels in the current layer, 2476 * and then clears those pixels to transparent black. 2477 * Restores the pixels on restore() by drawing them in SkBlendMode::kDstOver. 2478 * 2479 * @param subset conservative bounds of the area to be saved / restored. 2480 * @return depth of save state stack before this call was made. 2481 */ 2482 int only_axis_aligned_saveBehind(const SkRect* subset); 2483 2484 /** 2485 * Like drawPaint, but magically clipped to the most recent saveBehind buffer rectangle. 2486 * If there is no active saveBehind, then this draws nothing. 2487 */ 2488 void drawClippedToSaveBehind(const SkPaint&); 2489 2490 void resetForNextPicture(const SkIRect& bounds); 2491 2492 // needs gettotalclip() 2493 friend class SkCanvasStateUtils; 2494 2495 void init(sk_sp<SkBaseDevice>); 2496 2497 // All base onDrawX() functions should call this and skip drawing if it returns true. 2498 // If 'matrix' is non-null, it maps the paint's fast bounds before checking for quick rejection 2499 bool internalQuickReject(const SkRect& bounds, const SkPaint& paint, 2500 const SkMatrix* matrix = nullptr); 2501 2502 void internalDrawPaint(const SkPaint& paint); 2503 void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy); 2504 void internalSaveBehind(const SkRect*); 2505 2506 void internalConcat44(const SkM44&); 2507 2508 // shared by save() and saveLayer() 2509 void internalSave(); 2510 void internalRestore(); 2511 2512 enum class DeviceCompatibleWithFilter : bool { 2513 // Check the src device's local-to-device matrix for compatibility with the filter, and if 2514 // it is not compatible, introduce an intermediate image and transformation that allows the 2515 // filter to be evaluated on the modified src content. 2516 kUnknown = false, 2517 // Assume that the src device's local-to-device matrix is compatible with the filter. 2518 kYes = true 2519 }; 2520 /** 2521 * Filters the contents of 'src' and draws the result into 'dst'. The filter is evaluated 2522 * relative to the current canvas matrix, and src is drawn to dst using their relative transform 2523 * 'paint' is applied after the filter and must not have a mask or image filter of its own. 2524 * A null 'filter' behaves as if the identity filter were used. 2525 * 2526 * 'scaleFactor' is an extra uniform scale transform applied to downscale the 'src' image 2527 * before any filtering, or as part of the copy, and is then drawn with 1/scaleFactor to 'dst'. 2528 * Must be 1.0 if 'compat' is kYes (i.e. any scale factor has already been baked into the 2529 * relative transforms between the devices). 2530 */ 2531 void internalDrawDeviceWithFilter(SkBaseDevice* src, SkBaseDevice* dst, 2532 const SkImageFilter* filter, const SkPaint& paint, 2533 DeviceCompatibleWithFilter compat, 2534 SkScalar scaleFactor = 1.f); 2535 2536 /* 2537 * Returns true if drawing the specified rect (or all if it is null) with the specified 2538 * paint (or default if null) would overwrite the entire root device of the canvas 2539 * (i.e. the canvas' surface if it had one). 2540 */ 2541 bool wouldOverwriteEntireSurface(const SkRect*, const SkPaint*, ShaderOverrideOpacity) const; 2542 2543 /** 2544 * Returns true if the paint's imagefilter can be invoked directly, without needed a layer. 2545 */ 2546 bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkSamplingOptions&, 2547 const SkPaint&); 2548 2549 /** 2550 * Returns true if the clip (for any active layer) contains antialiasing. 2551 * If the clip is empty, this will return false. 2552 */ 2553 bool androidFramework_isClipAA() const; 2554 2555 /** 2556 * Reset the clip to be wide-open (modulo any separately specified device clip restriction). 2557 * This operate within the save/restore clip stack so it can be undone by restoring to an 2558 * earlier save point. 2559 */ 2560 void internal_private_resetClip(); 2561 internal_private_asPaintFilterCanvas()2562 virtual SkPaintFilterCanvas* internal_private_asPaintFilterCanvas() const { return nullptr; } 2563 2564 // Keep track of the device clip bounds in the canvas' global space to reject draws before 2565 // invoking the top-level device. 2566 SkRect fQuickRejectBounds; 2567 2568 // Compute the clip's bounds based on all clipped SkDevice's reported device bounds transformed 2569 // into the canvas' global space. 2570 SkRect computeDeviceClipBounds(bool outsetForAA=true) const; 2571 2572 class AutoUpdateQRBounds; 2573 void validateClip() const; 2574 2575 std::unique_ptr<sktext::GlyphRunBuilder> fScratchGlyphRunBuilder; 2576 2577 using INHERITED = SkRefCnt; 2578 }; 2579 2580 /** \class SkAutoCanvasRestore 2581 Stack helper class calls SkCanvas::restoreToCount when SkAutoCanvasRestore 2582 goes out of scope. Use this to guarantee that the canvas is restored to a known 2583 state. 2584 */ 2585 class SkAutoCanvasRestore { 2586 public: 2587 2588 /** Preserves SkCanvas::save() count. Optionally saves SkCanvas clip and SkCanvas matrix. 2589 2590 @param canvas SkCanvas to guard 2591 @param doSave call SkCanvas::save() 2592 @return utility to restore SkCanvas state on destructor 2593 */ SkAutoCanvasRestore(SkCanvas * canvas,bool doSave)2594 SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) { 2595 if (fCanvas) { 2596 fSaveCount = canvas->getSaveCount(); 2597 if (doSave) { 2598 canvas->save(); 2599 } 2600 } 2601 } 2602 2603 /** Restores SkCanvas to saved state. Destructor is called when container goes out of 2604 scope. 2605 */ ~SkAutoCanvasRestore()2606 ~SkAutoCanvasRestore() { 2607 if (fCanvas) { 2608 fCanvas->restoreToCount(fSaveCount); 2609 } 2610 } 2611 2612 /** Restores SkCanvas to saved state immediately. Subsequent calls and 2613 ~SkAutoCanvasRestore() have no effect. 2614 */ restore()2615 void restore() { 2616 if (fCanvas) { 2617 fCanvas->restoreToCount(fSaveCount); 2618 fCanvas = nullptr; 2619 } 2620 } 2621 2622 private: 2623 SkCanvas* fCanvas; 2624 int fSaveCount; 2625 2626 SkAutoCanvasRestore(SkAutoCanvasRestore&&) = delete; 2627 SkAutoCanvasRestore(const SkAutoCanvasRestore&) = delete; 2628 SkAutoCanvasRestore& operator=(SkAutoCanvasRestore&&) = delete; 2629 SkAutoCanvasRestore& operator=(const SkAutoCanvasRestore&) = delete; 2630 }; 2631 2632 #endif 2633