script/dom/canvas/2d/
canvasgradient.rs1use canvas_traits::canvas::{
6 CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle,
7};
8use dom_struct::dom_struct;
9use js::context::JSContext;
10
11use super::canvas_state::parse_color;
12use crate::dom::bindings::cell::DomRefCell;
13use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasGradientMethods;
14use crate::dom::bindings::error::{Error, ErrorResult};
15use crate::dom::bindings::num::Finite;
16use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_cx};
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::globalscope::GlobalScope;
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 cx: &mut JSContext,
48 style: CanvasGradientStyle,
49 ) -> DomRoot<CanvasGradient> {
50 reflect_dom_object_with_cx(Box::new(CanvasGradient::new_inherited(style)), global, cx)
51 }
52}
53
54impl CanvasGradientMethods<crate::DomTypeHolder> for CanvasGradient {
55 fn AddColorStop(&self, offset: Finite<f64>, color: DOMString) -> ErrorResult {
57 if *offset < 0f64 || *offset > 1f64 {
58 return Err(Error::IndexSize(None));
59 }
60
61 let color = match parse_color(None, &color) {
62 Ok(color) => color,
63 Err(_) => return Err(Error::Syntax(None)),
64 };
65
66 self.stops.borrow_mut().push(CanvasGradientStop {
67 offset: (*offset),
68 color,
69 });
70 Ok(())
71 }
72}
73
74pub(crate) trait ToFillOrStrokeStyle {
75 fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle;
76}
77
78impl ToFillOrStrokeStyle for &CanvasGradient {
79 fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
80 let gradient_stops = self.stops.borrow().clone();
81 match self.style {
82 CanvasGradientStyle::Linear(ref gradient) => {
83 FillOrStrokeStyle::LinearGradient(LinearGradientStyle::new(
84 gradient.x0,
85 gradient.y0,
86 gradient.x1,
87 gradient.y1,
88 gradient_stops,
89 ))
90 },
91 CanvasGradientStyle::Radial(ref gradient) => {
92 FillOrStrokeStyle::RadialGradient(RadialGradientStyle::new(
93 gradient.x0,
94 gradient.y0,
95 gradient.r0,
96 gradient.x1,
97 gradient.y1,
98 gradient.r1,
99 gradient_stops,
100 ))
101 },
102 }
103 }
104}