use core_graphics::{base::CGFloat, color_space::CGColorSpace, gradient::CGGradient};
use crate::{
geometry::FPoint,
gradient::{GradientBackend, GradientData},
paint::Color,
Float,
};
#[derive(Clone, Debug)]
pub struct CoreGraphicsGradient {
data: GradientData,
color_stops: Vec<(Float, Color)>,
gradient: Option<CGGradient>,
}
impl GradientBackend for CoreGraphicsGradient {
fn new_linear(x1: Float, y1: Float, x2: Float, y2: Float) -> Self {
Self {
gradient: None,
data: GradientData::Linear((FPoint::new(x1, y1), FPoint::new(x2, y2))),
color_stops: Vec::new(),
}
}
fn new_radial(x1: Float, y1: Float, x2: Float, y2: Float, r: Float) -> Self {
Self {
gradient: None,
data: GradientData::Radial((FPoint::new(x1, y1), FPoint::new(x2, y2), r)),
color_stops: Vec::new(),
}
}
fn add_color_stop(&mut self, offset: Float, color: Color) -> bool {
if offset.is_nan() || !(0.0..=1.0).contains(&offset) {
return false;
}
self.color_stops.push((offset, color));
self.gradient = None;
true
}
}
impl CoreGraphicsGradient {
pub(super) fn cg_gradient(&mut self) -> Option<CGGradient> {
if self.gradient.is_none() {
let len = self.color_stops.len();
let mut locations: Vec<CGFloat> = vec![0.0; len];
let mut colors: Vec<CGFloat> = vec![0.0; len * 4];
for i in 0..len {
locations[i] = self.color_stops[i].0 as CGFloat;
let (r, g, b, a) = self.color_stops[i].1.get_float_value();
colors[i * 4..i * 4 + 4].copy_from_slice(&[r, g, b, a]);
}
let cs = CGColorSpace::new_device_rgb();
self.gradient = CGGradient::from_color_components(cs.as_ref(), Some(&colors), Some(&locations));
}
self.gradient.clone()
}
pub(super) fn data(&self) -> GradientData {
self.data.clone()
}
}