Home | History | Annotate | Download | only in samplecode
      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 static void test_strokerect(SkCanvas* canvas) {
     19     int width = 100;
     20     int height = 100;
     21 
     22     SkBitmap bitmap;
     23     bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
     24     bitmap.eraseColor(SK_ColorTRANSPARENT);
     25 
     26     SkScalar dx = 20;
     27     SkScalar dy = 20;
     28 
     29     SkPath path;
     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));
     34 
     35     SkCanvas c(bitmap);
     36     c.translate(dx, dy);
     37 
     38     SkPaint paint;
     39     paint.setStyle(SkPaint::kStroke_Style);
     40     paint.setStrokeWidth(1);
     41 
     42     // use the rect
     43     c.clear(SK_ColorTRANSPARENT);
     44     c.drawRect(r, paint);
     45     canvas->drawBitmap(bitmap, 0, 0, NULL);
     46 
     47     // use the path
     48     c.clear(SK_ColorTRANSPARENT);
     49     c.drawPath(path, paint);
     50     canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, NULL);
     51 }
     52 
     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
     57     SkRect bounds;
     58     SkPaint::FontMetrics fm;
     59 
     60     paint.getFontMetrics(&fm);
     61     bounds.set(x, y + fm.fTop, x + paint.measureText(text, len), y + fm.fBottom);
     62 
     63     // may need to outset bounds a little, to account for hinting and/or
     64     // antialiasing
     65     bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
     66 
     67     canvas->saveLayer(&bounds, NULL);
     68     canvas->drawText(text, len, x, y, paint);
     69 
     70     const SkPoint pts[] = {
     71         { bounds.fLeft, y },
     72         { bounds.fRight, y }
     73     };
     74     const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
     75 
     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 };
     79 
     80     SkShader* s = SkGradientShader::CreateLinear(pts, colors, pos, 3,
     81                                                  SkShader::kClamp_TileMode);
     82     SkPaint p;
     83     p.setShader(s)->unref();
     84     p.setXfermodeMode(SkXfermode::kDstIn_Mode);
     85     canvas->drawRect(bounds, p);
     86 
     87     canvas->restore();
     88 }
     89 
     90 static void test_text(SkCanvas* canvas) {
     91     SkPaint paint;
     92     paint.setAntiAlias(true);
     93     paint.setTextSize(20);
     94 
     95     const char* str = "Hamburgefons";
     96     size_t len = strlen(str);
     97     SkScalar x = 20;
     98     SkScalar y = 20;
     99 
    100     canvas->drawText(str, len, x, y, paint);
    101 
    102     y += 20;
    103 
    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);
    112 
    113     y += 20;
    114     paint.setShader(NULL);
    115     drawFadingText(canvas, str, len, x, y, paint);
    116 }
    117 
    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); }
    121 #endif
    122 
    123 #ifdef SK_DEBUG
    124 static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
    125                      int count, int32_t runs[]) {
    126     SkIRect r;
    127     r.set(left, top, right, bottom);
    128 
    129     rgn->debugSetRuns(runs, count);
    130     SkASSERT(rgn->getBounds() == r);
    131 }
    132 
    133 static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
    134     static int32_t dataA[] = {
    135         0x00000001,
    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,
    142         0x7fffffff
    143     };
    144     make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
    145 
    146     static int32_t dataB[] = {
    147         0x000000b6,
    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,
    155         0x7fffffff
    156     };
    157     make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
    158 
    159     rc->op(*ra, *rb, SkRegion::kUnion_Op);
    160 }
    161 #endif
    162 
    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);
    168 }
    169 
    170 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
    171     SkRegion tmp;
    172     SkRegion::Iterator iter(src);
    173 
    174     for (; !iter.done(); iter.next()) {
    175         SkIRect r;
    176         scale_rect(&r, iter.rect(), scale);
    177         tmp.op(r, SkRegion::kUnion_Op);
    178     }
    179     dst->swap(tmp);
    180 }
    181 
    182 static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
    183                       const SkPaint& paint) {
    184     SkRegion scaled;
    185     scale_rgn(&scaled, rgn, 0.5f);
    186 
    187     SkRegion::Iterator  iter(rgn);
    188 
    189     for (; !iter.done(); iter.next())
    190     {
    191         SkRect    r;
    192         r.set(iter.rect());
    193         canvas->drawRect(r, paint);
    194     }
    195 }
    196 
    197 class RegionView : public SampleView {
    198 public:
    199     RegionView() {
    200         fBase.set(100, 100, 150, 150);
    201         fRect = fBase;
    202         fRect.inset(5, 5);
    203         fRect.offset(25, 25);
    204         this->setBGColor(0xFFDDDDDD);
    205     }
    206 
    207     void build_base_rgn(SkRegion* rgn) {
    208         rgn->setRect(fBase);
    209         SkIRect r = fBase;
    210         r.offset(75, 20);
    211         rgn->op(r, SkRegion::kUnion_Op);
    212     }
    213 
    214     void build_rgn(SkRegion* rgn, SkRegion::Op op) {
    215         build_base_rgn(rgn);
    216         rgn->op(fRect, op);
    217     }
    218 
    219 
    220 protected:
    221     // overrides from SkEventSink
    222     bool onQuery(SkEvent* evt) override {
    223         if (SampleCode::TitleQ(*evt)) {
    224             SampleCode::TitleR(evt, "Regions");
    225             return true;
    226         }
    227         return this->INHERITED::onQuery(evt);
    228     }
    229 
    230     static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
    231                         bool hilite) {
    232         SkPaint paint;
    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);
    237     }
    238 
    239     void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
    240         SkRegion rgn;
    241         build_base_rgn(&rgn);
    242 
    243         drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
    244         drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
    245     }
    246 
    247     void drawOrig(SkCanvas* canvas, bool bg) {
    248         SkRect      r;
    249         SkPaint     paint;
    250 
    251         paint.setStyle(SkPaint::kStroke_Style);
    252         if (bg)
    253             paint.setColor(0xFFBBBBBB);
    254 
    255         SkRegion rgn;
    256         build_base_rgn(&rgn);
    257         paint_rgn(canvas, rgn, paint);
    258 
    259         r.set(fRect);
    260         canvas->drawRect(r, paint);
    261     }
    262 
    263     void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
    264         SkRegion    rgn;
    265 
    266         this->build_rgn(&rgn, op);
    267 
    268         {
    269             SkRegion tmp, tmp2(rgn);
    270 
    271             tmp = tmp2;
    272             tmp.translate(5, -3);
    273 
    274             {
    275                 char    buffer[1000];
    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);
    280 
    281                 SkRegion    tmp3;
    282                 SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
    283                 SkASSERT(size == size2);
    284 
    285                 SkASSERT(tmp3 == tmp);
    286             }
    287 
    288             rgn.translate(20, 30, &tmp);
    289             SkASSERT(rgn.isEmpty() || tmp != rgn);
    290             tmp.translate(-20, -30);
    291             SkASSERT(tmp == rgn);
    292         }
    293 
    294         this->drawOrig(canvas, true);
    295 
    296         SkPaint paint;
    297         paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
    298         paint_rgn(canvas, rgn, paint);
    299 
    300         paint.setStyle(SkPaint::kStroke_Style);
    301         paint.setColor(color);
    302         paint_rgn(canvas, rgn, paint);
    303     }
    304 
    305     void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
    306         SkRegion    rgn;
    307         SkPath      path;
    308 
    309         this->build_rgn(&rgn, op);
    310         rgn.getBoundaryPath(&path);
    311 
    312         this->drawOrig(canvas, true);
    313 
    314         SkPaint paint;
    315 
    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);
    322     }
    323 
    324     void onDrawContent(SkCanvas* canvas) override {
    325         if (false) { // avoid bit rot, suppress warning
    326             test_strokerect(canvas);
    327             return;
    328         }
    329         if (false) { // avoid bit rot, suppress warning
    330             test_text(canvas);
    331             return;
    332         }
    333 #ifdef SK_DEBUG
    334         if (true) {
    335             SkRegion a, b, c;
    336             test_union_bug_1505668(&a, &b, &c);
    337 
    338             if (false) {    // draw the result of the test
    339                 SkPaint paint;
    340 
    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);
    349                 return;
    350             }
    351         }
    352 #endif
    353         const SkPoint origins[] = {
    354             { 30*SK_Scalar1, 50*SK_Scalar1 },
    355             { 150*SK_Scalar1, 50*SK_Scalar1 },
    356         };
    357         this->drawPredicates(canvas, origins);
    358 
    359         static const struct {
    360             SkColor         fColor;
    361             const char*     fName;
    362             SkRegion::Op    fOp;
    363         } gOps[] = {
    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           }
    368         };
    369 
    370         SkPaint textPaint;
    371         textPaint.setAntiAlias(true);
    372         textPaint.setTextSize(SK_Scalar1*24);
    373 
    374         this->drawOrig(canvas, false);
    375         canvas->save();
    376             canvas->translate(SkIntToScalar(200), 0);
    377             this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
    378         canvas->restore();
    379 
    380         canvas->translate(0, SkIntToScalar(200));
    381 
    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);
    384 
    385             this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
    386 
    387             canvas->save();
    388             canvas->translate(0, SkIntToScalar(200));
    389             this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
    390             canvas->restore();
    391 
    392             canvas->translate(SkIntToScalar(200), 0);
    393         }
    394     }
    395 
    396     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
    397                                               unsigned modi) override {
    398         return fRect.contains(SkScalarRoundToInt(x),
    399                               SkScalarRoundToInt(y)) ? new Click(this) : NULL;
    400     }
    401 
    402     bool onClick(Click* click) override {
    403         fRect.offset(click->fICurr.fX - click->fIPrev.fX,
    404                      click->fICurr.fY - click->fIPrev.fY);
    405         this->inval(NULL);
    406         return true;
    407     }
    408 
    409 private:
    410     SkIRect    fBase, fRect;
    411 
    412     typedef SampleView INHERITED;
    413 };
    414 
    415 //////////////////////////////////////////////////////////////////////////////
    416 
    417 static SkView* MyFactory() { return new RegionView; }
    418 static SkViewRegister reg(MyFactory);
    419