1c573a40ed5024b463e47088d307e3164a486dba5msarett/*
2c573a40ed5024b463e47088d307e3164a486dba5msarett * Copyright 2016 Google Inc.
3c573a40ed5024b463e47088d307e3164a486dba5msarett *
4c573a40ed5024b463e47088d307e3164a486dba5msarett * Use of this source code is governed by a BSD-style license that can be
5c573a40ed5024b463e47088d307e3164a486dba5msarett * found in the LICENSE file.
6c573a40ed5024b463e47088d307e3164a486dba5msarett */
7c573a40ed5024b463e47088d307e3164a486dba5msarett
8c573a40ed5024b463e47088d307e3164a486dba5msarett#include "gm.h"
9c573a40ed5024b463e47088d307e3164a486dba5msarett#include "SkSurface.h"
10c573a40ed5024b463e47088d307e3164a486dba5msarett
1171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarettstatic sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop,
1271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                     int padRight, int padBottom) {
1371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom);
14c573a40ed5024b463e47088d307e3164a486dba5msarett    auto surface = root->makeSurface(info);
15c573a40ed5024b463e47088d307e3164a486dba5msarett    if (!surface) {
16c573a40ed5024b463e47088d307e3164a486dba5msarett        surface = SkSurface::MakeRaster(info);
17c573a40ed5024b463e47088d307e3164a486dba5msarett    }
1871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
19c573a40ed5024b463e47088d307e3164a486dba5msarett    return surface;
20c573a40ed5024b463e47088d307e3164a486dba5msarett}
21c573a40ed5024b463e47088d307e3164a486dba5msarett
2271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarettstatic sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop,
2371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                 int padRight, int padBottom) {
24c573a40ed5024b463e47088d307e3164a486dba5msarett    const int kCap = 28;
25c573a40ed5024b463e47088d307e3164a486dba5msarett    const int kMid = 8;
26c573a40ed5024b463e47088d307e3164a486dba5msarett    const int kSize = 2*kCap + 3*kMid;
27c573a40ed5024b463e47088d307e3164a486dba5msarett
2871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
29c573a40ed5024b463e47088d307e3164a486dba5msarett    SkCanvas* canvas = surface->getCanvas();
3071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    canvas->translate((float) padLeft, (float) padTop);
31c573a40ed5024b463e47088d307e3164a486dba5msarett
32c573a40ed5024b463e47088d307e3164a486dba5msarett    SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
33c573a40ed5024b463e47088d307e3164a486dba5msarett    const SkScalar strokeWidth = SkIntToScalar(6);
34c573a40ed5024b463e47088d307e3164a486dba5msarett    const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
35c573a40ed5024b463e47088d307e3164a486dba5msarett
3671df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    xDivs[0] = kCap + padLeft;
3771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    yDivs[0] = kCap + padTop;
3871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    xDivs[1] = kCap + kMid + padLeft;
3971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    yDivs[1] = kCap + kMid + padTop;
4071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    xDivs[2] = kCap + 2 * kMid + padLeft;
4171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    yDivs[2] = kCap + 2 * kMid + padTop;
4271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    xDivs[3] = kCap + 3 * kMid + padLeft;
4371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    yDivs[3] = kCap + 3 * kMid + padTop;
44c573a40ed5024b463e47088d307e3164a486dba5msarett
45c573a40ed5024b463e47088d307e3164a486dba5msarett    SkPaint paint;
46c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setAntiAlias(true);
47c573a40ed5024b463e47088d307e3164a486dba5msarett
48c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0xFFFFFF00);
49c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRoundRect(r, radius, radius, paint);
50c573a40ed5024b463e47088d307e3164a486dba5msarett
51c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
52c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x8800FF00);
53c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
54c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
55c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x880000FF);
56c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
57c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
58c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x88FF00FF);
59c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
60c573a40ed5024b463e47088d307e3164a486dba5msarett
61c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
62c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x8800FF00);
63c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
64c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
65c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x880000FF);
66c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
67c573a40ed5024b463e47088d307e3164a486dba5msarett    r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
68c573a40ed5024b463e47088d307e3164a486dba5msarett    paint.setColor(0x88FF00FF);
69c573a40ed5024b463e47088d307e3164a486dba5msarett    canvas->drawRect(r, paint);
70c573a40ed5024b463e47088d307e3164a486dba5msarett
71c573a40ed5024b463e47088d307e3164a486dba5msarett    return surface->makeImageSnapshot();
72c573a40ed5024b463e47088d307e3164a486dba5msarett}
73c573a40ed5024b463e47088d307e3164a486dba5msarett
74c573a40ed5024b463e47088d307e3164a486dba5msarettstatic void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
75c573a40ed5024b463e47088d307e3164a486dba5msarett    SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
76c573a40ed5024b463e47088d307e3164a486dba5msarett    bm->allocPixels(info);
77c573a40ed5024b463e47088d307e3164a486dba5msarett    image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
78c573a40ed5024b463e47088d307e3164a486dba5msarett}
79c573a40ed5024b463e47088d307e3164a486dba5msarett
80c573a40ed5024b463e47088d307e3164a486dba5msarett/**
81c573a40ed5024b463e47088d307e3164a486dba5msarett *  This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
82c573a40ed5024b463e47088d307e3164a486dba5msarett *  than nine patches.
83c573a40ed5024b463e47088d307e3164a486dba5msarett */
84c573a40ed5024b463e47088d307e3164a486dba5msarettclass LatticeGM : public skiagm::GM {
85c573a40ed5024b463e47088d307e3164a486dba5msarettpublic:
86c573a40ed5024b463e47088d307e3164a486dba5msarett    LatticeGM() {}
87c573a40ed5024b463e47088d307e3164a486dba5msarett
88c573a40ed5024b463e47088d307e3164a486dba5msarettprotected:
89c573a40ed5024b463e47088d307e3164a486dba5msarett    SkString onShortName() override {
90c573a40ed5024b463e47088d307e3164a486dba5msarett        return SkString("lattice");
91c573a40ed5024b463e47088d307e3164a486dba5msarett    }
92c573a40ed5024b463e47088d307e3164a486dba5msarett
93c573a40ed5024b463e47088d307e3164a486dba5msarett    SkISize onISize() override {
9471df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        return SkISize::Make(800, 800);
95c573a40ed5024b463e47088d307e3164a486dba5msarett    }
96c573a40ed5024b463e47088d307e3164a486dba5msarett
9771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) {
9871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        canvas->save();
9971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
100c573a40ed5024b463e47088d307e3164a486dba5msarett        int xDivs[5];
101c573a40ed5024b463e47088d307e3164a486dba5msarett        int yDivs[5];
10271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        xDivs[0] = padLeft;
10371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        yDivs[0] = padTop;
104c573a40ed5024b463e47088d307e3164a486dba5msarett
105c573a40ed5024b463e47088d307e3164a486dba5msarett        SkBitmap bitmap;
10671df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop,
10771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                          padRight, padBottom);
108c573a40ed5024b463e47088d307e3164a486dba5msarett        image_to_bitmap(image.get(), &bitmap);
109c573a40ed5024b463e47088d307e3164a486dba5msarett
110c573a40ed5024b463e47088d307e3164a486dba5msarett        const SkTSize<SkScalar> size[] = {
111c573a40ed5024b463e47088d307e3164a486dba5msarett            {  50,  50, }, // shrink in both axes
112c573a40ed5024b463e47088d307e3164a486dba5msarett            {  50, 200, }, // shrink in X
113c573a40ed5024b463e47088d307e3164a486dba5msarett            { 200,  50, }, // shrink in Y
114c573a40ed5024b463e47088d307e3164a486dba5msarett            { 200, 200, },
115c573a40ed5024b463e47088d307e3164a486dba5msarett        };
116c573a40ed5024b463e47088d307e3164a486dba5msarett
117c573a40ed5024b463e47088d307e3164a486dba5msarett        canvas->drawImage(image, 10, 10, nullptr);
118c573a40ed5024b463e47088d307e3164a486dba5msarett
119c573a40ed5024b463e47088d307e3164a486dba5msarett        SkScalar x = SkIntToScalar(100);
120c573a40ed5024b463e47088d307e3164a486dba5msarett        SkScalar y = SkIntToScalar(100);
121c573a40ed5024b463e47088d307e3164a486dba5msarett
122c573a40ed5024b463e47088d307e3164a486dba5msarett        SkCanvas::Lattice lattice;
123c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fXCount = 4;
124c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fXDivs = xDivs + 1;
125c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fYCount = 4;
126c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fYDivs = yDivs + 1;
1270764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        lattice.fFlags = nullptr;
128c573a40ed5024b463e47088d307e3164a486dba5msarett
12971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
13071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                           image->width() - padRight, image->height() - padBottom);
13171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ?
13271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                nullptr : &bounds;
13371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
134c573a40ed5024b463e47088d307e3164a486dba5msarett        for (int iy = 0; iy < 2; ++iy) {
135c573a40ed5024b463e47088d307e3164a486dba5msarett            for (int ix = 0; ix < 2; ++ix) {
136c573a40ed5024b463e47088d307e3164a486dba5msarett                int i = ix * 2 + iy;
137c573a40ed5024b463e47088d307e3164a486dba5msarett                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
138c573a40ed5024b463e47088d307e3164a486dba5msarett                                            size[i].width(), size[i].height());
139c573a40ed5024b463e47088d307e3164a486dba5msarett                canvas->drawBitmapLattice(bitmap, lattice, r);
140c573a40ed5024b463e47088d307e3164a486dba5msarett            }
141c573a40ed5024b463e47088d307e3164a486dba5msarett        }
142c573a40ed5024b463e47088d307e3164a486dba5msarett
143c573a40ed5024b463e47088d307e3164a486dba5msarett        // Include the degenerate first div.  While normally the first patch is "scalable",
144c573a40ed5024b463e47088d307e3164a486dba5msarett        // this will mean that the first non-degenerate patch is "fixed".
145c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fXCount = 5;
146c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fXDivs = xDivs;
147c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fYCount = 5;
148c573a40ed5024b463e47088d307e3164a486dba5msarett        lattice.fYDivs = yDivs;
149c573a40ed5024b463e47088d307e3164a486dba5msarett
1500764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        // Let's skip a few rects.
1510764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        SkCanvas::Lattice::Flags flags[36];
1520764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::Flags));
1530764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        flags[4] = SkCanvas::Lattice::kTransparent_Flags;
1540764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        flags[9] = SkCanvas::Lattice::kTransparent_Flags;
1550764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        flags[12] = SkCanvas::Lattice::kTransparent_Flags;
1560764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        flags[19] = SkCanvas::Lattice::kTransparent_Flags;
1570764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        lattice.fFlags = flags;
1580764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
159c573a40ed5024b463e47088d307e3164a486dba5msarett        canvas->translate(400, 0);
160c573a40ed5024b463e47088d307e3164a486dba5msarett        for (int iy = 0; iy < 2; ++iy) {
161c573a40ed5024b463e47088d307e3164a486dba5msarett            for (int ix = 0; ix < 2; ++ix) {
162c573a40ed5024b463e47088d307e3164a486dba5msarett                int i = ix * 2 + iy;
163c573a40ed5024b463e47088d307e3164a486dba5msarett                SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
164c573a40ed5024b463e47088d307e3164a486dba5msarett                                            size[i].width(), size[i].height());
165c573a40ed5024b463e47088d307e3164a486dba5msarett                canvas->drawImageLattice(image.get(), lattice, r);
166c573a40ed5024b463e47088d307e3164a486dba5msarett            }
167c573a40ed5024b463e47088d307e3164a486dba5msarett        }
16871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
16971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        canvas->restore();
17071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    }
17171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
17271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    void onDraw(SkCanvas* canvas) override {
17371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        this->onDrawHelper(canvas, 0, 0, 0, 0);
17471df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        canvas->translate(0.0f, 400.0f);
17571df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        this->onDrawHelper(canvas, 3, 7, 4, 11);
176c573a40ed5024b463e47088d307e3164a486dba5msarett    }
177c573a40ed5024b463e47088d307e3164a486dba5msarett
178c573a40ed5024b463e47088d307e3164a486dba5msarettprivate:
179c573a40ed5024b463e47088d307e3164a486dba5msarett    typedef skiagm::GM INHERITED;
180c573a40ed5024b463e47088d307e3164a486dba5msarett};
181c573a40ed5024b463e47088d307e3164a486dba5msarettDEF_GM( return new LatticeGM; )
182