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#include "sk_tool_utils.h"
11
12static sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop,
13                                     int padRight, int padBottom) {
14    SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom);
15    return sk_tool_utils::makeSurface(root, info);
16}
17
18static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop,
19                                 int padRight, int padBottom) {
20    const int kCap = 28;
21    const int kMid = 8;
22    const int kSize = 2*kCap + 3*kMid;
23
24    auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
25    SkCanvas* canvas = surface->getCanvas();
26    canvas->translate((float) padLeft, (float) padTop);
27
28    SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
29    const SkScalar strokeWidth = SkIntToScalar(6);
30    const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
31
32    xDivs[0] = kCap + padLeft;
33    yDivs[0] = kCap + padTop;
34    xDivs[1] = kCap + kMid + padLeft;
35    yDivs[1] = kCap + kMid + padTop;
36    xDivs[2] = kCap + 2 * kMid + padLeft;
37    yDivs[2] = kCap + 2 * kMid + padTop;
38    xDivs[3] = kCap + 3 * kMid + padLeft;
39    yDivs[3] = kCap + 3 * kMid + padTop;
40
41    SkPaint paint;
42    paint.setAntiAlias(true);
43
44    paint.setColor(0xFFFFFF00);
45    canvas->drawRoundRect(r, radius, radius, paint);
46
47    r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
48    paint.setColor(0x8800FF00);
49    canvas->drawRect(r, paint);
50    r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
51    paint.setColor(0x880000FF);
52    canvas->drawRect(r, paint);
53    r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
54    paint.setColor(0x88FF00FF);
55    canvas->drawRect(r, paint);
56
57    r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
58    paint.setColor(0x8800FF00);
59    canvas->drawRect(r, paint);
60    r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
61    paint.setColor(0x880000FF);
62    canvas->drawRect(r, paint);
63    r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
64    paint.setColor(0x88FF00FF);
65    canvas->drawRect(r, paint);
66
67    return surface->makeImageSnapshot();
68}
69
70static void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
71    SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
72    bm->allocPixels(info);
73    image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
74}
75
76/**
77 *  This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
78 *  than nine patches.
79 */
80class LatticeGM : public skiagm::GM {
81public:
82    LatticeGM() {}
83
84protected:
85    SkString onShortName() override {
86        return SkString("lattice");
87    }
88
89    SkISize onISize() override {
90        return SkISize::Make(800, 800);
91    }
92
93    void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) {
94        canvas->save();
95
96        int xDivs[5];
97        int yDivs[5];
98        xDivs[0] = padLeft;
99        yDivs[0] = padTop;
100
101        SkBitmap bitmap;
102        sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop,
103                                          padRight, padBottom);
104        image_to_bitmap(image.get(), &bitmap);
105
106        const SkSize size[] = {
107            {  50,  50, }, // shrink in both axes
108            {  50, 200, }, // shrink in X
109            { 200,  50, }, // shrink in Y
110            { 200, 200, },
111        };
112
113        canvas->drawImage(image, 10, 10, nullptr);
114
115        SkScalar x = SkIntToScalar(100);
116        SkScalar y = SkIntToScalar(100);
117
118        SkCanvas::Lattice lattice;
119        lattice.fXCount = 4;
120        lattice.fXDivs = xDivs + 1;
121        lattice.fYCount = 4;
122        lattice.fYDivs = yDivs + 1;
123        lattice.fRectTypes = nullptr;
124        lattice.fColors = nullptr;
125
126        SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
127                                           image->width() - padRight, image->height() - padBottom);
128        lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ?
129                nullptr : &bounds;
130
131        for (int iy = 0; iy < 2; ++iy) {
132            for (int ix = 0; ix < 2; ++ix) {
133                int i = ix * 2 + iy;
134                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
135                                            size[i].width(), size[i].height());
136                canvas->drawBitmapLattice(bitmap, lattice, r);
137            }
138        }
139
140        // Provide hints about 3 solid color rects. These colors match
141        // what was already in the bitmap.
142        int fixedColorX[3] = {2, 4, 1};
143        int fixedColorY[3] = {1, 1, 2};
144        SkColor fixedColor[3] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
145        const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType,
146                                                   kUnpremul_SkAlphaType);
147        for (int rectNum = 0; rectNum < 3; rectNum++) {
148            int srcX = xDivs[fixedColorX[rectNum]-1];
149            int srcY = yDivs[fixedColorY[rectNum]-1];
150            image->readPixels(info, &fixedColor[rectNum], 4, srcX, srcY);
151        }
152
153        // Include the degenerate first div.  While normally the first patch is "scalable",
154        // this will mean that the first non-degenerate patch is "fixed".
155        lattice.fXCount = 5;
156        lattice.fXDivs = xDivs;
157        lattice.fYCount = 5;
158        lattice.fYDivs = yDivs;
159
160        // Let's skip a few rects.
161        SkCanvas::Lattice::RectType flags[36];
162        sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::RectType));
163        flags[4] = SkCanvas::Lattice::kTransparent;
164        flags[9] = SkCanvas::Lattice::kTransparent;
165        flags[12] = SkCanvas::Lattice::kTransparent;
166        flags[19] = SkCanvas::Lattice::kTransparent;
167        for (int rectNum = 0; rectNum < 3; rectNum++) {
168            flags[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
169                   = SkCanvas::Lattice::kFixedColor;
170        }
171        lattice.fRectTypes = flags;
172
173        SkColor colors[36];
174        sk_bzero(colors, 36 * sizeof(SkColor));
175        for (int rectNum = 0; rectNum < 3; rectNum++) {
176            colors[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
177                   = fixedColor[rectNum];
178        }
179
180        lattice.fColors = colors;
181
182        canvas->translate(400, 0);
183        for (int iy = 0; iy < 2; ++iy) {
184            for (int ix = 0; ix < 2; ++ix) {
185                int i = ix * 2 + iy;
186                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
187                                            size[i].width(), size[i].height());
188                canvas->drawImageLattice(image.get(), lattice, r);
189            }
190        }
191
192        canvas->restore();
193    }
194
195    void onDraw(SkCanvas* canvas) override {
196        this->onDrawHelper(canvas, 0, 0, 0, 0);
197        canvas->translate(0.0f, 400.0f);
198        this->onDrawHelper(canvas, 3, 7, 4, 11);
199    }
200
201private:
202    typedef skiagm::GM INHERITED;
203};
204DEF_GM( return new LatticeGM; )
205
206
207// LatticeGM2 exercises code paths that draw fixed color and 1x1 rectangles.
208class LatticeGM2 : public skiagm::GM {
209public:
210    LatticeGM2() {}
211    SkString onShortName() override {
212        return SkString("lattice2");
213    }
214
215    SkISize onISize() override {
216        return SkISize::Make(800, 800);
217    }
218
219    sk_sp<SkImage> makeImage(SkCanvas* root, int padLeft, int padTop, int padRight, int padBottom) {
220        const int kSize = 80;
221        auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
222        SkCanvas* canvas = surface->getCanvas();;
223        SkPaint paint;
224        paint.setAntiAlias(false);
225        SkRect r;
226
227        //first line
228        r.setXYWH(0, 0, 4, 1);  //4x1 green rect
229        paint.setColor(0xFF00FF00);
230        canvas->drawRect(r, paint);
231
232        r.setXYWH(4, 0, 1, 1); //1x1 blue pixel -> draws as rectangle
233        paint.setColor(0xFF0000FF);
234        canvas->drawRect(r, paint);
235
236        r.setXYWH(5, 0, kSize-5, 1); //the rest of the line is red
237        paint.setColor(0xFFFF0000);
238        canvas->drawRect(r, paint);
239
240
241        //second line -> draws as fixed color rectangles
242        r.setXYWH(0, 1, 4, 1);  //4x1 red rect
243        paint.setColor(0xFFFF0000);
244        canvas->drawRect(r, paint);
245
246        r.setXYWH(4, 1, 1, 1); //1x1 blue pixel with alpha
247        paint.setColor(0x880000FF);
248        canvas->drawRect(r, paint);
249
250        r.setXYWH(5, 1, kSize-5, 1); //the rest of the line is green
251        paint.setColor(0xFF00FF00);
252        canvas->drawRect(r, paint);
253
254
255        //third line - does not draw, because it is transparent
256        r.setXYWH(0, 2, 4, kSize-2);  //4x78 green rect
257        paint.setColor(0xFF00FF00);
258        canvas->drawRect(r, paint);
259
260        r.setXYWH(4, 2, 1, kSize-2); //1x78 red pixel with alpha
261        paint.setColor(0x88FF0000);
262        canvas->drawRect(r, paint);
263
264        r.setXYWH(5, 2, kSize-5, kSize-2); //the rest of the image is blue
265        paint.setColor(0xFF0000FF);
266        canvas->drawRect(r, paint);
267
268        return surface->makeImageSnapshot();
269    }
270
271    void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom,
272                      SkPaint& paint) {
273        int xDivs[2] = {4, 5};
274        int yDivs[2] = {1, 2};
275
276        canvas->save();
277
278        sk_sp<SkImage> image = makeImage(canvas, padLeft, padTop, padRight, padBottom);
279
280        canvas->drawImage(image, 10, 10, nullptr);
281
282        SkCanvas::Lattice lattice;
283        lattice.fXCount = 2;
284        lattice.fXDivs = xDivs;
285        lattice.fYCount = 2;
286        lattice.fYDivs = yDivs;
287        lattice.fBounds = nullptr;
288
289        SkCanvas::Lattice::RectType flags[9];
290        sk_bzero(flags, 9 * sizeof(SkCanvas::Lattice::RectType));
291        flags[3] = SkCanvas::Lattice::kFixedColor;
292        flags[4] = SkCanvas::Lattice::kFixedColor;
293        flags[5] = SkCanvas::Lattice::kFixedColor;
294
295        flags[6] = SkCanvas::Lattice::kTransparent;
296        flags[7] = SkCanvas::Lattice::kTransparent;
297        flags[8] = SkCanvas::Lattice::kTransparent;
298        lattice.fRectTypes = flags;
299
300        SkColor colors[9] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK,
301                             0xFFFF0000, 0x880000FF, 0xFF00FF00,
302                             SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
303        lattice.fColors = colors;
304        paint.setColor(0xFFFFFFFF);
305        canvas->drawImageLattice(image.get(), lattice,
306                                 SkRect::MakeXYWH(100, 100, 200, 200), &paint);
307
308        //draw the same content with alpha
309        canvas->translate(400, 0);
310        paint.setColor(0x80000FFF);
311        canvas->drawImageLattice(image.get(), lattice,
312                                 SkRect::MakeXYWH(100, 100, 200, 200), &paint);
313
314        canvas->restore();
315    }
316
317    void onDraw(SkCanvas* canvas) override {
318
319        //draw a rectangle in the background with transparent pixels
320        SkPaint paint;
321        paint.setColor(0x7F123456);
322        paint.setBlendMode(SkBlendMode::kSrc);
323        canvas->drawRect( SkRect::MakeXYWH(300, 0, 300, 800), paint);
324
325        //draw image lattice with kSrcOver blending
326        paint.setBlendMode(SkBlendMode::kSrcOver);
327        this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
328
329        //draw image lattice with kSrcATop blending
330        canvas->translate(0.0f, 400.0f);
331        paint.setBlendMode(SkBlendMode::kSrcATop);
332        this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
333    }
334
335private:
336    typedef skiagm::GM INHERITED;
337};
338DEF_GM( return new LatticeGM2; )
339
340
341
342