skia2/gm/gradients_degenerate.cpp

151 lines
5.1 KiB
C++
Raw Normal View History

Reland "Improve degenerate 2pt conical gradient cases" This reverts commit 95af4726bf91669e51250ebd3baa2925b6975e8e. Reason for revert: I think this may not have been the reason the Android roll was failing. We've rolled, so it's a good time to try again. Original change's description: > Revert "Improve degenerate 2pt conical gradient cases" > > This reverts commit 879dab87ab78613458f9d36f843bc3c6ffdafc74. > > Reason for revert: Android roll failed. > https://sponge.corp.google.com/target?id=93bc6b8d-9b42-4805-b204-46ae62f1b005&target=x86+CtsGraphicsTestCases&searchFor=&show=FAILED&sortBy=STATUS > A test VectorDrawableTest.testVectorDrawableGradient fails. > > Original change's description: > > Improve degenerate 2pt conical gradient cases > > > > This was originally a reland of "Fix div-by-zero loophole in gradient factory func", c34dd6c5263490b94ef9af7a14dee1b4bc872b58, but: > > > > The change caused blink layout tests when encountering very small or zero radii. The original patch switched the order of checking if the radii are equal and if the start radius was 0. In the case where both radii are 0, the original code created an actual radial gradient of radius 0 and the new code rejected the shader. A radial gradient with radius of 0 properly renders the last border color as a fill. > > > > This made me realize that the case when the center positions and the radii are the same can be handled more correctly than just always returning an empty shader, so the fix now applies simplifications to the gradient definition depending on the tile mode and should not trigger any blink tests. I added a row to the gradient edge cases GM to make sure it degrades gracefully. > > > > Original change's description: > > > Fix div-by-zero loophole in gradient factory func > > > > > > Bug: oss-fuzz:10373 > > > Change-Id: I4277fb63e3186ee34feaf09ecf6aeddeb532f9c1 > > > Reviewed-on: https://skia-review.googlesource.com/c/168269 > > > Reviewed-by: Kevin Lubick <kjlubick@google.com> > > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > > > Docs-Preview: https://skia.org/?cl=168487 > > Bug: oss-fuzz:10373 > > Change-Id: Ib0a6e7f807560a5dcf24d1c8e0146817af2d9606 > > Reviewed-on: https://skia-review.googlesource.com/c/168487 > > Reviewed-by: Mike Reed <reed@google.com> > > Reviewed-by: Florin Malita <fmalita@chromium.org> > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > TBR=caryclark@google.com,fmalita@chromium.org,fmalita@google.com,reed@google.com,michaelludwig@google.com > > Change-Id: I91b896c4a438c02206679b327a01b47f40993965 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: oss-fuzz:10373 > Reviewed-on: https://skia-review.googlesource.com/c/170272 > Reviewed-by: Stan Iliev <stani@google.com> > Commit-Queue: Stan Iliev <stani@google.com> TBR=caryclark@google.com,fmalita@chromium.org,fmalita@google.com,reed@google.com,stani@google.com,michaelludwig@google.com # Not skipping CQ checks because original CL landed > 1 day ago. Bug: oss-fuzz:10373 Change-Id: I7577fcea9eb8a875e94723ab2cca2fcc990b82b2 Reviewed-on: https://skia-review.googlesource.com/c/170279 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
2018-11-11 00:26:30 +00:00
/*
* Copyright 2018 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 "SkGradientShader.h"
// NOTE: The positions define hardstops for the red and green borders. For the repeating degenerate
// gradients, that means the red and green are never visible, so the average color used should only
// be based off of the white, blue, black blend.
static const SkColor COLORS[] = { SK_ColorRED, SK_ColorWHITE, SK_ColorBLUE,
SK_ColorBLACK, SK_ColorGREEN };
static const SkScalar POS[] = { 0.0, 0.0, 0.5, 1.0, 1.0 };
static const int COLOR_CT = SK_ARRAY_COUNT(COLORS);
static const SkShader::TileMode TILE_MODES[] = { SkShader::kDecal_TileMode,
SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode,
SkShader::kClamp_TileMode };
static const char* TILE_NAMES[] = { "decal", "repeat", "mirror", "clamp" };
static const int TILE_MODE_CT = SK_ARRAY_COUNT(TILE_MODES);
static constexpr int TILE_SIZE = 100;
static constexpr int TILE_GAP = 10;
static const SkPoint CENTER = SkPoint::Make(TILE_SIZE / 2, TILE_SIZE / 2);
typedef sk_sp<SkShader> (*GradientFactory)(SkShader::TileMode tm);
static void draw_tile_header(SkCanvas* canvas) {
canvas->save();
SkPaint paint;
paint.setColor(SK_ColorBLACK);
paint.setTextSize(12.0f);
paint.setAntiAlias(true);
for (int i = 0; i < TILE_MODE_CT; ++i) {
canvas->drawString(TILE_NAMES[i], 0, 0, paint);
canvas->translate(TILE_SIZE + TILE_GAP, 0);
}
canvas->restore();
// Now adjust to start at rows below the header
canvas->translate(0, 2 * TILE_GAP);
}
static void draw_row(SkCanvas* canvas, const char* desc, GradientFactory factory) {
canvas->save();
SkPaint text;
text.setColor(SK_ColorBLACK);
text.setTextSize(12.0f);
text.setAntiAlias(true);
canvas->translate(0, TILE_GAP);
canvas->drawString(desc, 0, 0, text);
canvas->translate(0, TILE_GAP);
SkPaint paint;
paint.setColor(SK_ColorBLACK);
paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(2.0f);
for (int i = 0; i < TILE_MODE_CT; ++i) {
paint.setShader(factory(TILE_MODES[i]));
canvas->drawRect(SkRect::MakeWH(TILE_SIZE, TILE_SIZE), paint);
canvas->translate(TILE_SIZE + TILE_GAP, 0);
}
canvas->restore();
// Now adjust to start the next row below this one (1 gap for text and 2 gap for margin)
canvas->translate(0, 3 * TILE_GAP + TILE_SIZE);
}
static sk_sp<SkShader> make_linear(SkShader::TileMode mode) {
// Same position
SkPoint pts[2] = {CENTER, CENTER};
return SkGradientShader::MakeLinear(pts, COLORS, POS, COLOR_CT, mode);
}
static sk_sp<SkShader> make_radial(SkShader::TileMode mode) {
// Radius = 0
return SkGradientShader::MakeRadial(CENTER, 0.0, COLORS, POS, COLOR_CT, mode);
}
static sk_sp<SkShader> make_sweep(SkShader::TileMode mode) {
// Start and end angles at 45
static constexpr SkScalar SWEEP_ANG = 45.0;
return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode,
SWEEP_ANG, SWEEP_ANG, 0, nullptr);
}
static sk_sp<SkShader> make_sweep_zero_ang(SkShader::TileMode mode) {
// Start and end angles at 0
return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode,
0.0, 0.0, 0, nullptr);
}
static sk_sp<SkShader> make_2pt_conic(SkShader::TileMode mode) {
// Start and end radius = TILE_SIZE, same position
return SkGradientShader::MakeTwoPointConical(CENTER, TILE_SIZE / 2, CENTER, TILE_SIZE / 2,
COLORS, POS, COLOR_CT, mode);
}
static sk_sp<SkShader> make_2pt_conic_zero_rad(SkShader::TileMode mode) {
// Start and end radius = 0, same position
return SkGradientShader::MakeTwoPointConical(CENTER, 0.0, CENTER, 0.0, COLORS, POS,
COLOR_CT, mode);
}
class DegenerateGradientGM : public skiagm::GM {
public:
DegenerateGradientGM() {
}
protected:
SkString onShortName() override {
return SkString("degenerate_gradients");
}
SkISize onISize() override {
return SkISize::Make(800, 800);
}
void onDraw(SkCanvas* canvas) override {
canvas->translate(3 * TILE_GAP, 3 * TILE_GAP);
draw_tile_header(canvas);
draw_row(canvas, "linear: empty, blue, blue, green", make_linear);
draw_row(canvas, "radial: empty, blue, blue, green", make_radial);
draw_row(canvas, "sweep-0: empty, blue, blue, green", make_sweep_zero_ang);
draw_row(canvas, "sweep-45: empty, blue, blue, red 45 degree sector then green",
make_sweep);
draw_row(canvas, "2pt-conic-0: empty, blue, blue, green", make_2pt_conic_zero_rad);
draw_row(canvas, "2pt-conic-1: empty, blue, blue, full red circle on green",
make_2pt_conic);
}
private:
typedef skiagm::GM INHERITED;
};
DEF_GM(return new DegenerateGradientGM;)