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