| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 1 | #include "SampleCode.h" | 
 | 2 | #include "SkView.h" | 
 | 3 | #include "SkCanvas.h" | 
 | 4 | #include "SkGradientShader.h" | 
 | 5 | #include "SkPath.h" | 
 | 6 | #include "SkRegion.h" | 
 | 7 | #include "SkShader.h" | 
 | 8 | #include "SkUtils.h" | 
 | 9 | #include "SkImageDecoder.h" | 
 | 10 |  | 
 | 11 | #ifdef SK_DEBUG | 
 | 12 | static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom, | 
 | 13 |                      size_t count, int32_t runs[]) { | 
 | 14 |     SkIRect r; | 
 | 15 |     r.set(left, top, right, bottom); | 
 | 16 |      | 
 | 17 |     rgn->debugSetRuns(runs, count); | 
 | 18 |     SkASSERT(rgn->getBounds() == r); | 
 | 19 | } | 
 | 20 |  | 
 | 21 | static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) { | 
 | 22 |     static int32_t dataA[] = { | 
 | 23 |         0x00000001, 0x000001dd, | 
 | 24 |         0x00000001, 0x0000000c, 0x0000000d, 0x00000025, | 
 | 25 |         0x7fffffff, 0x000001de, 0x00000001, 0x00000025, | 
 | 26 |         0x7fffffff, 0x000004b3, 0x00000001, 0x00000026, | 
 | 27 |         0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026, | 
 | 28 |         0x7fffffff, 0x00000579, 0x00000000, 0x0000013a, | 
 | 29 |         0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b, | 
 | 30 |         0x7fffffff, 0x7fffffff | 
 | 31 |     }; | 
 | 32 |     make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA); | 
 | 33 |  | 
 | 34 |     static int32_t dataB[] = { | 
 | 35 |         0x000000b6, 0x000000c4, | 
 | 36 |         0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6, | 
 | 37 |         0x7fffffff, 0x000000e4, 0x00000070, 0x00000079, | 
 | 38 |         0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6, | 
 | 39 |         0x7fffffff, 0x000000f4, 0x00000070, 0x00000079, | 
 | 40 |         0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6, | 
 | 41 |         0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0, | 
 | 42 |         0x7fffffff, 0x7fffffff | 
 | 43 |     }; | 
 | 44 |     make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB); | 
 | 45 |      | 
 | 46 |     rc->op(*ra, *rb, SkRegion::kUnion_Op); | 
 | 47 | } | 
 | 48 | #endif | 
 | 49 |  | 
