1 #Topic Paint 2 #Alias Paint_Reference ## 3 4 #Class SkPaint 5 6 #Code 7 #Populate 8 ## 9 10 Paint controls options applied when drawing and measuring. Paint collects all 11 options outside of the Canvas_Clip and Canvas_Matrix. 12 13 Various options apply to text, strokes and fills, and images. 14 15 Some options may not be implemented on all platforms; in these cases, setting 16 the option has no effect. Some options are conveniences that duplicate Canvas 17 functionality; for instance, text size is identical to matrix scale. 18 19 Paint options are rarely exclusive; each option modifies a stage of the drawing 20 pipeline and multiple pipeline stages may be affected by a single Paint. 21 22 Paint collects effects and filters that describe single-pass and multiple-pass 23 algorithms that alter the drawing geometry, color, and transparency. For instance, 24 Paint does not directly implement dashing or blur, but contains the objects that do so. 25 26 The objects contained by Paint are opaque, and cannot be edited outside of the Paint 27 to affect it. The implementation is free to defer computations associated with the 28 Paint, or ignore them altogether. For instance, some GPU implementations draw all 29 Path geometries with Anti_Aliasing, regardless of how SkPaint::kAntiAlias_Flag 30 is set in Paint. 31 32 Paint describes a single color, a single font, a single image quality, and so on. 33 Multiple colors are drawn either by using multiple paints or with objects like 34 Shader attached to Paint. 35 36 #Method SkPaint() 37 #Line # constructs with default values ## 38 Constructs Paint with default values. 39 40 #Table 41 #Legend 42 # attribute # default value ## 43 #Legend ## 44 # Anti_Alias # false ## 45 # Blend_Mode # SkBlendMode::kSrcOver ## 46 # Color # SK_ColorBLACK ## 47 # Color_Alpha # 255 ## 48 # Color_Filter # nullptr ## 49 # Dither # false ## 50 # Draw_Looper # nullptr ## 51 # Filter_Quality # kNone_SkFilterQuality ## 52 # Image_Filter # nullptr ## 53 # Miter_Limit # 4 ## 54 # Mask_Filter # nullptr ## 55 # Path_Effect # nullptr ## 56 # Shader # nullptr ## 57 # Style # kFill_Style ## 58 # Stroke_Cap # kButt_Cap ## 59 # Stroke_Join # kMiter_Join ## 60 # Stroke_Width # 0 ## 61 #Table ## 62 63 The miter limit may be overridden at compile time by defining 64 paint default values. The overrides may be included in "SkUserConfig.h" or predefined by the 65 build system. 66 67 #Return default initialized Paint ## 68 69 #Example 70 #ToDo mark this as no output ## 71 #Height 1 72 ###$ $ redefine markup character so preprocessor commands appear normally 73 #ifndef SkUserConfig_DEFINED 74 #define SkUserConfig_DEFINED 75 76 #define SkPaintDefaults_Flags 0x01 // always enable antialiasing 77 #define SkPaintDefaults_TextSize 24.f // double default font size 78 #define SkPaintDefaults_Hinting 3 // use full hinting 79 #define SkPaintDefaults_MiterLimit 10.f // use HTML Canvas miter limit setting 80 81 #endif 82 $$$# # restore original markup character 83 ## 84 85 86 ## 87 88 #Method SkPaint(const SkPaint& paint) 89 #Line # makes a shallow copy ## 90 #Populate 91 92 #Example 93 #ToDo why is this double-spaced on Fiddle? ## 94 SkPaint paint1; 95 paint1.setColor(SK_ColorRED); 96 SkPaint paint2(paint1); 97 paint2.setColor(SK_ColorBLUE); 98 SkDebugf("SK_ColorRED %c= paint1.getColor()\n", SK_ColorRED == paint1.getColor() ? '=' : '!'); 99 SkDebugf("SK_ColorBLUE %c= paint2.getColor()\n", SK_ColorBLUE == paint2.getColor() ? '=' : '!'); 100 101 #StdOut 102 SK_ColorRED == paint1.getColor() 103 SK_ColorBLUE == paint2.getColor() 104 ## 105 ## 106 107 ## 108 109 #Method SkPaint(SkPaint&& paint) 110 #Line # moves paint without copying it ## 111 #Populate 112 113 #Example 114 SkPaint paint; 115 float intervals[] = { 5, 5 }; 116 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 2.5f)); 117 SkPaint dashed(std::move(paint)); 118 SkDebugf("path effect unique: %s\n", dashed.getPathEffect()->unique() ? "true" : "false"); 119 120 #StdOut 121 path effect unique: true 122 ## 123 ## 124 125 ## 126 127 # ------------------------------------------------------------------------------ 128 129 #Method void reset() 130 #In Constructors 131 #Line # sets to default values ## 132 #Populate 133 134 #Example 135 SkPaint paint1, paint2; 136 paint1.setColor(SK_ColorRED); 137 paint1.reset(); 138 SkDebugf("paint1 %c= paint2", paint1 == paint2 ? '=' : '!'); 139 140 #StdOut 141 paint1 == paint2 142 ## 143 ## 144 145 ## 146 147 # ------------------------------------------------------------------------------ 148 149 #Method ~SkPaint() 150 #Line # decreases Reference_Count of owned objects ## 151 #Populate 152 153 #NoExample 154 ## 155 156 ## 157 158 159 # ------------------------------------------------------------------------------ 160 161 #Subtopic Management 162 #Line # paint copying, moving, comparing ## 163 ## 164 165 #Method SkPaint& operator=(const SkPaint& paint) 166 #In Management 167 #Line # makes a shallow copy ## 168 #Populate 169 170 #Example 171 SkPaint paint1, paint2; 172 paint1.setColor(SK_ColorRED); 173 paint2 = paint1; 174 SkDebugf("SK_ColorRED %c= paint1.getColor()\n", SK_ColorRED == paint1.getColor() ? '=' : '!'); 175 SkDebugf("SK_ColorRED %c= paint2.getColor()\n", SK_ColorRED == paint2.getColor() ? '=' : '!'); 176 177 #StdOut 178 SK_ColorRED == paint1.getColor() 179 SK_ColorRED == paint2.getColor() 180 ## 181 ## 182 183 ## 184 185 # ------------------------------------------------------------------------------ 186 187 #Method SkPaint& operator=(SkPaint&& paint) 188 #In Management 189 #Line # moves paint without copying it ## 190 #Populate 191 192 #Example 193 SkPaint paint1, paint2; 194 paint1.setColor(SK_ColorRED); 195 paint2 = std::move(paint1); 196 SkDebugf("SK_ColorRED == paint2.getColor()\n", SK_ColorRED == paint2.getColor() ? '=' : '!'); 197 198 #StdOut 199 SK_ColorRED == paint2.getColor() 200 ## 201 ## 202 203 ## 204 205 # ------------------------------------------------------------------------------ 206 207 #Method bool operator==(const SkPaint& a, const SkPaint& b) 208 #Line # compares paints for equality ## 209 #Populate 210 211 #Example 212 SkPaint paint1, paint2; 213 paint1.setColor(SK_ColorRED); 214 paint2.setColor(0xFFFF0000); 215 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 216 float intervals[] = { 5, 5 }; 217 paint1.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f)); 218 paint2.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f)); 219 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 220 221 #StdOut 222 paint1 == paint2 223 paint1 != paint2 224 ## 225 ## 226 #SeeAlso operator!=(const SkPaint& a, const SkPaint& b) 227 ## 228 229 # ------------------------------------------------------------------------------ 230 231 #Method bool operator!=(const SkPaint& a, const SkPaint& b) 232 #Line # compares paints for inequality ## 233 #Populate 234 235 #Example 236 SkPaint paint1, paint2; 237 paint1.setColor(SK_ColorRED); 238 paint2.setColor(0xFFFF0000); 239 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 240 SkDebugf("paint1 %c= paint2\n", paint1 != paint2 ? '!' : '='); 241 242 #StdOut 243 paint1 == paint2 244 paint1 == paint2 245 ## 246 ## 247 #SeeAlso operator==(const SkPaint& a, const SkPaint& b) 248 ## 249 250 # ------------------------------------------------------------------------------ 251 252 #Method uint32_t getHash() const 253 #In Management 254 #Line # returns a shallow hash for equality checks ## 255 #Populate 256 257 #Example 258 SkPaint paint1, paint2; 259 paint1.setColor(SK_ColorRED); 260 paint2.setColor(0xFFFF0000); 261 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 262 SkDebugf("paint1.getHash() %c= paint2.getHash()\n", 263 paint1.getHash() == paint2.getHash() ? '=' : '!'); 264 265 #StdOut 266 paint1 == paint2 267 paint1.getHash() == paint2.getHash() 268 ## 269 ## 270 271 ## 272 273 # ------------------------------------------------------------------------------ 274 #Subtopic Anti_Alias 275 #Alias Anti_Alias 276 #Substitute anti-alias 277 ## 278 #Alias Anti_Aliased 279 #Substitute anti-aliased 280 ## 281 #Alias Anti_Aliasing 282 #Substitute anti-aliasing 283 ## 284 #In Related_Function 285 #Line # approximating coverage with transparency ## 286 287 Anti_Alias drawing approximates partial pixel coverage with transparency. 288 If kAntiAlias_Flag is clear, pixel centers contained by the shape edge are drawn opaque. 289 If kAntiAlias_Flag is set, pixels are drawn with Color_Alpha equal to their coverage. 290 291 The rule for Aliased pixels is inconsistent across platforms. A shape edge 292 passing through the pixel center may, but is not required to, draw the pixel. 293 294 Raster_Engine draws Aliased pixels whose centers are on or to the right of the start of an 295 active Path edge, and whose center is to the left of the end of the active Path edge. 296 297 #ToDo add illustration of raster pixels ## 298 299 A platform may only support Anti_Aliased drawing. Some GPU-backed platforms use 300 Supersampling to Anti_Alias all drawing, and have no mechanism to selectively 301 Alias. 302 303 The amount of coverage computed for Anti_Aliased pixels also varies across platforms. 304 305 Anti_Alias is disabled by default. 306 Anti_Alias can be enabled by default by setting SkPaintDefaults_Flags to kAntiAlias_Flag 307 at compile time. 308 309 #Example 310 #Width 512 311 #Description 312 A red line is drawn with transparency on the edges to make it look smoother. 313 A blue line draws only where the pixel centers are contained. 314 The lines are drawn into Bitmap, then drawn magnified to make the 315 Aliasing easier to see. 316 ## 317 318 void draw(SkCanvas* canvas) { 319 SkBitmap bitmap; 320 bitmap.allocN32Pixels(50, 50); 321 SkCanvas offscreen(bitmap); 322 SkPaint paint; 323 paint.setStyle(SkPaint::kStroke_Style); 324 paint.setStrokeWidth(10); 325 for (bool antialias : { false, true }) { 326 paint.setColor(antialias ? SK_ColorRED : SK_ColorBLUE); 327 paint.setAntiAlias(antialias); 328 bitmap.eraseColor(0); 329 offscreen.drawLine(5, 5, 15, 30, paint); 330 canvas->drawLine(5, 5, 15, 30, paint); 331 canvas->save(); 332 canvas->scale(10, 10); 333 canvas->drawBitmap(bitmap, antialias ? 12 : 0, 0); 334 canvas->restore(); 335 canvas->translate(15, 0); 336 } 337 } 338 ## 339 #Subtopic Anti_Alias ## 340 341 #Method bool isAntiAlias() const 342 #In Anti_alias 343 #Line # returns true if Anti_Alias is set ## 344 #Populate 345 346 #Example 347 SkPaint paint; 348 SkDebugf("paint.isAntiAlias() %c= !!(paint.getFlags() & SkPaint::kAntiAlias_Flag)\n", 349 paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) ? '=' : '!'); 350 paint.setAntiAlias(true); 351 SkDebugf("paint.isAntiAlias() %c= !!(paint.getFlags() & SkPaint::kAntiAlias_Flag)\n", 352 paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) ? '=' : '!'); 353 354 #StdOut 355 paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) 356 paint.isAntiAlias() == !!(paint.getFlags() & SkPaint::kAntiAlias_Flag) 357 ## 358 ## 359 ## 360 361 #Method void setAntiAlias(bool aa) 362 #In Anti_alias 363 #Line # sets or clears Anti_Alias ## 364 #Populate 365 366 #Example 367 SkPaint paint1, paint2; 368 paint1.setAntiAlias(true); 369 paint2.setFlags(paint2.getFlags() | SkPaint::kAntiAlias_Flag); 370 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 371 372 #StdOut 373 paint1 == paint2 374 ## 375 ## 376 377 ## 378 379 # ------------------------------------------------------------------------------ 380 #Subtopic Dither 381 #Line # distributing color error ## 382 383 Dither increases fidelity by adjusting the color of adjacent pixels. 384 This can help to smooth color transitions and reducing banding in gradients. 385 Dithering lessens visible banding from kRGB_565_SkColorType 386 and kRGBA_8888_SkColorType gradients, 387 and improves rendering into a kRGB_565_SkColorType Surface. 388 389 Dithering is always enabled for linear gradients drawing into 390 kRGB_565_SkColorType Surface and kRGBA_8888_SkColorType Surface. 391 Dither cannot be enabled for kAlpha_8_SkColorType Surface and 392 kRGBA_F16_SkColorType Surface. 393 394 Dither is disabled by default. 395 Dither can be enabled by default by setting SkPaintDefaults_Flags to kDither_Flag 396 at compile time. 397 398 Some platform implementations may ignore dithering. Set #Formula # SK_IGNORE_GPU_DITHER ## 399 to ignore Dither on GPU_Surface. 400 401 #Example 402 #Description 403 Dithering in the bottom half more closely approximates the requested color by 404 alternating nearby colors from pixel to pixel. 405 ## 406 void draw(SkCanvas* canvas) { 407 SkBitmap bm16; 408 bm16.allocPixels(SkImageInfo::Make(32, 32, kRGB_565_SkColorType, kOpaque_SkAlphaType)); 409 SkCanvas c16(bm16); 410 SkPaint colorPaint; 411 for (auto dither : { false, true } ) { 412 colorPaint.setDither(dither); 413 for (auto colors : { 0xFF333333, 0xFF666666, 0xFF999999, 0xFFCCCCCC } ) { 414 for (auto mask : { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFFFFFF } ) { 415 colorPaint.setColor(colors & mask); 416 c16.drawRect({0, 0, 8, 4}, colorPaint); 417 c16.translate(8, 0); 418 } 419 c16.translate(-32, 4); 420 } 421 } 422 canvas->scale(8, 8); 423 canvas->drawBitmap(bm16, 0, 0); 424 } 425 ## 426 427 #Example 428 #Description 429 Dithering introduces subtle adjustments to color to smooth gradients. 430 Drawing the gradient repeatedly with SkBlendMode::kPlus exaggerates the 431 dither, making it easier to see. 432 ## 433 void draw(SkCanvas* canvas) { 434 canvas->clear(0); 435 SkBitmap bm32; 436 bm32.allocPixels(SkImageInfo::Make(20, 10, kN32_SkColorType, kPremul_SkAlphaType)); 437 SkCanvas c32(bm32); 438 SkPoint points[] = {{0, 0}, {20, 0}}; 439 SkColor colors[] = {0xFF334455, 0xFF662211 }; 440 SkPaint paint; 441 paint.setShader(SkGradientShader::MakeLinear( 442 points, colors, nullptr, SK_ARRAY_COUNT(colors), 443 SkShader::kClamp_TileMode, 0, nullptr)); 444 paint.setDither(true); 445 c32.drawPaint(paint); 446 canvas->scale(12, 12); 447 canvas->drawBitmap(bm32, 0, 0); 448 paint.setBlendMode(SkBlendMode::kPlus); 449 canvas->drawBitmap(bm32, 0, 11, &paint); 450 canvas->drawBitmap(bm32, 0, 11, &paint); 451 canvas->drawBitmap(bm32, 0, 11, &paint); 452 } 453 ## 454 #SeeAlso Gradient kRGB_565_SkColorType 455 #Subtopic Dither ## 456 457 #Method bool isDither() const 458 #In Dither 459 #Line # returns true if Dither is set ## 460 #Populate 461 462 #Example 463 SkPaint paint; 464 SkDebugf("paint.isDither() %c= !!(paint.getFlags() & SkPaint::kDither_Flag)\n", 465 paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) ? '=' : '!'); 466 paint.setDither(true); 467 SkDebugf("paint.isDither() %c= !!(paint.getFlags() & SkPaint::kDither_Flag)\n", 468 paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) ? '=' : '!'); 469 470 #StdOut 471 paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) 472 paint.isDither() == !!(paint.getFlags() & SkPaint::kDither_Flag) 473 ## 474 ## 475 476 ## 477 478 #Method void setDither(bool dither) 479 #In Dither 480 #Line # sets or clears Dither ## 481 #Populate 482 483 #Example 484 SkPaint paint1, paint2; 485 paint1.setDither(true); 486 paint2.setFlags(paint2.getFlags() | SkPaint::kDither_Flag); 487 SkDebugf("paint1 %c= paint2\n", paint1 == paint2 ? '=' : '!'); 488 489 #StdOut 490 paint1 == paint2 491 ## 492 ## 493 494 #SeeAlso kRGB_565_SkColorType 495 496 ## 497 498 # ------------------------------------------------------------------------------ 499 #Subtopic Device_Text 500 #Line # increase precision of glyph position ## 501 502 Font_Anti_Alias and Font_Subpixel increase the precision of glyph position. 503 504 When set, Flags kLCDRenderText_Flag takes advantage of the organization of RGB stripes that 505 create a color, and relies 506 on the small size of the stripe and visual perception to make the color fringing imperceptible. 507 Font_Anti_Alias can be enabled on devices that orient stripes horizontally or vertically, and that order 508 the color components as RGB or BGR. 509 510 Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset. 511 As the opaqueness 512 of the color increases, the edge of the glyph appears to move towards the outside of the pixel. 513 514 Either or both techniques can be enabled. 515 kLCDRenderText_Flag and kSubpixelText_Flag are clear by default. 516 Font_Anti_Alias or Font_Subpixel can be enabled by default by setting SkPaintDefaults_Flags to 517 kLCDRenderText_Flag or kSubpixelText_Flag (or both) at compile time. 518 519 #Example 520 #Description 521 Four commas are drawn normally and with combinations of Font_Anti_Alias and Font_Subpixel. 522 When Font_Subpixel is disabled, the comma Glyphs are identical, but not evenly spaced. 523 When Font_Subpixel is enabled, the comma Glyphs are unique, but appear evenly spaced. 524 ## 525 526 SkBitmap bitmap; 527 bitmap.allocN32Pixels(24, 33); 528 SkCanvas offscreen(bitmap); 529 offscreen.clear(SK_ColorWHITE); 530 SkPaint paint; 531 paint.setAntiAlias(true); 532 paint.setTextSize(20); 533 for (bool lcd : { false, true }) { 534 paint.setLCDRenderText(lcd); 535 for (bool subpixel : { false, true }) { 536 paint.setSubpixelText(subpixel); 537 offscreen.drawString(",,,,", 0, 4, paint); 538 offscreen.translate(0, 7); 539 } 540 } 541 canvas->drawBitmap(bitmap, 4, 12); 542 canvas->scale(9, 9); 543 canvas->drawBitmap(bitmap, 4, -1); 544 ## 545 #Subtopic Device_Text ## 546 547 #Subtopic Linear_Text 548 #Line # selects text rendering as Glyph or Path ## 549 550 Font_Linear selects whether text is rendered as a Glyph or as a Path. 551 If Font_Linear is set, it has the same effect as setting Hinting to SkFontHinting::kNormal. 552 If Font_Linear is clear, it is the same as setting Hinting to SkFontHinting::kNone. 553 #Subtopic Linear_Text ## 554 555 #Subtopic Subpixel_Text 556 #Line # uses pixel transparency to represent fractional offset ## 557 558 Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset. 559 As the opaqueness 560 of the color increases, the edge of the glyph appears to move towards the outside of the pixel. 561 #Subtopic Subpixel_Text ## 562 563 #Subtopic LCD_Text 564 #Line # text relying on the order of RGB stripes ## 565 566 When set, Font_Anti_Alias takes advantage of the organization of RGB stripes that 567 create a color, and relies 568 on the small size of the stripe and visual perception to make the color fringing imperceptible. 569 Font_Anti_Alias can be enabled on devices that orient stripes horizontally or vertically, and that order 570 the color components as RGB or BGR. 571 #Subtopic LCD_Text ## 572 573 # ------------------------------------------------------------------------------ 574 #Subtopic Embedded_Bitmaps 575 #Line # custom sized bitmap Glyphs ## 576 577 Font_Embedded_Bitmaps allows selecting custom sized bitmap Glyphs. 578 Flags kEmbeddedBitmapText_Flag when set chooses an embedded bitmap glyph over an outline contained 579 in a font if the platform supports this option. 580 581 FreeType selects the bitmap glyph if available when kEmbeddedBitmapText_Flag is set, and selects 582 the outline glyph if kEmbeddedBitmapText_Flag is clear. 583 Windows may select the bitmap glyph but is not required to do so. 584 OS_X and iOS do not support this option. 585 586 Font_Embedded_Bitmaps is disabled by default. 587 Font_Embedded_Bitmaps can be enabled by default by setting SkPaintDefaults_Flags to 588 kEmbeddedBitmapText_Flag at compile time. 589 590 #Example 591 #ToDo image will only output on Ubuntu ... how to handle that in fiddle? ## 592 #Platform !fiddle 593 #Description 594 The "hintgasp" TrueType font in the Skia resources/fonts directory 595 includes an embedded bitmap Glyph at odd font sizes. This example works 596 on platforms that use FreeType as their Font_Engine. 597 Windows may, but is not required to, return a bitmap glyph if 598 kEmbeddedBitmapText_Flag is set. 599 ## 600 #Image embeddedbitmap.png 601 602 SkBitmap bitmap; 603 bitmap.allocN32Pixels(30, 15); 604 bitmap.eraseColor(0); 605 SkCanvas offscreen(bitmap); 606 SkPaint paint; 607 paint.setAntiAlias(true); 608 paint.setTextSize(13); 609 paint.setTypeface(MakeResourceAsTypeface("fonts/hintgasp.ttf")); 610 for (bool embedded : { false, true}) { 611 paint.setEmbeddedBitmapText(embedded); 612 offscreen.drawString("A", embedded ? 5 : 15, 15, paint); 613 } 614 canvas->drawBitmap(bitmap, 0, 0); 615 canvas->scale(10, 10); 616 canvas->drawBitmap(bitmap, -2, 1); 617 ## 618 #Subtopic Embedded_Bitmaps ## 619 620 # ------------------------------------------------------------------------------ 621 #Subtopic Automatic_Hinting 622 #Line # always adjust glyph paths ## 623 624 If Hinting is set to SkFontHinting::kNormal or SkFontHinting::kFull, Font_Force_Hinting 625 instructs the Font_Manager to always hint Glyphs. 626 Font_Force_Hinting has no effect if Hinting is set to SkFontHinting::kNone or 627 SkFontHinting::kSlight. 628 629 Font_Force_Hinting only affects platforms that use FreeType as the Font_Manager. 630 #Subtopic Automatic_Hinting ## 631 632 # ------------------------------------------------------------------------------ 633 634 #Subtopic Fake_Bold 635 #Line # approximate font styles ## 636 637 Font_Embolden approximates the bold font style accompanying a normal font when a bold font face 638 is not available. Skia does not provide font substitution; it is up to the client to find the 639 bold font face using the platform Font_Manager. 640 641 Use Text_Skew_X to approximate an italic font style when the italic font face 642 is not available. 643 644 A FreeType based port may define SK_USE_FREETYPE_EMBOLDEN at compile time to direct 645 the font engine to create the bold Glyphs. Otherwise, the extra bold is computed 646 by increasing the stroke width and setting the Style to kStrokeAndFill_Style as needed. 647 648 Font_Embolden is disabled by default. 649 650 #Example 651 #Height 128 652 void draw(SkCanvas* canvas) { 653 SkPaint paint; 654 paint.setAntiAlias(true); 655 paint.setTextSize(40); 656 canvas->drawString("OjYy_-", 10, 35, paint); 657 paint.setFakeBoldText(true); 658 canvas->drawString("OjYy_-", 10, 75, paint); 659 // create a custom fake bold by varying the stroke width 660 paint.setFakeBoldText(false); 661 paint.setStyle(SkPaint::kStrokeAndFill_Style); 662 paint.setStrokeWidth(40.f / 48); 663 canvas->drawString("OjYy_-", 10, 115, paint); 664 } 665 ## 666 #Subtopic Fake_Bold ## 667 668 # ------------------------------------------------------------------------------ 669 #Subtopic Filter_Quality_Methods 670 #Line # get and set Filter_Quality ## 671 672 Filter_Quality trades speed for image filtering when the image is scaled. 673 A lower Filter_Quality draws faster, but has less fidelity. 674 A higher Filter_Quality draws slower, but looks better. 675 If the image is drawn without scaling, the Filter_Quality choice will not result 676 in a noticeable difference. 677 678 Filter_Quality is used in Paint passed as a parameter to 679 #List 680 # SkCanvas::drawBitmap ## 681 # SkCanvas::drawBitmapRect ## 682 # SkCanvas::drawImage ## 683 # SkCanvas::drawImageRect ## 684 #ToDo probably more... ## 685 #List ## 686 and when Paint has a Shader specialization that uses Image or Bitmap. 687 688 Filter_Quality is kNone_SkFilterQuality by default. 689 690 #Example 691 #Image 3 692 void draw(SkCanvas* canvas) { 693 SkPaint paint; 694 canvas->scale(.2f, .2f); 695 for (SkFilterQuality q : { kNone_SkFilterQuality, kLow_SkFilterQuality, 696 kMedium_SkFilterQuality, kHigh_SkFilterQuality } ) { 697 paint.setFilterQuality(q); 698 canvas->drawImage(image.get(), 0, 0, &paint); 699 canvas->translate(550, 0); 700 if (kLow_SkFilterQuality == q) canvas->translate(-1100, 550); 701 } 702 } 703 ## 704 #Subtopic Filter_Quality_Methods ## 705 706 #Method SkFilterQuality getFilterQuality() const 707 #In Filter_Quality_Methods 708 #Line # returns Filter_Quality, image filtering level ## 709 #Populate 710 711 #Example 712 SkPaint paint; 713 SkDebugf("kNone_SkFilterQuality %c= paint.getFilterQuality()\n", 714 kNone_SkFilterQuality == paint.getFilterQuality() ? '=' : '!'); 715 716 #StdOut 717 kNone_SkFilterQuality == paint.getFilterQuality() 718 ## 719 ## 720 721 ## 722 723 724 #Method void setFilterQuality(SkFilterQuality quality) 725 #In Filter_Quality_Methods 726 #Line # sets Filter_Quality, the image filtering level ## 727 #Populate 728 729 #Example 730 SkPaint paint; 731 paint.setFilterQuality(kHigh_SkFilterQuality); 732 SkDebugf("kHigh_SkFilterQuality %c= paint.getFilterQuality()\n", 733 kHigh_SkFilterQuality == paint.getFilterQuality() ? '=' : '!'); 734 735 #StdOut 736 kHigh_SkFilterQuality == paint.getFilterQuality() 737 ## 738 ## 739 740 #SeeAlso SkFilterQuality Image_Scaling 741 742 ## 743 744 # ------------------------------------------------------------------------------ 745 #Subtopic Color_Methods 746 #Line # get and set Color ## 747 748 #Table 749 #Legend 750 # name # description ## 751 #Legend ## 752 # getColor # returns Color_Alpha and RGB, one drawing color ## 753 # setColor # sets Color_Alpha and RGB, one drawing color ## 754 #Table ## 755 756 Color specifies the red, blue, green, and Color_Alpha 757 values used to draw a filled or stroked shape in a 32-bit value. Each component 758 occupies 8-bits, ranging from zero: no contribution; to 255: full intensity. 759 All values in any combination are valid. 760 761 Color is not Premultiplied; Color_Alpha sets the transparency independent of 762 RGB: red, blue, and green. 763 764 The bit positions of Color_Alpha and RGB are independent of the bit 765 positions on the output device, which may have more or fewer bits, and may have 766 a different arrangement. 767 768 #Table 769 #Legend 770 # bit positions # Color_Alpha # red # blue # green ## 771 #Legend ## 772 # # 31 - 24 # 23 - 16 # 15 - 8 # 7 - 0 ## 773 #Table ## 774 775 #Example 776 #Height 128 777 void draw(SkCanvas* canvas) { 778 SkPaint paint; 779 paint.setColor(0x8000FF00); // transparent green 780 canvas->drawCircle(50, 50, 40, paint); 781 paint.setARGB(128, 255, 0, 0); // transparent red 782 canvas->drawCircle(80, 50, 40, paint); 783 paint.setColor(SK_ColorBLUE); 784 paint.setAlpha(0x80); 785 canvas->drawCircle(65, 65, 40, paint); 786 } 787 ## 788 #Subtopic Color_Methods ## 789 790 #Method SkColor getColor() const 791 #In Color_Methods 792 #Line # returns Color_Alpha and RGB, one drawing color ## 793 #Populate 794 795 #Example 796 SkPaint paint; 797 paint.setColor(SK_ColorYELLOW); 798 SkColor y = paint.getColor(); 799 SkDebugf("Yellow is %d%% red, %d%% green, and %d%% blue.\n", (int) (SkColorGetR(y) / 2.55f), 800 (int) (SkColorGetG(y) / 2.55f), (int) (SkColorGetB(y) / 2.55f)); 801 802 #StdOut 803 Yellow is 100% red, 100% green, and 0% blue. 804 ## 805 ## 806 807 #SeeAlso getColor4f SkColor 808 809 ## 810 811 #Method SkColor4f getColor4f() const 812 #In Color_Methods 813 #Line # returns Color_Alpha and RGB, one drawing color ## 814 #Populate 815 816 #Example 817 SkPaint paint; 818 paint.setColor(SK_ColorYELLOW); 819 SkColor4f y = paint.getColor4f(); 820 SkDebugf("Yellow is %d%% red, %d%% green, and %d%% blue.\n", (int) (y.fR * 100), 821 (int) (y.fG * 100), (int) (y.fB * 100)); 822 823 #StdOut 824 Yellow is 100% red, 100% green, and 0% blue. 825 ## 826 ## 827 828 #SeeAlso getColor SkColor 829 ## 830 831 832 #Method void setColor(SkColor color) 833 #In Color_Methods 834 #Line # sets Color_Alpha and RGB, one drawing color ## 835 #Populate 836 837 #Example 838 SkPaint green1, green2; 839 unsigned a = 255; 840 unsigned r = 0; 841 unsigned g = 255; 842 unsigned b = 0; 843 green1.setColor((a << 24) + (r << 16) + (g << 8) + (b << 0)); 844 green2.setColor(0xFF00FF00); 845 SkDebugf("green1 %c= green2\n", green1 == green2 ? '=' : '!'); 846 847 #StdOut 848 green1 == green2 849 ## 850 ## 851 852 #SeeAlso SkColor setColor4f setARGB SkColorSetARGB 853 854 ## 855 856 #Method void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace) 857 #In Color_Methods 858 #Line # sets Color_Alpha and RGB, one drawing color ## 859 #Populate 860 861 #Example 862 SkPaint green1, green2; 863 green1.setColor4f({0, 1, 0, 1}, nullptr); // R=0 G=1 B=0 A=1 864 green2.setColor(0xFF00FF00); // A=255 R=0 G=255 B=0 865 SkDebugf("green1 %c= green2\n", green1 == green2 ? '=' : '!'); 866 867 #StdOut 868 green1 == green2 869 ## 870 ## 871 872 #SeeAlso SkColor setColor setARGB SkColorSetARGB 873 874 ## 875 876 #Subtopic Alpha_Methods 877 #Line # get and set Alpha ## 878 879 Color_Alpha sets the transparency independent of RGB: red, blue, and green. 880 #Subtopic Alpha_Methods ## 881 882 #Method uint8_t getAlpha() const 883 #In Alpha_Methods 884 #Line # returns Color_Alpha, color opacity ## 885 #Populate 886 887 #Example 888 SkPaint paint; 889 SkDebugf("255 %c= paint.getAlpha()\n", 255 == paint.getAlpha() ? '=' : '!'); 890 891 #StdOut 892 255 == paint.getAlpha() 893 ## 894 ## 895 896 ## 897 898 #Method void setAlpha(U8CPU a) 899 #In Alpha_Methods 900 #Line # sets Color_Alpha, color opacity ## 901 #Populate 902 903 #Example 904 SkPaint paint; 905 paint.setColor(0x00112233); 906 paint.setAlpha(0x44); 907 SkDebugf("0x44112233 %c= paint.getColor()\n", 0x44112233 == paint.getColor() ? '=' : '!'); 908 909 #StdOut 910 0x44112233 == paint.getColor() 911 ## 912 ## 913 914 ## 915 916 #Method void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) 917 #In Color_Methods 918 #Line # sets color by component ## 919 #Populate 920 921 #Example 922 SkPaint transRed1, transRed2; 923 transRed1.setARGB(255 / 2, 255, 0, 0); 924 transRed2.setColor(SkColorSetARGB(255 / 2, 255, 0, 0)); 925 SkDebugf("transRed1 %c= transRed2", transRed1 == transRed2 ? '=' : '!'); 926 927 #StdOut 928 transRed1 == transRed2 929 ## 930 ## 931 932 #SeeAlso setColor SkColorSetARGB 933 934 ## 935 936 # ------------------------------------------------------------------------------ 937 #Subtopic Style 938 #Line # geometry filling, stroking ## 939 940 Style specifies if the geometry is filled, stroked, or both filled and stroked. 941 Some shapes ignore Style and are always drawn filled or stroked. 942 943 #Subtopic Fill 944 Set Style to kFill_Style to fill the shape. 945 The fill covers the area inside the geometry for most shapes. 946 #Subtopic Fill ## 947 948 #Subtopic Stroke 949 Set Style to kStroke_Style to stroke the shape. 950 951 The stroke covers the area described by following the shape edge with a pen or brush of 952 Stroke_Width. The area covered where the shape starts and stops is described by Stroke_Cap. 953 The area covered where the shape turns a corner is described by Stroke_Join. 954 The stroke is centered on the shape; it extends equally on either side of the shape edge. 955 #Subtopic Stroke ## 956 957 As Stroke_Width gets smaller, the drawn path frame is thinner. Stroke_Width less than one 958 may have gaps, and if kAntiAlias_Flag is set, Color_Alpha will increase to visually decrease coverage. 959 960 #SeeAlso Path_Fill_Type Path_Effect Style_Fill Style_Stroke 961 #Subtopic Style ## 962 963 #Subtopic Hairline 964 Stroke_Width of zero has a special meaning and switches drawing to use Hairline. 965 Hairline draws the thinnest continuous frame. If kAntiAlias_Flag is clear, adjacent pixels 966 flow horizontally, vertically,or diagonally. 967 968 #ToDo what is the description of Anti_Aliased hairlines? ## 969 970 Path drawing with Hairline may hit the same pixel more than once. For instance, Path containing 971 two lines in one Path_Contour will draw the corner point once, but may both lines may draw the adjacent 972 pixel. If kAntiAlias_Flag is set, transparency is applied twice, resulting in a darker pixel. Some 973 GPU-backed implementations apply transparency at a later drawing stage, avoiding double hit pixels 974 while stroking. 975 976 #SeeAlso Path_Fill_Type Path_Effect Style_Fill Style_Stroke 977 #Subtopic Hairline ## 978 979 #Enum Style 980 #Line # stroke, fill, or both ## 981 982 #Code 983 #Populate 984 ## 985 986 #Code 987 #In Constant 988 #Filter kStyle 989 #Populate 990 ## 991 992 Set Style to fill, stroke, or both fill and stroke geometry. 993 The stroke and fill 994 share all paint attributes; for instance, they are drawn with the same color. 995 996 Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and 997 a fill draw. 998 999 #Const kFill_Style 0 1000 #Line # set to fill geometry ## 1001 Applies to Rect, Region, Round_Rect, Circles, Ovals, Path, and Text. 1002 Bitmap, Image, Patches, Region, Sprites, and Vertices are painted as if 1003 kFill_Style is set, and ignore the set Style. 1004 The Path_Fill_Type specifies additional rules to fill the area outside the path edge, 1005 and to create an unfilled hole inside the shape. 1006 Style is set to kFill_Style by default. 1007 ## 1008 1009 #Const kStroke_Style 1 1010 #Line # set to stroke geometry ## 1011 Applies to Rect, Region, Round_Rect, Arcs, Circles, Ovals, Path, and Text. 1012 Arcs, Lines, and points, are always drawn as if kStroke_Style is set, 1013 and ignore the set Style. 1014 The stroke construction is unaffected by the Path_Fill_Type. 1015 ## 1016 1017 #Const kStrokeAndFill_Style 2 1018 #Line # sets to stroke and fill geometry ## 1019 Applies to Rect, Region, Round_Rect, Circles, Ovals, Path, and Text. 1020 Path is treated as if it is set to SkPath::kWinding_FillType, 1021 and the set Path_Fill_Type is ignored. 1022 ## 1023 1024 #Const kStyleCount 3 1025 #Line # number of different Style values defined ## 1026 May be used to verify that Style is a legal value. 1027 ## 1028 1029 #Enum Style ## 1030 1031 #Method Style getStyle() const 1032 #In Style 1033 #Line # returns Style: stroke, fill, or both ## 1034 #Populate 1035 1036 #Example 1037 SkPaint paint; 1038 SkDebugf("SkPaint::kFill_Style %c= paint.getStyle()\n", 1039 SkPaint::kFill_Style == paint.getStyle() ? '=' : '!'); 1040 1041 #StdOut 1042 SkPaint::kFill_Style == paint.getStyle() 1043 ## 1044 ## 1045 1046 #SeeAlso Style setStyle 1047 ## 1048 1049 #Method void setStyle(Style style) 1050 #In Style 1051 #Line # sets Style: stroke, fill, or both ## 1052 #Populate 1053 1054 #Example 1055 void draw(SkCanvas* canvas) { 1056 SkPaint paint; 1057 paint.setStrokeWidth(5); 1058 SkRegion region; 1059 region.op(140, 10, 160, 30, SkRegion::kUnion_Op); 1060 region.op(170, 40, 190, 60, SkRegion::kUnion_Op); 1061 SkBitmap bitmap; 1062 bitmap.setInfo(SkImageInfo::MakeA8(50, 50), 50); 1063 uint8_t pixels[50][50]; 1064 for (int x = 0; x < 50; ++x) { 1065 for (int y = 0; y < 50; ++y) { 1066 pixels[y][x] = (x + y) % 5 ? 0xFF : 0x00; 1067 } 1068 } 1069 bitmap.setPixels(pixels); 1070 for (auto style : { SkPaint::kFill_Style, 1071 SkPaint::kStroke_Style, 1072 SkPaint::kStrokeAndFill_Style }) { 1073 paint.setStyle(style); 1074 canvas->drawLine(10, 10, 60, 60, paint); 1075 canvas->drawRect({80, 10, 130, 60}, paint); 1076 canvas->drawRegion(region, paint); 1077 canvas->drawBitmap(bitmap, 200, 10, &paint); 1078 canvas->translate(0, 80); 1079 } 1080 } 1081 ## 1082 1083 #SeeAlso Style getStyle 1084 ## 1085 1086 # ------------------------------------------------------------------------------ 1087 #Subtopic Stroke_Width 1088 #Line # thickness perpendicular to geometry ## 1089 1090 Stroke_Width sets the width for stroking. The width is the thickness 1091 of the stroke perpendicular to the path direction when the paint style is 1092 set to kStroke_Style or kStrokeAndFill_Style. 1093 1094 When width is greater than zero, the stroke encompasses as many pixels partially 1095 or fully as needed. When the width equals zero, the paint enables hairlines; 1096 the stroke is always one pixel wide. 1097 1098 The stroke dimensions are scaled by the canvas matrix, but Hairline stroke 1099 remains one pixel wide regardless of scaling. 1100 1101 The default width for the paint is zero. 1102 1103 #Example 1104 #Height 170 1105 #Platform raster gpu 1106 #Description 1107 The pixels hit to represent thin lines vary with the angle of the 1108 line and the platform implementation. 1109 ## 1110 void draw(SkCanvas* canvas) { 1111 SkPaint paint; 1112 for (bool antialias : { false, true }) { 1113 paint.setAntiAlias(antialias); 1114 for (int width = 0; width <= 4; ++width) { 1115 SkScalar offset = antialias * 100 + width * 20; 1116 paint.setStrokeWidth(width * 0.25f); 1117 canvas->drawLine(10 + offset, 10, 20 + offset, 60, paint); 1118 canvas->drawLine(10 + offset, 110, 60 + offset, 160, paint); 1119 } 1120 } 1121 } 1122 ## 1123 1124 #Method SkScalar getStrokeWidth() const 1125 1126 #In Stroke_Width 1127 #Line # returns thickness of the stroke ## 1128 #Populate 1129 1130 #Example 1131 SkPaint paint; 1132 SkDebugf("0 %c= paint.getStrokeWidth()\n", 0 == paint.getStrokeWidth() ? '=' : '!'); 1133 1134 #StdOut 1135 0 == paint.getStrokeWidth() 1136 ## 1137 ## 1138 1139 ## 1140 1141 #Method void setStrokeWidth(SkScalar width) 1142 1143 #In Stroke_Width 1144 #Line # sets thickness of the stroke ## 1145 #Populate 1146 1147 #Example 1148 SkPaint paint; 1149 paint.setStrokeWidth(5); 1150 paint.setStrokeWidth(-1); 1151 SkDebugf("5 %c= paint.getStrokeWidth()\n", 5 == paint.getStrokeWidth() ? '=' : '!'); 1152 1153 #StdOut 1154 5 == paint.getStrokeWidth() 1155 ## 1156 ## 1157 1158 ## 1159 1160 #Subtopic Stroke_Width ## 1161 # ------------------------------------------------------------------------------ 1162 #Subtopic Miter_Limit 1163 #Line # maximum length of stroked corners ## 1164 1165 Miter_Limit specifies the maximum miter length, 1166 relative to the stroke width. 1167 1168 Miter_Limit is used when the Stroke_Join 1169 is set to kMiter_Join, and the Style is either kStroke_Style 1170 or kStrokeAndFill_Style. 1171 1172 If the miter at a corner exceeds this limit, kMiter_Join 1173 is replaced with kBevel_Join. 1174 1175 Miter_Limit can be computed from the corner angle using: 1176 #Formula # miter limit = 1 / sin ( angle / 2 ) ##. 1177 1178 Miter_Limit default value is 4. 1179 The default may be changed at compile time by setting SkPaintDefaults_MiterLimit 1180 in "SkUserConfig.h" or as a define supplied by the build environment. 1181 1182 Here are some miter limits and the angles that triggers them. 1183 #Table 1184 #Legend 1185 # miter limit # angle in degrees ## 1186 #Legend ## 1187 # 10 # 11.48 ## 1188 # 9 # 12.76 ## 1189 # 8 # 14.36 ## 1190 # 7 # 16.43 ## 1191 # 6 # 19.19 ## 1192 # 5 # 23.07 ## 1193 # 4 # 28.96 ## 1194 # 3 # 38.94 ## 1195 # 2 # 60 ## 1196 # 1 # 180 ## 1197 #Table ## 1198 1199 #Example 1200 #Height 170 1201 #Width 384 1202 #Description 1203 This example draws a stroked corner and the miter length beneath. 1204 When the miter limit is decreased slightly, the miter join is replaced 1205 by a bevel join. 1206 ## 1207 void draw(SkCanvas* canvas) { 1208 SkPoint pts[] = {{ 10, 50 }, { 110, 80 }, { 10, 110 }}; 1209 SkVector v[] = { pts[0] - pts[1], pts[2] - pts[1] }; 1210 SkScalar angle1 = SkScalarATan2(v[0].fY, v[0].fX); 1211 SkScalar angle2 = SkScalarATan2(v[1].fY, v[1].fX); 1212 const SkScalar strokeWidth = 20; 1213 SkScalar miterLimit = 1 / SkScalarSin((angle2 - angle1) / 2); 1214 SkScalar miterLength = strokeWidth * miterLimit; 1215 SkPath path; 1216 path.moveTo(pts[0]); 1217 path.lineTo(pts[1]); 1218 path.lineTo(pts[2]); 1219 SkPaint paint; // set to default kMiter_Join 1220 paint.setAntiAlias(true); 1221 paint.setStyle(SkPaint::kStroke_Style); 1222 paint.setStrokeMiter(miterLimit); 1223 paint.setStrokeWidth(strokeWidth); 1224 canvas->drawPath(path, paint); 1225 paint.setStrokeWidth(1); 1226 canvas->drawLine(pts[1].fX - miterLength / 2, pts[1].fY + 50, 1227 pts[1].fX + miterLength / 2, pts[1].fY + 50, paint); 1228 canvas->translate(200, 0); 1229 miterLimit *= 0.99f; 1230 paint.setStrokeMiter(miterLimit); 1231 paint.setStrokeWidth(strokeWidth); 1232 canvas->drawPath(path, paint); 1233 paint.setStrokeWidth(1); 1234 canvas->drawLine(pts[1].fX - miterLength / 2, pts[1].fY + 50, 1235 pts[1].fX + miterLength / 2, pts[1].fY + 50, paint); 1236 } 1237 ## 1238 1239 #Method SkScalar getStrokeMiter() const 1240 1241 #In Miter_Limit 1242 #Line # returns Miter_Limit, angles with sharp corners ## 1243 #Populate 1244 1245 #Example 1246 SkPaint paint; 1247 SkDebugf("default miter limit == %g\n", paint.getStrokeMiter()); 1248 1249 #StdOut 1250 default miter limit == 4 1251 ## 1252 ## 1253 1254 #SeeAlso Miter_Limit setStrokeMiter Join 1255 1256 ## 1257 1258 #Method void setStrokeMiter(SkScalar miter) 1259 1260 #In Miter_Limit 1261 #Line # sets Miter_Limit, angles with sharp corners ## 1262 #Populate 1263 1264 #Example 1265 SkPaint paint; 1266 paint.setStrokeMiter(8); 1267 paint.setStrokeMiter(-1); 1268 SkDebugf("default miter limit == %g\n", paint.getStrokeMiter()); 1269 1270 #StdOut 1271 default miter limit == 8 1272 ## 1273 ## 1274 1275 #SeeAlso Miter_Limit getStrokeMiter Join 1276 1277 ## 1278 1279 #Subtopic Miter_Limit ## 1280 # ------------------------------------------------------------------------------ 1281 #Subtopic Stroke_Cap 1282 #Line # decorations at ends of open strokes ## 1283 #Subtopic Stroke_Cap ## 1284 1285 #Enum Cap 1286 #Line # start and end geometry on stroked shapes ## 1287 1288 #Code 1289 #Populate 1290 ## 1291 1292 #Code 1293 #In Constant 1294 #Filter kCap 1295 #Populate 1296 ## 1297 1298 Stroke_Cap draws at the beginning and end of an open Path_Contour. 1299 1300 #Const kButt_Cap 0 1301 #Line # no stroke extension ## 1302 Does not extend the stroke past the beginning or the end. 1303 ## 1304 #Const kRound_Cap 1 1305 #Line # adds circle ## 1306 Adds a circle with a diameter equal to Stroke_Width at the beginning 1307 and end. 1308 ## 1309 #Const kSquare_Cap 2 1310 #Line # adds square ## 1311 Adds a square with sides equal to Stroke_Width at the beginning 1312 and end. The square sides are parallel to the initial and final direction 1313 of the stroke. 1314 ## 1315 #Const kLast_Cap 2 1316 #Line # largest Stroke_Cap value ## 1317 Equivalent to the largest value for Stroke_Cap. 1318 ## 1319 #Const kDefault_Cap 0 1320 #Line # equivalent to kButt_Cap ## 1321 Stroke_Cap is set to kButt_Cap by default. 1322 ## 1323 1324 #Const kCapCount 3 1325 #Line # number of different Stroke_Cap values defined ## 1326 May be used to verify that Stroke_Cap is a legal value. 1327 ## 1328 #Enum ## 1329 1330 Stroke describes the area covered by a pen of Stroke_Width as it 1331 follows the Path_Contour, moving parallel to the contour direction. 1332 1333 If the Path_Contour is not terminated by SkPath::kClose_Verb, the contour has a 1334 visible beginning and end. 1335 1336 Path_Contour may start and end at the same point; defining Zero_Length_Contour. 1337 1338 kButt_Cap and Zero_Length_Contour is not drawn. 1339 kRound_Cap and Zero_Length_Contour draws a circle of diameter Stroke_Width 1340 at the contour point. 1341 kSquare_Cap and Zero_Length_Contour draws an upright square with a side of 1342 Stroke_Width at the contour point. 1343 1344 Stroke_Cap is kButt_Cap by default. 1345 1346 #Example 1347 #Height 200 1348 SkPaint paint; 1349 paint.setStyle(SkPaint::kStroke_Style); 1350 paint.setStrokeWidth(20); 1351 SkPath path; 1352 path.moveTo(30, 30); 1353 path.lineTo(30, 30); 1354 path.moveTo(70, 30); 1355 path.lineTo(90, 40); 1356 for (SkPaint::Cap c : { SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap } ) { 1357 paint.setStrokeCap(c); 1358 canvas->drawPath(path, paint); 1359 canvas->translate(0, 70); 1360 } 1361 ## 1362 1363 #Method Cap getStrokeCap() const 1364 1365 #In Stroke_Cap 1366 #Line # returns Cap, the area drawn at path ends ## 1367 #Populate 1368 1369 #Example 1370 SkPaint paint; 1371 SkDebugf("kButt_Cap %c= default stroke cap\n", 1372 SkPaint::kButt_Cap == paint.getStrokeCap() ? '=' : '!'); 1373 1374 #StdOut 1375 kButt_Cap == default stroke cap 1376 ## 1377 ## 1378 1379 #SeeAlso Stroke_Cap setStrokeCap 1380 ## 1381 1382 #Method void setStrokeCap(Cap cap) 1383 1384 #In Stroke_Cap 1385 #Line # sets Cap, the area drawn at path ends ## 1386 #Populate 1387 1388 #Example 1389 SkPaint paint; 1390 paint.setStrokeCap(SkPaint::kRound_Cap); 1391 paint.setStrokeCap((SkPaint::Cap) SkPaint::kCapCount); 1392 SkDebugf("kRound_Cap %c= paint.getStrokeCap()\n", 1393 SkPaint::kRound_Cap == paint.getStrokeCap() ? '=' : '!'); 1394 1395 #StdOut 1396 kRound_Cap == paint.getStrokeCap() 1397 ## 1398 ## 1399 1400 #SeeAlso Stroke_Cap getStrokeCap 1401 ## 1402 1403 # ------------------------------------------------------------------------------ 1404 #Subtopic Stroke_Join 1405 #Line # decoration at corners of strokes ## 1406 #Subtopic Stroke_Join ## 1407 1408 Stroke_Join draws at the sharp corners of an open or closed Path_Contour. 1409 1410 Stroke describes the area covered by a pen of Stroke_Width as it 1411 follows the Path_Contour, moving parallel to the contour direction. 1412 1413 If the contour direction changes abruptly, because the tangent direction leading 1414 to the end of a curve within the contour does not match the tangent direction of 1415 the following curve, the pair of curves meet at Stroke_Join. 1416 1417 #Example 1418 #Height 200 1419 SkPaint paint; 1420 paint.setStyle(SkPaint::kStroke_Style); 1421 paint.setStrokeWidth(20); 1422 SkPath path; 1423 path.moveTo(30, 20); 1424 path.lineTo(40, 40); 1425 path.conicTo(70, 20, 100, 20, .707f); 1426 for (SkPaint::Join j : { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join } ) { 1427 paint.setStrokeJoin(j); 1428 canvas->drawPath(path, paint); 1429 canvas->translate(0, 70); 1430 } 1431 ## 1432 1433 #Enum Join 1434 #Line # corner geometry on stroked shapes ## 1435 #Code 1436 #Populate 1437 ## 1438 1439 #Code 1440 #In Constant 1441 #Filter kJoin 1442 #Populate 1443 ## 1444 1445 Join specifies how corners are drawn when a shape is stroked. Join 1446 affects the four corners of a stroked rectangle, and the connected segments in a 1447 stroked path. 1448 1449 Choose miter join to draw sharp corners. Choose round join to draw a circle with a 1450 radius equal to the stroke width on top of the corner. Choose bevel join to minimally 1451 connect the thick strokes. 1452 1453 The fill path constructed to describe the stroked path respects the join setting but may 1454 not contain the actual join. For instance, a fill path constructed with round joins does 1455 not necessarily include circles at each connected segment. 1456 1457 #Const kMiter_Join 0 1458 #Line # extends to Miter_Limit ## 1459 Extends the outside corner to the extent allowed by Miter_Limit. 1460 If the extension exceeds Miter_Limit, kBevel_Join is used instead. 1461 ## 1462 1463 #Const kRound_Join 1 1464 #Line # adds circle ## 1465 Adds a circle with a diameter of Stroke_Width at the sharp corner. 1466 ## 1467 1468 #Const kBevel_Join 2 1469 #Line # connects outside edges ## 1470 Connects the outside edges of the sharp corner. 1471 ## 1472 1473 #Const kLast_Join 2 1474 #Line # equivalent to the largest value for Stroke_Join ## 1475 ## 1476 1477 #Const kDefault_Join 1 1478 #Line # equivalent to kMiter_Join ## 1479 Stroke_Join is set to kMiter_Join by default. 1480 ## 1481 1482 #Const kJoinCount 3 1483 #Line # number of different Stroke_Join values defined ## 1484 May be used to verify that Stroke_Join is a legal value. 1485 ## 1486 1487 #Example 1488 #Width 462 1489 void draw(SkCanvas* canvas) { 1490 SkPath path; 1491 path.moveTo(10, 50); 1492 path.quadTo(35, 110, 60, 210); 1493 path.quadTo(105, 110, 130, 10); 1494 SkPaint paint; // set to default kMiter_Join 1495 paint.setAntiAlias(true); 1496 paint.setStyle(SkPaint::kStroke_Style); 1497 paint.setStrokeWidth(20); 1498 canvas->drawPath(path, paint); 1499 canvas->translate(150, 0); 1500 paint.setStrokeJoin(SkPaint::kBevel_Join); 1501 canvas->drawPath(path, paint); 1502 canvas->translate(150, 0); 1503 paint.setStrokeJoin(SkPaint::kRound_Join); 1504 canvas->drawPath(path, paint); 1505 } 1506 ## 1507 1508 #SeeAlso setStrokeJoin getStrokeJoin setStrokeMiter getStrokeMiter 1509 1510 #Enum ## 1511 1512 #Method Join getStrokeJoin() const 1513 1514 #In Stroke_Join 1515 #Line # returns Join, geometry on path corners ## 1516 #Populate 1517 1518 #Example 1519 SkPaint paint; 1520 SkDebugf("kMiter_Join %c= default stroke join\n", 1521 SkPaint::kMiter_Join == paint.getStrokeJoin() ? '=' : '!'); 1522 1523 #StdOut 1524 kMiter_Join == default stroke join 1525 ## 1526 ## 1527 1528 #SeeAlso Stroke_Join setStrokeJoin 1529 ## 1530 1531 #Method void setStrokeJoin(Join join) 1532 1533 #In Stroke_Join 1534 #Line # sets Join, geometry on path corners ## 1535 #Populate 1536 1537 #Example 1538 SkPaint paint; 1539 paint.setStrokeJoin(SkPaint::kMiter_Join); 1540 paint.setStrokeJoin((SkPaint::Join) SkPaint::kJoinCount); 1541 SkDebugf("kMiter_Join %c= paint.getStrokeJoin()\n", 1542 SkPaint::kMiter_Join == paint.getStrokeJoin() ? '=' : '!'); 1543 1544 #StdOut 1545 kMiter_Join == paint.getStrokeJoin() 1546 ## 1547 ## 1548 1549 #SeeAlso Stroke_Join getStrokeJoin 1550 ## 1551 1552 #SeeAlso Miter_Limit 1553 1554 # ------------------------------------------------------------------------------ 1555 #Subtopic Fill_Path 1556 #Line # make Path from Path_Effect, stroking ## 1557 1558 Fill_Path creates a Path by applying the Path_Effect, followed by the Style_Stroke. 1559 1560 If Paint contains Path_Effect, Path_Effect operates on the source Path; the result 1561 replaces the destination Path. Otherwise, the source Path is replaces the 1562 destination Path. 1563 1564 Fill Path can request the Path_Effect to restrict to a culling rectangle, but 1565 the Path_Effect is not required to do so. 1566 1567 If Style is kStroke_Style or kStrokeAndFill_Style, 1568 and Stroke_Width is greater than zero, the Stroke_Width, Stroke_Cap, Stroke_Join, 1569 and Miter_Limit operate on the destination Path, replacing it. 1570 1571 Fill Path can specify the precision used by Stroke_Width to approximate the stroke geometry. 1572 1573 If the Style is kStroke_Style and the Stroke_Width is zero, getFillPath 1574 returns false since Hairline has no filled equivalent. 1575 1576 #SeeAlso Style_Stroke Stroke_Width Path_Effect 1577 1578 #Subtopic Fill_Path ## 1579 1580 #Method bool getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, 1581 SkScalar resScale = 1) const 1582 #In Fill_Path 1583 #Line # returns fill path equivalent to stroke ## 1584 #Populate 1585 1586 #Example 1587 #Height 192 1588 #Description 1589 A very small Quad stroke is turned into a filled path with increasing levels of precision. 1590 At the lowest precision, the Quad stroke is approximated by a rectangle. 1591 At the highest precision, the filled path has high fidelity compared to the original stroke. 1592 ## 1593 void draw(SkCanvas* canvas) { 1594 SkPaint strokePaint; 1595 strokePaint.setAntiAlias(true); 1596 strokePaint.setStyle(SkPaint::kStroke_Style); 1597 strokePaint.setStrokeWidth(.1f); 1598 SkPath strokePath; 1599 strokePath.moveTo(.08f, .08f); 1600 strokePath.quadTo(.09f, .08f, .17f, .17f); 1601 SkPath fillPath; 1602 SkPaint outlinePaint(strokePaint); 1603 outlinePaint.setStrokeWidth(2); 1604 SkMatrix scale = SkMatrix::MakeScale(300, 300); 1605 for (SkScalar precision : { 0.01f, .1f, 1.f, 10.f, 100.f } ) { 1606 strokePaint.getFillPath(strokePath, &fillPath, nullptr, precision); 1607 fillPath.transform(scale); 1608 canvas->drawPath(fillPath, outlinePaint); 1609 canvas->translate(60, 0); 1610 if (1.f == precision) canvas->translate(-180, 100); 1611 } 1612 strokePath.transform(scale); 1613 strokePaint.setStrokeWidth(30); 1614 canvas->drawPath(strokePath, strokePaint); 1615 } 1616 ## 1617 1618 ## 1619 1620 #Method bool getFillPath(const SkPath& src, SkPath* dst) const 1621 1622 #In Fill_Path 1623 #Populate 1624 1625 #Example 1626 #Height 128 1627 void draw(SkCanvas* canvas) { 1628 SkPaint paint; 1629 paint.setStyle(SkPaint::kStroke_Style); 1630 paint.setStrokeWidth(10); 1631 SkPath strokePath; 1632 strokePath.moveTo(20, 20); 1633 strokePath.lineTo(100, 100); 1634 canvas->drawPath(strokePath, paint); 1635 SkPath fillPath; 1636 paint.getFillPath(strokePath, &fillPath); 1637 paint.setStrokeWidth(2); 1638 canvas->translate(40, 0); 1639 canvas->drawPath(fillPath, paint); 1640 } 1641 ## 1642 1643 ## 1644 1645 # ------------------------------------------------------------------------------ 1646 #Subtopic Shader_Methods 1647 #Line # get and set Shader ## 1648 1649 Shader defines the colors used when drawing a shape. 1650 Shader may be an image, a gradient, or a computed fill. 1651 If Paint has no Shader, then Color fills the shape. 1652 1653 Shader is modulated by Color_Alpha component of Color. 1654 If Shader object defines only Color_Alpha, then Color modulated by Color_Alpha describes 1655 the fill. 1656 1657 The drawn transparency can be modified without altering Shader, by changing Color_Alpha. 1658 1659 #Example 1660 void draw(SkCanvas* canvas) { 1661 SkPaint paint; 1662 SkPoint center = { 50, 50 }; 1663 SkScalar radius = 50; 1664 const SkColor colors[] = { 0xFFFFFFFF, 0xFF000000 }; 1665 paint.setShader(SkGradientShader::MakeRadial(center, radius, colors, 1666 nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode)); 1667 for (SkScalar a : { 0.3f, 0.6f, 1.0f } ) { 1668 paint.setAlpha((int) (a * 255)); 1669 canvas->drawCircle(center.fX, center.fY, radius, paint); 1670 canvas->translate(70, 70); 1671 } 1672 } 1673 ## 1674 1675 If Shader generates only Color_Alpha then all components of Color modulate the output. 1676 1677 #Example 1678 void draw(SkCanvas* canvas) { 1679 SkPaint paint; 1680 SkBitmap bitmap; 1681 bitmap.setInfo(SkImageInfo::MakeA8(5, 1), 5); // bitmap only contains alpha 1682 uint8_t pixels[5] = { 0x22, 0x55, 0x88, 0xBB, 0xFF }; 1683 bitmap.setPixels(pixels); 1684 paint.setShader(SkShader::MakeBitmapShader(bitmap, 1685 SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)); 1686 for (SkColor c : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) { 1687 paint.setColor(c); // all components in color affect shader 1688 canvas->drawCircle(50, 50, 50, paint); 1689 canvas->translate(70, 70); 1690 } 1691 } 1692 ## 1693 1694 #Method SkShader* getShader() const 1695 1696 #In Shader_Methods 1697 #Line # returns Shader, multiple drawing colors; gradients ## 1698 #Populate 1699 1700 #Example 1701 void draw(SkCanvas* canvas) { 1702 SkPaint paint; 1703 SkDebugf("nullptr %c= shader\n", paint.getShader() ? '!' : '='); 1704 paint.setShader(SkShader::MakeEmptyShader()); 1705 SkDebugf("nullptr %c= shader\n", paint.getShader() ? '!' : '='); 1706 } 1707 1708 #StdOut 1709 nullptr == shader 1710 nullptr != shader 1711 ## 1712 ## 1713 1714 ## 1715 1716 #Method sk_sp<SkShader> refShader() const 1717 1718 #In Shader_Methods 1719 #Line # references Shader, multiple drawing colors; gradients ## 1720 #Populate 1721 1722 #Example 1723 void draw(SkCanvas* canvas) { 1724 SkPaint paint1, paint2; 1725 paint1.setShader(SkShader::MakeEmptyShader()); 1726 SkDebugf("shader unique: %s\n", paint1.getShader()->unique() ? "true" : "false"); 1727 paint2.setShader(paint1.refShader()); 1728 SkDebugf("shader unique: %s\n", paint1.getShader()->unique() ? "true" : "false"); 1729 } 1730 1731 #StdOut 1732 shader unique: true 1733 shader unique: false 1734 ## 1735 ## 1736 1737 ## 1738 1739 #Method void setShader(sk_sp<SkShader> shader) 1740 1741 #In Shader_Methods 1742 #Line # sets Shader, multiple drawing colors; gradients ## 1743 #Populate 1744 1745 #Example 1746 #Height 64 1747 void draw(SkCanvas* canvas) { 1748 SkPaint paint; 1749 paint.setColor(SK_ColorBLUE); 1750 paint.setShader(SkShader::MakeColorShader(SK_ColorRED)); 1751 canvas->drawRect(SkRect::MakeWH(40, 40), paint); 1752 paint.setShader(nullptr); 1753 canvas->translate(50, 0); 1754 canvas->drawRect(SkRect::MakeWH(40, 40), paint); 1755 } 1756 ## 1757 1758 ## 1759 1760 #Subtopic Shader_Methods ## 1761 # ------------------------------------------------------------------------------ 1762 #Subtopic Color_Filter_Methods 1763 #Line # get and set Color_Filter ## 1764 1765 Color_Filter alters the color used when drawing a shape. 1766 Color_Filter may apply Blend_Mode, transform the color through a matrix, or composite multiple filters. 1767 If Paint has no Color_Filter, the color is unaltered. 1768 1769 The drawn transparency can be modified without altering Color_Filter, by changing Color_Alpha. 1770 1771 #Example 1772 #Height 128 1773 void draw(SkCanvas* canvas) { 1774 SkPaint paint; 1775 paint.setColorFilter(SkColorMatrixFilter::MakeLightingFilter(0xFFFFFF, 0xFF0000)); 1776 for (SkColor c : { SK_ColorBLACK, SK_ColorGREEN } ) { 1777 paint.setColor(c); 1778 canvas->drawRect(SkRect::MakeXYWH(10, 10, 50, 50), paint); 1779 paint.setAlpha(0x80); 1780 canvas->drawRect(SkRect::MakeXYWH(60, 60, 50, 50), paint); 1781 canvas->translate(100, 0); 1782 } 1783 } 1784 ## 1785 1786 #Method SkColorFilter* getColorFilter() const 1787 1788 #In Color_Filter_Methods 1789 #Line # returns Color_Filter, how colors are altered ## 1790 #Populate 1791 1792 #Example 1793 void draw(SkCanvas* canvas) { 1794 SkPaint paint; 1795 SkDebugf("nullptr %c= color filter\n", paint.getColorFilter() ? '!' : '='); 1796 paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); 1797 SkDebugf("nullptr %c= color filter\n", paint.getColorFilter() ? '!' : '='); 1798 } 1799 1800 #StdOut 1801 nullptr == color filter 1802 nullptr != color filter 1803 ## 1804 ## 1805 ## 1806 1807 #Method sk_sp<SkColorFilter> refColorFilter() const 1808 1809 #In Color_Filter_Methods 1810 #Line # references Color_Filter, how colors are altered ## 1811 #Populate 1812 1813 #Example 1814 void draw(SkCanvas* canvas) { 1815 SkPaint paint1, paint2; 1816 paint1.setColorFilter(SkColorFilter::MakeModeFilter(0xFFFF0000, SkBlendMode::kSrcATop)); 1817 SkDebugf("color filter unique: %s\n", paint1.getColorFilter()->unique() ? "true" : "false"); 1818 paint2.setColorFilter(paint1.refColorFilter()); 1819 SkDebugf("color filter unique: %s\n", paint1.getColorFilter()->unique() ? "true" : "false"); 1820 } 1821 1822 #StdOut 1823 color filter unique: true 1824 color filter unique: false 1825 ## 1826 ## 1827 ## 1828 1829 #Method void setColorFilter(sk_sp<SkColorFilter> colorFilter) 1830 1831 #In Color_Filter_Methods 1832 #Line # sets Color_Filter, alters color ## 1833 #Populate 1834 1835 #Example 1836 #Height 64 1837 void draw(SkCanvas* canvas) { 1838 SkPaint paint; 1839 paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorLTGRAY, SkBlendMode::kSrcIn)); 1840 canvas->drawRect(SkRect::MakeWH(50, 50), paint); 1841 paint.setColorFilter(nullptr); 1842 canvas->translate(70, 0); 1843 canvas->drawRect(SkRect::MakeWH(50, 50), paint); 1844 } 1845 ## 1846 1847 ## 1848 1849 #Subtopic Color_Filter_Methods ## 1850 # ------------------------------------------------------------------------------ 1851 #Subtopic Blend_Mode_Methods 1852 #Line # get and set Blend_Mode ## 1853 1854 Blend_Mode describes how Color combines with the destination color. 1855 The default setting, SkBlendMode::kSrcOver, draws the source color 1856 over the destination color. 1857 1858 #Example 1859 void draw(SkCanvas* canvas) { 1860 SkPaint normal, blender; 1861 normal.setColor(0xFF58a889); 1862 blender.setColor(0xFF8958a8); 1863 canvas->clear(0); 1864 for (SkBlendMode m : { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn, SkBlendMode::kSrcOut } ) { 1865 normal.setBlendMode(SkBlendMode::kSrcOver); 1866 canvas->drawOval(SkRect::MakeXYWH(30, 30, 30, 80), normal); 1867 blender.setBlendMode(m); 1868 canvas->drawOval(SkRect::MakeXYWH(10, 50, 80, 30), blender); 1869 canvas->translate(70, 70); 1870 } 1871 } 1872 ## 1873 1874 #SeeAlso Blend_Mode 1875 1876 #Method SkBlendMode getBlendMode() const 1877 1878 #In Blend_Mode_Methods 1879 #Line # returns Blend_Mode, how colors combine with Device ## 1880 #Populate 1881 1882 #Example 1883 void draw(SkCanvas* canvas) { 1884 SkPaint paint; 1885 SkDebugf("kSrcOver %c= getBlendMode\n", 1886 SkBlendMode::kSrcOver == paint.getBlendMode() ? '=' : '!'); 1887 paint.setBlendMode(SkBlendMode::kSrc); 1888 SkDebugf("kSrcOver %c= getBlendMode\n", 1889 SkBlendMode::kSrcOver == paint.getBlendMode() ? '=' : '!'); 1890 } 1891 1892 #StdOut 1893 kSrcOver == getBlendMode 1894 kSrcOver != getBlendMode 1895 ## 1896 ## 1897 1898 ## 1899 1900 #Method bool isSrcOver() const 1901 1902 #In Blend_Mode_Methods 1903 #Line # returns true if Blend_Mode is SkBlendMode::kSrcOver ## 1904 #Populate 1905 1906 #Example 1907 void draw(SkCanvas* canvas) { 1908 SkPaint paint; 1909 SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); 1910 paint.setBlendMode(SkBlendMode::kSrc); 1911 SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); 1912 } 1913 1914 #StdOut 1915 isSrcOver == true 1916 isSrcOver != true 1917 ## 1918 ## 1919 1920 ## 1921 1922 #Method void setBlendMode(SkBlendMode mode) 1923 1924 #In Blend_Mode_Methods 1925 #Line # sets Blend_Mode, how colors combine with destination ## 1926 #Populate 1927 1928 #Example 1929 void draw(SkCanvas* canvas) { 1930 SkPaint paint; 1931 SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); 1932 paint.setBlendMode(SkBlendMode::kSrc); 1933 SkDebugf("isSrcOver %c= true\n", paint.isSrcOver() ? '=' : '!'); 1934 } 1935 1936 #StdOut 1937 isSrcOver == true 1938 isSrcOver != true 1939 ## 1940 ## 1941 1942 ## 1943 1944 #Subtopic Blend_Mode_Methods ## 1945 # ------------------------------------------------------------------------------ 1946 #Subtopic Path_Effect_Methods 1947 #Line # get and set Path_Effect ## 1948 1949 Path_Effect modifies the path geometry before drawing it. 1950 Path_Effect may implement dashing, custom fill effects and custom stroke effects. 1951 If Paint has no Path_Effect, the path geometry is unaltered when filled or stroked. 1952 1953 #Example 1954 #Height 160 1955 void draw(SkCanvas* canvas) { 1956 SkPaint paint; 1957 paint.setStyle(SkPaint::kStroke_Style); 1958 paint.setStrokeWidth(16); 1959 SkScalar intervals[] = {30, 10}; 1960 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 1)); 1961 canvas->drawRoundRect({20, 20, 120, 120}, 20, 20, paint); 1962 } 1963 ## 1964 1965 #SeeAlso Path_Effect 1966 1967 #Method SkPathEffect* getPathEffect() const 1968 1969 #In Path_Effect_Methods 1970 #Line # returns Path_Effect, modifications to path geometry; dashing ## 1971 #Populate 1972 1973 #Example 1974 void draw(SkCanvas* canvas) { 1975 SkPaint paint; 1976 SkDebugf("nullptr %c= path effect\n", paint.getPathEffect() ? '!' : '='); 1977 paint.setPathEffect(SkCornerPathEffect::Make(10)); 1978 SkDebugf("nullptr %c= path effect\n", paint.getPathEffect() ? '!' : '='); 1979 } 1980 1981 #StdOut 1982 nullptr == path effect 1983 nullptr != path effect 1984 ## 1985 ## 1986 1987 ## 1988 1989 1990 #Method sk_sp<SkPathEffect> refPathEffect() const 1991 1992 #In Path_Effect_Methods 1993 #Line # references Path_Effect, modifications to path geometry; dashing ## 1994 #Populate 1995 1996 #Example 1997 void draw(SkCanvas* canvas) { 1998 SkPaint paint1, paint2; 1999 SkScalar intervals[] = {1, 2}; 2000 paint1.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 10)); 2001 SkDebugf("path effect unique: %s\n", paint1.getPathEffect()->unique() ? "true" : "false"); 2002 paint2.setPathEffect(paint1.refPathEffect()); 2003 SkDebugf("path effect unique: %s\n", paint1.getPathEffect()->unique() ? "true" : "false"); 2004 } 2005 2006 #StdOut 2007 path effect unique: true 2008 path effect unique: false 2009 ## 2010 ## 2011 2012 ## 2013 2014 2015 #Method void setPathEffect(sk_sp<SkPathEffect> pathEffect) 2016 2017 #In Path_Effect_Methods 2018 #Line # sets Path_Effect, modifications to path geometry; dashing ## 2019 #Populate 2020 2021 #Example 2022 void draw(SkCanvas* canvas) { 2023 SkPaint paint; 2024 paint.setPathEffect(SkDiscretePathEffect::Make(3, 5)); 2025 canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); 2026 } 2027 ## 2028 2029 ## 2030 2031 #Subtopic Path_Effect_Methods ## 2032 # ------------------------------------------------------------------------------ 2033 #Subtopic Mask_Filter_Methods 2034 #Line # get and set Mask_Filter ## 2035 2036 Mask_Filter uses coverage of the shape drawn to create Mask_Alpha. 2037 Mask_Filter takes a Mask, and returns a Mask. 2038 2039 Mask_Filter may change the geometry and transparency of the shape, such as 2040 creating a blur effect. Set Mask_Filter to nullptr to prevent Mask_Filter from 2041 modifying the draw. 2042 2043 #Example 2044 void draw(SkCanvas* canvas) { 2045 SkPaint paint; 2046 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, 3)); 2047 canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); 2048 } 2049 ## 2050 2051 #Method SkMaskFilter* getMaskFilter() const 2052 2053 #In Mask_Filter_Methods 2054 #Line # returns Mask_Filter, alterations to Mask_Alpha ## 2055 #Populate 2056 2057 #Example 2058 void draw(SkCanvas* canvas) { 2059 SkPaint paint; 2060 SkDebugf("nullptr %c= mask filter\n", paint.getMaskFilter() ? '!' : '='); 2061 paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle, 3)); 2062 SkDebugf("nullptr %c= mask filter\n", paint.getMaskFilter() ? '!' : '='); 2063 } 2064 2065 #StdOut 2066 nullptr == mask filter 2067 nullptr != mask filter 2068 ## 2069 ## 2070 2071 ## 2072 2073 #Method sk_sp<SkMaskFilter> refMaskFilter() const 2074 2075 #In Mask_Filter_Methods 2076 #Line # references Mask_Filter, alterations to Mask_Alpha ## 2077 #Populate 2078 2079 #Example 2080 void draw(SkCanvas* canvas) { 2081 SkPaint paint1, paint2; 2082 paint1.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 1)); 2083 SkDebugf("mask filter unique: %s\n", paint1.getMaskFilter()->unique() ? "true" : "false"); 2084 paint2.setMaskFilter(paint1.refMaskFilter()); 2085 SkDebugf("mask filter unique: %s\n", paint1.getMaskFilter()->unique() ? "true" : "false"); 2086 } 2087 2088 #StdOut 2089 mask filter unique: true 2090 mask filter unique: false 2091 ## 2092 ## 2093 2094 ## 2095 2096 #Method void setMaskFilter(sk_sp<SkMaskFilter> maskFilter) 2097 2098 #In Mask_Filter_Methods 2099 #Line # sets Mask_Filter, alterations to Mask_Alpha ## 2100 #Populate 2101 2102 #Example 2103 void draw(SkCanvas* canvas) { 2104 SkPaint paint; 2105 paint.setStyle(SkPaint::kStroke_Style); 2106 paint.setStrokeWidth(10); 2107 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 10)); 2108 canvas->drawRect(SkRect::MakeXYWH(40, 40, 175, 175), paint); 2109 } 2110 ## 2111 2112 ## 2113 2114 #Subtopic Mask_Filter_Methods ## 2115 # ------------------------------------------------------------------------------ 2116 #Subtopic Typeface_Methods 2117 #Line # get and set Typeface ## 2118 2119 Typeface identifies the font used when drawing and measuring text. 2120 Typeface may be specified by name, from a file, or from a data stream. 2121 The default Typeface defers to the platform-specific default font 2122 implementation. 2123 2124 #Example 2125 #Height 100 2126 void draw(SkCanvas* canvas) { 2127 SkPaint paint; 2128 paint.setTypeface(SkTypeface::MakeFromName(nullptr, SkFontStyle())); 2129 paint.setAntiAlias(true); 2130 paint.setTextSize(36); 2131 canvas->drawString("A Big Hello!", 10, 40, paint); 2132 paint.setTypeface(nullptr); 2133 paint.setFakeBoldText(true); 2134 canvas->drawString("A Big Hello!", 10, 80, paint); 2135 } 2136 ## 2137 2138 #Subtopic Typeface_Methods ## 2139 # ------------------------------------------------------------------------------ 2140 #Subtopic Image_Filter_Methods 2141 #Line # get and set Image_Filter ## 2142 2143 Image_Filter operates on the pixel representation of the shape, as modified by Paint 2144 with Blend_Mode set to SkBlendMode::kSrcOver. Image_Filter creates a new bitmap, 2145 which is drawn to the device using the set Blend_Mode. 2146 2147 Image_Filter is higher level than Mask_Filter; for instance, an Image_Filter 2148 can operate on all channels of Color, while Mask_Filter generates Alpha only. 2149 Image_Filter operates independently of and can be used in combination with 2150 Mask_Filter. 2151 2152 #Example 2153 #ToDo explain why the two draws are so different ## 2154 #Function 2155 ###$ 2156 #include "SkBlurImageFilter.h" 2157 $$$# 2158 ## 2159 void draw(SkCanvas* canvas) { 2160 SkPaint paint; 2161 paint.setStyle(SkPaint::kStroke_Style); 2162 paint.setStrokeWidth(2); 2163 SkRegion region; 2164 region.op( 10, 10, 50, 50, SkRegion::kUnion_Op); 2165 region.op( 10, 50, 90, 90, SkRegion::kUnion_Op); 2166 paint.setImageFilter(SkBlurImageFilter::Make(5.0f, 5.0f, nullptr)); 2167 canvas->drawRegion(region, paint); 2168 paint.setImageFilter(nullptr); 2169 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5)); 2170 canvas->translate(100, 100); 2171 canvas->drawRegion(region, paint); 2172 } 2173 ## 2174 2175 #Method SkImageFilter* getImageFilter() const 2176 2177 #In Image_Filter_Methods 2178 #Line # returns Image_Filter, alter pixels; blur ## 2179 #Populate 2180 2181 #Example 2182 #Function 2183 ###$ 2184 #include "SkBlurImageFilter.h" 2185 $$$# 2186 ## 2187 void draw(SkCanvas* canvas) { 2188 SkPaint paint; 2189 SkDebugf("nullptr %c= image filter\n", paint.getImageFilter() ? '!' : '='); 2190 paint.setImageFilter(SkBlurImageFilter::Make(kOuter_SkBlurStyle, 3, nullptr, nullptr)); 2191 SkDebugf("nullptr %c= image filter\n", paint.getImageFilter() ? '!' : '='); 2192 } 2193 2194 #StdOut 2195 nullptr == image filter 2196 nullptr != image filter 2197 ## 2198 ## 2199 2200 ## 2201 2202 #Method sk_sp<SkImageFilter> refImageFilter() const 2203 2204 #In Image_Filter_Methods 2205 #Line # references Image_Filter, alter pixels; blur ## 2206 #Populate 2207 2208 #Example 2209 void draw(SkCanvas* canvas) { 2210 SkPaint paint1, paint2; 2211 paint1.setImageFilter(SkOffsetImageFilter::Make(25, 25, nullptr)); 2212 SkDebugf("image filter unique: %s\n", paint1.getImageFilter()->unique() ? "true" : "false"); 2213 paint2.setImageFilter(paint1.refImageFilter()); 2214 SkDebugf("image filter unique: %s\n", paint1.getImageFilter()->unique() ? "true" : "false"); 2215 } 2216 2217 #StdOut 2218 image filter unique: true 2219 image filter unique: false 2220 ## 2221 ## 2222 2223 ## 2224 2225 #Method void setImageFilter(sk_sp<SkImageFilter> imageFilter) 2226 2227 #In Image_Filter_Methods 2228 #Line # sets Image_Filter, alter pixels; blur ## 2229 #Populate 2230 2231 #Example 2232 #Height 160 2233 void draw(SkCanvas* canvas) { 2234 SkBitmap bitmap; 2235 bitmap.allocN32Pixels(100, 100); 2236 SkCanvas offscreen(bitmap); 2237 SkPaint paint; 2238 paint.setAntiAlias(true); 2239 paint.setColor(SK_ColorWHITE); 2240 paint.setTextSize(96); 2241 offscreen.clear(0); 2242 offscreen.drawString("e", 20, 70, paint); 2243 paint.setImageFilter( 2244 SkLightingImageFilter::MakePointLitDiffuse(SkPoint3::Make(80, 100, 10), 2245 SK_ColorWHITE, 1, 2, nullptr, nullptr)); 2246 canvas->drawBitmap(bitmap, 0, 0, &paint); 2247 } 2248 ## 2249 2250 ## 2251 2252 #Subtopic Image_Filter_Methods ## 2253 # ------------------------------------------------------------------------------ 2254 #Subtopic Draw_Looper_Methods 2255 #Line # get and set Draw_Looper ## 2256 2257 Draw_Looper sets a modifier that communicates state from one Draw_Layer 2258 to another to construct the draw. 2259 2260 Draw_Looper draws one or more times, modifying the canvas and paint each time. 2261 Draw_Looper may be used to draw multiple colors or create a colored shadow. 2262 Set Draw_Looper to nullptr to prevent Draw_Looper from modifying the draw. 2263 2264 #Example 2265 #Height 128 2266 void draw(SkCanvas* canvas) { 2267 SkLayerDrawLooper::LayerInfo info; 2268 info.fPaintBits = (SkLayerDrawLooper::BitFlags) SkLayerDrawLooper::kColorFilter_Bit; 2269 info.fColorMode = SkBlendMode::kSrc; 2270 SkLayerDrawLooper::Builder looperBuilder; 2271 SkPaint* loopPaint = looperBuilder.addLayer(info); 2272 loopPaint->setColor(SK_ColorRED); 2273 info.fOffset.set(20, 20); 2274 loopPaint = looperBuilder.addLayer(info); 2275 loopPaint->setColor(SK_ColorBLUE); 2276 SkPaint paint; 2277 paint.setDrawLooper(looperBuilder.detach()); 2278 canvas->drawCircle(50, 50, 50, paint); 2279 } 2280 2281 ## 2282 2283 #Method SkDrawLooper* getDrawLooper() const 2284 2285 #In Draw_Looper_Methods 2286 #Line # returns Draw_Looper, multiple layers ## 2287 #Populate 2288 2289 #Example 2290 void draw(SkCanvas* canvas) { 2291 SkPaint paint; 2292 SkDebugf("nullptr %c= draw looper\n", paint.getDrawLooper() ? '!' : '='); 2293 SkLayerDrawLooper::Builder looperBuilder; 2294 paint.setDrawLooper(looperBuilder.detach()); 2295 SkDebugf("nullptr %c= draw looper\n", paint.getDrawLooper() ? '!' : '='); 2296 } 2297 2298 #StdOut 2299 nullptr == draw looper 2300 nullptr != draw looper 2301 ## 2302 ## 2303 2304 ## 2305 2306 #Method sk_sp<SkDrawLooper> refDrawLooper() const 2307 2308 #In Draw_Looper_Methods 2309 #Line # references Draw_Looper, multiple layers ## 2310 #Populate 2311 2312 #Example 2313 void draw(SkCanvas* canvas) { 2314 SkPaint paint1, paint2; 2315 SkLayerDrawLooper::Builder looperBuilder; 2316 paint1.setDrawLooper(looperBuilder.detach()); 2317 SkDebugf("draw looper unique: %s\n", paint1.getDrawLooper()->unique() ? "true" : "false"); 2318 paint2.setDrawLooper(paint1.refDrawLooper()); 2319 SkDebugf("draw looper unique: %s\n", paint1.getDrawLooper()->unique() ? "true" : "false"); 2320 } 2321 2322 #StdOut 2323 draw looper unique: true 2324 draw looper unique: false 2325 ## 2326 ## 2327 2328 ## 2329 2330 #Method void setDrawLooper(sk_sp<SkDrawLooper> drawLooper) 2331 #In Draw_Looper_Methods 2332 #Line # sets Draw_Looper, multiple layers ## 2333 #Populate 2334 2335 #Example 2336 #Height 128 2337 void draw(SkCanvas* canvas) { 2338 SkPaint paint; 2339 paint.setDrawLooper(SkBlurDrawLooper::Make(0x7FFF0000, 4, -5, -10)); 2340 paint.setStyle(SkPaint::kStroke_Style); 2341 paint.setStrokeWidth(10); 2342 paint.setAntiAlias(true); 2343 paint.setColor(0x7f0000ff); 2344 canvas->drawCircle(70, 70, 50, paint); 2345 } 2346 ## 2347 2348 ## 2349 2350 #Subtopic Draw_Looper_Methods ## 2351 2352 #Subtopic Text_Size 2353 #Line # overall height in points ## 2354 2355 Text_Size adjusts the overall text size in points. 2356 Text_Size can be set to any positive value or zero. 2357 Text_Size defaults to 12. 2358 Set SkPaintDefaults_TextSize at compile time to change the default setting. 2359 2360 #Example 2361 #Height 135 2362 void draw(SkCanvas* canvas) { 2363 SkPaint paint; 2364 canvas->drawString("12 point", 10, 20, paint); 2365 paint.setTextSize(24); 2366 canvas->drawString("24 point", 10, 60, paint); 2367 paint.setTextSize(48); 2368 canvas->drawString("48 point", 10, 120, paint); 2369 } 2370 ## 2371 2372 #Subtopic Text_Size ## 2373 # ------------------------------------------------------------------------------ 2374 #Subtopic Text_Scale_X 2375 #Line # text horizontal scale ## 2376 2377 Text_Scale_X adjusts the text horizontal scale. 2378 Text scaling approximates condensed and expanded type faces when the actual face 2379 is not available. 2380 Text_Scale_X can be set to any value. 2381 Text_Scale_X defaults to 1. 2382 2383 #Example 2384 #Height 128 2385 void draw(SkCanvas* canvas) { 2386 SkPaint paint; 2387 paint.setAntiAlias(true); 2388 paint.setTextSize(24); 2389 paint.setTextScaleX(.8f); 2390 canvas->drawString("narrow", 10, 20, paint); 2391 paint.setTextScaleX(1); 2392 canvas->drawString("normal", 10, 60, paint); 2393 paint.setTextScaleX(1.2f); 2394 canvas->drawString("wide", 10, 100, paint); 2395 } 2396 ## 2397 2398 #Subtopic Text_Scale_X ## 2399 2400 #Subtopic Text_Skew_X 2401 #Line # text horizontal slant ## 2402 2403 2404 Text_Skew_X adjusts the text horizontal slant. 2405 Text skewing approximates italic and oblique type faces when the actual face 2406 is not available. 2407 Text_Skew_X can be set to any value. 2408 Text_Skew_X defaults to 0. 2409 2410 #Example 2411 #Height 128 2412 void draw(SkCanvas* canvas) { 2413 SkPaint paint; 2414 paint.setAntiAlias(true); 2415 paint.setTextSize(24); 2416 paint.setTextSkewX(-.25f); 2417 canvas->drawString("right-leaning", 10, 100, paint); 2418 paint.setTextSkewX(0); 2419 canvas->drawString("normal", 10, 60, paint); 2420 paint.setTextSkewX(.25f); 2421 canvas->drawString("left-leaning", 10, 20, paint); 2422 } 2423 ## 2424 2425 #Subtopic Text_Skew_X ## 2426 2427 # ------------------------------------------------------------------------------ 2428 #Subtopic Text_Encoding 2429 #Line # text encoded as characters or Glyphs ## 2430 2431 #Example 2432 #Height 128 2433 #Description 2434 First line is encoded in UTF-8. 2435 Second line is encoded in UTF-16. 2436 Third line is encoded in UTF-32. 2437 Fourth line has 16-bit glyph indices. 2438 ## 2439 void draw(SkCanvas* canvas) { 2440 SkPaint paint; 2441 const char hello8[] = "Hello" "\xE2" "\x98" "\xBA"; 2442 const uint16_t hello16[] = { 'H', 'e', 'l', 'l', 'o', 0x263A }; 2443 const uint32_t hello32[] = { 'H', 'e', 'l', 'l', 'o', 0x263A }; 2444 paint.setTextSize(24); 2445 canvas->drawText(hello8, sizeof(hello8) - 1, 10, 30, paint); 2446 paint.setTextEncoding(SkTextEncoding::kUTF16); 2447 canvas->drawText(hello16, sizeof(hello16), 10, 60, paint); 2448 paint.setTextEncoding(SkTextEncoding::kUTF32); 2449 canvas->drawText(hello32, sizeof(hello32), 10, 90, paint); 2450 uint16_t glyphs[SK_ARRAY_COUNT(hello32)]; 2451 SkFont font; 2452 font.textToGlyphs(hello32, sizeof(hello32), SkTextEncoding::kUTF32, 2453 glyphs, SK_ARRAY_COUNT(hello32)); 2454 paint.setTextEncoding(kGlyphID_SkTextEncoding); 2455 canvas->drawText(glyphs, sizeof(glyphs), 10, 120, paint); 2456 } 2457 ## 2458 2459 #Subtopic Text_Encoding ## 2460 2461 # ------------------------------------------------------------------------------ 2462 2463 #Method bool nothingToDraw() const 2464 #In Utility 2465 #Line # returns true if Paint prevents all drawing ## 2466 #Populate 2467 2468 #Example 2469 void draw(SkCanvas* canvas) { 2470 auto debugster = [](const char* prefix, const SkPaint& p) -> void { 2471 SkDebugf("%s nothing to draw: %s\n", prefix, 2472 p.nothingToDraw() ? "true" : "false"); 2473 }; 2474 SkPaint paint; 2475 debugster("initial", paint); 2476 paint.setBlendMode(SkBlendMode::kDst); 2477 debugster("blend dst", paint); 2478 paint.setBlendMode(SkBlendMode::kSrcOver); 2479 debugster("blend src over", paint); 2480 paint.setAlpha(0); 2481 debugster("alpha 0", paint); 2482 } 2483 2484 #StdOut 2485 initial nothing to draw: false 2486 blend dst nothing to draw: true 2487 blend src over nothing to draw: false 2488 alpha 0 nothing to draw: true 2489 #StdOut ## 2490 ## 2491 2492 ## 2493 2494 # ------------------------------------------------------------------------------ 2495 #Subtopic Utility 2496 #Line # rarely called management functions ## 2497 ## 2498 2499 # ------------------------------------------------------------------------------ 2500 2501 #Class SkPaint ## 2502 2503 #Topic Paint ## 2504