Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2015 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 "SampleCode.h"
      9 #include "SkCanvas.h"
     10 #include "SkInterpolator.h"
     11 #include "SkPath.h"
     12 #include "SkRRect.h"
     13 #include "SkTime.h"
     14 
     15 // This slide tests out the match up between BW clipping and rendering. It can
     16 // draw a large rect through some clip geometry and draw the same geometry
     17 // normally. Which one is drawn first can be toggled. The pair of objects is translated
     18 // fractionally (via an animator) to expose snapping bugs. The key bindings are:
     19 //      1-9: the different geometries
     20 //      t:   toggle which is drawn first the clip or the normal geometry
     21 //      f:   flip-flops which corner the bottom AA clip rect occupies in the complex clip cases
     22 
     23 // The possible geometric combinations to test
     24 enum Geometry {
     25     kRect_Geometry,
     26     kRRect_Geometry,
     27     kCircle_Geometry,
     28     kConvexPath_Geometry,
     29     kConcavePath_Geometry,
     30     kRectAndRect_Geometry,
     31     kRectAndRRect_Geometry,
     32     kRectAndConvex_Geometry,
     33     kRectAndConcave_Geometry
     34 };
     35 
     36 // The basic rect used is [kMin,kMin]..[kMax,kMax]
     37 static const float kMin = 100.5f;
     38 static const float kMid = 200.0f;
     39 static const float kMax = 299.5f;
     40 
     41 // The translation applied to the base AA rect in the combination cases
     42 // (i.e., kRectAndRect through kRectAndConcave)
     43 static const float kXlate = 100.0f;
     44 
     45 SkRect create_rect(const SkPoint& offset) {
     46     SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
     47     r.offset(offset);
     48     return r;
     49 }
     50 
     51 SkRRect create_rrect(const SkPoint& offset) {
     52     SkRRect rrect;
     53     rrect.setRectXY(create_rect(offset), 10, 10);
     54     return rrect;
     55 }
     56 
     57 SkRRect create_circle(const SkPoint& offset) {
     58     SkRRect circle;
     59     circle.setOval(create_rect(offset));
     60     return circle;
     61 }
     62 
     63 SkPath create_convex_path(const SkPoint& offset) {
     64     SkPath convexPath;
     65     convexPath.moveTo(kMin, kMin);
     66     convexPath.lineTo(kMax, kMax);
     67     convexPath.lineTo(kMin, kMax);
     68     convexPath.close();
     69     convexPath.offset(offset.fX, offset.fY);
     70     return convexPath;
     71 }
     72 
     73 SkPath create_concave_path(const SkPoint& offset) {
     74     SkPath concavePath;
     75     concavePath.moveTo(kMin, kMin);
     76     concavePath.lineTo(kMid, 105.0f);
     77     concavePath.lineTo(kMax, kMin);
     78     concavePath.lineTo(295.0f, kMid);
     79     concavePath.lineTo(kMax, kMax);
     80     concavePath.lineTo(kMid, 295.0f);
     81     concavePath.lineTo(kMin, kMax);
     82     concavePath.lineTo(105.0f, kMid);
     83     concavePath.close();
     84 
     85     concavePath.offset(offset.fX, offset.fY);
     86     return concavePath;
     87 }
     88 
     89 static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
     90     SkPaint p;
     91     p.setAntiAlias(useAA);
     92     p.setColor(SK_ColorBLACK);
     93 
     94     switch (geom) {
     95     case kRect_Geometry:                // fall thru
     96     case kRectAndRect_Geometry:
     97         canvas->drawRect(create_rect(offset), p);
     98         break;
     99     case kRRect_Geometry:               // fall thru
    100     case kRectAndRRect_Geometry:
    101         canvas->drawRRect(create_rrect(offset), p);
    102         break;
    103     case kCircle_Geometry:
    104         canvas->drawRRect(create_circle(offset), p);
    105         break;
    106     case kConvexPath_Geometry:          // fall thru
    107     case kRectAndConvex_Geometry:
    108         canvas->drawPath(create_convex_path(offset), p);
    109         break;
    110     case kConcavePath_Geometry:         // fall thru
    111     case kRectAndConcave_Geometry:
    112         canvas->drawPath(create_concave_path(offset), p);
    113         break;
    114     }
    115 }
    116 
    117 class ClipDrawMatchView : public SampleView {
    118 public:
    119     ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true), fSign(1) {
    120         SkScalar values[2];
    121 
    122         fTrans.setRepeatCount(999);
    123         values[0] = values[1] = 0;
    124         fTrans.setKeyFrame(0, GetMSecs() + 1000, values);
    125         values[1] = 1;
    126         fTrans.setKeyFrame(1, GetMSecs() + 2000, values);
    127         values[0] = values[1] = 1;
    128         fTrans.setKeyFrame(2, GetMSecs() + 3000, values);
    129         values[1] = 0;
    130         fTrans.setKeyFrame(3, GetMSecs() + 4000, values);
    131         values[0] = 0;
    132         fTrans.setKeyFrame(4, GetMSecs() + 5000, values);
    133     }
    134 
    135 protected:
    136     bool onQuery(SkEvent* evt) override {
    137         if (SampleCode::TitleQ(*evt)) {
    138             SampleCode::TitleR(evt, "ClipDrawMatch");
    139             return true;
    140         }
    141         SkUnichar uni;
    142         if (SampleCode::CharQ(*evt, &uni)) {
    143             switch (uni) {
    144                 case '1': fGeom = kRect_Geometry; this->inval(nullptr); return true;
    145                 case '2': fGeom = kRRect_Geometry; this->inval(nullptr); return true;
    146                 case '3': fGeom = kCircle_Geometry; this->inval(nullptr); return true;
    147                 case '4': fGeom = kConvexPath_Geometry; this->inval(nullptr); return true;
    148                 case '5': fGeom = kConcavePath_Geometry; this->inval(nullptr); return true;
    149                 case '6': fGeom = kRectAndRect_Geometry; this->inval(nullptr); return true;
    150                 case '7': fGeom = kRectAndRRect_Geometry; this->inval(nullptr); return true;
    151                 case '8': fGeom = kRectAndConvex_Geometry; this->inval(nullptr); return true;
    152                 case '9': fGeom = kRectAndConcave_Geometry; this->inval(nullptr); return true;
    153                 case 'f': fSign = -fSign; this->inval(nullptr); return true;
    154                 case 't': fClipFirst = !fClipFirst; this->inval(nullptr); return true;
    155                 default: break;
    156             }
    157         }
    158         return this->INHERITED::onQuery(evt);
    159     }
    160 
    161     void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
    162 
    163         int count = canvas->save();
    164 
    165         switch (fGeom) {
    166         case kRect_Geometry:
    167             canvas->clipRect(create_rect(offset), useAA);
    168             break;
    169         case kRRect_Geometry:
    170             canvas->clipRRect(create_rrect(offset), useAA);
    171             break;
    172         case kCircle_Geometry:
    173             canvas->clipRRect(create_circle(offset), useAA);
    174             break;
    175         case kConvexPath_Geometry:
    176             canvas->clipPath(create_convex_path(offset), useAA);
    177             break;
    178         case kConcavePath_Geometry:
    179             canvas->clipPath(create_concave_path(offset), useAA);
    180             break;
    181         case kRectAndRect_Geometry: {
    182             SkRect r = create_rect(offset);
    183             r.offset(fSign * kXlate, fSign * kXlate);
    184             canvas->clipRect(r, true); // AA here forces shader clips
    185             canvas->clipRect(create_rect(offset), useAA);
    186             } break;
    187         case kRectAndRRect_Geometry: {
    188             SkRect r = create_rect(offset);
    189             r.offset(fSign * kXlate, fSign * kXlate);
    190             canvas->clipRect(r, true); // AA here forces shader clips
    191             canvas->clipRRect(create_rrect(offset), useAA);
    192             } break;
    193         case kRectAndConvex_Geometry: {
    194             SkRect r = create_rect(offset);
    195             r.offset(fSign * kXlate, fSign * kXlate);
    196             canvas->clipRect(r, true); // AA here forces shader clips
    197             canvas->clipPath(create_convex_path(offset), useAA);
    198             } break;
    199         case kRectAndConcave_Geometry: {
    200             SkRect r = create_rect(offset);
    201             r.offset(fSign * kXlate, fSign * kXlate);
    202             canvas->clipRect(r, true); // AA here forces shader clips
    203             canvas->clipPath(create_concave_path(offset), useAA);
    204             } break;
    205         }
    206 
    207         SkISize size = canvas->getBaseLayerSize();
    208         SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
    209 
    210         SkPaint p;
    211         p.setColor(SK_ColorRED);
    212 
    213         canvas->drawRect(bigR, p);
    214         canvas->restoreToCount(count);
    215     }
    216 
    217     // Draw a big red rect through some clip geometry and also draw that same
    218     // geometry in black. The order in which they are drawn can be swapped.
    219     // This tests whether the clip and normally drawn geometry match up.
    220     void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
    221         if (fClipFirst) {
    222             this->drawClippedGeom(canvas, offset, useAA);
    223         }
    224 
    225         draw_normal_geom(canvas, offset, fGeom, useAA);
    226 
    227         if (!fClipFirst) {
    228             this->drawClippedGeom(canvas, offset, useAA);
    229         }
    230     }
    231 
    232     void onDrawContent(SkCanvas* canvas) override {
    233         SkScalar trans[2];
    234         fTrans.timeToValues(GetMSecs(), trans);
    235 
    236         SkPoint offset;
    237         offset.set(trans[0], trans[1]);
    238 
    239         int saveCount = canvas->save();
    240         this->drawGeometry(canvas, offset, false);
    241         canvas->restoreToCount(saveCount);
    242 
    243         this->inval(nullptr);
    244     }
    245 
    246     SkMSec GetMSecs() const {
    247         return static_cast<SkMSec>(SkTime::GetMSecs() - fStart);
    248     }
    249 
    250 private:
    251     SkInterpolator  fTrans;
    252     Geometry        fGeom;
    253     bool            fClipFirst;
    254     int             fSign;
    255     const double    fStart = SkTime::GetMSecs();
    256 
    257     typedef SampleView INHERITED;
    258 };
    259 
    260 //////////////////////////////////////////////////////////////////////////////
    261 
    262 static SkView* MyFactory() { return new ClipDrawMatchView; }
    263 static SkViewRegister reg(MyFactory);
    264