Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Macros | Functions
gradients.cpp File Reference
#include "gm/gm.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkFont.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.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 "include/private/base/SkAssert.h"
#include "tools/ToolUtils.h"
#include "tools/fonts/FontToolUtils.h"
#include <initializer_list>
#include <math.h>

Go to the source code of this file.

Classes

struct  GradRun
 

Macros

#define SIZE   121
 
#define DEF_POWERLESS_HUE_GM(colorSpace)
 

Functions

static sk_sp< SkShadermake_linear (const GradRun &run, SkTileMode mode)
 
static sk_sp< SkShadermake_radial (const GradRun &run, SkTileMode mode)
 
static sk_sp< SkShadermake_conical (const GradRun &run, SkTileMode mode)
 
static sk_sp< SkShadermake_sweep (const GradRun &run, SkTileMode)
 
 DEF_SIMPLE_GM (gradients_dup_color_stops, canvas, 704, 564)
 
static void draw_many_stops (SkCanvas *canvas)
 
 DEF_SIMPLE_GM (gradient_many_stops, canvas, 500, 500)
 
static void draw_many_hard_stops (SkCanvas *canvas)
 
 DEF_SIMPLE_GM (gradient_many_hard_stops, canvas, 500, 500)
 
static void draw_circle_shader (SkCanvas *canvas, SkScalar cx, SkScalar cy, SkScalar r, sk_sp< SkShader >(*shaderFunc)())
 
 DEF_SIMPLE_GM (fancy_gradients, canvas, 800, 300)
 
 DEF_SIMPLE_GM (sweep_tiling, canvas, 690, 512)
 
 DEF_SIMPLE_GM (rgbw_sweep_gradient, canvas, 100, 100)
 
 DEF_SIMPLE_GM (gradients_interesting, canvas, 640, 1300)
 
 DEF_SIMPLE_GM_BG (gradients_color_space, canvas, 265, 255, SK_ColorGRAY)
 
 DEF_SIMPLE_GM_BG (gradients_hue_method, canvas, 285, 155, SK_ColorGRAY)
 
 DEF_SIMPLE_GM_BG (gradients_color_space_tilemode, canvas, 360, 105, SK_ColorGRAY)
 
 DEF_SIMPLE_GM_BG (gradients_color_space_many_stops, canvas, 500, 500, SK_ColorGRAY)
 
static void draw_powerless_hue_gradients (SkCanvas *canvas, SkGradientShader::Interpolation::ColorSpace colorSpace)
 

Macro Definition Documentation

◆ DEF_POWERLESS_HUE_GM

