Skip to main content

script/dom/canvas/2d/
canvasrenderingcontext2d.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use euclid::default::Size2D;
7use js::context::{JSContext, NoGC};
8use pixels::Snapshot;
9use script_bindings::reflector::{AssociatedMemory, Reflector, reflect_dom_object_with_cx};
10use servo_base::{Epoch, generic_channel};
11use servo_canvas_traits::canvas::{CanvasCommand, CanvasId};
12use webrender_api::ImageKey;
13
14use super::canvas_state::CanvasState;
15use crate::canvas_context::{CanvasContext, CanvasHelpers, HTMLCanvasElementOrOffscreenCanvas};
16use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
17    CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
18    CanvasRenderingContext2DMethods, CanvasTextAlign, CanvasTextBaseline,
19};
20use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::DOMMatrix2DInit;
21use crate::dom::bindings::codegen::UnionTypes::{
22    HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas,
23    StringOrCanvasGradientOrCanvasPattern,
24};
25use crate::dom::bindings::error::{ErrorResult, Fallible};
26use crate::dom::bindings::num::Finite;
27use crate::dom::bindings::reflector::DomGlobal;
28use crate::dom::bindings::root::{Dom, DomRoot};
29use crate::dom::bindings::str::DOMString;
30use crate::dom::canvasgradient::CanvasGradient;
31use crate::dom::canvaspattern::CanvasPattern;
32use crate::dom::dommatrix::DOMMatrix;
33use crate::dom::globalscope::GlobalScope;
34use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
35use crate::dom::imagedata::ImageData;
36use crate::dom::path2d::Path2D;
37use crate::dom::textmetrics::TextMetrics;
38
39// https://html.spec.whatwg.org/multipage/#canvasrenderingcontext2d
40#[dom_struct(associated_memory)]
41pub(crate) struct CanvasRenderingContext2D {
42    reflector_: Reflector<AssociatedMemory>,
43    canvas: HTMLCanvasElementOrOffscreenCanvas,
44    canvas_state: CanvasState,
45}
46
47impl CanvasRenderingContext2D {
48    const RGBA8_BYTES_PER_PIXEL: usize = 4;
49    /// We have two bitmap buffers one in Canvas Paint Thread and one for WebRender
50    const ASSOCIATED_MEMORY_BUFFER_COUNT: usize = 2;
51
52    fn associated_memory_size(size: Size2D<u64>) -> usize {
53        (size.width as usize)
54            .saturating_mul(size.height as usize)
55            .saturating_mul(Self::RGBA8_BYTES_PER_PIXEL)
56            .saturating_mul(Self::ASSOCIATED_MEMORY_BUFFER_COUNT)
57    }
58
59    pub(crate) fn update_associated_memory_size(&self) {
60        self.reflector_.update_memory_size(
61            self,
62            Self::associated_memory_size(self.canvas_state.bitmap_dimensions()),
63        );
64    }
65
66    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
67    pub(crate) fn new_inherited(
68        global: &GlobalScope,
69        canvas: HTMLCanvasElementOrOffscreenCanvas,
70        size: Size2D<u32>,
71    ) -> Option<CanvasRenderingContext2D> {
72        let canvas_state =
73            CanvasState::new(global, Size2D::new(size.width as u64, size.height as u64))?;
74        Some(CanvasRenderingContext2D {
75            reflector_: Reflector::new(),
76            canvas,
77            canvas_state,
78        })
79    }
80
81    pub(crate) fn new(
82        cx: &mut JSContext,
83        global: &GlobalScope,
84        canvas: &HTMLCanvasElement,
85        size: Size2D<u32>,
86    ) -> Option<DomRoot<CanvasRenderingContext2D>> {
87        CanvasRenderingContext2D::new_inherited(
88            global,
89            HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(Dom::from_ref(canvas)),
90            size,
91        )
92        .map(|context| {
93            let context = reflect_dom_object_with_cx(Box::new(context), global, cx);
94            context.update_associated_memory_size();
95            context
96        })
97    }
98
99    pub(crate) fn send_canvas_command_immediate(&self, msg: CanvasCommand) {
100        self.canvas_state.send_canvas_command_immediate(msg)
101    }
102
103    pub(crate) fn set_image_key(&self, image_key: ImageKey) {
104        self.canvas_state.set_image_key(image_key);
105    }
106
107    pub(crate) fn update_rendering(&self, canvas_epoch: Epoch) -> bool {
108        if !self.onscreen() {
109            return false;
110        }
111        self.canvas_state.update_rendering(Some(canvas_epoch))
112    }
113}
114
115impl CanvasContext for CanvasRenderingContext2D {
116    type ID = CanvasId;
117
118    fn context_id(&self) -> Self::ID {
119        self.canvas_state.get_canvas_id()
120    }
121
122    fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
123        Some(RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas))
124    }
125
126    fn resize(&self) {
127        self.canvas_state.set_bitmap_dimensions(self.size().cast());
128        self.update_associated_memory_size();
129    }
130
131    fn reset_bitmap(&self) {
132        self.canvas_state.reset_bitmap()
133    }
134
135    fn get_image_data(&self) -> Option<Snapshot> {
136        if !self.canvas_state.is_paintable() {
137            return None;
138        }
139
140        let (sender, receiver) = generic_channel::channel().unwrap();
141        self.canvas_state
142            .send_canvas_command_immediate(CanvasCommand::GetImageData(None, sender));
143        Some(receiver.recv().unwrap().to_owned())
144    }
145
146    fn origin_is_clean(&self) -> bool {
147        self.canvas_state.origin_is_clean()
148    }
149
150    fn mark_as_dirty(&self) {
151        self.canvas.mark_as_dirty();
152    }
153}
154
155// We add a guard to each of methods by the spec:
156// http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/
157//
158// > Except where otherwise specified, for the 2D context interface,
159// > any method call with a numeric argument whose value is infinite or a NaN value must be ignored.
160//
161//  Restricted values are guarded in glue code. Therefore we need not add a guard.
162//
163// FIXME: this behavior should might be generated by some annotations to idl.
164impl CanvasRenderingContext2DMethods<crate::DomTypeHolder> for CanvasRenderingContext2D {
165    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-canvas>
166    fn Canvas(&self) -> DomRoot<HTMLCanvasElement> {
167        match &self.canvas {
168            HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => canvas.as_rooted(),
169            _ => panic!("Should not be called from offscreen canvas"),
170        }
171    }
172
173    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-save>
174    fn Save(&self) {
175        self.canvas_state.save()
176    }
177
178    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-restore>
179    fn Restore(&self) {
180        self.canvas_state.restore()
181    }
182
183    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-reset>
184    fn Reset(&self) {
185        self.canvas_state.reset()
186    }
187
188    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-scale>
189    fn Scale(&self, x: f64, y: f64) {
190        self.canvas_state.scale(x, y)
191    }
192
193    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-rotate>
194    fn Rotate(&self, angle: f64) {
195        self.canvas_state.rotate(angle)
196    }
197
198    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-translate>
199    fn Translate(&self, x: f64, y: f64) {
200        self.canvas_state.translate(x, y)
201    }
202
203    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-transform>
204    fn Transform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
205        self.canvas_state.transform(a, b, c, d, e, f)
206    }
207
208    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-gettransform>
209    fn GetTransform(&self, cx: &mut JSContext) -> DomRoot<DOMMatrix> {
210        self.canvas_state.get_transform(&self.global(), cx)
211    }
212
213    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform>
214    fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> ErrorResult {
215        self.canvas_state.set_transform(a, b, c, d, e, f);
216        Ok(())
217    }
218
219    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform-matrix>
220    fn SetTransform_(&self, transform: &DOMMatrix2DInit) -> ErrorResult {
221        self.canvas_state.set_transform_(transform)
222    }
223
224    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-resettransform>
225    fn ResetTransform(&self) {
226        self.canvas_state.reset_transform()
227    }
228
229    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha>
230    fn GlobalAlpha(&self) -> f64 {
231        self.canvas_state.global_alpha()
232    }
233
234    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha>
235    fn SetGlobalAlpha(&self, alpha: f64) {
236        self.canvas_state.set_global_alpha(alpha)
237    }
238
239    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-globalcompositeoperation>
240    fn GlobalCompositeOperation(&self) -> DOMString {
241        self.canvas_state.global_composite_operation()
242    }
243
244    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-globalcompositeoperation>
245    fn SetGlobalCompositeOperation(&self, op_str: DOMString) {
246        self.canvas_state.set_global_composite_operation(op_str)
247    }
248
249    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-fillrect>
250    fn FillRect(&self, x: f64, y: f64, width: f64, height: f64) {
251        self.canvas_state.fill_rect(x, y, width, height);
252        self.mark_as_dirty();
253    }
254
255    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-clearrect>
256    fn ClearRect(&self, x: f64, y: f64, width: f64, height: f64) {
257        self.canvas_state.clear_rect(x, y, width, height);
258        self.mark_as_dirty();
259    }
260
261    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-strokerect>
262    fn StrokeRect(&self, x: f64, y: f64, width: f64, height: f64) {
263        self.canvas_state.stroke_rect(x, y, width, height);
264        self.mark_as_dirty();
265    }
266
267    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-beginpath>
268    fn BeginPath(&self) {
269        self.canvas_state.begin_path()
270    }
271
272    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-closepath>
273    fn ClosePath(&self) {
274        self.canvas_state.close_path()
275    }
276
277    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-fill>
278    fn Fill(&self, fill_rule: CanvasFillRule) {
279        self.canvas_state.fill(fill_rule);
280        self.mark_as_dirty();
281    }
282
283    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-fill>
284    fn Fill_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
285        self.canvas_state.fill_(path.segments(), fill_rule);
286        self.mark_as_dirty();
287    }
288
289    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke>
290    fn Stroke(&self) {
291        self.canvas_state.stroke();
292        self.mark_as_dirty();
293    }
294
295    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-stroke>
296    fn Stroke_(&self, path: &Path2D) {
297        self.canvas_state.stroke_(path.segments());
298        self.mark_as_dirty();
299    }
300
301    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-clip>
302    fn Clip(&self, fill_rule: CanvasFillRule) {
303        self.canvas_state.clip(fill_rule)
304    }
305
306    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-clip>
307    fn Clip_(&self, path: &Path2D, fill_rule: CanvasFillRule) {
308        self.canvas_state.clip_(path.segments(), fill_rule)
309    }
310
311    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath>
312    fn IsPointInPath(&self, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
313        self.canvas_state
314            .is_point_in_path(&self.global(), x, y, fill_rule)
315    }
316
317    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-ispointinpath>
318    fn IsPointInPath_(&self, path: &Path2D, x: f64, y: f64, fill_rule: CanvasFillRule) -> bool {
319        self.canvas_state
320            .is_point_in_path_(&self.global(), path.segments(), x, y, fill_rule)
321    }
322
323    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext>
324    fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) {
325        self.canvas_state.fill_text(
326            &self.global(),
327            self.canvas.canvas().as_deref(),
328            text,
329            x,
330            y,
331            max_width,
332        );
333        self.mark_as_dirty();
334    }
335
336    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-stroketext>
337    fn StrokeText(&self, text: DOMString, x: f64, y: f64, max_width: Option<f64>) {
338        self.canvas_state.stroke_text(
339            &self.global(),
340            self.canvas.canvas().as_deref(),
341            text,
342            x,
343            y,
344            max_width,
345        );
346        self.mark_as_dirty();
347    }
348
349    /// <https://html.spec.whatwg.org/multipage/#textmetrics>
350    fn MeasureText(&self, cx: &mut JSContext, text: DOMString) -> DomRoot<TextMetrics> {
351        self.canvas_state
352            .measure_text(&self.global(), self.canvas.canvas().as_deref(), text, cx)
353    }
354
355    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-font>
356    fn Font(&self) -> DOMString {
357        self.canvas_state.font()
358    }
359
360    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-font>
361    fn SetFont(&self, value: DOMString) {
362        self.canvas_state
363            .set_font(self.canvas.canvas().as_deref(), value)
364    }
365
366    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign>
367    fn TextAlign(&self) -> CanvasTextAlign {
368        self.canvas_state.text_align()
369    }
370
371    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign>
372    fn SetTextAlign(&self, value: CanvasTextAlign) {
373        self.canvas_state.set_text_align(value)
374    }
375
376    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline>
377    fn TextBaseline(&self) -> CanvasTextBaseline {
378        self.canvas_state.text_baseline()
379    }
380
381    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-textbaseline>
382    fn SetTextBaseline(&self, value: CanvasTextBaseline) {
383        self.canvas_state.set_text_baseline(value)
384    }
385
386    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-direction>
387    fn Direction(&self) -> CanvasDirection {
388        self.canvas_state.direction()
389    }
390
391    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-direction>
392    fn SetDirection(&self, value: CanvasDirection) {
393        self.canvas_state.set_direction(value)
394    }
395
396    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
397    fn DrawImage(&self, image: CanvasImageSource, dx: f64, dy: f64) -> ErrorResult {
398        self.canvas_state
399            .draw_image(self.canvas.canvas().as_deref(), image, dx, dy)
400    }
401
402    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
403    fn DrawImage_(
404        &self,
405        image: CanvasImageSource,
406        dx: f64,
407        dy: f64,
408        dw: f64,
409        dh: f64,
410    ) -> ErrorResult {
411        self.canvas_state
412            .draw_image_(self.canvas.canvas().as_deref(), image, dx, dy, dw, dh)
413    }
414
415    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
416    fn DrawImage__(
417        &self,
418        image: CanvasImageSource,
419        sx: f64,
420        sy: f64,
421        sw: f64,
422        sh: f64,
423        dx: f64,
424        dy: f64,
425        dw: f64,
426        dh: f64,
427    ) -> ErrorResult {
428        self.canvas_state.draw_image__(
429            self.canvas.canvas().as_deref(),
430            image,
431            sx,
432            sy,
433            sw,
434            sh,
435            dx,
436            dy,
437            dw,
438            dh,
439        )
440    }
441
442    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto>
443    fn MoveTo(&self, x: f64, y: f64) {
444        self.canvas_state.move_to(x, y)
445    }
446
447    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-lineto>
448    fn LineTo(&self, x: f64, y: f64) {
449        self.canvas_state.line_to(x, y)
450    }
451
452    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-rect>
453    fn Rect(&self, x: f64, y: f64, width: f64, height: f64) {
454        self.canvas_state.rect(x, y, width, height)
455    }
456
457    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-quadraticcurveto>
458    fn QuadraticCurveTo(&self, cpx: f64, cpy: f64, x: f64, y: f64) {
459        self.canvas_state.quadratic_curve_to(cpx, cpy, x, y)
460    }
461
462    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-beziercurveto>
463    fn BezierCurveTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
464        self.canvas_state
465            .bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y)
466    }
467
468    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-arc>
469    fn Arc(&self, x: f64, y: f64, r: f64, start: f64, end: f64, ccw: bool) -> ErrorResult {
470        self.canvas_state.arc(x, y, r, start, end, ccw)
471    }
472
473    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-arcto>
474    fn ArcTo(&self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, r: f64) -> ErrorResult {
475        self.canvas_state.arc_to(cp1x, cp1y, cp2x, cp2y, r)
476    }
477
478    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-ellipse>
479    fn Ellipse(
480        &self,
481        x: f64,
482        y: f64,
483        rx: f64,
484        ry: f64,
485        rotation: f64,
486        start: f64,
487        end: f64,
488        ccw: bool,
489    ) -> ErrorResult {
490        self.canvas_state
491            .ellipse(x, y, rx, ry, rotation, start, end, ccw)
492    }
493
494    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-imagesmoothingenabled>
495    fn ImageSmoothingEnabled(&self) -> bool {
496        self.canvas_state.image_smoothing_enabled()
497    }
498
499    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-imagesmoothingenabled>
500    fn SetImageSmoothingEnabled(&self, value: bool) {
501        self.canvas_state.set_image_smoothing_enabled(value)
502    }
503
504    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle>
505    fn StrokeStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
506        self.canvas_state.stroke_style()
507    }
508
509    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle>
510    fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
511        self.canvas_state
512            .set_stroke_style(self.canvas.canvas().as_deref(), value)
513    }
514
515    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle>
516    fn FillStyle(&self) -> StringOrCanvasGradientOrCanvasPattern {
517        self.canvas_state.fill_style()
518    }
519
520    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle>
521    fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
522        self.canvas_state
523            .set_fill_style(self.canvas.canvas().as_deref(), value)
524    }
525
526    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata>
527    fn CreateImageData(
528        &self,
529        cx: &mut JSContext,
530        sw: i32,
531        sh: i32,
532    ) -> Fallible<DomRoot<ImageData>> {
533        self.canvas_state
534            .create_image_data(cx, &self.global(), sw, sh)
535    }
536
537    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata>
538    fn CreateImageData_(
539        &self,
540        cx: &mut JSContext,
541        imagedata: &ImageData,
542    ) -> Fallible<DomRoot<ImageData>> {
543        self.canvas_state
544            .create_image_data_(cx, &self.global(), imagedata)
545    }
546
547    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata>
548    fn GetImageData(
549        &self,
550        cx: &mut JSContext,
551        sx: i32,
552        sy: i32,
553        sw: i32,
554        sh: i32,
555    ) -> Fallible<DomRoot<ImageData>> {
556        self.canvas_state
557            .get_image_data(cx, self.canvas.size(), &self.global(), sx, sy, sw, sh)
558    }
559
560    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata>
561    fn PutImageData(&self, no_gc: &NoGC, imagedata: &ImageData, dx: i32, dy: i32) {
562        self.canvas_state
563            .put_image_data(no_gc, self.canvas.size(), imagedata, dx, dy);
564        self.mark_as_dirty();
565    }
566
567    // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
568    fn PutImageData_(
569        &self,
570        no_gc: &NoGC,
571        imagedata: &ImageData,
572        dx: i32,
573        dy: i32,
574        dirty_x: i32,
575        dirty_y: i32,
576        dirty_width: i32,
577        dirty_height: i32,
578    ) {
579        self.canvas_state.put_image_data_(
580            no_gc,
581            self.canvas.size(),
582            imagedata,
583            dx,
584            dy,
585            dirty_x,
586            dirty_y,
587            dirty_width,
588            dirty_height,
589        );
590        self.mark_as_dirty();
591    }
592
593    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient>
594    fn CreateLinearGradient(
595        &self,
596        cx: &mut JSContext,
597        x0: Finite<f64>,
598        y0: Finite<f64>,
599        x1: Finite<f64>,
600        y1: Finite<f64>,
601    ) -> DomRoot<CanvasGradient> {
602        self.canvas_state
603            .create_linear_gradient(&self.global(), cx, x0, y0, x1, y1)
604    }
605
606    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient>
607    fn CreateRadialGradient(
608        &self,
609        cx: &mut JSContext,
610        x0: Finite<f64>,
611        y0: Finite<f64>,
612        r0: Finite<f64>,
613        x1: Finite<f64>,
614        y1: Finite<f64>,
615        r1: Finite<f64>,
616    ) -> Fallible<DomRoot<CanvasGradient>> {
617        self.canvas_state
618            .create_radial_gradient(&self.global(), cx, x0, y0, r0, x1, y1, r1)
619    }
620
621    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern>
622    fn CreatePattern(
623        &self,
624        cx: &mut JSContext,
625        image: CanvasImageSource,
626        repetition: DOMString,
627    ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
628        self.canvas_state
629            .create_pattern(&self.global(), cx, image, repetition)
630    }
631
632    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth>
633    fn LineWidth(&self) -> f64 {
634        self.canvas_state.line_width()
635    }
636
637    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth>
638    fn SetLineWidth(&self, width: f64) {
639        self.canvas_state.set_line_width(width)
640    }
641
642    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap>
643    fn LineCap(&self) -> CanvasLineCap {
644        self.canvas_state.line_cap()
645    }
646
647    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap>
648    fn SetLineCap(&self, cap: CanvasLineCap) {
649        self.canvas_state.set_line_cap(cap)
650    }
651
652    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin>
653    fn LineJoin(&self) -> CanvasLineJoin {
654        self.canvas_state.line_join()
655    }
656
657    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin>
658    fn SetLineJoin(&self, join: CanvasLineJoin) {
659        self.canvas_state.set_line_join(join)
660    }
661
662    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit>
663    fn MiterLimit(&self) -> f64 {
664        self.canvas_state.miter_limit()
665    }
666
667    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit>
668    fn SetMiterLimit(&self, limit: f64) {
669        self.canvas_state.set_miter_limit(limit)
670    }
671
672    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-setlinedash>
673    fn SetLineDash(&self, segments: Vec<f64>) {
674        self.canvas_state.set_line_dash(segments);
675    }
676
677    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash>
678    fn GetLineDash(&self) -> Vec<f64> {
679        self.canvas_state.line_dash()
680    }
681
682    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset>
683    fn LineDashOffset(&self) -> f64 {
684        self.canvas_state.line_dash_offset()
685    }
686
687    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset>
688    fn SetLineDashOffset(&self, offset: f64) {
689        self.canvas_state.set_line_dash_offset(offset);
690    }
691
692    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx>
693    fn ShadowOffsetX(&self) -> f64 {
694        self.canvas_state.shadow_offset_x()
695    }
696
697    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx>
698    fn SetShadowOffsetX(&self, value: f64) {
699        self.canvas_state.set_shadow_offset_x(value)
700    }
701
702    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsety>
703    fn ShadowOffsetY(&self) -> f64 {
704        self.canvas_state.shadow_offset_y()
705    }
706
707    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsety>
708    fn SetShadowOffsetY(&self, value: f64) {
709        self.canvas_state.set_shadow_offset_y(value)
710    }
711
712    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowblur>
713    fn ShadowBlur(&self) -> f64 {
714        self.canvas_state.shadow_blur()
715    }
716
717    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowblur>
718    fn SetShadowBlur(&self, value: f64) {
719        self.canvas_state.set_shadow_blur(value)
720    }
721
722    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor>
723    fn ShadowColor(&self) -> DOMString {
724        self.canvas_state.shadow_color()
725    }
726
727    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor>
728    fn SetShadowColor(&self, value: DOMString) {
729        self.canvas_state
730            .set_shadow_color(self.canvas.canvas().as_deref(), value)
731    }
732}