1/*
2 * Copyright 2016 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#include "SkSurface.h"
10
11static sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop,
12                                     int padRight, int padBottom) {
13    SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom);
14    auto surface = root->makeSurface(info);
15    if (!surface) {
16        surface = SkSurface::MakeRaster(info);
17    }
18
19    return surface;
20}
21
22static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop,
23                                 int padRight, int padBottom) {
24    const int kCap = 28;
25    const int kMid = 8;
26    const int kSize = 2*kCap + 3*kMid;
27
28    auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
29    SkCanvas* canvas = surface->getCanvas();
30    canvas->translate((float) padLeft, (float) padTop);
31
32    SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
33    const SkScalar strokeWidth = SkIntToScalar(6);
34    const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
35
36    xDivs[0] = kCap + padLeft;
37    yDivs[0] = kCap + padTop;
38    xDivs[1] = kCap + kMid + padLeft;
39    yDivs[1] = kCap + kMid + padTop;
40    xDivs[2] = kCap + 2 * kMid + padLeft;
41    yDivs[2] = kCap + 2 * kMid + padTop;
42    xDivs[3] = kCap + 3 * kMid + padLeft;
43    yDivs[3] = kCap + 3 * kMid + padTop;
44
45    SkPaint paint;
46    paint.setAntiAlias(true);
47
48    paint.setColor(0xFFFFFF00);
49    canvas->drawRoundRect(r, radius, radius, paint);
50
51    r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
52    paint.setColor(0x8800FF00);
53    canvas->drawRect(r, paint);
54    r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
55    paint.setColor(0x880000FF);
56    canvas->drawRect(r, paint);
57    r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
58    paint.setColor(0x88FF00FF);
59    canvas->drawRect(r, paint);
60
61    r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
62    paint.setColor(0x8800FF00);
63    canvas->drawRect(r, paint);
64    r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
65    paint.setColor(0x880000FF);
66    canvas->drawRect(r, paint);
67    r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
68    paint.setColor(0x88FF00FF);
69    canvas->drawRect(r, paint);
70
71    return surface->makeImageSnapshot();
72}
73
74static void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
75    SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
76    bm->allocPixels(info);
77    image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
78}
79
80/**
81 *  This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
82 *  than nine patches.
83 */
84class LatticeGM : public skiagm::GM {
85public:
86    LatticeGM() {}
87
88protected:
89    SkString onShortName() override {
90        return SkString("lattice");
91    }
92
93    SkISize onISize() override {
94        return SkISize::Make(800, 800);
95    }
96
97    void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) {
98        canvas->save();
99
100        int xDivs[5];
101        int yDivs[5];
102        xDivs[0] = padLeft;
103        yDivs[0] = padTop;
104
105        SkBitmap bitmap;
106        sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop,
107                                          padRight, padBottom);
108        image_to_bitmap(image.get(), &bitmap);
109
110        const SkTSize<SkScalar> size[] = {
111            {  50,  50, }, // shrink in both axes
112            {  50, 200, }, // shrink in X
113            { 200,  50, }, // shrink in Y
114            { 200, 200, },
115        };
116
117        canvas->drawImage(image, 10, 10, nullptr);
118
119        SkScalar x = SkIntToScalar(100);
120        SkScalar y = SkIntToScalar(100);
121
122        SkCanvas::Lattice lattice;
123        lattice.fXCount = 4;
124        lattice.fXDivs = xDivs + 1;
125        lattice.fYCount = 4;
126        lattice.fYDivs = yDivs + 1;
127        lattice.fFlags = nullptr;
128
129        SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
130                                           image->width() - padRight, image->height() - padBottom);
131        lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ?
132                nullptr : &bounds;
133
134        for (int iy = 0; iy < 2; ++iy) {
135            for (int ix = 0; ix < 2; ++ix) {
136                int i = ix * 2 + iy;
137                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
138                                            size[i].width(), size[i].height());
139                canvas->drawBitmapLattice(bitmap, lattice, r);
140            }
141        }
142
143        // Include the degenerate first div.  While normally the first patch is "scalable",
144        // this will mean that the first non-degenerate patch is "fixed".
145        lattice.fXCount = 5;
146        lattice.fXDivs = xDivs;
147        lattice.fYCount = 5;
148        lattice.fYDivs = yDivs;
149
150        // Let's skip a few rects.
151        SkCanvas::Lattice::Flags flags[36];
152        sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::Flags));
153        flags[4] = SkCanvas::Lattice::kTransparent_Flags;
154        flags[9] = SkCanvas::Lattice::kTransparent_Flags;
155        flags[12] = SkCanvas::Lattice::kTransparent_Flags;
156        flags[19] = SkCanvas::Lattice::kTransparent_Flags;
157        lattice.fFlags = flags;
158
159        canvas->translate(400, 0);
160        for (int iy = 0; iy < 2; ++iy) {
161            for (int ix = 0; ix < 2; ++ix) {
162                int i = ix * 2 + iy;
163                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
164                                            size[i].width(), size[i].height());
165                canvas->drawImageLattice(image.get(), lattice, r);
166            }
167        }
168
169        canvas->restore();
170    }
171
172    void onDraw(SkCanvas* canvas) override {
173        this->onDrawHelper(canvas, 0, 0, 0, 0);
174        canvas->translate(0.0f, 400.0f);
175        this->onDrawHelper(canvas, 3, 7, 4, 11);
176    }
177
178private:
179    typedef skiagm::GM INHERITED;
180};
181DEF_GM( return new LatticeGM; )
182