#define DEF_POWERLESS_HUE_GM (   colorSpace)
Value:
DEF_SIMPLE_GM(gradients_powerless_hue_##colorSpace, canvas, 415, 330) { \
draw_powerless_hue_gradients(canvas, \
SkGradientShader::Interpolation::ColorSpace::k##colorSpace); \
}
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50

Definition at line 1394 of file gradients.cpp.

1395 { \
1396 draw_powerless_hue_gradients(canvas, \
1397 SkGradientShader::Interpolation::ColorSpace::k##colorSpace); \
1398 }

◆ SIZE

#define SIZE   121

Definition at line 776 of file gradients.cpp.

Function Documentation

◆ DEF_SIMPLE_GM() [1/7]

DEF_SIMPLE_GM ( fancy_gradients  ,
canvas  ,
800  ,
300   
)

Definition at line 927 of file gradients.cpp.

927 {
928 draw_circle_shader(canvas, 150, 150, 100, []() -> sk_sp<SkShader> {
929 // Checkerboard using two linear gradients + picture shader.
930 SkScalar kTileSize = 80 / sqrtf(2);
931 SkColor colors1[] = { 0xff000000, 0xff000000,
932 0xffffffff, 0xffffffff,
933 0xff000000, 0xff000000 };
934 SkColor colors2[] = { 0xff000000, 0xff000000,
935 0x00000000, 0x00000000,
936 0xff000000, 0xff000000 };
937 SkScalar pos[] = { 0, .25f, .25f, .75f, .75f, 1 };
938 static_assert(std::size(colors1) == std::size(pos), "color/pos size mismatch");
939 static_assert(std::size(colors2) == std::size(pos), "color/pos size mismatch");
940
941 SkPictureRecorder recorder;
942 recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize));
943
944 SkPaint p;
945
946 SkPoint pts1[] = { { 0, 0 }, { kTileSize, kTileSize }};
947 p.setShader(SkGradientShader::MakeLinear(pts1, colors1, pos, std::size(colors1),
948 SkTileMode::kClamp, 0, nullptr));
949 recorder.getRecordingCanvas()->drawPaint(p);
950
951 SkPoint pts2[] = { { 0, kTileSize }, { kTileSize, 0 }};
952 p.setShader(SkGradientShader::MakeLinear(pts2, colors2, pos, std::size(colors2),
953 SkTileMode::kClamp, 0, nullptr));
954 recorder.getRecordingCanvas()->drawPaint(p);
955
957 m.preRotate(45);
958 return recorder.finishRecordingAsPicture()->makeShader(
960 SkFilterMode::kNearest, &m, nullptr);
961 });
962
963 draw_circle_shader(canvas, 400, 150, 100, []() -> sk_sp<SkShader> {
964 // Checkerboard using a sweep gradient + picture shader.
965 SkScalar kTileSize = 80;
966 SkColor colors[] = { 0xff000000, 0xff000000,
967 0xffffffff, 0xffffffff,
968 0xff000000, 0xff000000,
969 0xffffffff, 0xffffffff };
970 SkScalar pos[] = { 0, .25f, .25f, .5f, .5f, .75f, .75f, 1 };
971 static_assert(std::size(colors) == std::size(pos), "color/pos size mismatch");
972
973 SkPaint p;
974 p.setShader(SkGradientShader::MakeSweep(kTileSize / 2, kTileSize / 2,
975 colors, pos, std::size(colors), 0, nullptr));
976 SkPictureRecorder recorder;
977 recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize))->drawPaint(p);
978
979 return recorder.finishRecordingAsPicture()->makeShader(
982 });
983
984 draw_circle_shader(canvas, 650, 150, 100, []() -> sk_sp<SkShader> {
985 // Dartboard using sweep + radial.
986 const SkColor a = 0xffffffff;
987 const SkColor b = 0xff000000;
988 SkColor colors[] = { a, a, b, b, a, a, b, b, a, a, b, b, a, a, b, b};
989 SkScalar pos[] = { 0, .125f, .125f, .25f, .25f, .375f, .375f, .5f, .5f,
990 .625f, .625f, .75f, .75f, .875f, .875f, 1};
991 static_assert(std::size(colors) == std::size(pos), "color/pos size mismatch");
992
993 SkPoint center = { 650, 150 };
995 std::size(colors), 0, nullptr);
997 m.preRotate(22.5f, center.x(), center.y());
999 std::size(colors), 0, &m);
1000
1001 sk_sp<SkShader> sweep(SkShaders::Blend(SkBlendMode::kExclusion, sweep1, sweep2));
1002
1003 SkScalar radialPos[] = { 0, .02f, .02f, .04f, .04f, .08f, .08f, .16f, .16f, .31f, .31f,
1004 .62f, .62f, 1, 1, 1 };
1005 static_assert(std::size(colors) == std::size(radialPos),
1006 "color/pos size mismatch");
1007
1008 return SkShaders::Blend(SkBlendMode::kExclusion, sweep,
1010 radialPos,
1011 std::size(radialPos),
1013 });
1014}
SkPoint pos
@ kExclusion
rc = s + d - two(s*d), ra = kSrcOver
uint32_t SkColor
Definition SkColor.h:37
static SkScalar center(float pos0, float pos1)
void drawPaint(const SkPaint &paint)
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static const SkMatrix & I()
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
SkCanvas * getRecordingCanvas()
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, const SkMatrix *localMatrix, const SkRect *tileRect) const
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
static void draw_circle_shader(SkCanvas *canvas, SkScalar cx, SkScalar cy, SkScalar r, sk_sp< SkShader >(*shaderFunc)())
PODArray< SkColor > colors
Definition SkRecords.h:276
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609

◆ DEF_SIMPLE_GM() [2/7]

