1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SampleCode.h" 9 #include "SkView.h" 10 #include "SkCanvas.h" 11 #include "SkGradientShader.h" 12 #include "SkPath.h" 13 #include "SkRegion.h" 14 #include "SkShader.h" 15 #include "SkUtils.h" 16 #include "SkImageDecoder.h" 17 18 #ifdef SK_BUILD_FOR_WIN 19 // windows doesn't have roundf 20 inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); } 21 #endif 22 23 #ifdef SK_DEBUG 24 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom, 25 size_t count, int32_t runs[]) { 26 SkIRect r; 27 r.set(left, top, right, bottom); 28 29 rgn->debugSetRuns(runs, count); 30 SkASSERT(rgn->getBounds() == r); 31 } 32 33 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) { 34 static int32_t dataA[] = { 35 0x00000001, 0x000001dd, 36 0x00000001, 0x0000000c, 0x0000000d, 0x00000025, 37 0x7fffffff, 0x000001de, 0x00000001, 0x00000025, 38 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026, 39 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026, 40 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a, 41 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b, 42 0x7fffffff, 0x7fffffff 43 }; 44 make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA); 45 46 static int32_t dataB[] = { 47 0x000000b6, 0x000000c4, 48 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6, 49 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079, 50 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6, 51 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079, 52 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6, 53 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0, 54 0x7fffffff, 0x7fffffff 55 }; 56 make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB); 57 58 rc->op(*ra, *rb, SkRegion::kUnion_Op); 59 } 60 #endif 61 62 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) { 63 dst->fLeft = (int)::roundf(src.fLeft * scale); 64 dst->fTop = (int)::roundf(src.fTop * scale); 65 dst->fRight = (int)::roundf(src.fRight * scale); 66 dst->fBottom = (int)::roundf(src.fBottom * scale); 67 } 68 69 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { 70 SkRegion tmp; 71 SkRegion::Iterator iter(src); 72 73 for (; !iter.done(); iter.next()) { 74 SkIRect r; 75 scale_rect(&r, iter.rect(), scale); 76 tmp.op(r, SkRegion::kUnion_Op); 77 } 78 dst->swap(tmp); 79 } 80 81 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn, 82 const SkPaint& paint) { 83 SkRegion scaled; 84 scale_rgn(&scaled, rgn, 0.5f); 85 86 SkRegion::Iterator iter(rgn); 87 88 for (; !iter.done(); iter.next()) 89 { 90 SkRect r; 91 r.set(iter.rect()); 92 canvas->drawRect(r, paint); 93 } 94 } 95 96 class RegionView : public SampleView { 97 public: 98 RegionView() { 99 fBase.set(100, 100, 150, 150); 100 fRect = fBase; 101 fRect.inset(5, 5); 102 fRect.offset(25, 25); 103 this->setBGColor(0xFFDDDDDD); 104 } 105 106 void build_rgn(SkRegion* rgn, SkRegion::Op op) { 107 rgn->setRect(fBase); 108 SkIRect r = fBase; 109 r.offset(75, 20); 110 rgn->op(r, SkRegion::kUnion_Op); 111 rgn->op(fRect, op); 112 } 113 114 115 protected: 116 // overrides from SkEventSink 117 virtual bool onQuery(SkEvent* evt) { 118 if (SampleCode::TitleQ(*evt)) { 119 SampleCode::TitleR(evt, "Regions"); 120 return true; 121 } 122 return this->INHERITED::onQuery(evt); 123 } 124 125 void drawOrig(SkCanvas* canvas, bool bg) { 126 SkRect r; 127 SkPaint paint; 128 129 paint.setStyle(SkPaint::kStroke_Style); 130 if (bg) 131 paint.setColor(0xFFBBBBBB); 132 133 r.set(fBase); 134 canvas->drawRect(r, paint); 135 r.set(fRect); 136 canvas->drawRect(r, paint); 137 } 138 139 void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) { 140 SkRegion rgn; 141 142 this->build_rgn(&rgn, op); 143 144 { 145 SkRegion tmp, tmp2(rgn); 146 147 tmp = tmp2; 148 tmp.translate(5, -3); 149 150 { 151 char buffer[1000]; 152 size_t size = tmp.flatten(NULL); 153 SkASSERT(size <= sizeof(buffer)); 154 size_t size2 = tmp.flatten(buffer); 155 SkASSERT(size == size2); 156 157 SkRegion tmp3; 158 size2 = tmp3.unflatten(buffer); 159 SkASSERT(size == size2); 160 161 SkASSERT(tmp3 == tmp); 162 } 163 164 rgn.translate(20, 30, &tmp); 165 SkASSERT(rgn.isEmpty() || tmp != rgn); 166 tmp.translate(-20, -30); 167 SkASSERT(tmp == rgn); 168 } 169 170 this->drawOrig(canvas, true); 171 172 SkPaint paint; 173 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); 174 paint_rgn(canvas, rgn, paint); 175 176 paint.setStyle(SkPaint::kStroke_Style); 177 paint.setColor(color); 178 paint_rgn(canvas, rgn, paint); 179 } 180 181 void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) { 182 SkRegion rgn; 183 SkPath path; 184 185 this->build_rgn(&rgn, op); 186 rgn.getBoundaryPath(&path); 187 188 this->drawOrig(canvas, true); 189 190 SkPaint paint; 191 192 paint.setStyle(SkPaint::kFill_Style); 193 paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); 194 canvas->drawPath(path, paint); 195 paint.setColor(color); 196 paint.setStyle(SkPaint::kStroke_Style); 197 canvas->drawPath(path, paint); 198 } 199 200 virtual void onDrawContent(SkCanvas* canvas) { 201 #ifdef SK_DEBUG 202 if (true) { 203 SkRegion a, b, c; 204 test_union_bug_1505668(&a, &b, &c); 205 206 if (false) { // draw the result of the test 207 SkPaint paint; 208 209 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); 210 paint.setColor(SK_ColorRED); 211 paint_rgn(canvas, a, paint); 212 paint.setColor(0x800000FF); 213 paint_rgn(canvas, b, paint); 214 paint.setColor(SK_ColorBLACK); 215 paint.setStyle(SkPaint::kStroke_Style); 216 // paint_rgn(canvas, c, paint); 217 return; 218 } 219 } 220 #endif 221 222 static const struct { 223 SkColor fColor; 224 const char* fName; 225 SkRegion::Op fOp; 226 } gOps[] = { 227 { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op }, 228 { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op }, 229 { 0xFF008800, "Union", SkRegion::kUnion_Op }, 230 { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op } 231 }; 232 233 SkPaint textPaint; 234 textPaint.setAntiAlias(true); 235 textPaint.setTextSize(SK_Scalar1*24); 236 237 this->drawOrig(canvas, false); 238 canvas->save(); 239 canvas->translate(SkIntToScalar(200), 0); 240 this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK); 241 canvas->restore(); 242 243 canvas->translate(0, SkIntToScalar(200)); 244 245 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) { 246 canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint); 247 248 this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor); 249 250 canvas->save(); 251 canvas->translate(0, SkIntToScalar(200)); 252 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor); 253 canvas->restore(); 254 255 canvas->translate(SkIntToScalar(200), 0); 256 } 257 } 258 259 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { 260 return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL; 261 } 262 263 virtual bool onClick(Click* click) { 264 fRect.offset(click->fICurr.fX - click->fIPrev.fX, 265 click->fICurr.fY - click->fIPrev.fY); 266 this->inval(NULL); 267 return true; 268 } 269 270 private: 271 SkIRect fBase, fRect; 272 273 typedef SampleView INHERITED; 274 }; 275 276 ////////////////////////////////////////////////////////////////////////////// 277 278 static SkView* MyFactory() { return new RegionView; } 279 static SkViewRegister reg(MyFactory); 280 281