script/dom/
canvasgradient.rs1use canvas_traits::canvas::{
6 CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle,
7};
8use dom_struct::dom_struct;
9
10use crate::canvas_state::parse_color;
11use crate::dom::bindings::cell::DomRefCell;
12use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasGradientMethods;
13use crate::dom::bindings::error::{Error, ErrorResult};
14use crate::dom::bindings::num::Finite;
15use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::bindings::str::DOMString;
18use crate::dom::globalscope::GlobalScope;
19use crate::script_runtime::CanGc;
20
21#[dom_struct]
23pub(crate) struct CanvasGradient {
24 reflector_: Reflector,
25 style: CanvasGradientStyle,
26 #[no_trace]
27 stops: DomRefCell<Vec<CanvasGradientStop>>,
28}
29
30#[derive(Clone, JSTraceable, MallocSizeOf)]
31pub(crate) enum CanvasGradientStyle {
32 Linear(#[no_trace] LinearGradientStyle),
33 Radial(#[no_trace] RadialGradientStyle),
34}
35
36impl CanvasGradient {
37 fn new_inherited(style: CanvasGradientStyle) -> CanvasGradient {
38 CanvasGradient {
39 reflector_: Reflector::new(),
40 style,
41 stops: DomRefCell::new(Vec::new()),
42 }
43 }
44
45 pub(crate) fn new(
46 global: &GlobalScope,
47 style: CanvasGradientStyle,
48 can_gc: CanGc,
49 ) -> DomRoot<CanvasGradient> {
50 reflect_dom_object(
51 Box::new(CanvasGradient::new_inherited(style)),
52 global,
53 can_gc,
54 )
55 }
56}
57
58impl CanvasGradientMethods<crate::DomTypeHolder> for CanvasGradient {
59 fn AddColorStop(&self, offset: Finite<f64>, color: DOMString) -> ErrorResult {
61 if *offset < 0f64 || *offset > 1f64 {
62 return Err(Error::IndexSize);
63 }
64
65 let color = match parse_color(None, &color) {
66 Ok(color) => color,
67 Err(_) => return Err(Error::Syntax),
68 };
69
70 self.stops.borrow_mut().push(CanvasGradientStop {
71 offset: (*offset),
72 color,
73 });
74 Ok(())
75 }
76}
77
78pub(crate) trait ToFillOrStrokeStyle {
79 fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle;
80}
81
82impl ToFillOrStrokeStyle for &CanvasGradient {
83 fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
84 let gradient_stops = self.stops.borrow().clone();
85 match self.style {
86 CanvasGradientStyle::Linear(ref gradient) => {
87 FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(
88 gradient.x0,
89 gradient.y0,
90 gradient.x1,
91 gradient.y1,
92 gradient_stops,
93 ))
94 },
95 CanvasGradientStyle::Radial(ref gradient) => {
96 FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
97 gradient.x0,
98 gradient.y0,
99 gradient.r0,
100 gradient.x1,
101 gradient.y1,
102 gradient.r1,
103 gradient_stops,
104 ))
105 },
106 }
107 }
108}