DEF_SIMPLE_GM ( gradient_many_hard_stops  ,
canvas  ,
500  ,
500   
)

Definition at line 909 of file gradients.cpp.

909 {
910 draw_many_hard_stops(canvas);
911}
static void draw_many_hard_stops(SkCanvas *canvas)

◆ DEF_SIMPLE_GM() [3/7]

DEF_SIMPLE_GM ( gradient_many_stops  ,
canvas  ,
500  ,
500   
)

Definition at line 880 of file gradients.cpp.

880 {
881 draw_many_stops(canvas);
882}
static void draw_many_stops(SkCanvas *canvas)

◆ DEF_SIMPLE_GM() [4/7]

DEF_SIMPLE_GM ( gradients_dup_color_stops  ,
canvas  ,
704  ,
564   
)

Definition at line 807 of file gradients.cpp.

807 {
808 const SkColor preColor = 0xFFFF0000; // clamp color before start
809 const SkColor postColor = 0xFF0000FF; // clamp color after end
810 const SkColor color0 = 0xFF000000;
811 const SkColor color1 = 0xFF00FF00;
812 const SkColor badColor = 0xFF3388BB; // should never be seen, fills out fixed-size array
813
814 const GradRun runs[] = {
815 { { color0, color1, badColor, badColor },
816 { 0, 1, -1, -1 },
817 2,
818 },
819 { { preColor, color0, color1, badColor },
820 { 0, 0, 1, -1 },
821 3,
822 },
823 { { color0, color1, postColor, badColor },
824 { 0, 1, 1, -1 },
825 3,
826 },
827 { { preColor, color0, color1, postColor },
828 { 0, 0, 1, 1 },
829 4,
830 },
831 { { color0, color0, color1, color1 },
832 { 0, 0.5f, 0.5f, 1 },
833 4,
834 },
835 };
836 sk_sp<SkShader> (*factories[])(const GradRun&, SkTileMode) {
838 };
839
841 const SkScalar dx = SIZE + 20;
842 const SkScalar dy = SIZE + 20;
844
846 canvas->translate(10, 10 - dy);
847 for (auto factory : factories) {
848 canvas->translate(0, dy);
849 SkAutoCanvasRestore acr(canvas, true);
850 for (const auto& run : runs) {
851 paint.setShader(factory(run, mode));
852 canvas->drawRect(rect, paint);
853 canvas->translate(dx, 0);
854 }
855 }
856}
SkTileMode
Definition SkTileMode.h:13
static sk_sp< SkShader > make_radial()
Definition blurrect.cpp:85
const Paint & paint
static sk_sp< SkShader > make_linear(const GradRun &run, SkTileMode mode)
#define SIZE
static sk_sp< SkShader > make_conical(const GradRun &run, SkTileMode mode)
static sk_sp< SkShader > make_sweep(const GradRun &run, SkTileMode)
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition switches.h:228
Definition run.py:1

◆ DEF_SIMPLE_GM() [5/7]

DEF_SIMPLE_GM ( gradients_interesting  ,
canvas  ,
640  ,
1300   
)

Definition at line 1070 of file gradients.cpp.

1070 {
1071 static const SkColor colors2[] = { SK_ColorRED, SK_ColorBLUE };
1072 static const SkColor colors3[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorBLUE };
1073 static const SkColor colors4[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorYELLOW, SK_ColorBLUE };
1074
1075 static const SkScalar softRight[] = { 0, .999f, 1 }; // Based on Android launcher "clipping"
1076 static const SkScalar hardLeft[] = { 0, 0, 1 };
1077 static const SkScalar hardRight[] = { 0, 1, 1 };
1078 static const SkScalar hardCenter[] = { 0, .5f, .5f, 1 };
1079
1080 static const struct {
1081 const SkColor* colors;
1082 const SkScalar* pos;
1083 int count;
1084 } configs[] = {
1085 { colors2, nullptr, 2 }, // kTwo_ColorType
1086 { colors3, nullptr, 3 }, // kThree_ColorType (simple)
1087 { colors3, softRight, 3 }, // kThree_ColorType (tricky)
1088 { colors3, hardLeft, 3 }, // kHardStopLeftEdged_ColorType
1089 { colors3, hardRight, 3 }, // kHardStopRightEdged_ColorType
1090 { colors4, hardCenter, 4 }, // kSingleHardStop_ColorType
1091 };
1092
1093 static const SkTileMode modes[] = {
1097 };
1098
1099 static constexpr SkScalar size = 200;
1100 static const SkPoint pts[] = { { size / 3, size / 3 }, { size * 2 / 3, size * 2 / 3} };
1101
1102 SkPaint p;
1103 for (const auto& cfg : configs) {
1104 {
1105 SkAutoCanvasRestore acr(canvas, true);
1106 for (auto mode : modes) {
1107 p.setShader(SkGradientShader::MakeLinear(pts, cfg.colors, cfg.pos, cfg.count,
1108 mode));
1109 canvas->drawRect(SkRect::MakeWH(size, size), p);
1110 canvas->translate(size * 1.1f, 0);
1111 }
1112 }
1113 canvas->translate(0, size * 1.1f);
1114 }
1115}
int count
constexpr SkColor SK_ColorYELLOW
Definition SkColor.h:139
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259