| reed@android.com | f76bacf | 2009-05-13 14:00:33 +0000 | [diff] [blame] | 50 | static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) { | 
 | 51 |     dst->fLeft = (int)::roundf(src.fLeft * scale); | 
 | 52 |     dst->fTop = (int)::roundf(src.fTop * scale); | 
 | 53 |     dst->fRight = (int)::roundf(src.fRight * scale); | 
 | 54 |     dst->fBottom = (int)::roundf(src.fBottom * scale); | 
 | 55 | } | 
 | 56 |  | 
 | 57 | static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { | 
 | 58 |     SkRegion tmp; | 
 | 59 |     SkRegion::Iterator iter(src); | 
 | 60 |  | 
 | 61 |     for (; !iter.done(); iter.next()) { | 
 | 62 |         SkIRect r; | 
 | 63 |         scale_rect(&r, iter.rect(), scale); | 
 | 64 |         tmp.op(r, SkRegion::kUnion_Op); | 
 | 65 |     } | 
 | 66 |     dst->swap(tmp); | 
 | 67 | } | 
 | 68 |  | 
 | 69 | static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn, | 
 | 70 |                       const SkPaint& paint) { | 
 | 71 |     SkRegion scaled; | 
 | 72 |     scale_rgn(&scaled, rgn, 0.5f); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 73 |      | 
| reed@android.com | f76bacf | 2009-05-13 14:00:33 +0000 | [diff] [blame] | 74 |     SkRegion::Iterator  iter(rgn); | 
 | 75 |  | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 76 |     for (; !iter.done(); iter.next()) | 
 | 77 |     { | 
 | 78 |         SkRect    r; | 
 | 79 |         r.set(iter.rect()); | 
 | 80 |         canvas->drawRect(r, paint); | 
 | 81 |     } | 
 | 82 | } | 
 | 83 |  | 
 | 84 | class RegionView : public SkView { | 
 | 85 | public: | 
 | 86 | 	RegionView()  | 
 | 87 | 	{ | 
 | 88 |         fBase.set(100, 100, 150, 150); | 
 | 89 |         fRect = fBase; | 
 | 90 |         fRect.inset(5, 5); | 
 | 91 |         fRect.offset(25, 25); | 
 | 92 |     } | 
 | 93 |  | 
 | 94 |     void build_rgn(SkRegion* rgn, SkRegion::Op op) | 
 | 95 |     { | 
 | 96 |         rgn->setRect(fBase); | 
 | 97 |         SkIRect r = fBase; | 
 | 98 |         r.offset(75, 20); | 
 | 99 |         rgn->op(r, SkRegion::kUnion_Op); | 
 | 100 |         rgn->op(fRect, op); | 
 | 101 |     } | 
 | 102 |  | 
 | 103 |  | 
 | 104 | protected: | 
 | 105 |     // overrides from SkEventSink | 
 | 106 |     virtual bool onQuery(SkEvent* evt) | 
 | 107 |     { | 
 | 108 |         if (SampleCode::TitleQ(*evt)) | 
 | 109 |         { | 
 | 110 |             SampleCode::TitleR(evt, "Regions"); | 
 | 111 |             return true; | 
 | 112 |         } | 
 | 113 |         return this->INHERITED::onQuery(evt); | 
 | 114 |     } | 
 | 115 |      | 
 | 116 |     void drawOrig(SkCanvas* canvas, bool bg) | 
 | 117 |     { | 
 | 118 |         SkRect      r; | 
 | 119 |         SkPaint     paint; | 
 | 120 |          | 
 | 121 |         paint.setStyle(SkPaint::kStroke_Style); | 
 | 122 |         if (bg) | 
 | 123 |             paint.setColor(0xFFBBBBBB); | 
 | 124 |          | 
 | 125 |         r.set(fBase); | 
 | 126 |         canvas->drawRect(r, paint); | 
 | 127 |         r.set(fRect); | 
 | 128 |         canvas->drawRect(r, paint); | 
 | 129 |     } | 
 | 130 |      | 
 | 131 |     void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) | 
 | 132 |     { | 
 | 133 |         SkRegion    rgn; | 
 | 134 |  | 
 | 135 |         this->build_rgn(&rgn, op); | 
 | 136 |          | 
 | 137 |         { | 
 | 138 |             SkRegion tmp, tmp2(rgn); | 
 | 139 |              | 
 | 140 |             tmp = tmp2; | 
 | 141 |             tmp.translate(5, -3); | 
 | 142 |              | 
 | 143 |             { | 
 | 144 |                 char    buffer[1000]; | 
 | 145 |                 size_t  size = tmp.flatten(NULL); | 
 | 146 |                 SkASSERT(size <= sizeof(buffer)); | 
 | 147 |                 size_t  size2 = tmp.flatten(buffer); | 
 | 148 |                 SkASSERT(size == size2); | 
 | 149 |                  | 
 | 150 |                 SkRegion    tmp3; | 
 | 151 |                 size2 = tmp3.unflatten(buffer); | 
 | 152 |                 SkASSERT(size == size2); | 
 | 153 |                  | 
 | 154 |                 SkASSERT(tmp3 == tmp); | 
 | 155 |             } | 
 | 156 |  | 
 | 157 |             rgn.translate(20, 30, &tmp); | 
 | 158 |             SkASSERT(rgn.isEmpty() || tmp != rgn); | 
 | 159 |             tmp.translate(-20, -30); | 
 | 160 |             SkASSERT(tmp == rgn); | 
 | 161 |         } | 
 | 162 |  | 
 | 163 |         this->drawOrig(canvas, true); | 
 | 164 |  | 
 | 165 |         SkPaint paint; | 
 | 166 |         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); | 
 | 167 |         paint_rgn(canvas, rgn, paint); | 
 | 168 |  | 
 | 169 |         paint.setStyle(SkPaint::kStroke_Style); | 
 | 170 |         paint.setColor(color); | 
 | 171 |         paint_rgn(canvas, rgn, paint); | 
 | 172 |     } | 
 | 173 |      | 
 | 174 |     void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) | 
 | 175 |     { | 
 | 176 |         SkRegion    rgn; | 
 | 177 |         SkPath      path; | 
 | 178 |  | 
 | 179 |         this->build_rgn(&rgn, op); | 
 | 180 |         rgn.getBoundaryPath(&path); | 
 | 181 |  | 
 | 182 |         this->drawOrig(canvas, true); | 
 | 183 |  | 
 | 184 |         SkPaint paint; | 
 | 185 |  | 
 | 186 |         paint.setStyle(SkPaint::kFill_Style); | 
 | 187 |         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); | 
 | 188 |         canvas->drawPath(path, paint); | 
 | 189 |         paint.setColor(color); | 
 | 190 |         paint.setStyle(SkPaint::kStroke_Style); | 
 | 191 |         canvas->drawPath(path, paint); | 
 | 192 |     } | 
 | 193 |      | 
 | 194 |     void drawBG(SkCanvas* canvas) | 
 | 195 |     { | 
 | 196 |         canvas->drawColor(0xFFDDDDDD); | 
 | 197 |         return; | 
 | 198 |  | 
 | 199 | #if 0 | 
 | 200 |         SkColorTable    ct; | 
 | 201 |         SkPMColor       colors[] = { SK_ColorRED, SK_ColorBLUE }; | 
 | 202 |         ct.setColors(colors, 2); | 
 | 203 |         ct.setFlags(ct.getFlags() | SkColorTable::kColorsAreOpaque_Flag); | 
 | 204 |  | 
 | 205 |         SkBitmap        bm; | 
 | 206 |         bm.setConfig(SkBitmap::kIndex8_Config, 20, 20, 21); | 
 | 207 |         bm.setColorTable(&ct); | 
 | 208 |         bm.allocPixels(); | 
 | 209 |         sk_memset16((uint16_t*)bm.getAddr8(0, 0), 0x0001, bm.rowBytes() * bm.height() / 2); | 
 | 210 | #endif | 
 | 211 | #if 0 | 
 | 212 |         SkBitmap        bm; | 
 | 213 |         bm.setConfig(SkBitmap::kRGB_565_Config, 20, 20, 42); | 
 | 214 |         bm.allocPixels(); | 
 | 215 |         sk_memset32((uint32_t*)bm.getAddr16(0, 0), 0x0000FFFF, bm.rowBytes() * bm.height() / 4); | 
 | 216 | #endif | 
 | 217 | #if 1 | 
 | 218 |         SkBitmap        bm; | 
 | 219 |         bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20); | 
 | 220 |         bm.allocPixels(); | 
 | 221 |         sk_memset32((uint32_t*)bm.getAddr32(0, 0), 0xFFDDDDDD, bm.rowBytes() * bm.height() / 4); | 
 | 222 | #endif | 
 | 223 |  | 
 | 224 |         SkPaint paint; | 
 | 225 |  | 
 | 226 | //        SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kBilinear_FilterType, SkShader::kRepeat_TileMode); | 
 | 227 |         SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(0) }; | 
 | 228 |         SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE }; | 
