Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2014 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 
      8 #include "gm.h"
      9 
     10 #include "SkColorFilter.h"
     11 #include "SkMultiPictureDraw.h"
     12 #include "SkPictureRecorder.h"
     13 #include "SkSurface.h"
     14 
     15 static const SkScalar kRoot3Over2 = 0.86602545f;  // sin(60)
     16 static const SkScalar kRoot3      = 1.73205081f;
     17 
     18 static const int kHexSide = 30;
     19 static const int kNumHexX = 6;
     20 static const int kNumHexY = 6;
     21 static const int kPicWidth = kNumHexX * kHexSide;
     22 static const int kPicHeight = SkScalarCeilToInt((kNumHexY - 0.5f) * 2 * kHexSide * kRoot3Over2);
     23 static const SkScalar kInset = 20.0f;
     24 static const int kNumPictures = 4;
     25 
     26 static const int kTriSide = 40;
     27 
     28 // Create a hexagon centered at (originX, originY)
     29 static SkPath make_hex_path(SkScalar originX, SkScalar originY) {
     30     SkPath hex;
     31     hex.moveTo(originX-kHexSide, originY);
     32     hex.rLineTo(SkScalarHalf(kHexSide), kRoot3Over2 * kHexSide);
     33     hex.rLineTo(SkIntToScalar(kHexSide), 0);
     34     hex.rLineTo(SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
     35     hex.rLineTo(-SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
     36     hex.rLineTo(-SkIntToScalar(kHexSide), 0);
     37     hex.close();
     38     return hex;
     39 }
     40 
     41 // Make a picture that is a tiling of the plane with stroked hexagons where
     42 // each hexagon is in its own layer. The layers are to exercise Ganesh's
     43 // layer hoisting.
     44 static const SkPicture* make_hex_plane_picture(SkColor fillColor) {
     45 
     46     // Create a hexagon with its center at the origin
     47     SkPath hex = make_hex_path(0, 0);
     48 
     49     SkPaint fill;
     50     fill.setStyle(SkPaint::kFill_Style);
     51     fill.setColor(fillColor);
     52 
     53     SkPaint stroke;
     54     stroke.setStyle(SkPaint::kStroke_Style);
     55     stroke.setStrokeWidth(3);
     56 
     57     SkPictureRecorder recorder;
     58     SkRTreeFactory bbhFactory;
     59 
     60     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
     61                                                SkIntToScalar(kPicHeight),
     62                                                &bbhFactory,
     63                                                SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
     64 
     65     SkScalar xPos, yPos = 0;
     66 
     67     for (int y = 0; y < kNumHexY; ++y) {
     68         xPos = 0;
     69 
     70         for (int x = 0; x < kNumHexX; ++x) {
     71             canvas->saveLayer(nullptr, nullptr);
     72             canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
     73             canvas->drawPath(hex, fill);
     74             canvas->drawPath(hex, stroke);
     75             canvas->restore();
     76 
     77             xPos += 1.5f * kHexSide;
     78         }
     79 
     80         yPos += 2 * kHexSide * kRoot3Over2;
     81     }
     82 
     83     return recorder.endRecording();
     84 }
     85 
     86 // Create a picture that consists of a single large layer that is tiled
     87 // with hexagons.
     88 // This is intended to exercise the layer hoisting code's clip handling (in
     89 // tile mode).
     90 static const SkPicture* make_single_layer_hex_plane_picture() {
     91 
     92     // Create a hexagon with its center at the origin
     93     SkPath hex = make_hex_path(0, 0);
     94 
     95     SkPaint whiteFill;
     96     whiteFill.setStyle(SkPaint::kFill_Style);
     97     whiteFill.setColor(SK_ColorWHITE);
     98 
     99     SkPaint greyFill;
    100     greyFill.setStyle(SkPaint::kFill_Style);
    101     greyFill.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY));
    102 
    103     SkPaint stroke;
    104     stroke.setStyle(SkPaint::kStroke_Style);
    105     stroke.setStrokeWidth(3);
    106 
    107     SkPictureRecorder recorder;
    108     SkRTreeFactory bbhFactory;
    109 
    110     static const SkScalar kBig = 10000.0f;
    111     SkCanvas* canvas = recorder.beginRecording(kBig, kBig, &bbhFactory,
    112                                                SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
    113 
    114     canvas->saveLayer(nullptr, nullptr);
    115 
    116     SkScalar xPos = 0.0f, yPos = 0.0f;
    117 
    118     for (int y = 0; yPos < kBig; ++y) {
    119         xPos = 0;
    120 
    121         for (int x = 0; xPos < kBig; ++x) {
    122             canvas->save();
    123             canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
    124             // The color of the filled hex is swapped to yield a different
    125             // pattern in each tile. This allows an error in layer hoisting (e.g.,
    126             // the clip isn't blocking cache reuse) to cause a visual discrepancy.
    127             canvas->drawPath(hex, ((x+y) % 3) ? whiteFill : greyFill);
    128             canvas->drawPath(hex, stroke);
    129             canvas->restore();
    130 
    131             xPos += 1.5f * kHexSide;
    132         }
    133 
    134         yPos += 2 * kHexSide * kRoot3Over2;
    135     }
    136 
    137     canvas->restore();
    138 
    139     return recorder.endRecording();
    140 }
    141 
    142 // Make an equilateral triangle path with its top corner at (originX, originY)
    143 static SkPath make_tri_path(SkScalar originX, SkScalar originY) {
    144     SkPath tri;
    145     tri.moveTo(originX, originY);
    146     tri.rLineTo(SkScalarHalf(kTriSide), 1.5f * kTriSide / kRoot3);
    147     tri.rLineTo(-kTriSide, 0);
    148     tri.close();
    149     return tri;
    150 }
    151 
    152 static const SkPicture* make_tri_picture() {
    153     SkPath tri = make_tri_path(SkScalarHalf(kTriSide), 0);
    154 
    155     SkPaint fill;
    156     fill.setStyle(SkPaint::kFill_Style);
    157     fill.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY));
    158 
    159     SkPaint stroke;
    160     stroke.setStyle(SkPaint::kStroke_Style);
    161     stroke.setStrokeWidth(3);
    162 
    163     SkPictureRecorder recorder;
    164     SkRTreeFactory bbhFactory;
    165 
    166     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
    167                                                SkIntToScalar(kPicHeight),
    168                                                &bbhFactory,
    169                                                SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
    170     SkRect r = tri.getBounds();
    171     r.outset(2.0f, 2.0f);       // outset for stroke
    172     canvas->clipRect(r);
    173     // The saveLayer/restore block is to exercise layer hoisting
    174     canvas->saveLayer(nullptr, nullptr);
    175         canvas->drawPath(tri, fill);
    176         canvas->drawPath(tri, stroke);
    177     canvas->restore();
    178 
    179     return recorder.endRecording();
    180 }
    181 
    182 static const SkPicture* make_sub_picture(const SkPicture* tri) {
    183     SkPictureRecorder recorder;
    184     SkRTreeFactory bbhFactory;
    185 
    186     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
    187                                                SkIntToScalar(kPicHeight),
    188                                                &bbhFactory,
    189                                                SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
    190 
    191     canvas->scale(1.0f/2.0f, 1.0f/2.0f);
    192 
    193     canvas->save();
    194     canvas->translate(SkScalarHalf(kTriSide), 0);
    195     canvas->drawPicture(tri);
    196     canvas->restore();
    197 
    198     canvas->save();
    199     canvas->translate(SkIntToScalar(kTriSide), 1.5f * kTriSide / kRoot3);
    200     canvas->drawPicture(tri);
    201     canvas->restore();
    202 
    203     canvas->save();
    204     canvas->translate(0, 1.5f * kTriSide / kRoot3);
    205     canvas->drawPicture(tri);
    206     canvas->restore();
    207 
    208     return recorder.endRecording();
    209 }
    210 
    211 // Create a Sierpinkski-like picture that starts with a top row with a picture
    212 // that just contains a triangle. Subsequent rows take the prior row's picture,
    213 // shrinks it and replicates it 3 times then draws and appropriate number of
    214 // copies of it.
    215 static const SkPicture* make_sierpinski_picture() {
    216     SkAutoTUnref<const SkPicture> pic(make_tri_picture());
    217 
    218     SkPictureRecorder recorder;
    219     SkRTreeFactory bbhFactory;
    220 
    221     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
    222                                                SkIntToScalar(kPicHeight),
    223                                                &bbhFactory,
    224                                                SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
    225 
    226     static const int kNumLevels = 4;
    227     for (int i = 0; i < kNumLevels; ++i) {
    228         canvas->save();
    229             canvas->translate(kPicWidth/2 - (i+1) * (kTriSide/2.0f), 0.0f);
    230             for (int j = 0; j < i+1; ++j) {
    231                 canvas->drawPicture(pic);
    232                 canvas->translate(SkIntToScalar(kTriSide), 0);
    233             }
    234         canvas->restore();
    235 
    236         pic.reset(make_sub_picture(pic));
    237 
    238         canvas->translate(0, 1.5f * kTriSide / kRoot3);
    239     }
    240 
    241     return recorder.endRecording();
    242 }
    243 
    244 static SkSurface* create_compat_surface(SkCanvas* canvas, int width, int height) {
    245     SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
    246 
    247     SkSurface* surface = canvas->newSurface(info);
    248     if (nullptr == surface) {
    249         // picture canvas returns nullptr so fall back to raster
    250         surface = SkSurface::NewRaster(info);
    251     }
    252 
    253     return surface;
    254 }
    255 
    256 // This class stores the information required to compose all the result
    257 // fragments potentially generated by the MultiPictureDraw object
    258 class ComposeStep {
    259 public:
    260     ComposeStep() : fSurf(nullptr), fX(0.0f), fY(0.0f), fPaint(nullptr) { }
    261     ~ComposeStep() {
    262         SkSafeUnref(fSurf);
    263         delete fPaint;
    264     }
    265 
    266     SkSurface* fSurf;
    267     SkScalar   fX;
    268     SkScalar   fY;
    269     SkPaint*   fPaint;
    270 };
    271 
    272 typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]);
    273 
    274 // Just a single picture with no clip
    275 static void no_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    276     canvas->drawPicture(pictures[0]);
    277 }
    278 
    279 // Two pictures with a rect clip on the second one
    280 static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    281     canvas->drawPicture(pictures[0]);
    282 
    283     SkRect rect = pictures[0]->cullRect();
    284     rect.inset(kInset, kInset);
    285 
    286     canvas->clipRect(rect);
    287 
    288     canvas->drawPicture(pictures[1]);
    289 }
    290 
    291 // Two pictures with a round rect clip on the second one
    292 static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    293     canvas->drawPicture(pictures[0]);
    294 
    295     SkRect rect = pictures[0]->cullRect();
    296     rect.inset(kInset, kInset);
    297 
    298     SkRRect rrect;
    299     rrect.setRectXY(rect, kInset, kInset);
    300 
    301     canvas->clipRRect(rrect);
    302 
    303     canvas->drawPicture(pictures[1]);
    304 }
    305 
    306 // Two pictures with a clip path on the second one
    307 static void path_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    308     canvas->drawPicture(pictures[0]);
    309 
    310     // Create a hexagon centered on the middle of the hex grid
    311     SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
    312 
    313     canvas->clipPath(hex);
    314 
    315     canvas->drawPicture(pictures[1]);
    316 }
    317 
    318 // Two pictures with an inverse clip path on the second one
    319 static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    320     canvas->drawPicture(pictures[0]);
    321 
    322     // Create a hexagon centered on the middle of the hex grid
    323     SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
    324     hex.setFillType(SkPath::kInverseEvenOdd_FillType);
    325 
    326     canvas->clipPath(hex);
    327 
    328     canvas->drawPicture(pictures[1]);
    329 }
    330 
    331 // Reuse a single base (triangular) picture a _lot_ (rotated, scaled and translated).
    332 static void sierpinski(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    333     canvas->save();
    334         canvas->drawPicture(pictures[2]);
    335 
    336         canvas->rotate(180.0f);
    337         canvas->translate(-SkIntToScalar(kPicWidth), -SkIntToScalar(kPicHeight));
    338         canvas->drawPicture(pictures[2]);
    339     canvas->restore();
    340 }
    341 
    342 static void big_layer(SkCanvas* canvas, const SkPicture* pictures[kNumPictures]) {
    343     canvas->drawPicture(pictures[3]);
    344 }
    345 
    346 static const PFContentMtd gContentMthds[] = {
    347     no_clip,
    348     rect_clip,
    349     rrect_clip,
    350     path_clip,
    351     invpath_clip,
    352     sierpinski,
    353     big_layer,
    354 };
    355 
    356 static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen,
    357                            const SkPicture* pictures[kNumPictures],
    358                            SkCanvas* dest, const SkMatrix& xform) {
    359     SkAutoTUnref<SkPicture> composite;
    360 
    361     {
    362         SkPictureRecorder recorder;
    363         SkRTreeFactory bbhFactory;
    364 
    365         SkCanvas* pictureCanvas = recorder.beginRecording(SkIntToScalar(kPicWidth),
    366                                                           SkIntToScalar(kPicHeight),
    367                                                           &bbhFactory,
    368                                                           SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
    369 
    370         (*pfGen)(pictureCanvas, pictures);
    371 
    372         composite.reset(recorder.endRecording());
    373     }
    374 
    375     mpd->add(dest, composite, &xform);
    376 }
    377 
    378 typedef void(*PFLayoutMtd)(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
    379                            PFContentMtd pfGen, const SkPicture* pictures[kNumPictures],
    380                            SkTArray<ComposeStep>* composeSteps);
    381 
    382 // Draw the content into a single canvas
    383 static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
    384                    PFContentMtd pfGen,
    385                    const SkPicture* pictures[kNumPictures],
    386                    SkTArray<ComposeStep> *composeSteps) {
    387 
    388     ComposeStep& step = composeSteps->push_back();
    389 
    390     step.fSurf = create_compat_surface(finalCanvas, kPicWidth, kPicHeight);
    391 
    392     SkCanvas* subCanvas = step.fSurf->getCanvas();
    393 
    394     create_content(mpd, pfGen, pictures, subCanvas, SkMatrix::I());
    395 }
    396 
    397 // Draw the content into multiple canvases/tiles
    398 static void tiled(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
    399                   PFContentMtd pfGen,
    400                   const SkPicture* pictures[kNumPictures],
    401                   SkTArray<ComposeStep> *composeSteps) {
    402     static const int kNumTilesX = 2;
    403     static const int kNumTilesY = 2;
    404     static const int kTileWidth = kPicWidth / kNumTilesX;
    405     static const int kTileHeight = kPicHeight / kNumTilesY;
    406 
    407     SkASSERT(kPicWidth == kNumTilesX * kTileWidth);
    408     SkASSERT(kPicHeight == kNumTilesY * kTileHeight);
    409 
    410     static const SkColor colors[kNumTilesX][kNumTilesY] = {
    411         { SK_ColorCYAN,   SK_ColorMAGENTA },
    412         { SK_ColorYELLOW, SK_ColorGREEN   }
    413     };
    414 
    415     for (int y = 0; y < kNumTilesY; ++y) {
    416         for (int x = 0; x < kNumTilesX; ++x) {
    417             ComposeStep& step = composeSteps->push_back();
    418 
    419             step.fX = SkIntToScalar(x*kTileWidth);
    420             step.fY = SkIntToScalar(y*kTileHeight);
    421             step.fPaint = new SkPaint;
    422             step.fPaint->setColorFilter(
    423                 SkColorFilter::CreateModeFilter(colors[x][y], SkXfermode::kModulate_Mode))->unref();
    424 
    425             step.fSurf = create_compat_surface(finalCanvas, kTileWidth, kTileHeight);
    426 
    427             SkCanvas* subCanvas = step.fSurf->getCanvas();
    428 
    429             const SkMatrix trans = SkMatrix::MakeTrans(-SkIntToScalar(x*kTileWidth),
    430                                                        -SkIntToScalar(y*kTileHeight));
    431 
    432             create_content(mpd, pfGen, pictures, subCanvas, trans);
    433         }
    434     }
    435 }
    436 
    437 static const PFLayoutMtd gLayoutMthds[] = { simple, tiled };
    438 
    439 namespace skiagm {
    440     /**
    441      * This GM exercises the SkMultiPictureDraw object. It tests the
    442      * cross product of:
    443      *      tiled vs. all-at-once rendering (e.g., into many or just 1 canvas)
    444      *      different clips (e.g., none, rect, rrect)
    445      *      single vs. multiple pictures (e.g., normal vs. picture-pile-style content)
    446      */
    447     class MultiPictureDraw : public GM {
    448     public:
    449         enum Content {
    450             kNoClipSingle_Content,
    451             kRectClipMulti_Content,
    452             kRRectClipMulti_Content,
    453             kPathClipMulti_Content,
    454             kInvPathClipMulti_Content,
    455             kSierpinski_Content,
    456             kBigLayer_Content,
    457 
    458             kLast_Content = kBigLayer_Content
    459         };
    460 
    461         static const int kContentCnt = kLast_Content + 1;
    462 
    463         enum Layout {
    464             kSimple_Layout,
    465             kTiled_Layout,
    466 
    467             kLast_Layout = kTiled_Layout
    468         };
    469 
    470         static const int kLayoutCnt = kLast_Layout + 1;
    471 
    472         MultiPictureDraw(Content content, Layout layout) : fContent(content), fLayout(layout) {
    473             SkASSERT(SK_ARRAY_COUNT(gLayoutMthds) == kLayoutCnt);
    474             SkASSERT(SK_ARRAY_COUNT(gContentMthds) == kContentCnt);
    475 
    476             for (int i = 0; i < kNumPictures; ++i) {
    477                 fPictures[i] = nullptr;
    478             }
    479         }
    480 
    481         virtual ~MultiPictureDraw() {
    482             for (int i = 0; i < kNumPictures; ++i) {
    483                 SkSafeUnref(fPictures[i]);
    484             }
    485         }
    486 
    487     protected:
    488         Content          fContent;
    489         Layout           fLayout;
    490         const SkPicture* fPictures[kNumPictures];
    491 
    492         void onOnceBeforeDraw() override {
    493             fPictures[0] = make_hex_plane_picture(SK_ColorWHITE);
    494             fPictures[1] = make_hex_plane_picture(sk_tool_utils::color_to_565(SK_ColorGRAY));
    495             fPictures[2] = make_sierpinski_picture();
    496             fPictures[3] = make_single_layer_hex_plane_picture();
    497         }
    498 
    499         void onDraw(SkCanvas* canvas) override {
    500             SkMultiPictureDraw mpd;
    501             SkTArray<ComposeStep> composeSteps;
    502 
    503             // Fill up the MultiPictureDraw
    504             (*gLayoutMthds[fLayout])(canvas, &mpd,
    505                                      gContentMthds[fContent],
    506                                      fPictures, &composeSteps);
    507 
    508             mpd.draw();
    509 
    510             // Compose all the drawn canvases into the final canvas
    511             for (int i = 0; i < composeSteps.count(); ++i) {
    512                 const ComposeStep& step = composeSteps[i];
    513 
    514                 SkAutoTUnref<SkImage> image(step.fSurf->newImageSnapshot());
    515 
    516                 canvas->drawImage(image, step.fX, step.fY, step.fPaint);
    517             }
    518         }
    519 
    520         SkISize onISize() override { return SkISize::Make(kPicWidth, kPicHeight); }
    521 
    522         SkString onShortName() override {
    523             static const char* gContentNames[] = {
    524                 "noclip", "rectclip", "rrectclip", "pathclip",
    525                 "invpathclip", "sierpinski", "biglayer"
    526             };
    527             static const char* gLayoutNames[] = { "simple", "tiled" };
    528 
    529             SkASSERT(SK_ARRAY_COUNT(gLayoutNames) == kLayoutCnt);
    530             SkASSERT(SK_ARRAY_COUNT(gContentNames) == kContentCnt);
    531 
    532             SkString name("multipicturedraw_");
    533 
    534             name.append(gContentNames[fContent]);
    535             name.append("_");
    536             name.append(gLayoutNames[fLayout]);
    537             return name;
    538         }
    539 
    540         bool runAsBench() const override { return true; }
    541 
    542     private:
    543         typedef GM INHERITED;
    544     };
    545 
    546     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kNoClipSingle_Content,
    547                                        MultiPictureDraw::kSimple_Layout);)
    548     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRectClipMulti_Content,
    549                                        MultiPictureDraw::kSimple_Layout);)
    550     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRRectClipMulti_Content,
    551                                        MultiPictureDraw::kSimple_Layout);)
    552     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kPathClipMulti_Content,
    553                                        MultiPictureDraw::kSimple_Layout);)
    554     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kInvPathClipMulti_Content,
    555                                        MultiPictureDraw::kSimple_Layout);)
    556     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kSierpinski_Content,
    557                                        MultiPictureDraw::kSimple_Layout);)
    558     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kBigLayer_Content,
    559                                        MultiPictureDraw::kSimple_Layout);)
    560 
    561     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kNoClipSingle_Content,
    562                                        MultiPictureDraw::kTiled_Layout);)
    563     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRectClipMulti_Content,
    564                                        MultiPictureDraw::kTiled_Layout);)
    565     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kRRectClipMulti_Content,
    566                                        MultiPictureDraw::kTiled_Layout);)
    567     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kPathClipMulti_Content,
    568                                        MultiPictureDraw::kTiled_Layout);)
    569     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kInvPathClipMulti_Content,
    570                                        MultiPictureDraw::kTiled_Layout);)
    571     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kSierpinski_Content,
    572                                        MultiPictureDraw::kTiled_Layout);)
    573     DEF_GM(return new MultiPictureDraw(MultiPictureDraw::kBigLayer_Content,
    574                                        MultiPictureDraw::kTiled_Layout);)
    575 }
    576