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