• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkFont.h"
11 #include "include/core/SkFontMetrics.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkRegion.h"
14 #include "include/core/SkShader.h"
15 #include "include/effects/SkGradientShader.h"
16 #include "samplecode/Sample.h"
17 #include "src/utils/SkUTF.h"
18 
19 #include <math.h>
20 
test_strokerect(SkCanvas * canvas)21 static void test_strokerect(SkCanvas* canvas) {
22     int width = 100;
23     int height = 100;
24 
25     SkBitmap bitmap;
26     bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
27     bitmap.eraseColor(SK_ColorTRANSPARENT);
28 
29     SkScalar dx = 20;
30     SkScalar dy = 20;
31 
32     SkPath path;
33     path.addRect(0.0f, 0.0f,
34                  SkIntToScalar(width), SkIntToScalar(height),
35                  SkPath::kCW_Direction);
36     SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
37 
38     SkCanvas c(bitmap);
39     c.translate(dx, dy);
40 
41     SkPaint paint;
42     paint.setStyle(SkPaint::kStroke_Style);
43     paint.setStrokeWidth(1);
44 
45     // use the rect
46     c.clear(SK_ColorTRANSPARENT);
47     c.drawRect(r, paint);
48     canvas->drawBitmap(bitmap, 0, 0, nullptr);
49 
50     // use the path
51     c.clear(SK_ColorTRANSPARENT);
52     c.drawPath(path, paint);
53     canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
54 }
55 
drawFadingText(SkCanvas * canvas,const char * text,size_t len,SkScalar x,SkScalar y,const SkFont & font,const SkPaint & paint)56 static void drawFadingText(SkCanvas* canvas,
57                            const char* text, size_t len, SkScalar x, SkScalar y,
58                            const SkFont& font, const SkPaint& paint) {
59     // Need a bounds for the text
60     SkRect bounds;
61     SkFontMetrics fm;
62 
63     font.getMetrics(&fm);
64     bounds.set(x, y + fm.fTop, x + font.measureText(text, len, SkTextEncoding::kUTF8), y + fm.fBottom);
65 
66     // may need to outset bounds a little, to account for hinting and/or
67     // antialiasing
68     bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
69 
70     canvas->saveLayer(&bounds, nullptr);
71     canvas->drawSimpleText(text, len, SkTextEncoding::kUTF8, x, y, font, paint);
72 
73     const SkPoint pts[] = {
74         { bounds.fLeft, y },
75         { bounds.fRight, y }
76     };
77     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
78 
79     // pos[1] value is where we start to fade, relative to the width
80     // of our pts[] array.
81     const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
82 
83     SkPaint p;
84     p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkTileMode::kClamp));
85     p.setBlendMode(SkBlendMode::kDstIn);
86     canvas->drawRect(bounds, p);
87 
88     canvas->restore();
89 }
90 
test_text(SkCanvas * canvas)91 static void test_text(SkCanvas* canvas) {
92     SkPaint paint;
93     paint.setAntiAlias(true);
94 
95     SkFont font;
96     font.setSize(20);
97 
98     const char* str = "Hamburgefons";
99     size_t len = strlen(str);
100     SkScalar x = 20;
101     SkScalar y = 20;
102 
103     canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
104 
105     y += 20;
106 
107     const SkPoint pts[] = { { x                                                    , y },
108                             { x + font.measureText(str, len, SkTextEncoding::kUTF8), y } };
109     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
110     const SkScalar pos[] = { 0, 0.9f, 1 };
111     paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
112                                                  SK_ARRAY_COUNT(colors),
113                                                  SkTileMode::kClamp));
114     canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
115 
116     y += 20;
117     paint.setShader(nullptr);
118     drawFadingText(canvas, str, len, x, y, font, paint);
119 }
120 
scale_rect(SkIRect * dst,const SkIRect & src,float scale)121 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
122     dst->fLeft = (int)::roundf(src.fLeft * scale);
123     dst->fTop = (int)::roundf(src.fTop * scale);
124     dst->fRight = (int)::roundf(src.fRight * scale);
125     dst->fBottom = (int)::roundf(src.fBottom * scale);
126 }
127 
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)128 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
129     SkRegion tmp;
130     SkRegion::Iterator iter(src);
131 
132     for (; !iter.done(); iter.next()) {
133         SkIRect r;
134         scale_rect(&r, iter.rect(), scale);
135         tmp.op(r, SkRegion::kUnion_Op);
136     }
137     dst->swap(tmp);
138 }
139 
paint_rgn(SkCanvas * canvas,const SkRegion & rgn,const SkPaint & paint)140 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
141                       const SkPaint& paint) {
142     SkRegion scaled;
143     scale_rgn(&scaled, rgn, 0.5f);
144 
145     SkRegion::Iterator  iter(rgn);
146 
147     for (; !iter.done(); iter.next())
148     {
149         SkRect    r;
150         r.set(iter.rect());
151         canvas->drawRect(r, paint);
152     }
153 }
154 
155 class RegionView : public Sample {
156 public:
RegionView()157     RegionView() {
158         fBase.set(100, 100, 150, 150);
159         fRect = fBase;
160         fRect.inset(5, 5);
161         fRect.offset(25, 25);
162         this->setBGColor(0xFFDDDDDD);
163     }
164 
build_base_rgn(SkRegion * rgn)165     void build_base_rgn(SkRegion* rgn) {
166         rgn->setRect(fBase);
167         SkIRect r = fBase;
168         r.offset(75, 20);
169         rgn->op(r, SkRegion::kUnion_Op);
170     }
171 
build_rgn(SkRegion * rgn,SkRegion::Op op)172     void build_rgn(SkRegion* rgn, SkRegion::Op op) {
173         build_base_rgn(rgn);
174         rgn->op(fRect, op);
175     }
176 
177 
178 protected:
name()179     SkString name() override { return SkString("Regions"); }
180 
drawstr(SkCanvas * canvas,const char text[],const SkPoint & loc,bool hilite)181     static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
182                         bool hilite) {
183         SkPaint paint;
184         paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
185         SkFont font;
186         font.setSize(SkIntToScalar(20));
187         canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, loc.fX, loc.fY, font, paint);
188     }
189 
drawPredicates(SkCanvas * canvas,const SkPoint pts[])190     void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
191         SkRegion rgn;
192         build_base_rgn(&rgn);
193 
194         drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
195         drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
196     }
197 
drawOrig(SkCanvas * canvas,bool bg)198     void drawOrig(SkCanvas* canvas, bool bg) {
199         SkRect      r;
200         SkPaint     paint;
201 
202         paint.setStyle(SkPaint::kStroke_Style);
203         if (bg)
204             paint.setColor(0xFFBBBBBB);
205 
206         SkRegion rgn;
207         build_base_rgn(&rgn);
208         paint_rgn(canvas, rgn, paint);
209 
210         r.set(fRect);
211         canvas->drawRect(r, paint);
212     }
213 
drawRgnOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)214     void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
215         SkRegion    rgn;
216 
217         this->build_rgn(&rgn, op);
218 
219         {
220             SkRegion tmp, tmp2(rgn);
221 
222             tmp = tmp2;
223             tmp.translate(5, -3);
224 
225             {
226                 char    buffer[1000];
227                 SkDEBUGCODE(size_t  size = ) tmp.writeToMemory(nullptr);
228                 SkASSERT(size <= sizeof(buffer));
229                 SkDEBUGCODE(size_t  size2 = ) tmp.writeToMemory(buffer);
230                 SkASSERT(size == size2);
231 
232                 SkRegion    tmp3;
233                 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
234                 SkASSERT(size == size2);
235 
236                 SkASSERT(tmp3 == tmp);
237             }
238 
239             rgn.translate(20, 30, &tmp);
240             SkASSERT(rgn.isEmpty() || tmp != rgn);
241             tmp.translate(-20, -30);
242             SkASSERT(tmp == rgn);
243         }
244 
245         this->drawOrig(canvas, true);
246 
247         SkPaint paint;
248         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
249         paint_rgn(canvas, rgn, paint);
250 
251         paint.setStyle(SkPaint::kStroke_Style);
252         paint.setColor(color);
253         paint_rgn(canvas, rgn, paint);
254     }
255 
drawPathOped(SkCanvas * canvas,SkRegion::Op op,SkColor color)256     void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
257         SkRegion    rgn;
258         SkPath      path;
259 
260         this->build_rgn(&rgn, op);
261         rgn.getBoundaryPath(&path);
262 
263         this->drawOrig(canvas, true);
264 
265         SkPaint paint;
266 
267         paint.setStyle(SkPaint::kFill_Style);
268         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
269         canvas->drawPath(path, paint);
270         paint.setColor(color);
271         paint.setStyle(SkPaint::kStroke_Style);
272         canvas->drawPath(path, paint);
273     }
274 
onDrawContent(SkCanvas * canvas)275     void onDrawContent(SkCanvas* canvas) override {
276         if (false) { // avoid bit rot, suppress warning
277             test_strokerect(canvas);
278             return;
279         }
280         if (false) { // avoid bit rot, suppress warning
281             test_text(canvas);
282             return;
283         }
284 
285         const SkPoint origins[] = {
286             { 30*SK_Scalar1, 50*SK_Scalar1 },
287             { 150*SK_Scalar1, 50*SK_Scalar1 },
288         };
289         this->drawPredicates(canvas, origins);
290 
291         static const struct {
292             SkColor         fColor;
293             const char*     fName;
294             SkRegion::Op    fOp;
295         } gOps[] = {
296             { SK_ColorBLACK,    "Difference",   SkRegion::kDifference_Op    },
297             { SK_ColorRED,      "Intersect",    SkRegion::kIntersect_Op     },
298             { 0xFF008800,       "Union",        SkRegion::kUnion_Op         },
299             { SK_ColorBLUE,     "XOR",          SkRegion::kXOR_Op           }
300         };
301 
302         SkFont font;
303         font.setSize(SK_Scalar1*24);
304 
305         this->drawOrig(canvas, false);
306         canvas->save();
307             canvas->translate(SkIntToScalar(200), 0);
308             this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
309         canvas->restore();
310 
311         canvas->translate(0, SkIntToScalar(200));
312 
313         for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
314             canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8,
315                                    SkIntToScalar(75), SkIntToScalar(50), font, SkPaint());
316 
317             this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
318 
319             canvas->save();
320             canvas->translate(0, SkIntToScalar(200));
321             this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
322             canvas->restore();
323 
324             canvas->translate(SkIntToScalar(200), 0);
325         }
326     }
327 
onFindClickHandler(SkScalar x,SkScalar y,ModifierKey modi)328     virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
329                                               ModifierKey modi) override {
330         return fRect.contains(SkScalarRoundToInt(x),
331                               SkScalarRoundToInt(y)) ? new Click() : nullptr;
332     }
333 
onClick(Click * click)334     bool onClick(Click* click) override {
335         fRect.offset(click->fCurr.fX - click->fPrev.fX,
336                      click->fCurr.fY - click->fPrev.fY);
337         return true;
338     }
339 
340 private:
341     SkIRect    fBase, fRect;
342 
343     typedef Sample INHERITED;
344 };
345 
346 //////////////////////////////////////////////////////////////////////////////
347 
348 DEF_SAMPLE( return new RegionView(); )
349