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