| /* | 
 |  * Copyright 2015 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "SampleCode.h" | 
 | #include "SkCanvas.h" | 
 | #include "SkInterpolator.h" | 
 | #include "SkTime.h" | 
 |  | 
 | // This slide tests out the match up between BW clipping and rendering. It can | 
 | // draw a large rect through some clip geometry and draw the same geometry | 
 | // normally. Which one is drawn first can be toggled. The pair of objects is translated | 
 | // fractionally (via an animator) to expose snapping bugs. The key bindings are: | 
 | //      1-9: the different geometries | 
 | //      t:   toggle which is drawn first the clip or the normal geometry | 
 | //      f:   flip-flops which corner the bottom AA clip rect occupies in the complex clip cases | 
 |  | 
 | // The possible geometric combinations to test | 
 | enum Geometry { | 
 |     kRect_Geometry, | 
 |     kRRect_Geometry, | 
 |     kCircle_Geometry, | 
 |     kConvexPath_Geometry, | 
 |     kConcavePath_Geometry, | 
 |     kRectAndRect_Geometry, | 
 |     kRectAndRRect_Geometry, | 
 |     kRectAndConvex_Geometry, | 
 |     kRectAndConcave_Geometry | 
 | }; | 
 |  | 
 | // The basic rect used is [kMin,kMin]..[kMax,kMax] | 
 | static const float kMin = 100.5f; | 
 | static const float kMid = 200.0f; | 
 | static const float kMax = 299.5f; | 
 |  | 
 | // The translation applied to the base AA rect in the combination cases | 
 | // (i.e., kRectAndRect through kRectAndConcave) | 
 | static const float kXlate = 100.0f; | 
 |  | 
 | SkRect create_rect(const SkPoint& offset) { | 
 |     SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax); | 
 |     r.offset(offset); | 
 |     return r; | 
 | } | 
 |  | 
 | SkRRect create_rrect(const SkPoint& offset) { | 
 |     SkRRect rrect; | 
 |     rrect.setRectXY(create_rect(offset), 10, 10); | 
 |     return rrect; | 
 | } | 
 |  | 
 | SkRRect create_circle(const SkPoint& offset) { | 
 |     SkRRect circle; | 
 |     circle.setOval(create_rect(offset)); | 
 |     return circle; | 
 | } | 
 |  | 
 | SkPath create_convex_path(const SkPoint& offset) { | 
 |     SkPath convexPath; | 
 |     convexPath.moveTo(kMin, kMin); | 
 |     convexPath.lineTo(kMax, kMax); | 
 |     convexPath.lineTo(kMin, kMax); | 
 |     convexPath.close(); | 
 |     convexPath.offset(offset.fX, offset.fY); | 
 |     return convexPath; | 
 | } | 
 |  | 
 | SkPath create_concave_path(const SkPoint& offset) { | 
 |     SkPath concavePath; | 
 |     concavePath.moveTo(kMin, kMin); | 
 |     concavePath.lineTo(kMid, 105.0f); | 
 |     concavePath.lineTo(kMax, kMin); | 
 |     concavePath.lineTo(295.0f, kMid); | 
 |     concavePath.lineTo(kMax, kMax); | 
 |     concavePath.lineTo(kMid, 295.0f); | 
 |     concavePath.lineTo(kMin, kMax); | 
 |     concavePath.lineTo(105.0f, kMid); | 
 |     concavePath.close(); | 
 |  | 
 |     concavePath.offset(offset.fX, offset.fY); | 
 |     return concavePath; | 
 | } | 
 |  | 
 | static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) { | 
 |     SkPaint p; | 
 |     p.setAntiAlias(useAA); | 
 |     p.setColor(SK_ColorBLACK); | 
 |  | 
 |     switch (geom) { | 
 |     case kRect_Geometry:                // fall thru | 
 |     case kRectAndRect_Geometry: | 
 |         canvas->drawRect(create_rect(offset), p); | 
 |         break; | 
 |     case kRRect_Geometry:               // fall thru | 
 |     case kRectAndRRect_Geometry: | 
 |         canvas->drawRRect(create_rrect(offset), p); | 
 |         break; | 
 |     case kCircle_Geometry: | 
 |         canvas->drawRRect(create_circle(offset), p); | 
 |         break; | 
 |     case kConvexPath_Geometry:          // fall thru | 
 |     case kRectAndConvex_Geometry: | 
 |         canvas->drawPath(create_convex_path(offset), p); | 
 |         break; | 
 |     case kConcavePath_Geometry:         // fall thru | 
 |     case kRectAndConcave_Geometry: | 
 |         canvas->drawPath(create_concave_path(offset), p); | 
 |         break; | 
 |     }  | 
 | } | 
 |  | 
 | class ClipDrawMatchView : public SampleView { | 
 | public: | 
 |     ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true), fSign(1) { | 
 |         SkScalar values[2]; | 
 |  | 
 |         fTrans.setRepeatCount(999); | 
 |         values[0] = values[1] = 0; | 
 |         fTrans.setKeyFrame(0, SkTime::GetMSecs() + 1000, values); | 
 |         values[1] = 1; | 
 |         fTrans.setKeyFrame(1, SkTime::GetMSecs() + 2000, values); | 
 |         values[0] = values[1] = 1; | 
 |         fTrans.setKeyFrame(2, SkTime::GetMSecs() + 3000, values); | 
 |         values[1] = 0; | 
 |         fTrans.setKeyFrame(3, SkTime::GetMSecs() + 4000, values); | 
 |         values[0] = 0; | 
 |         fTrans.setKeyFrame(4, SkTime::GetMSecs() + 5000, values); | 
 |     } | 
 |  | 
 | protected: | 
 |     bool onQuery(SkEvent* evt) override { | 
 |         if (SampleCode::TitleQ(*evt)) { | 
 |             SampleCode::TitleR(evt, "ClipDrawMatch"); | 
 |             return true; | 
 |         } | 
 |         SkUnichar uni; | 
 |         if (SampleCode::CharQ(*evt, &uni)) { | 
 |             switch (uni) { | 
 |                 case '1': fGeom = kRect_Geometry; this->inval(NULL); return true; | 
 |                 case '2': fGeom = kRRect_Geometry; this->inval(NULL); return true; | 
 |                 case '3': fGeom = kCircle_Geometry; this->inval(NULL); return true; | 
 |                 case '4': fGeom = kConvexPath_Geometry; this->inval(NULL); return true; | 
 |                 case '5': fGeom = kConcavePath_Geometry; this->inval(NULL); return true; | 
 |                 case '6': fGeom = kRectAndRect_Geometry; this->inval(NULL); return true; | 
 |                 case '7': fGeom = kRectAndRRect_Geometry; this->inval(NULL); return true; | 
 |                 case '8': fGeom = kRectAndConvex_Geometry; this->inval(NULL); return true; | 
 |                 case '9': fGeom = kRectAndConcave_Geometry; this->inval(NULL); return true; | 
 |                 case 'f': fSign = -fSign; this->inval(NULL); return true; | 
 |                 case 't': fClipFirst = !fClipFirst; this->inval(NULL); return true; | 
 |                 default: break; | 
 |             } | 
 |         } | 
 |         return this->INHERITED::onQuery(evt); | 
 |     } | 
 |  | 
 |     void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) { | 
 |  | 
 |         int count = canvas->save(); | 
 |  | 
 |         switch (fGeom) { | 
 |         case kRect_Geometry: | 
 |             canvas->clipRect(create_rect(offset), SkRegion::kReplace_Op, useAA); | 
 |             break; | 
 |         case kRRect_Geometry: | 
 |             canvas->clipRRect(create_rrect(offset), SkRegion::kReplace_Op, useAA); | 
 |             break; | 
 |         case kCircle_Geometry: | 
 |             canvas->clipRRect(create_circle(offset), SkRegion::kReplace_Op, useAA); | 
 |             break; | 
 |         case kConvexPath_Geometry: | 
 |             canvas->clipPath(create_convex_path(offset), SkRegion::kReplace_Op, useAA); | 
 |             break; | 
 |         case kConcavePath_Geometry: | 
 |             canvas->clipPath(create_concave_path(offset), SkRegion::kReplace_Op, useAA); | 
 |             break; | 
 |         case kRectAndRect_Geometry: { | 
 |             SkRect r = create_rect(offset); | 
 |             r.offset(fSign * kXlate, fSign * kXlate); | 
 |             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips | 
 |             canvas->clipRect(create_rect(offset), SkRegion::kIntersect_Op, useAA); | 
 |             } break; | 
 |         case kRectAndRRect_Geometry: { | 
 |             SkRect r = create_rect(offset); | 
 |             r.offset(fSign * kXlate, fSign * kXlate); | 
 |             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips | 
 |             canvas->clipRRect(create_rrect(offset), SkRegion::kIntersect_Op, useAA); | 
 |             } break; | 
 |         case kRectAndConvex_Geometry: { | 
 |             SkRect r = create_rect(offset); | 
 |             r.offset(fSign * kXlate, fSign * kXlate); | 
 |             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips | 
 |             canvas->clipPath(create_convex_path(offset), SkRegion::kIntersect_Op, useAA); | 
 |             } break; | 
 |         case kRectAndConcave_Geometry: { | 
 |             SkRect r = create_rect(offset); | 
 |             r.offset(fSign * kXlate, fSign * kXlate); | 
 |             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips | 
 |             canvas->clipPath(create_concave_path(offset), SkRegion::kIntersect_Op, useAA); | 
 |             } break; | 
 |         }  | 
 |  | 
 |         SkISize size = canvas->getDeviceSize(); | 
 |         SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height())); | 
 |  | 
 |         SkPaint p; | 
 |         p.setColor(SK_ColorRED); | 
 |  | 
 |         canvas->drawRect(bigR, p); | 
 |         canvas->restoreToCount(count); | 
 |     } | 
 |  | 
 |     // Draw a big red rect through some clip geometry and also draw that same | 
 |     // geometry in black. The order in which they are drawn can be swapped. | 
 |     // This tests whether the clip and normally drawn geometry match up. | 
 |     void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) { | 
 |         if (fClipFirst) { | 
 |             this->drawClippedGeom(canvas, offset, useAA); | 
 |         } | 
 |  | 
 |         draw_normal_geom(canvas, offset, fGeom, useAA); | 
 |  | 
 |         if (!fClipFirst) { | 
 |             this->drawClippedGeom(canvas, offset, useAA); | 
 |         } | 
 |     } | 
 |  | 
 |     void onDrawContent(SkCanvas* canvas) override { | 
 |         SkScalar trans[2]; | 
 |         fTrans.timeToValues(SkTime::GetMSecs(), trans); | 
 |  | 
 |         SkPoint offset; | 
 |         offset.set(trans[0], trans[1]); | 
 |  | 
 |         int saveCount = canvas->save(); | 
 |         this->drawGeometry(canvas, offset, false); | 
 |         canvas->restoreToCount(saveCount); | 
 |  | 
 |         this->inval(NULL); | 
 |     } | 
 |  | 
 | private: | 
 |     SkInterpolator  fTrans; | 
 |     Geometry        fGeom; | 
 |     bool            fClipFirst; | 
 |     int             fSign; | 
 |  | 
 |     typedef SampleView INHERITED; | 
 | }; | 
 |  | 
 | ////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | static SkView* MyFactory() { return new ClipDrawMatchView; } | 
 | static SkViewRegister reg(MyFactory); |