9ce9d6772d
not forced yet, as we still have the build-guard. waiting on chrome CL BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1810813003 TBR= Review URL: https://codereview.chromium.org/1810813003
311 lines
9.8 KiB
C++
311 lines
9.8 KiB
C++
/*
|
|
* Copyright 2015 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "gm.h"
|
|
|
|
#include "Resources.h"
|
|
#include "SampleCode.h"
|
|
#include "SkAnimTimer.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkInterpolator.h"
|
|
#include "SkGradientShader.h"
|
|
#include "SkData.h"
|
|
#include "SkPath.h"
|
|
#include "SkSurface.h"
|
|
#include "SkRandom.h"
|
|
#include "SkTime.h"
|
|
|
|
static SkSurface* make_surface(SkCanvas* canvas, const SkImageInfo& info) {
|
|
SkSurface* surface = canvas->newSurface(info);
|
|
if (!surface) {
|
|
surface = SkSurface::NewRaster(info);
|
|
}
|
|
return surface;
|
|
}
|
|
|
|
static sk_sp<SkShader> make_shader(const SkRect& bounds) {
|
|
sk_sp<SkImage> image(GetResourceAsImage("mandrill_128.png"));
|
|
if (!image) {
|
|
return nullptr;
|
|
}
|
|
return image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
|
|
}
|
|
|
|
#define N 128
|
|
#define ANGLE_DELTA 3
|
|
#define SCALE_DELTA (SK_Scalar1 / 32)
|
|
|
|
static sk_sp<SkImage> make_image() {
|
|
SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
|
|
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
|
|
SkCanvas* canvas = surface->getCanvas();
|
|
canvas->drawColor(SK_ColorWHITE);
|
|
|
|
SkPath path;
|
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
|
|
|
path.addRect(SkRect::MakeWH(N/2, N));
|
|
path.addRect(SkRect::MakeWH(N, N/2));
|
|
path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
|
|
|
|
SkPaint paint;
|
|
paint.setShader(make_shader(SkRect::MakeWH(N, N)));
|
|
|
|
canvas->drawPath(path, paint);
|
|
return surface->makeImageSnapshot();
|
|
}
|
|
|
|
static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
|
|
const SkScalar S = 16; // amount to scale up
|
|
const int D = 2; // dimension scaling for the offscreen
|
|
// since we only view the center, don't need to produce the entire thing
|
|
|
|
SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
|
|
kOpaque_SkAlphaType);
|
|
SkAutoTUnref<SkSurface> surface(origSurf->newSurface(info));
|
|
SkCanvas* canvas = surface->getCanvas();
|
|
canvas->drawColor(SK_ColorWHITE);
|
|
canvas->scale(S, S);
|
|
canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
|
|
-SkScalarHalf(orig->height()) * (S - D) / S);
|
|
canvas->drawImage(orig, 0, 0, nullptr);
|
|
|
|
if (S > 3) {
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorWHITE);
|
|
for (int i = 1; i < orig->height(); ++i) {
|
|
SkScalar y = SkIntToScalar(i);
|
|
canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
|
|
}
|
|
for (int i = 1; i < orig->width(); ++i) {
|
|
SkScalar x = SkIntToScalar(i);
|
|
canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
|
|
}
|
|
}
|
|
return surface->makeImageSnapshot();
|
|
}
|
|
|
|
struct AnimValue {
|
|
SkScalar fValue;
|
|
SkScalar fMin;
|
|
SkScalar fMax;
|
|
SkScalar fMod;
|
|
|
|
operator SkScalar() const { return fValue; }
|
|
|
|
void set(SkScalar value, SkScalar min, SkScalar max) {
|
|
fValue = value;
|
|
fMin = min;
|
|
fMax = max;
|
|
fMod = 0;
|
|
}
|
|
|
|
void setMod(SkScalar value, SkScalar mod) {
|
|
fValue = value;
|
|
fMin = 0;
|
|
fMax = 0;
|
|
fMod = mod;
|
|
}
|
|
|
|
SkScalar inc(SkScalar delta) {
|
|
fValue += delta;
|
|
return this->fixUp();
|
|
}
|
|
|
|
SkScalar fixUp() {
|
|
if (fMod) {
|
|
fValue = SkScalarMod(fValue, fMod);
|
|
} else {
|
|
if (fValue > fMax) {
|
|
fValue = fMax;
|
|
} else if (fValue < fMin) {
|
|
fValue = fMin;
|
|
}
|
|
}
|
|
return fValue;
|
|
}
|
|
};
|
|
|
|
static void draw_box_frame(SkCanvas* canvas, int width, int height) {
|
|
SkPaint p;
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
p.setColor(SK_ColorRED);
|
|
SkRect r = SkRect::MakeIWH(width, height);
|
|
r.inset(0.5f, 0.5f);
|
|
canvas->drawRect(r, p);
|
|
canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
|
|
canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
|
|
}
|
|
|
|
class FilterQualityView : public SampleView {
|
|
sk_sp<SkImage> fImage;
|
|
AnimValue fScale, fAngle;
|
|
SkSize fCell;
|
|
SkInterpolator fTrans;
|
|
SkMSec fCurrTime;
|
|
bool fShowFatBits;
|
|
|
|
public:
|
|
FilterQualityView() : fImage(make_image()), fTrans(2, 2), fShowFatBits(true) {
|
|
fCell.set(256, 256);
|
|
|
|
fScale.set(1, SK_Scalar1 / 8, 1);
|
|
fAngle.setMod(0, 360);
|
|
|
|
SkScalar values[2];
|
|
fTrans.setMirror(true);
|
|
fTrans.setReset(true);
|
|
|
|
fCurrTime = 0;
|
|
|
|
fTrans.setRepeatCount(999);
|
|
values[0] = values[1] = 0;
|
|
fTrans.setKeyFrame(0, fCurrTime, values);
|
|
values[0] = values[1] = 1;
|
|
fTrans.setKeyFrame(1, fCurrTime + 2000, values);
|
|
}
|
|
|
|
protected:
|
|
bool onQuery(SkEvent* evt) override {
|
|
if (SampleCode::TitleQ(*evt)) {
|
|
SampleCode::TitleR(evt, "FilterQuality");
|
|
return true;
|
|
}
|
|
SkUnichar uni;
|
|
if (SampleCode::CharQ(*evt, &uni)) {
|
|
switch (uni) {
|
|
case '1': fAngle.inc(-ANGLE_DELTA); this->inval(nullptr); return true;
|
|
case '2': fAngle.inc( ANGLE_DELTA); this->inval(nullptr); return true;
|
|
case '3': fScale.inc(-SCALE_DELTA); this->inval(nullptr); return true;
|
|
case '4': fScale.inc( SCALE_DELTA); this->inval(nullptr); return true;
|
|
case '5': fShowFatBits = !fShowFatBits; this->inval(nullptr); return true;
|
|
default: break;
|
|
}
|
|
}
|
|
return this->INHERITED::onQuery(evt);
|
|
}
|
|
|
|
void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
|
|
SkScalar dx, SkScalar dy) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setFilterQuality(filter);
|
|
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
canvas->translate(dx, dy);
|
|
|
|
canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
|
|
canvas->scale(fScale, fScale);
|
|
canvas->rotate(fAngle);
|
|
canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
|
|
&paint);
|
|
|
|
if (false) {
|
|
acr.restore();
|
|
draw_box_frame(canvas, size.width(), size.height());
|
|
}
|
|
}
|
|
|
|
void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
|
|
SkCanvas* origCanvas = canvas;
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
SkISize size = SkISize::Make(fImage->width(), fImage->height());
|
|
|
|
SkAutoTUnref<SkSurface> surface;
|
|
if (fShowFatBits) {
|
|
// scale up so we don't clip rotations
|
|
SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
|
|
kOpaque_SkAlphaType);
|
|
surface.reset(make_surface(canvas, info));
|
|
canvas = surface->getCanvas();
|
|
canvas->drawColor(SK_ColorWHITE);
|
|
size.set(info.width(), info.height());
|
|
} else {
|
|
canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
|
|
SkScalarHalf(fCell.height() - fImage->height()));
|
|
}
|
|
this->drawTheImage(canvas, size, filter, dx, dy);
|
|
|
|
if (surface) {
|
|
sk_sp<SkImage> orig(surface->makeImageSnapshot());
|
|
sk_sp<SkImage> zoomed(zoom_up(surface, orig.get()));
|
|
origCanvas->drawImage(zoomed.get(),
|
|
SkScalarHalf(fCell.width() - zoomed->width()),
|
|
SkScalarHalf(fCell.height() - zoomed->height()));
|
|
}
|
|
}
|
|
|
|
void drawBorders(SkCanvas* canvas) {
|
|
SkPaint p;
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
p.setColor(SK_ColorBLUE);
|
|
|
|
SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
|
|
r.inset(SK_ScalarHalf, SK_ScalarHalf);
|
|
canvas->drawRect(r, p);
|
|
canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
|
|
canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
|
|
}
|
|
|
|
void onDrawContent(SkCanvas* canvas) override {
|
|
fCell.set(this->height() / 2, this->height() / 2);
|
|
|
|
SkScalar trans[2];
|
|
fTrans.timeToValues(fCurrTime, trans);
|
|
|
|
for (int y = 0; y < 2; ++y) {
|
|
for (int x = 0; x < 2; ++x) {
|
|
int index = y * 2 + x;
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
canvas->translate(fCell.width() * x, fCell.height() * y);
|
|
SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
|
|
r.inset(4, 4);
|
|
canvas->clipRect(r);
|
|
this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
|
|
}
|
|
}
|
|
|
|
this->drawBorders(canvas);
|
|
|
|
const SkScalar textX = fCell.width() * 2 + 30;
|
|
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setTextSize(36);
|
|
SkString str;
|
|
str.appendScalar(fScale);
|
|
canvas->drawText(str.c_str(), str.size(), textX, 100, paint);
|
|
str.reset(); str.appendScalar(fAngle);
|
|
canvas->drawText(str.c_str(), str.size(), textX, 150, paint);
|
|
|
|
str.reset(); str.appendScalar(trans[0]);
|
|
canvas->drawText(str.c_str(), str.size(), textX, 200, paint);
|
|
str.reset(); str.appendScalar(trans[1]);
|
|
canvas->drawText(str.c_str(), str.size(), textX, 250, paint);
|
|
}
|
|
|
|
bool onAnimate(const SkAnimTimer& timer) override {
|
|
fCurrTime = timer.msec();
|
|
return true;
|
|
}
|
|
|
|
virtual bool handleKey(SkKey key) {
|
|
this->inval(nullptr);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
typedef SampleView INHERITED;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static SkView* MyFactory() { return new FilterQualityView; }
|
|
static SkViewRegister reg(MyFactory);
|