| reed@android.com | 671cd65 | 2009-05-22 20:44:12 +0000 | [diff] [blame] | 229 |         SkShader* shader = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kMirror_TileMode); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 230 |         paint.setShader(shader)->unref(); | 
 | 231 |  | 
 | 232 |         canvas->drawPaint(paint); | 
 | 233 |     } | 
 | 234 |  | 
 | 235 |     virtual void onDraw(SkCanvas* canvas) | 
 | 236 |     { | 
 | 237 |         if (true) { | 
 | 238 |             SkRect r = { 0, 0, 1 << 30, 1 << 30 }; | 
 | 239 |             bool open = canvas->clipRect(r); | 
 | 240 |             SkDebugf("---- giant clip is %d\n", open); | 
 | 241 |         } | 
 | 242 |         this->drawBG(canvas); | 
 | 243 |          | 
| reed@android.com | 3469c76 | 2009-02-24 19:03:20 +0000 | [diff] [blame] | 244 |         if (false) { | 
 | 245 |             SkPaint paint; | 
 | 246 |             paint.setAntiAlias(true); | 
 | 247 |             SkBitmap bm; | 
 | 248 |             bm.setConfig(SkBitmap::kA8_Config, 100, 100); | 
 | 249 |             bm.allocPixels(); | 
 | 250 |             bm.eraseColor(0); | 
 | 251 |             SkCanvas c(bm); | 
 | 252 |             c.drawCircle(50, 50, 50, paint); | 
 | 253 |  | 
 | 254 |             paint.setColor(SK_ColorBLUE); | 
 | 255 |             canvas->drawBitmap(bm, 0, 0, &paint); | 
 | 256 |             canvas->scale(SK_Scalar1/2, SK_Scalar1/2); | 
 | 257 |             paint.setColor(SK_ColorRED); | 
 | 258 |             canvas->drawBitmap(bm, 0, 0, &paint); | 
 | 259 |             return; | 
 | 260 |         } | 
 | 261 |          | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 262 | #ifdef SK_DEBUG | 
 | 263 |         if (true) { | 
 | 264 |             SkRegion a, b, c; | 
 | 265 |             test_union_bug_1505668(&a, &b, &c); | 
 | 266 |              | 
 | 267 |             if (false) {    // draw the result of the test | 
 | 268 |                 SkPaint paint; | 
 | 269 |                  | 
 | 270 |                 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); | 
 | 271 |                 paint.setColor(SK_ColorRED); | 
 | 272 |                 paint_rgn(canvas, a, paint); | 
 | 273 |                 paint.setColor(0x800000FF); | 
 | 274 |                 paint_rgn(canvas, b, paint); | 
 | 275 |                 paint.setColor(SK_ColorBLACK); | 
 | 276 |                 paint.setStyle(SkPaint::kStroke_Style); | 
 | 277 |              //   paint_rgn(canvas, c, paint); | 
 | 278 |                 return; | 
 | 279 |             } | 
 | 280 |         } | 
 | 281 | #endif | 
 | 282 |  | 
 | 283 |         static const struct { | 
 | 284 |             SkColor         fColor; | 
 | 285 |             const char*     fName; | 
 | 286 |             SkRegion::Op    fOp; | 
 | 287 |         } gOps[] = { | 
 | 288 |             { SK_ColorBLACK,    "Difference",   SkRegion::kDifference_Op    }, | 
 | 289 |             { SK_ColorRED,      "Intersect",    SkRegion::kIntersect_Op     }, | 
 | 290 |             { 0xFF008800,       "Union",        SkRegion::kUnion_Op         }, | 
 | 291 |             { SK_ColorBLUE,     "XOR",          SkRegion::kXOR_Op           } | 
 | 292 |         }; | 
 | 293 |  | 
 | 294 |         SkPaint textPaint; | 
 | 295 |         textPaint.setAntiAlias(true); | 
 | 296 |         textPaint.setTextSize(SK_Scalar1*24); | 
 | 297 |  | 
 | 298 |         this->drawOrig(canvas, false); | 
 | 299 |         canvas->save(); | 
 | 300 |             canvas->translate(SkIntToScalar(200), 0); | 
 | 301 |             this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK); | 
 | 302 |         canvas->restore(); | 
 | 303 |          | 
 | 304 |         canvas->translate(0, SkIntToScalar(200)); | 
 | 305 |  | 
 | 306 |         for (int op = 0; op < SK_ARRAY_COUNT(gOps); op++) | 
 | 307 |         { | 
 | 308 |             canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint); | 
 | 309 |  | 
 | 310 |             this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor); | 
 | 311 |  | 
 | 312 |             if (true) | 
 | 313 |             { | 
 | 314 |                 canvas->save(); | 
 | 315 |                 canvas->translate(0, SkIntToScalar(200)); | 
 | 316 |                 this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor); | 
 | 317 |                 canvas->restore(); | 
 | 318 |             } | 
 | 319 |              | 
 | 320 |             canvas->translate(SkIntToScalar(200), 0); | 
 | 321 |         } | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 322 |     } | 
 | 323 |      | 
 | 324 |     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)  | 
 | 325 |     { | 
| reed@android.com | 671cd65 | 2009-05-22 20:44:12 +0000 | [diff] [blame] | 326 |         return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL; | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 327 |     } | 
 | 328 |      | 
 | 329 |     virtual bool onClick(Click* click)  | 
 | 330 |     { | 
 | 331 |         fRect.offset(click->fICurr.fX - click->fIPrev.fX, | 
 | 332 |                      click->fICurr.fY - click->fIPrev.fY); | 
| reed@android.com | 671cd65 | 2009-05-22 20:44:12 +0000 | [diff] [blame] | 333 |         this->inval(NULL); | 
| reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 334 |         return true; | 
 | 335 |     } | 
 | 336 |      | 
 | 337 | private: | 
 | 338 |     SkIRect    fBase, fRect; | 
 | 339 |      | 
 | 340 |     typedef SkView INHERITED; | 
 | 341 | }; | 
 | 342 |  | 
 | 343 | ////////////////////////////////////////////////////////////////////////////// | 
 | 344 |  | 
 | 345 | static SkView* MyFactory() { return new RegionView; } | 
 | 346 | static SkViewRegister reg(MyFactory); | 
 | 347 |  |