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