Make the ColorInput's gradient rendering strategy to use that of SliderInput (#4546)

Make the ColorInput's gradient rendering strategy to use that of SliderInput, fixing a flicker in Firefox when editing gradients
This commit is contained in:
Keavon Chambers
2026-09-16 23:53:38 -07:00
committed by GitHub
parent eb4a122322
commit 3f1351e3b9
8 changed files with 44 additions and 88 deletions
@@ -546,7 +546,15 @@ fn populate_computed_display_fields(layout: &mut Layout) {
for instance in layout.iter_mut() {
match &mut *instance.widget {
Widget::ColorInput(color_input) => {
color_input.chosen_gradient = color_input.value.to_css_background_image();
color_input.swatch_samples = match &color_input.value {
FillChoice::None => Vec::new(),
FillChoice::Solid(color) => vec![GradientSample::new(0., graphene_std::Color::from(*color))],
FillChoice::Gradient(ramp) => graphene_std::vector::style::Gradient::from(&ramp.stops)
.interpolated_samples_or_black(ramp.into())
.into_iter()
.map(|(position, color, _)| GradientSample::new(position, color))
.collect(),
};
}
Widget::TransferCurveInput(curve_input) => {
const SAMPLE_COUNT: usize = 128;
@@ -578,7 +586,7 @@ fn populate_computed_display_fields(layout: &mut Layout) {
slider_input.track_samples = track_gradient
.interpolated_samples_or_black(settings)
.into_iter()
.map(|(position, color, _)| SliderSample::new(position, color))
.map(|(position, color, _)| GradientSample::new(position, color))
.collect();
// The end caps sample the track's boundary colors, which a cyclic wrap makes the wrapped interval's boundary-crossing color rather than the outermost stops'
let track_evaluator = track_gradient.evaluator(settings);
@@ -193,11 +193,11 @@ pub struct ColorInput {
// Content
#[widget_builder(constructor)]
pub value: FillChoice<SRGBA8>,
/// CSS `linear-gradient(...)` (or solid-color stand-in) for the swatch's `background-image`. Auto-populated from `value` at layout-send time.
/// `None` when `value` is `FillChoice::<SRGBA8>::None`, in which case the frontend uses its "none" fallback styling.
#[serde(rename = "chosenGradient")]
/// Straight-alpha color samples drawn by the frontend as the stops of an SVG gradient filling the swatch. Auto-populated from `value` at layout-send time.
/// Empty when `value` is `FillChoice::<SRGBA8>::None`, in which case the frontend uses its "none" fallback styling.
#[serde(rename = "swatchSamples")]
#[widget_builder(skip)]
pub chosen_gradient: Option<String>,
pub swatch_samples: Vec<GradientSample>,
#[serde(rename = "allowNone")]
#[derivative(Default(value = "true"))]
pub allow_none: bool,
@@ -641,10 +641,10 @@ pub struct SliderInput {
/// The path the track's stops interpolate along, used to bake `track_samples` and by the frontend to suppress the midpoint diamonds when stepped.
#[serde(rename = "trackInterpolation")]
pub track_interpolation: GradientInterpolation,
/// Straight-alpha samples the frontend draws as the stops of an SVG gradient filling the track strip. Auto-populated from `track` at layout-send time.
/// Straight-alpha color samples drawn by the frontend as the stops of an SVG gradient filling the track strip. Auto-populated from `track` at layout-send time.
#[serde(rename = "trackSamples")]
#[widget_builder(skip)]
pub track_samples: Vec<SliderSample>,
pub track_samples: Vec<GradientSample>,
/// Hex string for the track strip's leftmost solid-color end-cap. Auto-populated by evaluating `track` at position 0.
#[serde(rename = "trackStartCSS")]
#[widget_builder(skip)]
@@ -748,8 +748,8 @@ impl SliderMarker {
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct SliderSample {
/// Position (0..1) of the sample along the slider track, drawn as the SVG stop's `offset`.
pub struct GradientSample {
/// Position (0..1) of the sample along the gradient, drawn as the SVG stop's `offset`.
position: f64,
/// `#rrggbb` hex of the sample's color, drawn as the SVG stop's `stop-color`.
color: String,
@@ -757,7 +757,7 @@ pub struct SliderSample {
alpha: f32,
}
impl SliderSample {
impl GradientSample {
pub fn new(position: f64, color: Color) -> Self {
Self {
position,
@@ -1975,7 +1975,7 @@ fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessa
}
responses.add(PropertiesPanelMessage::Refresh);
// Refresh the tool options so the swatch's `chosen_gradient` (precomputed CSS string) updates live as the user edits stops in the picker.
// Refresh the tool options so the swatch's `swatch_samples` update live as the user edits stops in the picker.
responses.add(ToolMessage::RefreshToolOptions);
}