aboutsummaryrefslogtreecommitdiffstats
path: root/gm/gradients_degenerate.cpp
diff options
context:
space:
mode:
authorMichael Ludwig <michaelludwig@google.com>2018-11-08 15:34:34 -0500
committerSkia Commit-Bot <skia-commit-bot@chromium.org>2018-11-09 16:36:05 +0000
commit879dab87ab78613458f9d36f843bc3c6ffdafc74 (patch)
treeca313ce8c615c08240a2ab3b7fbdc5bf76bd9a3c /gm/gradients_degenerate.cpp
parent0b50838beb5e1037b9980142705fe14c0056db6e (diff)
downloadplatform_external_skqp-879dab87ab78613458f9d36f843bc3c6ffdafc74.tar.gz
platform_external_skqp-879dab87ab78613458f9d36f843bc3c6ffdafc74.tar.bz2
platform_external_skqp-879dab87ab78613458f9d36f843bc3c6ffdafc74.zip
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>
Diffstat (limited to 'gm/gradients_degenerate.cpp')
-rw-r--r--gm/gradients_degenerate.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/gm/gradients_degenerate.cpp b/gm/gradients_degenerate.cpp
new file mode 100644
index 0000000000..583bbed552
--- /dev/null
+++ b/gm/gradients_degenerate.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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;)