| /* | 
 |  * Copyright 2013 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "gm/gm.h" | 
 | #include "include/core/SkBlurTypes.h" | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkMaskFilter.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/core/SkPath.h" | 
 | #include "include/core/SkPathEffect.h" | 
 | #include "include/core/SkRect.h" | 
 | #include "include/core/SkRefCnt.h" | 
 | #include "include/core/SkScalar.h" | 
 | #include "include/core/SkTypes.h" | 
 | #include "include/effects/SkDashPathEffect.h" | 
 | #include "include/effects/SkImageFilters.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | static SkPath generate_square(SkScalar cx, SkScalar cy, SkScalar w) { | 
 |     return SkPath::Rect(SkRect::MakeXYWH(cx - w / 2, cy - w / 2, w, w)); | 
 | } | 
 |  | 
 | static SkPath generate_rect_line(SkScalar cx, SkScalar cy, SkScalar l) { | 
 |     return SkPath::Rect(SkRect::MakeXYWH(cx - l / 2, cy, l, 0)); | 
 | } | 
 |  | 
 | static SkPath generate_circle(SkScalar cx, SkScalar cy, SkScalar d) { | 
 |     return SkPath::Circle(cx, cy, d/2, SkPathDirection::kCW); | 
 | } | 
 |  | 
 | static SkPath generate_line(SkScalar cx, SkScalar cy, SkScalar l) { | 
 |     return SkPath::Line({cx - l / 2, cy}, {cx + l / 2, cy}); | 
 | } | 
 |  | 
 | namespace { | 
 | struct Style { | 
 |     Style(SkPaint::Style paintStyle, sk_sp<SkPathEffect> pe = sk_sp<SkPathEffect>()) | 
 |         : fPaintStyle(paintStyle) | 
 |         , fPathEffect(std::move(pe)) {} | 
 |     SkPaint::Style      fPaintStyle; | 
 |     sk_sp<SkPathEffect> fPathEffect; | 
 | }; | 
 |  | 
 | sk_sp<SkPathEffect> make_dash() { | 
 |     constexpr SkScalar kIntervals[] = { 4.f, 3.f }; | 
 |     return SkDashPathEffect::Make(kIntervals, std::size(kIntervals), 0); | 
 | } | 
 |  | 
 | Style styles[] { | 
 |     {SkPaint::kStroke_Style}, | 
 |     {SkPaint::kStrokeAndFill_Style}, | 
 |     {SkPaint::kFill_Style}, | 
 |     {SkPaint::kStroke_Style, make_dash()}, | 
 | }; | 
 |  | 
 | SkScalar pathSizes[] = { | 
 |         40, | 
 |         10, | 
 |         0 | 
 | }; | 
 | SkScalar strokeWidths[] = { | 
 |         10, | 
 |         0 | 
 | }; | 
 | SkPath (*paths[])(SkScalar, SkScalar, SkScalar) = { | 
 |         generate_square, | 
 |         generate_rect_line, | 
 |         generate_circle, | 
 |         generate_line | 
 | }; | 
 |  | 
 | const SkScalar slideWidth = 90, slideHeight = 90; | 
 | const SkScalar slideBoundary = 5; | 
 |  | 
 | }  // namespace | 
 |  | 
 | DEF_SIMPLE_GM(inverse_paths, canvas, 800, 1200) { | 
 |     SkScalar cx = slideWidth / 2 + slideBoundary; | 
 |     SkScalar cy = slideHeight / 2 + slideBoundary; | 
 |     SkScalar dx = slideWidth + 2 * slideBoundary; | 
 |     SkScalar dy = slideHeight + 2 * slideBoundary; | 
 |  | 
 |     SkRect clipRect = SkRect::MakeLTRB(slideBoundary, slideBoundary, | 
 |                                        slideBoundary + slideWidth, | 
 |                                        slideBoundary + slideHeight); | 
 |     SkPaint clipPaint; | 
 |     clipPaint.setStyle(SkPaint::kStroke_Style); | 
 |     clipPaint.setStrokeWidth(SkIntToScalar(2)); | 
 |  | 
 |     SkPaint outlinePaint; | 
 |     outlinePaint.setColor(0x40000000); | 
 |     outlinePaint.setStyle(SkPaint::kStroke_Style); | 
 |     outlinePaint.setStrokeWidth(SkIntToScalar(0)); | 
 |  | 
 |     for (size_t styleIndex = 0; styleIndex < std::size(styles); | 
 |             styleIndex++) { | 
 |         for (size_t sizeIndex = 0; sizeIndex < std::size(pathSizes); | 
 |                 sizeIndex++) { | 
 |             SkScalar size = pathSizes[sizeIndex]; | 
 |  | 
 |             canvas->save(); | 
 |  | 
 |             for (size_t widthIndex = 0; | 
 |                     widthIndex < std::size(strokeWidths); | 
 |                     widthIndex++) { | 
 |                 SkPaint paint; | 
 |                 paint.setColor(0xff007000); | 
 |                 paint.setStrokeWidth(strokeWidths[widthIndex]); | 
 |                 paint.setStyle(styles[styleIndex].fPaintStyle); | 
 |                 paint.setPathEffect(styles[styleIndex].fPathEffect); | 
 |  | 
 |                 for (size_t pathIndex = 0; | 
 |                         pathIndex < std::size(paths); | 
 |                         pathIndex++) { | 
 |                     canvas->drawRect(clipRect, clipPaint); | 
 |  | 
 |                     canvas->save(); | 
 |                     canvas->clipRect(clipRect); | 
 |  | 
 |                     SkPath path = paths[pathIndex](cx, cy, size); | 
 |                     path.setFillType(SkPathFillType::kInverseWinding); | 
 |                     canvas->drawPath(path, paint); | 
 |  | 
 |                     path.setFillType(SkPathFillType::kWinding); | 
 |                     canvas->drawPath(path, outlinePaint); | 
 |  | 
 |                     canvas->restore(); | 
 |                     canvas->translate(dx, 0); | 
 |                 } | 
 |             } | 
 |             canvas->restore(); | 
 |             canvas->translate(0, dy); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | DEF_SIMPLE_GM(inverse_fill_filters, canvas, 384, 128) { | 
 |     auto draw = [canvas](const SkPaint& paint) { | 
 |         SkPath path = SkPath::Circle(65.f, 65.f, 30.f); | 
 |         path.setFillType(SkPathFillType::kInverseWinding); | 
 |  | 
 |         canvas->save(); | 
 |         canvas->clipRect({0, 0, 128, 128}); | 
 |         canvas->drawPath(path, paint); | 
 |         canvas->restore(); | 
 |  | 
 |         SkPaint stroke; | 
 |         stroke.setStyle(SkPaint::kStroke_Style); | 
 |         stroke.setColor(SK_ColorWHITE); | 
 |         canvas->drawRect({0, 0, 128, 128}, stroke); | 
 |     }; | 
 |  | 
 |     SkPaint paint; | 
 |     paint.setAntiAlias(true); | 
 |  | 
 |     draw(paint); | 
 |  | 
 |     canvas->translate(128, 0); | 
 |     paint.setImageFilter(SkImageFilters::Blur(5.f, 5.f, nullptr)); | 
 |     draw(paint); | 
 |  | 
 |     canvas->translate(128, 0); | 
 |     paint.setImageFilter(nullptr); | 
 |     paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5)); | 
 |     draw(paint); | 
 | } | 
 |  | 
 | DEF_SIMPLE_GM(inverse_windingmode_filters, canvas, 256, 100) { | 
 |     SkPath path; | 
 |     path.addRect({10, 10, 30, 30}, SkPathDirection::kCW); | 
 |     path.addRect({20, 20, 40, 40}, SkPathDirection::kCW); | 
 |     path.addRect({10, 60, 30, 80}, SkPathDirection::kCW); | 
 |     path.addRect({20, 70, 40, 90}, SkPathDirection::kCCW); | 
 |     SkPaint strokePaint; | 
 |     strokePaint.setStyle(SkPaint::kStroke_Style); | 
 |     SkRect clipRect = {0, 0, 51, 99}; | 
 |     canvas->drawPath(path, strokePaint); | 
 |     SkPaint fillPaint; | 
 |     fillPaint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 1.0f)); | 
 |     for (auto fillType : { SkPathFillType::kWinding, | 
 |                            SkPathFillType::kEvenOdd, | 
 |                            SkPathFillType::kInverseWinding, | 
 |                            SkPathFillType::kInverseEvenOdd } ) { | 
 |         canvas->translate(51, 0); | 
 |         canvas->save(); | 
 |         canvas->clipRect(clipRect); | 
 |         path.setFillType(fillType); | 
 |         canvas->drawPath(path, fillPaint); | 
 |         canvas->restore(); | 
 |         SkPaint clipPaint; | 
 |         clipPaint.setColor(SK_ColorRED); | 
 |         clipPaint.setStyle(SkPaint::kStroke_Style); | 
 |         clipPaint.setStrokeWidth(1.f); | 
 |         canvas->drawRect(clipRect, clipPaint); | 
 |     } | 
 | } |