◆ DEF_SIMPLE_GM() [6/7]

DEF_SIMPLE_GM ( rgbw_sweep_gradient  ,
canvas  ,
100  ,
100   
)

Definition at line 1055 of file gradients.cpp.

1055 {
1056 static constexpr SkScalar size = 100;
1057 static constexpr SkColor colors[] = {SK_ColorWHITE, SK_ColorWHITE,
1061 static constexpr SkScalar pos[] = { 0, .25f, .25f, .50f, .50f, .75, .75, 1 };
1062 static_assert(std::size(colors) == std::size(pos), "size mismatch");
1063
1064 SkPaint p;
1065 p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos, std::size(colors)));
1066 canvas->drawRect(SkRect::MakeWH(size, size), p);
1067}
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122

◆ DEF_SIMPLE_GM() [7/7]

DEF_SIMPLE_GM ( sweep_tiling  ,
canvas  ,
690  ,
512   
)

Definition at line 1016 of file gradients.cpp.

1016 {
1017 static constexpr SkScalar size = 160;
1018 static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN };
1019 static constexpr SkScalar pos[] = { 0, .25f, .50f };
1020 static_assert(std::size(colors) == std::size(pos), "size mismatch");
1021
1022 static constexpr SkTileMode modes[] = { SkTileMode::kClamp,
1025
1026 static const struct {
1028 } angles[] = {
1029 { -330, -270 },
1030 { 30, 90 },
1031 { 390, 450 },
1032 { -30, 800 },
1033 };
1034
1035 SkPaint p;
1036 const SkRect r = SkRect::MakeWH(size, size);
1037
1038 for (auto mode : modes) {
1039 {
1040 SkAutoCanvasRestore acr(canvas, true);
1041
1042 for (auto angle : angles) {
1043 p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos,
1044 std::size(colors), mode,
1045 angle.start, angle.end, 0, nullptr));
1046
1047 canvas->drawRect(r, p);
1048 canvas->translate(size * 1.1f, 0);
1049 }
1050 }
1051 canvas->translate(0, size * 1.1f);
1052 }
1053}
glong glong end

◆ DEF_SIMPLE_GM_BG() [1/4]

DEF_SIMPLE_GM_BG ( gradients_color_space  ,
canvas  ,
265  ,
255  ,
SK_ColorGRAY   
)

Definition at line 1118 of file gradients.cpp.

