skia2/gm/lattice.cpp
Ben Wagner 7fde8e1728 IWYU for gms.
This almost gets gms to be iwyu clean. The last bit is around gm.cpp
and the tracing framework and its use of atomic. Will also need a way
of keeping things from regressing, which is difficult due to needing to
do this outside-in.

Change-Id: I1393531e99da8b0f1a29f55c53c86d53f459af7d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211593
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2019-05-02 17:48:53 +00:00

375 lines
13 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/private/SkMalloc.h"
#include "tools/ToolUtils.h"
static sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop,
int padRight, int padBottom) {
SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom);
return ToolUtils::makeSurface(root, info);
}
static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop,
int padRight, int padBottom) {
const int kCap = 28;
const int kMid = 8;
const int kSize = 2*kCap + 3*kMid;
auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
SkCanvas* canvas = surface->getCanvas();
canvas->translate((float) padLeft, (float) padTop);
SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
const SkScalar strokeWidth = SkIntToScalar(6);
const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
xDivs[0] = kCap + padLeft;
yDivs[0] = kCap + padTop;
xDivs[1] = kCap + kMid + padLeft;
yDivs[1] = kCap + kMid + padTop;
xDivs[2] = kCap + 2 * kMid + padLeft;
yDivs[2] = kCap + 2 * kMid + padTop;
xDivs[3] = kCap + 3 * kMid + padLeft;
yDivs[3] = kCap + 3 * kMid + padTop;
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xFFFFFF00);
canvas->drawRoundRect(r, radius, radius, paint);
r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
paint.setColor(0x8800FF00);
canvas->drawRect(r, paint);
r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
paint.setColor(0x880000FF);
canvas->drawRect(r, paint);
r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
paint.setColor(0x88FF00FF);
canvas->drawRect(r, paint);
r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
paint.setColor(0x8800FF00);
canvas->drawRect(r, paint);
r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
paint.setColor(0x880000FF);
canvas->drawRect(r, paint);
r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
paint.setColor(0x88FF00FF);
canvas->drawRect(r, paint);
return surface->makeImageSnapshot();
}
static void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
bm->allocPixels(info);
image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
}
/**
* This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
* than nine patches.
*/
class LatticeGM : public skiagm::GM {
public:
LatticeGM() {}
protected:
SkString onShortName() override {
return SkString("lattice");
}
SkISize onISize() override {
return SkISize::Make(800, 800);
}
void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) {
canvas->save();
int xDivs[5];
int yDivs[5];
xDivs[0] = padLeft;
yDivs[0] = padTop;
SkBitmap bitmap;
sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop,
padRight, padBottom);
image_to_bitmap(image.get(), &bitmap);
const SkSize size[] = {
{ 50, 50, }, // shrink in both axes
{ 50, 200, }, // shrink in X
{ 200, 50, }, // shrink in Y
{ 200, 200, },
};
canvas->drawImage(image, 10, 10, nullptr);
SkScalar x = SkIntToScalar(100);
SkScalar y = SkIntToScalar(100);
SkCanvas::Lattice lattice;
lattice.fXCount = 4;
lattice.fXDivs = xDivs + 1;
lattice.fYCount = 4;
lattice.fYDivs = yDivs + 1;
lattice.fRectTypes = nullptr;
lattice.fColors = nullptr;
SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
image->width() - padRight, image->height() - padBottom);
lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ?
nullptr : &bounds;
for (int iy = 0; iy < 2; ++iy) {
for (int ix = 0; ix < 2; ++ix) {
int i = ix * 2 + iy;
SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
size[i].width(), size[i].height());
canvas->drawBitmapLattice(bitmap, lattice, r);
}
}
// Provide hints about 3 solid color rects. These colors match
// what was already in the bitmap.
int fixedColorX[3] = {2, 4, 1};
int fixedColorY[3] = {1, 1, 2};
SkColor fixedColor[3] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType,
kUnpremul_SkAlphaType);
for (int rectNum = 0; rectNum < 3; rectNum++) {
int srcX = xDivs[fixedColorX[rectNum]-1];
int srcY = yDivs[fixedColorY[rectNum]-1];
image->readPixels(info, &fixedColor[rectNum], 4, srcX, srcY);
}
// Include the degenerate first div. While normally the first patch is "scalable",
// this will mean that the first non-degenerate patch is "fixed".
lattice.fXCount = 5;
lattice.fXDivs = xDivs;
lattice.fYCount = 5;
lattice.fYDivs = yDivs;
// Let's skip a few rects.
SkCanvas::Lattice::RectType flags[36];
sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::RectType));
flags[4] = SkCanvas::Lattice::kTransparent;
flags[9] = SkCanvas::Lattice::kTransparent;
flags[12] = SkCanvas::Lattice::kTransparent;
flags[19] = SkCanvas::Lattice::kTransparent;
for (int rectNum = 0; rectNum < 3; rectNum++) {
flags[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
= SkCanvas::Lattice::kFixedColor;
}
lattice.fRectTypes = flags;
SkColor colors[36];
sk_bzero(colors, 36 * sizeof(SkColor));
for (int rectNum = 0; rectNum < 3; rectNum++) {
colors[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
= fixedColor[rectNum];
}
lattice.fColors = colors;
canvas->translate(400, 0);
for (int iy = 0; iy < 2; ++iy) {
for (int ix = 0; ix < 2; ++ix) {
int i = ix * 2 + iy;
SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
size[i].width(), size[i].height());
canvas->drawImageLattice(image.get(), lattice, r);
}
}
canvas->restore();
}
void onDraw(SkCanvas* canvas) override {
this->onDrawHelper(canvas, 0, 0, 0, 0);
canvas->translate(0.0f, 400.0f);
this->onDrawHelper(canvas, 3, 7, 4, 11);
}
private:
typedef skiagm::GM INHERITED;
};
DEF_GM( return new LatticeGM; )
// LatticeGM2 exercises code paths that draw fixed color and 1x1 rectangles.
class LatticeGM2 : public skiagm::GM {
public:
LatticeGM2() {}
SkString onShortName() override {
return SkString("lattice2");
}
SkISize onISize() override {
return SkISize::Make(800, 800);
}
sk_sp<SkImage> makeImage(SkCanvas* root, int padLeft, int padTop, int padRight, int padBottom) {
const int kSize = 80;
auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
SkCanvas* canvas = surface->getCanvas();
SkPaint paint;
paint.setAntiAlias(false);
SkRect r;
//first line
r.setXYWH(0, 0, 4, 1); //4x1 green rect
paint.setColor(0xFF00FF00);
canvas->drawRect(r, paint);
r.setXYWH(4, 0, 1, 1); //1x1 blue pixel -> draws as rectangle
paint.setColor(0xFF0000FF);
canvas->drawRect(r, paint);
r.setXYWH(5, 0, kSize-5, 1); //the rest of the line is red
paint.setColor(0xFFFF0000);
canvas->drawRect(r, paint);
//second line -> draws as fixed color rectangles
r.setXYWH(0, 1, 4, 1); //4x1 red rect
paint.setColor(0xFFFF0000);
canvas->drawRect(r, paint);
r.setXYWH(4, 1, 1, 1); //1x1 blue pixel with alpha
paint.setColor(0x880000FF);
canvas->drawRect(r, paint);
r.setXYWH(5, 1, kSize-5, 1); //the rest of the line is green
paint.setColor(0xFF00FF00);
canvas->drawRect(r, paint);
//third line - does not draw, because it is transparent
r.setXYWH(0, 2, 4, kSize-2); //4x78 green rect
paint.setColor(0xFF00FF00);
canvas->drawRect(r, paint);
r.setXYWH(4, 2, 1, kSize-2); //1x78 red pixel with alpha
paint.setColor(0x88FF0000);
canvas->drawRect(r, paint);
r.setXYWH(5, 2, kSize-5, kSize-2); //the rest of the image is blue
paint.setColor(0xFF0000FF);
canvas->drawRect(r, paint);
return surface->makeImageSnapshot();
}
void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom,
SkPaint& paint) {
int xDivs[2] = {4, 5};
int yDivs[2] = {1, 2};
canvas->save();
sk_sp<SkImage> image = makeImage(canvas, padLeft, padTop, padRight, padBottom);
canvas->drawImage(image, 10, 10, nullptr);
SkCanvas::Lattice lattice;
lattice.fXCount = 2;
lattice.fXDivs = xDivs;
lattice.fYCount = 2;
lattice.fYDivs = yDivs;
lattice.fBounds = nullptr;
SkCanvas::Lattice::RectType flags[9];
sk_bzero(flags, 9 * sizeof(SkCanvas::Lattice::RectType));
flags[3] = SkCanvas::Lattice::kFixedColor;
flags[4] = SkCanvas::Lattice::kFixedColor;
flags[5] = SkCanvas::Lattice::kFixedColor;
flags[6] = SkCanvas::Lattice::kTransparent;
flags[7] = SkCanvas::Lattice::kTransparent;
flags[8] = SkCanvas::Lattice::kTransparent;
lattice.fRectTypes = flags;
SkColor colors[9] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK,
0xFFFF0000, 0x880000FF, 0xFF00FF00,
SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
lattice.fColors = colors;
paint.setColor(0xFFFFFFFF);
canvas->drawImageLattice(image.get(), lattice,
SkRect::MakeXYWH(100, 100, 200, 200), &paint);
//draw the same content with alpha
canvas->translate(400, 0);
paint.setColor(0x80000FFF);
canvas->drawImageLattice(image.get(), lattice,
SkRect::MakeXYWH(100, 100, 200, 200), &paint);
canvas->restore();
}
void onDraw(SkCanvas* canvas) override {
//draw a rectangle in the background with transparent pixels
SkPaint paint;
paint.setColor(0x7F123456);
paint.setBlendMode(SkBlendMode::kSrc);
canvas->drawRect( SkRect::MakeXYWH(300, 0, 300, 800), paint);
//draw image lattice with kSrcOver blending
paint.setBlendMode(SkBlendMode::kSrcOver);
this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
//draw image lattice with kSrcATop blending
canvas->translate(0.0f, 400.0f);
paint.setBlendMode(SkBlendMode::kSrcATop);
this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
}
private:
typedef skiagm::GM INHERITED;
};
DEF_GM( return new LatticeGM2; )
// Code paths that incorporate the paint color when drawing the lattice (using an alpha image)
DEF_SIMPLE_GM_BG(lattice_alpha, canvas, 120, 120, SK_ColorWHITE) {
auto surface = ToolUtils::makeSurface(canvas, SkImageInfo::MakeA8(100, 100));
surface->getCanvas()->clear(0);
surface->getCanvas()->drawCircle(50, 50, 50, SkPaint());
auto image = surface->makeImageSnapshot();
int divs[] = { 20, 40, 60, 80 };
SkCanvas::Lattice lattice;
lattice.fXCount = 4;
lattice.fXDivs = divs;
lattice.fYCount = 4;
lattice.fYDivs = divs;
lattice.fRectTypes = nullptr;
lattice.fColors = nullptr;
lattice.fBounds = nullptr;
SkPaint paint;
paint.setColor(SK_ColorMAGENTA);
canvas->drawImageLattice(image.get(), lattice, SkRect::MakeWH(120, 120), &paint);
}