/* * 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 stops) { std::vector colors; std::vector 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 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;)