blob: 40d148f3eaa9ab864856b5f62808e1ae0301fd5b [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* This GM creates the same gradients as the Chromium test fillrect_gradient:
* http://osscs/chromium/chromium/src/+/main:third_party/blink/web_tests/fast/canvas/fillrect_gradient.html
*/
#include "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTileMode.h"
#include "include/effects/SkGradientShader.h"
const int kCellSize = 50;
const int kNumColumns = 2;
const int kNumRows = 9;
const int kPadSize = 10;
class FillrectGradientGM : public skiagm::GM {
public:
FillrectGradientGM() {}
protected:
struct GradientStop {
float pos;
SkColor color;
};
SkString onShortName() override {
return SkString("fillrect_gradient");
}
SkISize onISize() override {
return SkISize::Make(kNumColumns * (kCellSize + kPadSize),
kNumRows * (kCellSize + kPadSize));
}
void drawGradient(SkCanvas* canvas, std::initializer_list<GradientStop> stops) {
std::vector<SkColor> colors;
std::vector<SkScalar> positions;
colors.reserve(stops.size());
positions.reserve(stops.size());
for (const GradientStop& stop : stops) {
colors.push_back(stop.color);
positions.push_back(stop.pos);
}
static constexpr SkPoint points[] = {
SkPoint::Make(kCellSize, 0),
SkPoint::Make(kCellSize, kCellSize),
};
// Draw the gradient linearly.
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points,
colors.data(),
positions.data(),
colors.size(),
SkTileMode::kClamp);
SkPaint paint;
paint.setShader(shader);
canvas->drawRect(SkRect::MakeXYWH(0, 0, kCellSize, kCellSize), paint);
canvas->save();
canvas->translate(kCellSize + kPadSize, 0);
// Draw the gradient radially.
shader = SkGradientShader::MakeRadial(SkPoint::Make(kCellSize / 2, kCellSize / 2),
kCellSize / 2,
colors.data(),
positions.data(),
colors.size(),
SkTileMode::kClamp);
paint.setShader(shader);
canvas->drawRect(SkRect::MakeXYWH(0, 0, kCellSize, kCellSize), paint);
canvas->restore();
canvas->translate(0, kCellSize + kPadSize);
}
void onDraw(SkCanvas* canvas) override {
// Simple gradient: Green to white
this->drawGradient(canvas, {{0.0f, SK_ColorGREEN}, {1.0f, SK_ColorWHITE}});
// Multiple sections: Green to white to red
this->drawGradient(canvas,
{{0.0f, SK_ColorGREEN}, {0.5f, SK_ColorWHITE}, {1.0f, SK_ColorRED}});
// No stops at 0.0 or 1.0: Larger green to white to larger red
this->drawGradient(canvas,
{{0.4f, SK_ColorGREEN}, {0.5f, SK_ColorWHITE}, {0.6f, SK_ColorRED}});
// Only one stop, at zero: Solid red
this->drawGradient(canvas, {{0.0f, SK_ColorRED}});
// Only one stop, at 1.0: Solid red
this->drawGradient(canvas, {{1.0f, SK_ColorRED}});
// Only one stop, in the middle: Solid red
this->drawGradient(canvas, {{0.5f, SK_ColorRED}});
// Disjoint gradients (multiple stops at the same offset)
// Blue to white in the top (inner) half, red to yellow in the bottom (outer) half
this->drawGradient(canvas,
{{0.0f, SK_ColorBLUE},
{0.5f, SK_ColorWHITE},
{0.5f, SK_ColorRED},
{1.0f, SK_ColorYELLOW}});
// Ignored stops: Blue to white, red to yellow (same as previous)
this->drawGradient(canvas,
{{0.0f, SK_ColorBLUE},
{0.5f, SK_ColorWHITE},
{0.5f, SK_ColorGRAY},
{0.5f, SK_ColorCYAN},
{0.5f, SK_ColorRED},
{1.0f, SK_ColorYELLOW}});
// Unsorted stops: Blue to white, red to yellow
// Unlike Chrome, we don't sort the stops, so this renders differently than the prior cell.
this->drawGradient(canvas,
{{0.5f, SK_ColorWHITE},
{0.5f, SK_ColorGRAY},
{1.0f, SK_ColorYELLOW},
{0.5f, SK_ColorCYAN},
{0.5f, SK_ColorRED},
{0.0f, SK_ColorBLUE}});
}
private:
using INHERITED = skiagm::GM;
};
DEF_GM(return new FillrectGradientGM;)