1118 {
1120
1121 struct Config {
1122 CS fColorSpace;
1123 const char* fLabel;
1124 };
1125 static const Config kConfigs[] = {
1126 { CS::kSRGB, "sRGB" },
1127 { CS::kSRGBLinear, "Linear" },
1128 { CS::kLab, "Lab" },
1129 { CS::kOKLab, "OKLab" },
1130 { CS::kOKLabGamutMap, "OKLabGamutMap" },
1131 { CS::kLCH, "LCH" },
1132 { CS::kOKLCH, "OKLCH" },
1133 { CS::kOKLCHGamutMap, "OKLCHGamutMap" },
1134 { CS::kHSL, "HSL" },
1135 { CS::kHWB, "HWB" },
1136 };
1137
1138 SkPoint pts[] = {{0, 0}, {200, 0}};
1140
1141 SkPaint labelPaint;
1142 SkPaint p;
1143 SkGradientShader::Interpolation interpolation;
1144 canvas->translate(5, 5);
1146
1147 for (const Config& config : kConfigs) {
1148 interpolation.fColorSpace = config.fColorSpace;
1149 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 2,
1150 SkTileMode::kClamp, interpolation, nullptr));
1151 canvas->drawRect({0, 0, 200, 20}, p);
1152 canvas->drawSimpleText(config.fLabel, strlen(config.fLabel), SkTextEncoding::kUTF8, 210, 15,
1153 font, labelPaint);
1154 canvas->translate(0, 25);
1155 }
1156}
@ kUTF8
uses bytes to represent UTF-8 or ASCII
static sk_sp< SkColorSpace > MakeSRGB()
constexpr SkColor4f kBlue
Definition SkColor.h:442
constexpr SkColor4f kYellow
Definition SkColor.h:443
SkFont DefaultPortableFont()
font
Font Metadata and Metrics.

◆ DEF_SIMPLE_GM_BG() [2/4]

DEF_SIMPLE_GM_BG ( gradients_color_space_many_stops  ,
canvas  ,
500  ,
500  ,
SK_ColorGRAY   
)

Definition at line 1240 of file gradients.cpp.

1240 {
1241 // Test exotic (CSS) gradient color spaces with many stops. Rather than test every combination,
1242 // we pick one color space that has a sufficiently strange interpolated representation (OKLCH)
1243 // and just use that. We're mostly interested in making sure that the texture fallback on GPU
1244 // works correctly.
1245 const SkPoint pts[] = { {50, 50}, {450, 465}};
1246
1247 const unsigned kStopCount = 200;
1249 for (unsigned i = 0; i < kStopCount; i++) {
1250 switch (i % 5) {
1251 case 0: colors[i] = SkColors::kRed; break;
1252 case 1: colors[i] = SkColors::kGreen; break;
1253 case 2: colors[i] = SkColors::kGreen; break;
1254 case 3: colors[i] = SkColors::kBlue; break;
1255 case 4: colors[i] = SkColors::kRed; break;
1256 }
1257 }
1258
1259 SkPaint p;
1260
1261 SkGradientShader::Interpolation interpolation;
1263 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr,
1264 std::size(colors), SkTileMode::kClamp, interpolation,
1265 nullptr));
1266
1267 canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
1268}
static const int kStopCount
constexpr SkColor4f kGreen
Definition SkColor.h:441
constexpr SkColor4f kRed
Definition SkColor.h:440
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659

◆ DEF_SIMPLE_GM_BG() [3/4]

DEF_SIMPLE_GM_BG ( gradients_color_space_tilemode  ,
canvas  ,
360  ,
105  ,
SK_ColorGRAY   
)

Definition at line 1216 of file gradients.cpp.

1216 {
1217 // Test exotic (CSS) gradient color spaces in conjunction with tile modes. Rather than test
1218 // every combination, we pick one color space that has a sufficiently strange interpolated
1219 // representation (OKLCH) and just use that. We're mostly interested in making sure that things
1220 // like decal mode are implemented at the correct time in the pipeline, relative to hue
1221 // conversion, re-premultiplication, etc.
1222 SkPoint pts[] = {{20, 0}, {120, 0}};
1224
1225 SkPaint p;
1226 SkGradientShader::Interpolation interpolation;
1228
1229 canvas->translate(5, 5);
1230
1231 for (int tm = 0; tm < kSkTileModeCount; ++tm) {
1232 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 2,
1233 static_cast<SkTileMode>(tm), interpolation,
1234 nullptr));
1235 canvas->drawRect({0, 0, 350, 20}, p);
1236 canvas->translate(0, 25);
1237 }
1238}
static constexpr int kSkTileModeCount
Definition SkTileMode.h:39

◆ DEF_SIMPLE_GM_BG() [4/4]

DEF_SIMPLE_GM_BG ( gradients_hue_method  ,
canvas  ,
285  ,
155  ,
SK_ColorGRAY   
)

Definition at line 1158 of file gradients.cpp.

