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