script/dom/canvas/2d/
canvaspattern.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 canvas_traits::canvas::{FillOrStrokeStyle, RepetitionStyle, SurfaceStyle};
6use dom_struct::dom_struct;
7use euclid::default::{Size2D, Transform2D};
8use pixels::{IpcSnapshot, Snapshot};
9
10use crate::dom::bindings::cell::DomRefCell;
11use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasPatternMethods;
12use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::DOMMatrix2DInit;
13use crate::dom::bindings::error::ErrorResult;
14use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::canvasgradient::ToFillOrStrokeStyle;
17use crate::dom::dommatrixreadonly::dommatrix2dinit_to_matrix;
18use crate::dom::globalscope::GlobalScope;
19use crate::script_runtime::CanGc;
20
21/// <https://html.spec.whatwg.org/multipage/#canvaspattern>
22#[dom_struct]
23pub(crate) struct CanvasPattern {
24    reflector_: Reflector,
25    #[no_trace]
26    surface_data: IpcSnapshot,
27    #[no_trace]
28    surface_size: Size2D<u32>,
29    repeat_x: bool,
30    repeat_y: bool,
31    #[no_trace]
32    transform: DomRefCell<Transform2D<f32>>,
33    origin_clean: bool,
34}
35
36impl CanvasPattern {
37    fn new_inherited(
38        surface_data: Snapshot,
39        surface_size: Size2D<u32>,
40        repeat: RepetitionStyle,
41        origin_clean: bool,
42    ) -> CanvasPattern {
43        let (x, y) = match repeat {
44            RepetitionStyle::Repeat => (true, true),
45            RepetitionStyle::RepeatX => (true, false),
46            RepetitionStyle::RepeatY => (false, true),
47            RepetitionStyle::NoRepeat => (false, false),
48        };
49
50        CanvasPattern {
51            reflector_: Reflector::new(),
52            surface_data: surface_data.as_ipc(),
53            surface_size,
54            repeat_x: x,
55            repeat_y: y,
56            transform: DomRefCell::new(Transform2D::identity()),
57            origin_clean,
58        }
59    }
60    pub(crate) fn new(
61        global: &GlobalScope,
62        surface_data: Snapshot,
63        surface_size: Size2D<u32>,
64        repeat: RepetitionStyle,
65        origin_clean: bool,
66        can_gc: CanGc,
67    ) -> DomRoot<CanvasPattern> {
68        reflect_dom_object(
69            Box::new(CanvasPattern::new_inherited(
70                surface_data,
71                surface_size,
72                repeat,
73                origin_clean,
74            )),
75            global,
76            can_gc,
77        )
78    }
79    pub(crate) fn origin_is_clean(&self) -> bool {
80        self.origin_clean
81    }
82}
83
84impl CanvasPatternMethods<crate::DomTypeHolder> for CanvasPattern {
85    /// <https://html.spec.whatwg.org/multipage/#dom-canvaspattern-settransform>
86    fn SetTransform(&self, transform: &DOMMatrix2DInit) -> ErrorResult {
87        // Step 1. Let matrix be the result of creating a DOMMatrix from the 2D
88        // dictionary transform.
89        let matrix = dommatrix2dinit_to_matrix(transform)?;
90
91        // Step 2. If one or more of matrix's m11 element, m12 element, m21
92        // element, m22 element, m41 element, or m42 element are infinite or
93        // NaN, then return.
94        if !matrix.m11.is_finite() ||
95            !matrix.m12.is_finite() ||
96            !matrix.m21.is_finite() ||
97            !matrix.m22.is_finite() ||
98            !matrix.m31.is_finite() ||
99            !matrix.m32.is_finite()
100        {
101            return Ok(());
102        }
103
104        // Step 3. Reset the pattern's transformation matrix to matrix.
105        *self.transform.borrow_mut() = matrix.cast();
106
107        Ok(())
108    }
109}
110
111impl ToFillOrStrokeStyle for &CanvasPattern {
112    fn to_fill_or_stroke_style(self) -> FillOrStrokeStyle {
113        FillOrStrokeStyle::Surface(SurfaceStyle::new(
114            self.surface_data.clone(),
115            self.surface_size,
116            self.repeat_x,
117            self.repeat_y,
118            *self.transform.borrow(),
119        ))
120    }
121}