1 /*
2  * Copyright 2016 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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkRRect.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkString.h"
18 #include "src/core/SkCanvasPriv.h"
19 #include "src/core/SkClipOpPriv.h"
20 
21 namespace skiagm {
22 
23 // This test exercise SkCanvas::androidFramework_replaceClip behavior
24 class ComplexClip4GM : public GM {
25 public:
ComplexClip4GM(bool aaclip)26   ComplexClip4GM(bool aaclip)
27     : fDoAAClip(aaclip) {
28         this->setBGColor(0xFFDEDFDE);
29     }
30 
31 protected:
onShortName()32     SkString onShortName() override {
33         SkString str;
34         str.printf("complexclip4_%s",
35                    fDoAAClip ? "aa" : "bw");
36         return str;
37     }
38 
onISize()39     SkISize onISize() override { return SkISize::Make(970, 780); }
40 
41     // Android Framework will still support the legacy kReplace SkClipOp on older devices, so
42     // this represents how to do so while also respecting the device restriction using the newer
43     // androidFramework_replaceClip() API.
emulateDeviceRestriction(SkCanvas * canvas,const SkIRect & deviceRestriction)44     void emulateDeviceRestriction(SkCanvas* canvas, const SkIRect& deviceRestriction) {
45         // or any other device-space rect intersection
46         SkCanvasPriv::ReplaceClip(canvas, deviceRestriction);
47         // save for later replace clip ops
48         fDeviceRestriction = deviceRestriction;
49     }
50 
emulateClipRectReplace(SkCanvas * canvas,const SkRect & clipRect,bool aa)51     void emulateClipRectReplace(SkCanvas* canvas,
52                                 const SkRect& clipRect,
53                                 bool aa) {
54         SkCanvasPriv::ReplaceClip(canvas, fDeviceRestriction);
55         canvas->clipRect(clipRect, SkClipOp::kIntersect, aa);
56     }
57 
emulateClipRRectReplace(SkCanvas * canvas,const SkRRect & clipRRect,bool aa)58     void emulateClipRRectReplace(SkCanvas* canvas,
59                                  const SkRRect& clipRRect,
60                                  bool aa) {
61         SkCanvasPriv::ReplaceClip(canvas, fDeviceRestriction);
62         canvas->clipRRect(clipRRect, SkClipOp::kIntersect, aa);
63     }
64 
emulateClipPathReplace(SkCanvas * canvas,const SkPath & path,bool aa)65     void emulateClipPathReplace(SkCanvas* canvas,
66                                 const SkPath& path,
67                                 bool aa) {
68         SkCanvasPriv::ReplaceClip(canvas, fDeviceRestriction);
69         canvas->clipPath(path, SkClipOp::kIntersect, aa);
70     }
71 
onDraw(SkCanvas * canvas)72     void onDraw(SkCanvas* canvas) override {
73         SkPaint p;
74         p.setAntiAlias(fDoAAClip);
75         p.setColor(SK_ColorYELLOW);
76 
77         canvas->save();
78             // draw a yellow rect through a rect clip
79             canvas->save();
80                 emulateDeviceRestriction(canvas, SkIRect::MakeLTRB(100, 100, 300, 300));
81                 canvas->drawColor(SK_ColorGREEN);
82                 emulateClipRectReplace(canvas, SkRect::MakeLTRB(100, 200, 400, 500), fDoAAClip);
83                 canvas->drawRect(SkRect::MakeLTRB(100, 200, 400, 500), p);
84             canvas->restore();
85 
86             // draw a yellow rect through a diamond clip
87             canvas->save();
88                 emulateDeviceRestriction(canvas, SkIRect::MakeLTRB(500, 100, 800, 300));
89                 canvas->drawColor(SK_ColorGREEN);
90 
91                 SkPath pathClip = SkPath::Polygon({
92                     {650, 200},
93                     {900, 300},
94                     {650, 400},
95                     {650, 300},
96                 }, true);
97                 emulateClipPathReplace(canvas, pathClip, fDoAAClip);
98                 canvas->drawRect(SkRect::MakeLTRB(500, 200, 900, 500), p);
99             canvas->restore();
100 
101             // draw a yellow rect through a round rect clip
102             canvas->save();
103                 emulateDeviceRestriction(canvas, SkIRect::MakeLTRB(500, 500, 800, 700));
104                 canvas->drawColor(SK_ColorGREEN);
105 
106                 emulateClipRRectReplace(
107                         canvas, SkRRect::MakeOval(SkRect::MakeLTRB(500, 600, 900, 750)), fDoAAClip);
108                 canvas->drawRect(SkRect::MakeLTRB(500, 600, 900, 750), p);
109             canvas->restore();
110 
111             // fill the clip with yellow color showing that androidFramework_replaceClip is
112             // in device space
113             canvas->save();
114                 canvas->clipRect(SkRect::MakeLTRB(100, 400, 300, 750),
115                                  kIntersect_SkClipOp, fDoAAClip);
116                 canvas->drawColor(SK_ColorGREEN);
117                 // should not affect the device-space clip
118                 canvas->rotate(20.f);
119                 canvas->translate(50.f, 50.f);
120                 emulateDeviceRestriction(canvas, SkIRect::MakeLTRB(150, 450, 250, 700));
121                 canvas->drawColor(SK_ColorYELLOW);
122             canvas->restore();
123 
124         canvas->restore();
125     }
126 private:
127     SkIRect fDeviceRestriction;
128     bool    fDoAAClip;
129 
130     using INHERITED = GM;
131 };
132 
133 //////////////////////////////////////////////////////////////////////////////
134 
135 DEF_GM(return new ComplexClip4GM(false);)
136 DEF_GM(return new ComplexClip4GM(true);)
137 }  // namespace skiagm
138