1158 {
1160
1161 struct Config {
1162 HM fHueMethod;
1163 const char* fLabel;
1164 };
1165 static const Config kConfigs[] = {
1166 { HM::kShorter, "Shorter" },
1167 { HM::kLonger, "Longer" },
1168 { HM::kIncreasing, "Increasing" },
1169 { HM::kDecreasing, "Decreasing" },
1170 };
1171
1172 SkPoint pts[] = {{0, 0}, {200, 0}};
1174
1175 SkPaint labelPaint;
1176 SkPaint p;
1177 SkGradientShader::Interpolation interpolation;
1179 canvas->translate(5, 5);
1181
1182 for (const Config& config : kConfigs) {
1183 interpolation.fHueMethod = config.fHueMethod;
1184 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), nullptr, 4,
1185 SkTileMode::kClamp, interpolation, nullptr));
1186 canvas->drawRect({0, 0, 200, 20}, p);
1187 canvas->drawSimpleText(config.fLabel, strlen(config.fLabel), SkTextEncoding::kUTF8, 210, 15,
1188 font, labelPaint);
1189 canvas->translate(0, 25);
1190 }
1191
1192 // Test a bug (skia:13941) with how gradient shaders handle explicit positions.
1193 // If there are no explicit positions at 0 or 1, those are automatically added, with copies of
1194 // the first/last color. When using kLonger, this can produce extra gradient that should
1195 // actually be solid. This gradient *should* be:
1196 // |- solid red -|- red to green, the long way -|- solid green -|
1197 interpolation.fHueMethod = HM::kLonger;
1198 SkScalar middlePos[] = { 0.3f, 0.7f };
1199 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), middlePos, 2,
1200 SkTileMode::kClamp, interpolation, nullptr));
1201 canvas->drawRect({0, 0, 200, 20}, p);
1202 canvas->translate(0, 25);
1203
1204 // However... if the user explicitly includes those duplicate color stops in kLonger mode,
1205 // we expect the gradient to do a full rotation in those regions:
1206 // |- full circle, red to red -|- red to green -|- full circle, green to green -|
1207 colors[0] = colors[1] = SkColors::kRed;
1208 colors[2] = colors[3] = SkColors::kGreen;
1209 SkScalar allPos[] = { 0.0f, 0.3f, 0.7f, 1.0f };
1210 p.setShader(SkGradientShader::MakeLinear(pts, colors, SkColorSpace::MakeSRGB(), allPos, 4,
1211 SkTileMode::kClamp, interpolation, nullptr));
1212 canvas->drawRect({0, 0, 200, 20}, p);
1213 canvas->translate(0, 25);
1214}

◆ draw_circle_shader()

static void draw_circle_shader ( SkCanvas canvas,
SkScalar  cx,
SkScalar  cy,
SkScalar  r,
sk_sp< SkShader >(*)()  shaderFunc 
)
static

Definition at line 913 of file gradients.cpp.

914 {
915 SkPaint p;
916 p.setAntiAlias(true);
917 p.setShader(shaderFunc());
918 canvas->drawCircle(cx, cy, r, p);
919
920 p.setShader(nullptr);
921 p.setColor(SK_ColorGRAY);
922 p.setStyle(SkPaint::kStroke_Style);
923 p.setStrokeWidth(2);
924 canvas->drawCircle(cx, cy, r, p);
925}
constexpr SkColor SK_ColorGRAY
Definition SkColor.h:113
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194

◆ draw_many_hard_stops()

static void draw_many_hard_stops ( SkCanvas canvas)
static

Definition at line 884 of file gradients.cpp.

884 {
885 const unsigned kStopCount = 300;
886 const SkPoint pts[] = {{50, 50}, {450, 450}};
887
890 for (unsigned i = 0; i < kStopCount; i++) {
891 switch (i % 6) {
892 case 0: colors[i] = SK_ColorRED; break;
893 case 1: colors[i] = SK_ColorGREEN; break;
894 case 2: colors[i] = SK_ColorGREEN; break;
895 case 3: colors[i] = SK_ColorBLUE; break;
896 case 4: colors[i] = SK_ColorBLUE; break;
897 case 5: colors[i] = SK_ColorRED; break;
898 }
899 pos[i] = (2.0f * (i / 2)) / kStopCount;
900 }
901
902 SkPaint p;
903 p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, std::size(colors),
905
906 canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
907}
void drawRect(const SkRect &rect, const SkPaint &paint)

