/* * 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/gm.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" #include "include/core/SkFont.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/core/SkTypes.h" #include "include/effects/SkGradientShader.h" #include "tools/ToolUtils.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 SkTileMode TILE_MODES[] = { SkTileMode::kDecal, SkTileMode::kRepeat, SkTileMode::kMirror, SkTileMode::kClamp }; 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 (*GradientFactory)(SkTileMode tm); static void draw_tile_header(SkCanvas* canvas) { canvas->save(); SkFont font(ToolUtils::create_portable_typeface(), 12); for (int i = 0; i < TILE_MODE_CT; ++i) { canvas->drawString(TILE_NAMES[i], 0, 0, font, SkPaint()); 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.setAntiAlias(true); SkFont font(ToolUtils::create_portable_typeface(), 12); canvas->translate(0, TILE_GAP); canvas->drawString(desc, 0, 0, font, 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 make_linear(SkTileMode mode) { // Same position SkPoint pts[2] = {CENTER, CENTER}; return SkGradientShader::MakeLinear(pts, COLORS, POS, COLOR_CT, mode); } static sk_sp make_radial(SkTileMode mode) { // Radius = 0 return SkGradientShader::MakeRadial(CENTER, 0.0, COLORS, POS, COLOR_CT, mode); } static sk_sp make_sweep(SkTileMode 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 make_sweep_zero_ang(SkTileMode 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 make_2pt_conic(SkTileMode 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 make_2pt_conic_zero_rad(SkTileMode 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;)