Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 #include "sk_tool_utils.h"
     10 #include "SkCanvas.h"
     11 #include "SkFont.h"
     12 #include "SkPath.h"
     13 
     14 namespace skiagm {
     15 
     16 constexpr SkColor gPathColor = SK_ColorBLACK;
     17 constexpr SkColor gClipAColor = SK_ColorBLUE;
     18 constexpr SkColor gClipBColor = SK_ColorRED;
     19 
     20 class ComplexClipGM : public GM {
     21 public:
     22     ComplexClipGM(bool aaclip, bool saveLayer, bool invertDraw)
     23     : fDoAAClip(aaclip)
     24     , fDoSaveLayer(saveLayer)
     25     , fInvertDraw(invertDraw) {
     26         this->setBGColor(0xFFDEDFDE);
     27     }
     28 
     29 protected:
     30     SkString onShortName() override {
     31         SkString str;
     32         str.printf("complexclip_%s%s%s",
     33                    fDoAAClip ? "aa" : "bw",
     34                    fDoSaveLayer ? "_layer" : "",
     35                    fInvertDraw ? "_invert" : "");
     36         return str;
     37     }
     38 
     39     SkISize onISize() override { return SkISize::Make(970, 780); }
     40 
     41     void onDraw(SkCanvas* canvas) override {
     42         SkPath path;
     43         path.moveTo(0,   50)
     44             .quadTo(0,   0,   50,  0)
     45             .lineTo(175, 0)
     46             .quadTo(200, 0,   200, 25)
     47             .lineTo(200, 150)
     48             .quadTo(200, 200, 150, 200)
     49             .lineTo(0,   200)
     50             .close()
     51             .moveTo(50,  50)
     52             .lineTo(150, 50)
     53             .lineTo(150, 125)
     54             .quadTo(150, 150, 125, 150)
     55             .lineTo(50,  150)
     56             .close();
     57         if (fInvertDraw) {
     58             path.setFillType(SkPath::kInverseEvenOdd_FillType);
     59         } else {
     60             path.setFillType(SkPath::kEvenOdd_FillType);
     61         }
     62         SkPaint pathPaint;
     63         pathPaint.setAntiAlias(true);
     64         pathPaint.setColor(gPathColor);
     65 
     66         SkPath clipA;
     67         clipA.addPoly({{10,  20}, {165, 22}, {70,  105}, {165, 177}, {-5,  180}}, false).close();
     68 
     69         SkPath clipB;
     70         clipB.addPoly({{40,  10}, {190, 15}, {195, 190}, {40,  185}, {155, 100}}, false).close();
     71 
     72         SkFont font(sk_tool_utils::create_portable_typeface(), 20);
     73 
     74         constexpr struct {
     75             SkClipOp fOp;
     76             const char*      fName;
     77         } gOps[] = { //extra spaces in names for measureText
     78             {kIntersect_SkClipOp,         "Isect "},
     79             {kDifference_SkClipOp,        "Diff " },
     80             {kUnion_SkClipOp,             "Union "},
     81             {kXOR_SkClipOp,               "Xor "  },
     82             {kReverseDifference_SkClipOp, "RDiff "}
     83         };
     84 
     85         canvas->translate(20, 20);
     86         canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
     87 
     88         if (fDoSaveLayer) {
     89             // We want the layer to appear symmetric relative to actual
     90             // device boundaries so we need to "undo" the effect of the
     91             // scale and translate
     92             SkRect bounds = SkRect::MakeLTRB(
     93               4.0f/3.0f * -20,
     94               4.0f/3.0f * -20,
     95               4.0f/3.0f * (this->getISize().fWidth - 20),
     96               4.0f/3.0f * (this->getISize().fHeight - 20));
     97 
     98             bounds.inset(100, 100);
     99             SkPaint boundPaint;
    100             boundPaint.setColor(SK_ColorRED);
    101             boundPaint.setStyle(SkPaint::kStroke_Style);
    102             canvas->drawRect(bounds, boundPaint);
    103             canvas->clipRect(bounds);
    104             canvas->saveLayer(&bounds, nullptr);
    105         }
    106 
    107         for (int invBits = 0; invBits < 4; ++invBits) {
    108             canvas->save();
    109             for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
    110                 this->drawHairlines(canvas, path, clipA, clipB);
    111 
    112                 bool doInvA = SkToBool(invBits & 1);
    113                 bool doInvB = SkToBool(invBits & 2);
    114                 canvas->save();
    115                     // set clip
    116                     clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
    117                                       SkPath::kEvenOdd_FillType);
    118                     clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
    119                                       SkPath::kEvenOdd_FillType);
    120                     canvas->clipPath(clipA, fDoAAClip);
    121                     canvas->clipPath(clipB, gOps[op].fOp, fDoAAClip);
    122 
    123                     // In the inverse case we need to prevent the draw from covering the whole
    124                     // canvas.
    125                     if (fInvertDraw) {
    126                         SkRect rectClip = clipA.getBounds();
    127                         rectClip.join(path.getBounds());
    128                         rectClip.join(path.getBounds());
    129                         rectClip.outset(5, 5);
    130                         canvas->clipRect(rectClip);
    131                     }
    132 
    133                     // draw path clipped
    134                     canvas->drawPath(path, pathPaint);
    135                 canvas->restore();
    136 
    137 
    138                 SkPaint paint;
    139                 SkScalar txtX = 45;
    140                 paint.setColor(gClipAColor);
    141                 const char* aTxt = doInvA ? "InvA " : "A ";
    142                 canvas->drawSimpleText(aTxt, strlen(aTxt), kUTF8_SkTextEncoding, txtX, 220, font, paint);
    143                 txtX += font.measureText(aTxt, strlen(aTxt), kUTF8_SkTextEncoding);
    144                 paint.setColor(SK_ColorBLACK);
    145                 canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), kUTF8_SkTextEncoding, txtX, 220,
    146                                        font, paint);
    147                 txtX += font.measureText(gOps[op].fName, strlen(gOps[op].fName), kUTF8_SkTextEncoding);
    148                 paint.setColor(gClipBColor);
    149                 const char* bTxt = doInvB ? "InvB " : "B ";
    150                 canvas->drawSimpleText(bTxt, strlen(bTxt), kUTF8_SkTextEncoding, txtX, 220, font, paint);
    151 
    152                 canvas->translate(250,0);
    153             }
    154             canvas->restore();
    155             canvas->translate(0, 250);
    156         }
    157 
    158         if (fDoSaveLayer) {
    159             canvas->restore();
    160         }
    161     }
    162 private:
    163     void drawHairlines(SkCanvas* canvas, const SkPath& path,
    164                        const SkPath& clipA, const SkPath& clipB) {
    165         SkPaint paint;
    166         paint.setAntiAlias(true);
    167         paint.setStyle(SkPaint::kStroke_Style);
    168         const SkAlpha fade = 0x33;
    169 
    170         // draw path in hairline
    171         paint.setColor(gPathColor); paint.setAlpha(fade);
    172         canvas->drawPath(path, paint);
    173 
    174         // draw clips in hair line
    175         paint.setColor(gClipAColor); paint.setAlpha(fade);
    176         canvas->drawPath(clipA, paint);
    177         paint.setColor(gClipBColor); paint.setAlpha(fade);
    178         canvas->drawPath(clipB, paint);
    179     }
    180 
    181     bool fDoAAClip;
    182     bool fDoSaveLayer;
    183     bool fInvertDraw;
    184 
    185     typedef GM INHERITED;
    186 };
    187 
    188 //////////////////////////////////////////////////////////////////////////////
    189 
    190 DEF_GM(return new ComplexClipGM(false, false, false);)
    191 DEF_GM(return new ComplexClipGM(false, false, true);)
    192 DEF_GM(return new ComplexClipGM(false, true, false);)
    193 DEF_GM(return new ComplexClipGM(false, true, true);)
    194 DEF_GM(return new ComplexClipGM(true, false, false);)
    195 DEF_GM(return new ComplexClipGM(true, false, true);)
    196 DEF_GM(return new ComplexClipGM(true, true, false);)
    197 DEF_GM(return new ComplexClipGM(true, true, true);)
    198 }
    199