111 buffer.writeColor4fArray(colors, colorCount);
112 if (colorSpaceData) {
113 buffer.writeDataAsByteArray(colorSpaceData.
get());
116 buffer.writeScalarArray(positions, colorCount);
120template <
int N,
typename T,
bool MEM_MOVE>
150 fColors = fColorStorage.begin();
169 buffer.readMatrix(legacyLocalMatrix);
183 , fColorsAreOpaque(
true) {
205 if (desc.fPositions) {
219 *colors++ = desc.fColors[0];
221 for (
int i = 0; i < desc.fColorCount; ++i) {
222 colors[i] = desc.fColors[i];
223 fColorsAreOpaque = fColorsAreOpaque && (desc.fColors[i].fA == 1);
226 colors += desc.fColorCount;
227 *colors = desc.fColors[desc.fColorCount - 1];
230 if (desc.fPositions) {
238 bool uniformStops =
true;
239 const SkScalar uniformStep = desc.fPositions[startIndex] -
prev;
240 for (
int i = startIndex; i <
count; i++) {
242 auto curr = (i == desc.fColorCount) ? 1 :
SkTPin(desc.fPositions[i],
prev, 1.0f);
245 *positions++ =
prev = curr;
261 (ctx->
fs[0])[stop] = Fs.
fR;
262 (ctx->
fs[1])[stop] = Fs.
fG;
263 (ctx->
fs[2])[stop] = Fs.
fB;
264 (ctx->
fs[3])[stop] = Fs.
fA;
266 (ctx->
bs[0])[stop] = Bs.
fR;
267 (ctx->
bs[1])[stop] = Bs.
fG;
268 (ctx->
bs[2])[stop] = Bs.
fB;
269 (ctx->
bs[3])[stop] = Bs.
fA;
285 (c_r.
fR - c_l.
fR) * gapCount,
286 (c_r.
fG - c_l.
fG) * gapCount,
287 (c_r.
fB - c_l.
fB) * gapCount,
288 (c_r.
fA - c_l.
fA) * gapCount,
291 c_l.
fR - Fs.
fR * (stop / gapCount),
292 c_l.
fG - Fs.
fG * (stop / gapCount),
293 c_l.
fB - Fs.
fB * (stop / gapCount),
294 c_l.
fA - Fs.
fA * (stop / gapCount),
315 c_l.
fR - Fs.
fR * t_l,
316 c_l.
fG - Fs.
fG * t_l,
317 c_l.
fB - Fs.
fB * t_l,
318 c_l.
fA - Fs.
fA * t_l,
330 if (
count == 2 && positions ==
nullptr) {
331 const SkPMColor4f c_l = pmColors[0], c_r = pmColors[1];
338 p->append(SkRasterPipelineOp::evenly_spaced_2_stop_gradient, ctx);
344 for (
int i = 0; i < 4; i++) {
350 if (positions ==
nullptr) {
353 size_t stopCount =
count;
354 float gapCount = stopCount - 1;
357 for (
size_t i = 0; i < stopCount - 1; i++) {
364 ctx->stopCount = stopCount;
365 p->append(SkRasterPipelineOp::evenly_spaced_gradient, ctx);
376 firstStop = pmColors[0] != pmColors[1] ? 0 : 1;
383 size_t stopCount = 0;
384 float t_l = positions[firstStop];
388 for (
int i = firstStop; i < lastStop; i++) {
389 float t_r = positions[i + 1];
403 ctx->ts[stopCount] = t_l;
406 ctx->stopCount = stopCount;
407 p->append(SkRasterPipelineOp::gradient, ctx);
414 bool colorsAreOpaque,
419 bool colorIsPremul =
static_cast<bool>(interpolation.
fInPremul);
424 case ColorSpace::kLab:
425 case ColorSpace::kOKLab:
426 case ColorSpace::kOKLabGamutMap:
427 p->append(SkRasterPipelineOp::unpremul);
428 colorIsPremul =
false;
430 case ColorSpace::kLCH:
431 case ColorSpace::kOKLCH:
432 case ColorSpace::kOKLCHGamutMap:
433 case ColorSpace::kHSL:
434 case ColorSpace::kHWB:
435 p->append(SkRasterPipelineOp::unpremul_polar);
436 colorIsPremul =
false;
445 case ColorSpace::kLab: p->append(SkRasterPipelineOp::css_lab_to_xyz);
break;
446 case ColorSpace::kOKLab: p->append(SkRasterPipelineOp::css_oklab_to_linear_srgb);
break;
447 case ColorSpace::kOKLabGamutMap:
448 p->append(SkRasterPipelineOp::css_oklab_gamut_map_to_linear_srgb);
450 case ColorSpace::kLCH: p->append(SkRasterPipelineOp::css_hcl_to_lab);
451 p->append(SkRasterPipelineOp::css_lab_to_xyz);
break;
452 case ColorSpace::kOKLCH: p->append(SkRasterPipelineOp::css_hcl_to_lab);
453 p->append(SkRasterPipelineOp::css_oklab_to_linear_srgb);
break;
454 case ColorSpace::kOKLCHGamutMap:
455 p->append(SkRasterPipelineOp::css_hcl_to_lab);
456 p->append(SkRasterPipelineOp::css_oklab_gamut_map_to_linear_srgb);
458 case ColorSpace::kHSL: p->append(SkRasterPipelineOp::css_hsl_to_srgb);
break;
459 case ColorSpace::kHWB: p->append(SkRasterPipelineOp::css_hwb_to_srgb);
break;
465 if (!dstColorSpace) {
477 intermediateColorSpace, intermediateAlphaType, dstColorSpace, dstAlphaType)
487 std::optional<SkShaders::MatrixRec> newMRec = mRec.
apply(rec,
fPtsToUnit);
488 if (!newMRec.has_value()) {
498 p->append(SkRasterPipelineOp::mirror_x_1);
501 p->append(SkRasterPipelineOp::repeat_x_1);
507 p->append(SkRasterPipelineOp::decal_x, decal_ctx);
516 p->append(SkRasterPipelineOp::clamp_x_1);
531 p->append(SkRasterPipelineOp::check_decal_mask, decal_ctx);
534 p->extend(postPipeline);
567 case ColorSpace::kDestination:
572 case ColorSpace::kSRGBLinear:
575 case ColorSpace::kSRGB:
576 case ColorSpace::kHSL:
577 case ColorSpace::kHWB:
580 case ColorSpace::kLab:
581 case ColorSpace::kLCH:
585 case ColorSpace::kOKLab:
586 case ColorSpace::kOKLabGamutMap:
587 case ColorSpace::kOKLCH:
588 case ColorSpace::kOKLCHGamutMap:
604 float mx = std::max({rgb.
fR, rgb.
fG, rgb.
fB});
605 float mn = std::min({rgb.
fR, rgb.
fG, rgb.
fB});
606 float hue = 0,
sat = 0, light = (mn + mx) / 2;
610 sat = (light == 0 || light == 1) ? 0 : (mx - light) / std::min(light, 1 - light);
612 hue = (rgb.
fG - rgb.
fB) /
d + (rgb.
fG < rgb.
fB ? 6 : 0);
613 }
else if (mx == rgb.
fG) {
622 *hueIsPowerless =
true;
624 return {
hue,
sat * 100, light * 100, rgb.
fA};
629 float white = std::min({rgb.
fR, rgb.
fG, rgb.
fB});
630 float black = 1 - std::max({rgb.
fR, rgb.
fG, rgb.
fB});
631 return {hsl.
fR, white * 100, black * 100, rgb.
fA};
635 constexpr float D50[3] = {0.3457f / 0.3585f, 1.0f, (1.0f - 0.3457f - 0.3585f) / 0.3585f};
637 constexpr float e = 216.0f / 24389;
638 constexpr float k = 24389.0f / 27;
641 for (
int i = 0; i < 3; ++i) {
642 float v = xyz[i] / D50[i];
643 f[i] = (v > e) ? std::cbrtf(v) : (k * v + 16) / 116;
646 return {(116 * f[1]) - 16, 500 * (f[0] - f[1]), 200 * (f[1] - f[2]), xyz.
fA};
654 float chroma = sqrtf(Lab[1] * Lab[1] + Lab[2] * Lab[2]);
656 constexpr float kMaxChromaForPowerlessHue = 1e-2f;
657 if (chroma <= kMaxChromaForPowerlessHue) {
658 *hueIsPowerless =
true;
660 return {
hue >= 0 ?
hue :
hue + 360, chroma, Lab[0], xyz.
fA};
665 float l = 0.4122214708f * rgb.
fR + 0.5363325363f * rgb.
fG + 0.0514459929f * rgb.
fB;
666 float m = 0.2119034982f * rgb.
fR + 0.6806995451f * rgb.
fG + 0.1073969566f * rgb.
fB;
667 float s = 0.0883024619f * rgb.
fR + 0.2817188376f * rgb.
fG + 0.6299787005f * rgb.
fB;
671 return {0.2104542553f * l + 0.7936177850f * m - 0.0040720468f *
s,
672 1.9779984951f * l - 2.4285922050f * m + 0.4505937099f *
s,
673 0.0259040371f * l + 0.7827717662f * m - 0.8086757660f *
s,
682 float chroma = sqrtf(OKLab[1] * OKLab[1] + OKLab[2] * OKLab[2]);
684 constexpr float kMaxChromaForPowerlessHue = 1e-6f;
685 if (chroma <= kMaxChromaForPowerlessHue) {
686 *hueIsPowerless =
true;
688 return {
hue >= 0 ?
hue :
hue + 360, chroma, OKLab[0], rgb.
fA};
692 return {hsl.
fR, hsl.
fG * hsl.
fA, hsl.
fB * hsl.
fA, hsl.
fA};
696 return {rgb.
fR * rgb.
fA, rgb.
fG * rgb.
fA, rgb.
fB * rgb.
fA, rgb.
fA};
702 case ColorSpace::kLCH:
703 case ColorSpace::kOKLCH:
704 case ColorSpace::kHSL:
705 case ColorSpace::kHWB:
737 bool forceExplicitPositions) {
763 info.minRowBytes()));
768 case ColorSpace::kHSL: convertFn =
srgb_to_hsl;
break;
769 case ColorSpace::kHWB: convertFn =
srgb_to_hwb;
break;
780 bool anyPowerlessHue =
false;
783 for (
int i = 0; i < colorCount; ++i) {
785 anyPowerlessHue = anyPowerlessHue || hueIsPowerless[i];
789 if (anyPowerlessHue) {
796 for (
int i = 0; i < colorCount; ++i) {
798 float curPos = shader->
getPos(i);
800 if (!hueIsPowerless[i]) {
818 if (i != colorCount - 1) {
838 for (
int i = 0; i < colorCount - 1; ++i) {
843 case HueMethod::kShorter:
847 }
else if (h2 - h1 < -180) {
852 case HueMethod::kLonger:
857 }
else if (0 < h2 - h1 && h2 - h1 < 180) {
860 }
else if (-180 < h2 - h1 && h2 - h1 <= 0) {
865 case HueMethod::kIncreasing:
871 case HueMethod::kDecreasing:
883 if (
static_cast<bool>(interpolation.
fInPremul)) {
885 case ColorSpace::kHSL:
886 case ColorSpace::kHWB:
887 case ColorSpace::kLCH:
888 case ColorSpace::kOKLCH:
898 for (
int i = 0; i < colorCount; ++i) {
906 float posScale = 1.0f / (colorCount - 1);
907 for (
int i = 0; i < colorCount; i++) {
915 const float ONE_OVER_255 = 1.f / 255;
916 for (
int i = 0; i <
count; ++i) {
932 if (
info->fColorOffsets) {
941 info->fGradientFlags =
964 , fColorSpace(
std::move(colorSpace))
965 , fPositions(positions)
966 , fColorCount(colorCount)
968 , fInterpolation(interpolation) {
980 for (
int i = 0; i < colorCount - 1; ++i) {
1004 if (i == colorCount - 2) {
1009 blend += (1.f - p1) * c;
1013 w = 1.f / (colorCount - 1);
1016 blend += 0.5f *
w * (c1 + c0);
1036 return SkShaders::Empty();
1043 std::move(colorSpace));
1047 return SkShaders::Color(colors[colorCount - 1], std::move(colorSpace));
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static float prev(float f)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SkAssertResult(cond)
#define SkDEBUGFAIL(message)
SkRGBA4f< kPremul_SkAlphaType > SkPMColor4f
SkColorSpace * sk_srgb_singleton()
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
#define SkColorGetR(color)
#define SkColorGetG(color)
#define SkColorGetA(color)
#define SkColorGetB(color)
bool SkConvertPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRB, const SkImageInfo &srcInfo, const void *srcPixels, size_t srcRB)
static float SkBits2Float(uint32_t bits)
static uint32_t SkFloat2Bits(float value)
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static constexpr float sk_float_radians_to_degrees(float radians)
static void add_const_color(SkRasterPipeline_GradientCtx *ctx, size_t stop, SkPMColor4f color)
static void init_stop_evenly(SkRasterPipeline_GradientCtx *ctx, float gapCount, size_t stop, SkPMColor4f c_l, SkPMColor4f c_r)
static void add_stop_color(SkRasterPipeline_GradientCtx *ctx, size_t stop, SkPMColor4f Fs, SkPMColor4f Bs)
static SkPMColor4f srgb_to_hwb(SkPMColor4f rgb, bool *hueIsPowerless)
static SkPMColor4f lin_srgb_to_okhcl(SkPMColor4f rgb, bool *hueIsPowerless)
static SkPMColor4f xyzd50_to_lab(SkPMColor4f xyz, bool *)
SkPMColor4f(*)(SkPMColor4f, bool *) ConvertColorProc
static SkPMColor4f srgb_to_hsl(SkPMColor4f rgb, bool *hueIsPowerless)
static bool color_space_is_polar(SkGradientShader::Interpolation::ColorSpace cs)
GradientSerializationFlags
@ kInterpolationColorSpaceMask_GSF
@ kHasLegacyLocalMatrix_GSF
@ kInterpolationColorSpaceShift_GSF
@ kInterpolationHueMethodShift_GSF
@ kInterpolationInPremul_GSF
@ kInterpolationHueMethodMask_GSF
SkPMColor4f(*)(SkPMColor4f) PremulColorProc
static bool validate_array(SkReadBuffer &buffer, size_t count, STArray< N, T, MEM_MOVE > *array)
static SkColor4f average_gradient_color(const SkColor4f colors[], const SkScalar pos[], int colorCount)
static SkPMColor4f xyzd50_to_hcl(SkPMColor4f xyz, bool *hueIsPowerless)
static void init_stop_pos(SkRasterPipeline_GradientCtx *ctx, size_t stop, float t_l, float c_scale, SkPMColor4f c_l, SkPMColor4f c_r)
static SkPMColor4f premul_polar(SkPMColor4f hsl)
static SkPMColor4f premul_rgb(SkPMColor4f rgb)
static SkPMColor4f lin_srgb_to_oklab(SkPMColor4f rgb, bool *)
static sk_sp< SkColorSpace > intermediate_color_space(SkGradientShader::Interpolation::ColorSpace cs, SkColorSpace *dst)
static void sk_bzero(void *buffer, size_t size)
static bool apply(Pass *pass, SkRecord *record)
sk_sp< T > sk_ref_sp(T *obj)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
static constexpr int kSkTileModeCount
static constexpr bool SkToBool(const T &x)
T * makeArray(size_t count)
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > Deserialize(const void *data, size_t length)
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
sk_sp< SkData > serialize() const
static sk_sp< SkColorSpace > MakeSRGBLinear()
bool unflatten(SkReadBuffer &, SkMatrix *legacyLocalMatrix)
static bool ValidGradient(const SkColor4f colors[], int count, SkTileMode tileMode, const Interpolation &interpolation)
Interpolation fInterpolation
SkColor getLegacyColor(int i) const
bool colorsAreOpaque() const
bool isOpaque() const override
SkGradientBaseShader(const Descriptor &desc, const SkMatrix &ptsToUnit)
bool fFirstStopIsImplicit
virtual void appendGradientStages(SkArenaAlloc *alloc, SkRasterPipeline *tPipeline, SkRasterPipeline *postPipeline) const =0
bool onAsLuminanceColor(SkColor4f *) const override
SkScalar getPos(int i) const
static sk_sp< SkShader > MakeDegenerateGradient(const SkColor4f colors[], const SkScalar pos[], int colorCount, sk_sp< SkColorSpace > colorSpace, SkTileMode mode)
~SkGradientBaseShader() override
void flatten(SkWriteBuffer &) const override
bool appendStages(const SkStageRec &, const SkShaders::MatrixRec &) const override
const SkMatrix fPtsToUnit
void commonAsAGradient(GradientInfo *) const
sk_sp< SkColorSpace > fColorSpace
bool interpolateInPremul() const
static void AppendGradientFillStages(SkRasterPipeline *p, SkArenaAlloc *alloc, const SkPMColor4f *colors, const SkScalar *positions, int count)
static void AppendInterpolatedToDstStages(SkRasterPipeline *p, SkArenaAlloc *alloc, bool colorsAreOpaque, const Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace)
SkTileMode getTileMode() const
@ kInterpolateColorsInPremul_Flag
static const SkMatrix & I()
std::optional< MatrixRec > apply(const SkStageRec &rec, const SkMatrix &postInv={}) const
void resize_back(int newCount)
void reserve_exact(int n)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
FlutterSemanticsFlag flags
static const uint8_t buffer[]
static SkColor blend(SkColor dst, SkColor src, void(*mode)(float, float, float, float *, float *, float *))
static float sat(float r, float g, float b)
static void hue(float dr, float dg, float db, float *sr, float *sg, float *sb)
static float lum(float r, float g, float b)
static constexpr skcms_Matrix3x3 kXYZ
static constexpr skcms_TransferFunction kLinear
SkColorConverter(const SkColor *colors, int count)
skia_private::STArray< 2, SkColor4f > fColors4f
static constexpr int kColorSpaceCount
static constexpr int kHueMethodCount
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
const float * vec() const
SkRasterPipeline * fPipeline
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)