1#Topic Paint
2#Alias Paint_Reference ##
3
4#Class SkPaint
5
6#Code
7#Populate
8##
9
10Paint controls options applied when drawing and measuring. Paint collects all
11options outside of the Canvas_Clip and Canvas_Matrix.
12
13Various options apply to text, strokes and fills, and images.
14
15Some options may not be implemented on all platforms; in these cases, setting
16the option has no effect. Some options are conveniences that duplicate Canvas
17functionality; for instance, text size is identical to matrix scale.
18
19Paint options are rarely exclusive; each option modifies a stage of the drawing
20pipeline and multiple pipeline stages may be affected by a single Paint.
21
22Paint collects effects and filters that describe single-pass and multiple-pass
23algorithms that alter the drawing geometry, color, and transparency. For instance,
24Paint does not directly implement dashing or blur, but contains the objects that do so.
25
26The objects contained by Paint are opaque, and cannot be edited outside of the Paint
27to affect it. The implementation is free to defer computations associated with the
28Paint, or ignore them altogether. For instance, some GPU implementations draw all
29Path geometries with Anti_Aliasing, regardless of how SkPaint::kAntiAlias_Flag
30is set in Paint.
31
32Paint describes a single color, a single font, a single image quality, and so on.
33Multiple colors are drawn either by using multiple paints or with objects like
34Shader attached to Paint.
35
36#Method SkPaint()
37#Line # constructs with default values ##
38Constructs 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
63The miter limit may be overridden at compile time by defining
64paint default values. The overrides may be included in "SkUserConfig.h" or predefined by the
65build 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
287Anti_Alias drawing approximates partial pixel coverage with transparency.
288If kAntiAlias_Flag is clear, pixel centers contained by the shape edge are drawn opaque.
289If kAntiAlias_Flag is set, pixels are drawn with Color_Alpha equal to their coverage.
290
291The rule for Aliased pixels is inconsistent across platforms. A shape edge
292passing through the pixel center may, but is not required to, draw the pixel.
293
294Raster_Engine draws Aliased pixels whose centers are on or to the right of the start of an
295active 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
299A platform may only support Anti_Aliased drawing. Some GPU-backed platforms use
300Supersampling to Anti_Alias all drawing, and have no mechanism to selectively
301Alias.
302
303The amount of coverage computed for Anti_Aliased pixels also varies across platforms.
304
305Anti_Alias is disabled by default.
306Anti_Alias can be enabled by default by setting SkPaintDefaults_Flags to kAntiAlias_Flag
307at 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
383Dither increases fidelity by adjusting the color of adjacent pixels.
384This can help to smooth color transitions and reducing banding in gradients.
385Dithering lessens visible banding from kRGB_565_SkColorType
386and kRGBA_8888_SkColorType gradients,
387and improves rendering into a kRGB_565_SkColorType Surface.
388
389Dithering is always enabled for linear gradients drawing into
390kRGB_565_SkColorType Surface and kRGBA_8888_SkColorType Surface.
391Dither cannot be enabled for kAlpha_8_SkColorType Surface and
392kRGBA_F16_SkColorType Surface.
393
394Dither is disabled by default.
395Dither can be enabled by default by setting SkPaintDefaults_Flags to kDither_Flag
396at compile time.
397
398Some platform implementations may ignore dithering. Set #Formula # SK_IGNORE_GPU_DITHER ##
399to ignore Dither on GPU_Surface.
400
401#Example
402#Description
403Dithering in the bottom half more closely approximates the requested color by
404alternating nearby colors from pixel to pixel.
405##
406void 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
429Dithering introduces subtle adjustments to color to smooth gradients.
430Drawing the gradient repeatedly with SkBlendMode::kPlus exaggerates the
431dither, making it easier to see.
432##
433void 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
502Font_Anti_Alias and Font_Subpixel increase the precision of glyph position.
503
504When set, Flags kLCDRenderText_Flag takes advantage of the organization of RGB stripes that
505create a color, and relies
506on the small size of the stripe and visual perception to make the color fringing imperceptible.
507Font_Anti_Alias can be enabled on devices that orient stripes horizontally or vertically, and that order
508the color components as RGB or BGR.
509
510Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset.
511As the opaqueness
512of the color increases, the edge of the glyph appears to move towards the outside of the pixel.
513
514Either or both techniques can be enabled.
515kLCDRenderText_Flag and kSubpixelText_Flag are clear by default.
516Font_Anti_Alias or Font_Subpixel can be enabled by default by setting SkPaintDefaults_Flags to
517kLCDRenderText_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
550Font_Linear selects whether text is rendered as a Glyph or as a Path.
551If Font_Linear is set, it has the same effect as setting Hinting to SkFontHinting::kNormal.
552If 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
558Flags kSubpixelText_Flag uses the pixel transparency to represent a fractional offset.
559As the opaqueness
560of 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
566When set, Font_Anti_Alias takes advantage of the organization of RGB stripes that
567create a color, and relies
568on the small size of the stripe and visual perception to make the color fringing imperceptible.
569Font_Anti_Alias can be enabled on devices that orient stripes horizontally or vertically, and that order
570the color components as RGB or BGR.
571#Subtopic LCD_Text ##
572
573# ------------------------------------------------------------------------------
574#Subtopic Embedded_Bitmaps
575#Line # custom sized bitmap Glyphs ##
576
577Font_Embedded_Bitmaps allows selecting custom sized bitmap Glyphs.
578Flags kEmbeddedBitmapText_Flag when set chooses an embedded bitmap glyph over an outline contained
579in a font if the platform supports this option.
580
581FreeType selects the bitmap glyph if available when kEmbeddedBitmapText_Flag is set, and selects
582the outline glyph if kEmbeddedBitmapText_Flag is clear.
583Windows may select the bitmap glyph but is not required to do so.
584OS_X and iOS do not support this option.
585
586Font_Embedded_Bitmaps is disabled by default.
587Font_Embedded_Bitmaps can be enabled by default by setting SkPaintDefaults_Flags to
588kEmbeddedBitmapText_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
624If Hinting is set to SkFontHinting::kNormal or SkFontHinting::kFull, Font_Force_Hinting
625instructs the Font_Manager to always hint Glyphs.
626Font_Force_Hinting has no effect if Hinting is set to SkFontHinting::kNone or
627SkFontHinting::kSlight.
628
629Font_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
637Font_Embolden approximates the bold font style accompanying a normal font when a bold font face
638is not available. Skia does not provide font substitution; it is up to the client to find the
639bold font face using the platform Font_Manager.
640
641Use Text_Skew_X to approximate an italic font style when the italic font face
642is not available.
643
644A FreeType based port may define SK_USE_FREETYPE_EMBOLDEN at compile time to direct
645the font engine to create the bold Glyphs. Otherwise, the extra bold is computed
646by increasing the stroke width and setting the Style to kStrokeAndFill_Style as needed.
647
648Font_Embolden is disabled by default.
649
650#Example
651#Height 128
652void 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
672Filter_Quality trades speed for image filtering when the image is scaled.
673A lower Filter_Quality draws faster, but has less fidelity.
674A higher Filter_Quality draws slower, but looks better.
675If the image is drawn without scaling, the Filter_Quality choice will not result
676in a noticeable difference.
677
678Filter_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 ##
686and when Paint has a Shader specialization that uses Image or Bitmap.
687
688Filter_Quality is kNone_SkFilterQuality by default.
689
690#Example
691#Image 3
692void 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
756Color specifies the red, blue, green, and Color_Alpha
757values used to draw a filled or stroked shape in a 32-bit value. Each component
758occupies 8-bits, ranging from zero: no contribution; to 255: full intensity.
759All values in any combination are valid.
760
761Color is not Premultiplied; Color_Alpha sets the transparency independent of
762RGB: red, blue, and green.
763
764The bit positions of Color_Alpha and RGB are independent of the bit
765positions on the output device, which may have more or fewer bits, and may have
766a 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
879Color_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
940Style specifies if the geometry is filled, stroked, or both filled and stroked.
941Some shapes ignore Style and are always drawn filled or stroked.
942
943#Subtopic Fill
944Set Style to kFill_Style to fill the shape.
945The fill covers the area inside the geometry for most shapes.
946#Subtopic Fill ##
947
948#Subtopic Stroke
949Set Style to kStroke_Style to stroke the shape.
950
951The stroke covers the area described by following the shape edge with a pen or brush of
952Stroke_Width. The area covered where the shape starts and stops is described by Stroke_Cap.
953The area covered where the shape turns a corner is described by Stroke_Join.
954The stroke is centered on the shape; it extends equally on either side of the shape edge.
955#Subtopic Stroke ##
956
957As Stroke_Width gets smaller, the drawn path frame is thinner. Stroke_Width less than one
958may 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
964Stroke_Width of zero has a special meaning and switches drawing to use Hairline.
965Hairline draws the thinnest continuous frame. If kAntiAlias_Flag is clear, adjacent pixels
966flow horizontally, vertically,or diagonally.
967
968#ToDo  what is the description of Anti_Aliased hairlines? ##
969
970Path drawing with Hairline may hit the same pixel more than once. For instance, Path containing
971two lines in one Path_Contour will draw the corner point once, but may both lines may draw the adjacent
972pixel. If kAntiAlias_Flag is set, transparency is applied twice, resulting in a darker pixel. Some
973GPU-backed implementations apply transparency at a later drawing stage, avoiding double hit pixels
974while 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
992Set Style to fill, stroke, or both fill and stroke geometry.
993The stroke and fill
994share all paint attributes; for instance, they are drawn with the same color.
995
996Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and
997a 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 ##
1026May 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
1090Stroke_Width sets the width for stroking. The width is the thickness
1091of the stroke perpendicular to the path direction when the paint style is
1092set to kStroke_Style or kStrokeAndFill_Style.
1093
1094When width is greater than zero, the stroke encompasses as many pixels partially
1095or fully as needed. When the width equals zero, the paint enables hairlines;
1096the stroke is always one pixel wide.
1097
1098The stroke dimensions are scaled by the canvas matrix, but Hairline stroke
1099remains one pixel wide regardless of scaling.
1100
1101The 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
1165Miter_Limit specifies the maximum miter length,
1166relative to the stroke width.
1167
1168Miter_Limit is used when the Stroke_Join
1169is set to kMiter_Join, and the Style is either kStroke_Style
1170or kStrokeAndFill_Style.
1171
1172If the miter at a corner exceeds this limit, kMiter_Join
1173is replaced with kBevel_Join.
1174
1175Miter_Limit can be computed from the corner angle using:
1176#Formula # miter limit = 1 / sin ( angle / 2 ) ##.
1177
1178Miter_Limit default value is 4.
1179The default may be changed at compile time by setting SkPaintDefaults_MiterLimit
1180in "SkUserConfig.h" or as a define supplied by the build environment.
1181
1182Here 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
1298Stroke_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
1330Stroke describes the area covered by a pen of Stroke_Width as it
1331follows the Path_Contour, moving parallel to the contour direction.
1332
1333If the Path_Contour is not terminated by SkPath::kClose_Verb, the contour has a
1334visible beginning and end.
1335
1336Path_Contour may start and end at the same point; defining Zero_Length_Contour.
1337
1338kButt_Cap and Zero_Length_Contour is not drawn.
1339kRound_Cap and Zero_Length_Contour draws a circle of diameter Stroke_Width
1340at the contour point.
1341kSquare_Cap and Zero_Length_Contour draws an upright square with a side of
1342Stroke_Width at the contour point.
1343
1344Stroke_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
1408Stroke_Join draws at the sharp corners of an open or closed Path_Contour.
1409
1410Stroke describes the area covered by a pen of Stroke_Width as it
1411follows the Path_Contour, moving parallel to the contour direction.
1412
1413If the contour direction changes abruptly, because the tangent direction leading
1414to the end of a curve within the contour does not match the tangent direction of
1415the 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
1445Join specifies how corners are drawn when a shape is stroked. Join
1446affects the four corners of a stroked rectangle, and the connected segments in a
1447stroked path.
1448
1449Choose miter join to draw sharp corners. Choose round join to draw a circle with a
1450radius equal to the stroke width on top of the corner. Choose bevel join to minimally
1451connect the thick strokes.
1452
1453The fill path constructed to describe the stroked path respects the join setting but may
1454not contain the actual join. For instance, a fill path constructed with round joins does
1455not 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
1489void 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
1558Fill_Path creates a Path by applying the Path_Effect, followed by the Style_Stroke.
1559
1560If Paint contains Path_Effect, Path_Effect operates on the source Path; the result
1561replaces the destination Path. Otherwise, the source Path is replaces the
1562destination Path.
1563
1564Fill Path can request the Path_Effect to restrict to a culling rectangle, but
1565the Path_Effect is not required to do so.
1566
1567If Style is kStroke_Style or kStrokeAndFill_Style,
1568and Stroke_Width is greater than zero, the Stroke_Width, Stroke_Cap, Stroke_Join,
1569and Miter_Limit operate on the destination Path, replacing it.
1570
1571Fill Path can specify the precision used by Stroke_Width to approximate the stroke geometry.
1572
1573If the Style is kStroke_Style and the Stroke_Width is zero, getFillPath
1574returns 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
1649Shader defines the colors used when drawing a shape.
1650Shader may be an image, a gradient, or a computed fill.
1651If Paint has no Shader, then Color fills the shape.
1652
1653Shader is modulated by Color_Alpha component of Color.
1654If Shader object defines only Color_Alpha, then Color modulated by Color_Alpha describes
1655the fill.
1656
1657The drawn transparency can be modified without altering Shader, by changing Color_Alpha.
1658
1659#Example
1660void 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
1675If Shader generates only Color_Alpha then all components of Color modulate the output.
1676
1677#Example
1678void 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
1765Color_Filter alters the color used when drawing a shape.
1766Color_Filter may apply Blend_Mode, transform the color through a matrix, or composite multiple filters.
1767If Paint has no Color_Filter, the color is unaltered.
1768
1769The drawn transparency can be modified without altering Color_Filter, by changing Color_Alpha.
1770
1771#Example
1772#Height 128
1773void 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
1854Blend_Mode describes how Color combines with the destination color.
1855The default setting, SkBlendMode::kSrcOver, draws the source color
1856over the destination color.
1857
1858#Example
1859void 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
1949Path_Effect modifies the path geometry before drawing it.
1950Path_Effect may implement dashing, custom fill effects and custom stroke effects.
1951If 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
2036Mask_Filter uses coverage of the shape drawn to create Mask_Alpha.
2037Mask_Filter takes a Mask, and returns a Mask.
2038
2039Mask_Filter may change the geometry and transparency of the shape, such as
2040creating a blur effect. Set Mask_Filter to nullptr to prevent Mask_Filter from
2041modifying 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
2119Typeface identifies the font used when drawing and measuring text.
2120Typeface may be specified by name, from a file, or from a data stream.
2121The default Typeface defers to the platform-specific default font
2122implementation.
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
2143Image_Filter operates on the pixel representation of the shape, as modified by Paint
2144with Blend_Mode set to SkBlendMode::kSrcOver. Image_Filter creates a new bitmap,
2145which is drawn to the device using the set Blend_Mode.
2146
2147Image_Filter is higher level than Mask_Filter; for instance, an Image_Filter
2148can operate on all channels of Color, while Mask_Filter generates Alpha only.
2149Image_Filter operates independently of and can be used in combination with
2150Mask_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
2257Draw_Looper sets a modifier that communicates state from one Draw_Layer
2258to another to construct the draw.
2259
2260Draw_Looper draws one or more times, modifying the canvas and paint each time.
2261Draw_Looper may be used to draw multiple colors or create a colored shadow.
2262Set 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
2355Text_Size adjusts the overall text size in points.
2356Text_Size can be set to any positive value or zero.
2357Text_Size defaults to 12.
2358Set 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
2377Text_Scale_X adjusts the text horizontal scale.
2378Text scaling approximates condensed and expanded type faces when the actual face
2379is not available.
2380Text_Scale_X can be set to any value.
2381Text_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
2404Text_Skew_X adjusts the text horizontal slant.
2405Text skewing approximates italic and oblique type faces when the actual face
2406is not available.
2407Text_Skew_X can be set to any value.
2408Text_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
2434First line is encoded in UTF-8.
2435Second line is encoded in UTF-16.
2436Third line is encoded in UTF-32.
2437Fourth line has 16-bit glyph indices.
2438##
2439void 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