◆ draw_many_stops()

static void draw_many_stops ( SkCanvas canvas)
static

Definition at line 858 of file gradients.cpp.

858 {
859 const unsigned kStopCount = 200;
860 const SkPoint pts[] = { {50, 50}, {450, 450}};
861
863 for (unsigned i = 0; i < kStopCount; i++) {
864 switch (i % 5) {
865 case 0: colors[i] = SK_ColorRED; break;
866 case 1: colors[i] = SK_ColorGREEN; break;
867 case 2: colors[i] = SK_ColorGREEN; break;
868 case 3: colors[i] = SK_ColorBLUE; break;
869 case 4: colors[i] = SK_ColorRED; break;
870 }
871 }
872
873 SkPaint p;
874 p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, std::size(colors),
876
877 canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
878}

◆ draw_powerless_hue_gradients()

static void draw_powerless_hue_gradients ( SkCanvas canvas,
SkGradientShader::Interpolation::ColorSpace  colorSpace 
)
static

Definition at line 1270 of file gradients.cpp.

1271 {
1273
1274 auto nextRow = [=]() {
1275 canvas->restore();
1276 canvas->translate(0, 25);
1277 canvas->save();
1278 };
1279
1280 auto gradient = [&](std::initializer_list<SkColor4f> colors,
1281 std::initializer_list<float> pos,
1282 bool inPremul = false) {
1283 using Interpolation = SkGradientShader::Interpolation;
1284 SkASSERT(pos.size() == 0 || pos.size() == colors.size());
1285 SkPaint paint;
1286 SkPoint pts[] = {{0, 0}, {200, 0}};
1287 Interpolation interpolation;
1288 interpolation.fColorSpace = colorSpace;
1289 interpolation.fInPremul = static_cast<Interpolation::InPremul>(inPremul);
1290 paint.setShader(SkGradientShader::MakeLinear(pts,
1291 colors.begin(),
1293 pos.size() == 0 ? nullptr : pos.begin(),
1294 colors.size(),
1296 interpolation,
1297 nullptr));
1298 canvas->drawRect({0, 0, 200, 20}, paint);
1299 canvas->translate(205, 0); // next column
1300 };
1301
1302 canvas->translate(5, 5);
1303 canvas->save();
1304
1305 // For each test case, the first gradient (first column) has an under-specified result due to a
1306 // powerless component after conversion to LCH. The second gradient (second column) "hints" the
1307 // correct result, by slightly tinting the otherwise powerless color.
1308
1309 gradient({SkColors::kWhite, SkColors::kBlue}, {});
1310 gradient({{0.99f, 0.99f, 1.00f, 1.0f}, SkColors::kBlue}, {}); // white, with blue hue
1311 nextRow();
1312
1313 gradient({SkColors::kBlack, SkColors::kBlue}, {});
1314 gradient({{0.00f, 0.00f, 0.01f, 1.0f}, SkColors::kBlue}, {}); // black, with blue hue
1315 nextRow();
1316
1317 // Transparent cases are done in both premul and unpremul interpolation:
1318
1319 gradient({SkColors::kTransparent, SkColors::kBlue}, {}, /*inPremul=*/false);
1320 gradient({{0.00f, 0.00f, 0.01f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1321 nextRow();
1322
1323 gradient({SkColors::kTransparent, SkColors::kBlue}, {}, /*inPremul=*/true);
1324 gradient({{0.00f, 0.00f, 0.01f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1325 nextRow();
1326
1327 gradient({{1.00f, 1.00f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1328 gradient({{0.99f, 0.99f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/false);
1329 nextRow();
1330
1331 gradient({{1.00f, 1.00f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1332 gradient({{0.99f, 0.99f, 1.00f, 0.0f}, SkColors::kBlue}, {}, /*inPremul=*/true);
1333 nextRow();
1334
1335 // Now we test three-stop gradients, where the middle stop needs to be "split" to handle the
1336 // different hues on either side. Again, the second column explicitly injects those to produce
1337 // a reference result. See: https://github.com/w3c/csswg-drafts/issues/9295
1338
1340 gradient({SkColors::kRed,
1341 {1.00f, 0.99f, 0.99f, 1.0f},
1342 {0.99f, 0.99f, 1.00f, 1.0f},
1344 {0.0f, 0.5f, 0.5f, 1.0f});
1345 nextRow();
1346
1348 gradient({SkColors::kRed,
1349 {0.01f, 0.00f, 0.00f, 1.0f},
1350 {0.00f, 0.00f, 0.01f, 1.0f},
1352 {0.0f, 0.5f, 0.5f, 1.0f});
1353 nextRow();
1354
1356 gradient({SkColors::kRed,
1357 {0.01f, 0.00f, 0.00f, 0.0f},
1358 {0.00f, 0.00f, 0.01f, 0.0f},
1360 {0.0f, 0.5f, 0.5f, 1.0f});
1361 nextRow();
1362
1363 // Now do a few black-white tests, to ensure that the hue propagation works correctly, even
1364 // when there isn't any hue in the adjacent stops.
1366 auto blackWhiteGradient = [&](HueMethod hm) {
1367 using Interpolation = SkGradientShader::Interpolation;
1368 SkPaint paint;
1369 SkPoint pts[] = {{0, 0}, {405, 0}};
1370 Interpolation interpolation;
1371 interpolation.fColorSpace = colorSpace;
1372 interpolation.fHueMethod = hm;
1376 paint.setShader(SkGradientShader::MakeLinear(pts,
1377 colors,
1379 nullptr,
1380 std::size(colors),
1382 interpolation,
1383 nullptr));
1384 canvas->drawRect({0, 0, 405, 20}, paint);
1385 nextRow();
1386 };
1387
1388 blackWhiteGradient(HueMethod::kShorter);
1389 blackWhiteGradient(HueMethod::kIncreasing);
1390 blackWhiteGradient(HueMethod::kDecreasing);
1391 blackWhiteGradient(HueMethod::kLonger);
1392}
#define SkASSERT(cond)
Definition SkAssert.h:116
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
int save()
Definition SkCanvas.cpp:451
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
constexpr SkColor4f kWhite
Definition SkColor.h:439
constexpr SkColor4f kTransparent
Definition SkColor.h:434
constexpr SkColor4f kBlack
Definition SkColor.h:435
constexpr SkColor4f kGray
Definition SkColor.h:437
constexpr SkColor4f kDkGray
Definition SkColor.h:436
void draw_checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)

◆ make_conical()

static sk_sp< SkShader > make_conical ( const GradRun run,
SkTileMode  mode 
)
static

Definition at line 789 of file gradients.cpp.

789 {
790 const SkScalar half = SIZE * 0.5f;
791 const SkPoint center { half, half };
793 run.fColors, run.fPos, run.fCount, mode);
794}
static sk_sp< SkShader > MakeTwoPointConical(const SkPoint &start, SkScalar startRadius, const SkPoint &end, SkScalar endRadius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)

◆ make_linear()

static sk_sp< SkShader > make_linear ( const GradRun run,
SkTileMode  mode 
)
static

Definition at line 778 of file gradients.cpp.

778 {
779 const SkPoint pts[] { { 30, 30 }, { SIZE - 30, SIZE - 30 } };
780 return SkGradientShader::MakeLinear(pts, run.fColors, run.fPos, run.fCount, mode);
781}

◆ make_radial()

static sk_sp< SkShader > make_radial ( const GradRun run,
SkTileMode  mode 
)
static

Definition at line 783 of file gradients.cpp.

783 {
784 const SkScalar half = SIZE * 0.5f;
785 return SkGradientShader::MakeRadial({half,half}, half - 10, run.fColors, run.fPos,
786 run.fCount, mode);
787}

◆ make_sweep()

static sk_sp< SkShader > make_sweep ( const GradRun run,
SkTileMode   
)
static

Definition at line 796 of file gradients.cpp.

796 {
797 const SkScalar half = SIZE * 0.5f;
798 return SkGradientShader::MakeSweep(half, half, run.fColors, run.fPos, run.fCount);
799}