3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "SampleCode.h"
11 #include "SkGradientShader.h"
16 #include "SkImageDecoder.h"
18 static void test_strokerect(SkCanvas* canvas) {
23 bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
24 bitmap.eraseColor(SK_ColorTRANSPARENT);
30 path.addRect(0.0f, 0.0f,
31 SkIntToScalar(width), SkIntToScalar(height),
32 SkPath::kCW_Direction);
33 SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
39 paint.setStyle(SkPaint::kStroke_Style);
40 paint.setStrokeWidth(1);
43 c.clear(SK_ColorTRANSPARENT);
45 canvas->drawBitmap(bitmap, 0, 0, NULL);
48 c.clear(SK_ColorTRANSPARENT);
49 c.drawPath(path, paint);
50 canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, NULL);
53 static void drawFadingText(SkCanvas* canvas,
54 const char* text, size_t len, SkScalar x, SkScalar y,
55 const SkPaint& paint) {
56 // Need a bounds for the text
58 SkPaint::FontMetrics fm;
60 paint.getFontMetrics(&fm);
61 bounds.set(x, y + fm.fTop, x + paint.measureText(text, len), y + fm.fBottom);
63 // may need to outset bounds a little, to account for hinting and/or
65 bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
67 canvas->saveLayer(&bounds, NULL);
68 canvas->drawText(text, len, x, y, paint);
70 const SkPoint pts[] = {
74 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
76 // pos[1] value is where we start to fade, relative to the width
77 // of our pts[] array.
78 const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
80 SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, 3,
81 SkShader::kClamp_TileMode);
83 p.setShader(s)->unref();
84 p.setXfermodeMode(SkXfermode::kDstIn_Mode);
85 canvas->drawRect(bounds, p);
90 static void test_text(SkCanvas* canvas) {
92 paint.setAntiAlias(true);
93 paint.setTextSize(20);
95 const char* str = "Hamburgefons";
96 size_t len = strlen(str);
100 canvas->drawText(str, len, x, y, paint);
104 const SkPoint pts[] = { { x, y }, { x + paint.measureText(str, len), y } };
105 const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
106 const SkScalar pos[] = { 0, 0.9f, 1 };
107 SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos,
108 SK_ARRAY_COUNT(colors),
109 SkShader::kClamp_TileMode);
110 paint.setShader(s)->unref();
111 canvas->drawText(str, len, x, y, paint);
114 paint.setShader(NULL);
115 drawFadingText(canvas, str, len, x, y, paint);
118 #ifdef SK_BUILD_FOR_WIN
119 // windows doesn't have roundf
120 inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
124 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
125 int count, int32_t runs[]) {
127 r.set(left, top, right, bottom);
129 rgn->debugSetRuns(runs, count);
130 SkASSERT(rgn->getBounds() == r);
133 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
134 static int32_t dataA[] = {
136 0x000001dd, 2, 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 0x7fffffff,
137 0x000001de, 1, 0x00000001, 0x00000025, 0x7fffffff,
138 0x000004b3, 1, 0x00000001, 0x00000026, 0x7fffffff,
139 0x000004b4, 1, 0x0000000c, 0x00000026, 0x7fffffff,
140 0x00000579, 1, 0x00000000, 0x0000013a, 0x7fffffff,
141 0x000005d8, 1, 0x00000000, 0x0000013b, 0x7fffffff,
144 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
146 static int32_t dataB[] = {
148 0x000000c4, 1, 0x000000a1, 0x000000f0, 0x7fffffff,
149 0x000000d6, 0, 0x7fffffff,
150 0x000000e4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
151 0x000000e6, 0, 0x7fffffff,
152 0x000000f4, 2, 0x00000070, 0x00000079, 0x000000a1, 0x000000b0, 0x7fffffff,
153 0x000000f6, 0, 0x7fffffff,
154 0x00000104, 1, 0x000000a1, 0x000000b0, 0x7fffffff,
157 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
159 rc->op(*ra, *rb, SkRegion::kUnion_Op);
163 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
164 dst->fLeft = (int)::roundf(src.fLeft * scale);
165 dst->fTop = (int)::roundf(src.fTop * scale);
166 dst->fRight = (int)::roundf(src.fRight * scale);
167 dst->fBottom = (int)::roundf(src.fBottom * scale);
170 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
172 SkRegion::Iterator iter(src);
174 for (; !iter.done(); iter.next()) {
176 scale_rect(&r, iter.rect(), scale);
177 tmp.op(r, SkRegion::kUnion_Op);
182 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
183 const SkPaint& paint) {
185 scale_rgn(&scaled, rgn, 0.5f);
187 SkRegion::Iterator iter(rgn);
189 for (; !iter.done(); iter.next())
193 canvas->drawRect(r, paint);
197 class RegionView : public SampleView {
200 fBase.set(100, 100, 150, 150);
203 fRect.offset(25, 25);
204 this->setBGColor(0xFFDDDDDD);
207 void build_base_rgn(SkRegion* rgn) {
211 rgn->op(r, SkRegion::kUnion_Op);
214 void build_rgn(SkRegion* rgn, SkRegion::Op op) {
221 // overrides from SkEventSink
222 bool onQuery(SkEvent* evt) SK_OVERRIDE {
223 if (SampleCode::TitleQ(*evt)) {
224 SampleCode::TitleR(evt, "Regions");
227 return this->INHERITED::onQuery(evt);
230 static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
233 paint.setAntiAlias(true);
234 paint.setTextSize(SkIntToScalar(20));
235 paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
236 canvas->drawText(text, strlen(text), loc.fX, loc.fY, paint);
239 void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
241 build_base_rgn(&rgn);
243 drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
244 drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
247 void drawOrig(SkCanvas* canvas, bool bg) {
251 paint.setStyle(SkPaint::kStroke_Style);
253 paint.setColor(0xFFBBBBBB);
256 build_base_rgn(&rgn);
257 paint_rgn(canvas, rgn, paint);
260 canvas->drawRect(r, paint);
263 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
266 this->build_rgn(&rgn, op);
269 SkRegion tmp, tmp2(rgn);
272 tmp.translate(5, -3);
276 SkDEBUGCODE(size_t size = ) tmp.writeToMemory(NULL);
277 SkASSERT(size <= sizeof(buffer));
278 SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
279 SkASSERT(size == size2);
282 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
283 SkASSERT(size == size2);
285 SkASSERT(tmp3 == tmp);
288 rgn.translate(20, 30, &tmp);
289 SkASSERT(rgn.isEmpty() || tmp != rgn);
290 tmp.translate(-20, -30);
291 SkASSERT(tmp == rgn);
294 this->drawOrig(canvas, true);
297 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
298 paint_rgn(canvas, rgn, paint);
300 paint.setStyle(SkPaint::kStroke_Style);
301 paint.setColor(color);
302 paint_rgn(canvas, rgn, paint);
305 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
309 this->build_rgn(&rgn, op);
310 rgn.getBoundaryPath(&path);
312 this->drawOrig(canvas, true);
316 paint.setStyle(SkPaint::kFill_Style);
317 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
318 canvas->drawPath(path, paint);
319 paint.setColor(color);
320 paint.setStyle(SkPaint::kStroke_Style);
321 canvas->drawPath(path, paint);
324 void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
325 if (false) { // avoid bit rot, suppress warning
326 test_strokerect(canvas);
329 if (false) { // avoid bit rot, suppress warning
336 test_union_bug_1505668(&a, &b, &c);
338 if (false) { // draw the result of the test
341 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
342 paint.setColor(SK_ColorRED);
343 paint_rgn(canvas, a, paint);
344 paint.setColor(0x800000FF);
345 paint_rgn(canvas, b, paint);
346 paint.setColor(SK_ColorBLACK);
347 paint.setStyle(SkPaint::kStroke_Style);
348 // paint_rgn(canvas, c, paint);
353 const SkPoint origins[] = {
354 { 30*SK_Scalar1, 50*SK_Scalar1 },
355 { 150*SK_Scalar1, 50*SK_Scalar1 },
357 this->drawPredicates(canvas, origins);
359 static const struct {
364 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
365 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
366 { 0xFF008800, "Union", SkRegion::kUnion_Op },
367 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
371 textPaint.setAntiAlias(true);
372 textPaint.setTextSize(SK_Scalar1*24);
374 this->drawOrig(canvas, false);
376 canvas->translate(SkIntToScalar(200), 0);
377 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
380 canvas->translate(0, SkIntToScalar(200));
382 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
383 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
385 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
388 canvas->translate(0, SkIntToScalar(200));
389 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
392 canvas->translate(SkIntToScalar(200), 0);
396 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
397 unsigned modi) SK_OVERRIDE {
398 return fRect.contains(SkScalarRoundToInt(x),
399 SkScalarRoundToInt(y)) ? new Click(this) : NULL;
402 bool onClick(Click* click) SK_OVERRIDE {
403 fRect.offset(click->fICurr.fX - click->fIPrev.fX,
404 click->fICurr.fY - click->fIPrev.fY);
410 SkIRect fBase, fRect;
412 typedef SampleView INHERITED;
415 //////////////////////////////////////////////////////////////////////////////
417 static SkView* MyFactory() { return new RegionView; }
418 static SkViewRegister reg(MyFactory);