bcfc554fde
Note: The polarity of the staging flag is inverted from usual because a G3 dependency with no SkUserConfig.h relies on the legacy API. Once this lands, we will migrate them and others, then remove the staging API. The inverted staging flag is kind of nice, actually - I may use that pattern in the future. It means less total CLs and it's just as easy to flip the bit on or off during debugging. Bug: skia:104662 Change-Id: I48cba1eeae3e2e6f79918c6d243e0666e68ec71b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/310656 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Adlai Holler <adlai@google.com>
384 lines
13 KiB
C++
384 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/gpu/GrDirectContext.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(GrDirectContext* dContext, const SkImage* image, SkBitmap* bm) {
|
|
SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
|
|
bm->allocPixels(info);
|
|
image->readPixels(dContext, 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(GrDirectContext* dContext, 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(dContext, 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->drawImageLattice(image.get(), 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(dContext, 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();
|
|
}
|
|
|
|
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
|
|
auto rContext = canvas->recordingContext();
|
|
auto dContext = GrAsDirectContext(rContext);
|
|
if (rContext && !dContext) {
|
|
*errorMsg = "not supported in ddl";
|
|
return DrawResult::kSkip;
|
|
}
|
|
this->onDrawHelper(dContext, canvas, 0, 0, 0, 0);
|
|
canvas->translate(0.0f, 400.0f);
|
|
this->onDrawHelper(dContext, canvas, 3, 7, 4, 11);
|
|
return DrawResult::kOk;
|
|
}
|
|
|
|
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);
|
|
}
|