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