script/dom/
dommatrix.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::id::{DomMatrixId, DomMatrixIndex};
6use constellation_traits::DomMatrix;
7use dom_struct::dom_struct;
8use euclid::default::Transform3D;
9use js::rust::{CustomAutoRooterGuard, HandleObject};
10use js::typedarray::{Float32Array, Float64Array};
11use rustc_hash::FxHashMap;
12use script_bindings::str::DOMString;
13
14use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::{DOMMatrixInit, DOMMatrixMethods};
15use crate::dom::bindings::codegen::Bindings::DOMMatrixReadOnlyBinding::DOMMatrixReadOnlyMethods;
16use crate::dom::bindings::codegen::UnionTypes::StringOrUnrestrictedDoubleSequence;
17use crate::dom::bindings::error;
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::inheritance::Castable;
20use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::serializable::Serializable;
23use crate::dom::bindings::structuredclone::StructuredData;
24use crate::dom::dommatrixreadonly::{
25    DOMMatrixReadOnly, dommatrixinit_to_matrix, entries_to_matrix, transform_to_matrix,
26};
27use crate::dom::globalscope::GlobalScope;
28use crate::dom::window::Window;
29use crate::script_runtime::CanGc;
30
31#[dom_struct]
32pub(crate) struct DOMMatrix {
33    parent: DOMMatrixReadOnly,
34}
35
36#[allow(non_snake_case)]
37impl DOMMatrix {
38    pub(crate) fn new(
39        global: &GlobalScope,
40        is2D: bool,
41        matrix: Transform3D<f64>,
42        can_gc: CanGc,
43    ) -> DomRoot<Self> {
44        Self::new_with_proto(global, None, is2D, matrix, can_gc)
45    }
46
47    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
48    fn new_with_proto(
49        global: &GlobalScope,
50        proto: Option<HandleObject>,
51        is2D: bool,
52        matrix: Transform3D<f64>,
53        can_gc: CanGc,
54    ) -> DomRoot<Self> {
55        let dommatrix = Self::new_inherited(is2D, matrix);
56        reflect_dom_object_with_proto(Box::new(dommatrix), global, proto, can_gc)
57    }
58
59    pub(crate) fn new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self {
60        DOMMatrix {
61            parent: DOMMatrixReadOnly::new_inherited(is2D, matrix),
62        }
63    }
64
65    pub(crate) fn from_readonly(
66        global: &GlobalScope,
67        ro: &DOMMatrixReadOnly,
68        can_gc: CanGc,
69    ) -> DomRoot<Self> {
70        Self::new(global, ro.is2D(), *ro.matrix(), can_gc)
71    }
72}
73
74#[allow(non_snake_case)]
75impl DOMMatrixMethods<crate::DomTypeHolder> for DOMMatrix {
76    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly
77    fn Constructor(
78        global: &GlobalScope,
79        proto: Option<HandleObject>,
80        can_gc: CanGc,
81        init: Option<StringOrUnrestrictedDoubleSequence>,
82    ) -> Fallible<DomRoot<Self>> {
83        if init.is_none() {
84            return Ok(Self::new_with_proto(
85                global,
86                proto,
87                true,
88                Transform3D::identity(),
89                can_gc,
90            ));
91        }
92        match init.unwrap() {
93            StringOrUnrestrictedDoubleSequence::String(ref s) => {
94                if !global.is::<Window>() {
95                    return Err(error::Error::Type(
96                        "String constructor is only supported in the main thread.".to_owned(),
97                    ));
98                }
99                if s.is_empty() {
100                    return Ok(Self::new(global, true, Transform3D::identity(), can_gc));
101                }
102                transform_to_matrix(s.to_string())
103                    .map(|(is2D, matrix)| Self::new_with_proto(global, proto, is2D, matrix, can_gc))
104            },
105            StringOrUnrestrictedDoubleSequence::UnrestrictedDoubleSequence(ref entries) => {
106                entries_to_matrix(&entries[..])
107                    .map(|(is2D, matrix)| Self::new_with_proto(global, proto, is2D, matrix, can_gc))
108            },
109        }
110    }
111
112    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-frommatrix
113    fn FromMatrix(
114        global: &GlobalScope,
115        other: &DOMMatrixInit,
116        can_gc: CanGc,
117    ) -> Fallible<DomRoot<Self>> {
118        dommatrixinit_to_matrix(other).map(|(is2D, matrix)| Self::new(global, is2D, matrix, can_gc))
119    }
120
121    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-fromfloat32array
122    fn FromFloat32Array(
123        global: &GlobalScope,
124        array: CustomAutoRooterGuard<Float32Array>,
125        can_gc: CanGc,
126    ) -> Fallible<DomRoot<DOMMatrix>> {
127        let vec: Vec<f64> = array.to_vec().iter().map(|&x| x as f64).collect();
128        DOMMatrix::Constructor(
129            global,
130            None,
131            can_gc,
132            Some(StringOrUnrestrictedDoubleSequence::UnrestrictedDoubleSequence(vec)),
133        )
134    }
135
136    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-fromfloat64array
137    fn FromFloat64Array(
138        global: &GlobalScope,
139        array: CustomAutoRooterGuard<Float64Array>,
140        can_gc: CanGc,
141    ) -> Fallible<DomRoot<DOMMatrix>> {
142        let vec: Vec<f64> = array.to_vec();
143        DOMMatrix::Constructor(
144            global,
145            None,
146            can_gc,
147            Some(StringOrUnrestrictedDoubleSequence::UnrestrictedDoubleSequence(vec)),
148        )
149    }
150
151    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
152    fn M11(&self) -> f64 {
153        self.upcast::<DOMMatrixReadOnly>().M11()
154    }
155
156    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
157    fn SetM11(&self, value: f64) {
158        self.upcast::<DOMMatrixReadOnly>().set_m11(value);
159    }
160
161    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m12
162    fn M12(&self) -> f64 {
163        self.upcast::<DOMMatrixReadOnly>().M12()
164    }
165
166    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m12
167    fn SetM12(&self, value: f64) {
168        self.upcast::<DOMMatrixReadOnly>().set_m12(value);
169    }
170
171    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m13
172    fn M13(&self) -> f64 {
173        self.upcast::<DOMMatrixReadOnly>().M13()
174    }
175
176    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m13
177    fn SetM13(&self, value: f64) {
178        self.upcast::<DOMMatrixReadOnly>().set_m13(value);
179    }
180
181    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m14
182    fn M14(&self) -> f64 {
183        self.upcast::<DOMMatrixReadOnly>().M14()
184    }
185
186    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m14
187    fn SetM14(&self, value: f64) {
188        self.upcast::<DOMMatrixReadOnly>().set_m14(value);
189    }
190
191    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m21
192    fn M21(&self) -> f64 {
193        self.upcast::<DOMMatrixReadOnly>().M21()
194    }
195
196    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m21
197    fn SetM21(&self, value: f64) {
198        self.upcast::<DOMMatrixReadOnly>().set_m21(value);
199    }
200
201    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m22
202    fn M22(&self) -> f64 {
203        self.upcast::<DOMMatrixReadOnly>().M22()
204    }
205
206    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m22
207    fn SetM22(&self, value: f64) {
208        self.upcast::<DOMMatrixReadOnly>().set_m22(value);
209    }
210
211    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m23
212    fn M23(&self) -> f64 {
213        self.upcast::<DOMMatrixReadOnly>().M23()
214    }
215
216    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m23
217    fn SetM23(&self, value: f64) {
218        self.upcast::<DOMMatrixReadOnly>().set_m23(value);
219    }
220
221    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m24
222    fn M24(&self) -> f64 {
223        self.upcast::<DOMMatrixReadOnly>().M24()
224    }
225
226    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m24
227    fn SetM24(&self, value: f64) {
228        self.upcast::<DOMMatrixReadOnly>().set_m24(value);
229    }
230
231    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m31
232    fn M31(&self) -> f64 {
233        self.upcast::<DOMMatrixReadOnly>().M31()
234    }
235
236    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m31
237    fn SetM31(&self, value: f64) {
238        self.upcast::<DOMMatrixReadOnly>().set_m31(value);
239    }
240
241    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m32
242    fn M32(&self) -> f64 {
243        self.upcast::<DOMMatrixReadOnly>().M32()
244    }
245
246    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m32
247    fn SetM32(&self, value: f64) {
248        self.upcast::<DOMMatrixReadOnly>().set_m32(value);
249    }
250
251    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m33
252    fn M33(&self) -> f64 {
253        self.upcast::<DOMMatrixReadOnly>().M33()
254    }
255
256    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m33
257    fn SetM33(&self, value: f64) {
258        self.upcast::<DOMMatrixReadOnly>().set_m33(value);
259    }
260
261    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m34
262    fn M34(&self) -> f64 {
263        self.upcast::<DOMMatrixReadOnly>().M34()
264    }
265
266    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m34
267    fn SetM34(&self, value: f64) {
268        self.upcast::<DOMMatrixReadOnly>().set_m34(value);
269    }
270
271    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m41
272    fn M41(&self) -> f64 {
273        self.upcast::<DOMMatrixReadOnly>().M41()
274    }
275
276    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m41
277    fn SetM41(&self, value: f64) {
278        self.upcast::<DOMMatrixReadOnly>().set_m41(value);
279    }
280
281    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m42
282    fn M42(&self) -> f64 {
283        self.upcast::<DOMMatrixReadOnly>().M42()
284    }
285
286    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m42
287    fn SetM42(&self, value: f64) {
288        self.upcast::<DOMMatrixReadOnly>().set_m42(value);
289    }
290
291    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m43
292    fn M43(&self) -> f64 {
293        self.upcast::<DOMMatrixReadOnly>().M43()
294    }
295
296    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m43
297    fn SetM43(&self, value: f64) {
298        self.upcast::<DOMMatrixReadOnly>().set_m43(value);
299    }
300
301    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m44
302    fn M44(&self) -> f64 {
303        self.upcast::<DOMMatrixReadOnly>().M44()
304    }
305
306    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m44
307    fn SetM44(&self, value: f64) {
308        self.upcast::<DOMMatrixReadOnly>().set_m44(value);
309    }
310
311    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-a
312    fn A(&self) -> f64 {
313        self.upcast::<DOMMatrixReadOnly>().A()
314    }
315
316    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-a
317    fn SetA(&self, value: f64) {
318        self.upcast::<DOMMatrixReadOnly>().set_m11(value);
319    }
320
321    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-b
322    fn B(&self) -> f64 {
323        self.upcast::<DOMMatrixReadOnly>().B()
324    }
325
326    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-b
327    fn SetB(&self, value: f64) {
328        self.upcast::<DOMMatrixReadOnly>().set_m12(value);
329    }
330
331    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-c
332    fn C(&self) -> f64 {
333        self.upcast::<DOMMatrixReadOnly>().C()
334    }
335
336    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-c
337    fn SetC(&self, value: f64) {
338        self.upcast::<DOMMatrixReadOnly>().set_m21(value);
339    }
340
341    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-d
342    fn D(&self) -> f64 {
343        self.upcast::<DOMMatrixReadOnly>().D()
344    }
345
346    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-d
347    fn SetD(&self, value: f64) {
348        self.upcast::<DOMMatrixReadOnly>().set_m22(value);
349    }
350
351    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-e
352    fn E(&self) -> f64 {
353        self.upcast::<DOMMatrixReadOnly>().E()
354    }
355
356    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-e
357    fn SetE(&self, value: f64) {
358        self.upcast::<DOMMatrixReadOnly>().set_m41(value);
359    }
360
361    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-f
362    fn F(&self) -> f64 {
363        self.upcast::<DOMMatrixReadOnly>().F()
364    }
365
366    // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-f
367    fn SetF(&self, value: f64) {
368        self.upcast::<DOMMatrixReadOnly>().set_m42(value);
369    }
370
371    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
372    fn MultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
373        // Steps 1-3.
374        self.upcast::<DOMMatrixReadOnly>()
375            .multiply_self(other)
376            // Step 4.
377            .and(Ok(DomRoot::from_ref(self)))
378    }
379
380    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-premultiplyself
381    fn PreMultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
382        // Steps 1-3.
383        self.upcast::<DOMMatrixReadOnly>()
384            .pre_multiply_self(other)
385            // Step 4.
386            .and(Ok(DomRoot::from_ref(self)))
387    }
388
389    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-translateself
390    fn TranslateSelf(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> {
391        // Steps 1-2.
392        self.upcast::<DOMMatrixReadOnly>()
393            .translate_self(tx, ty, tz);
394        // Step 3.
395        DomRoot::from_ref(self)
396    }
397
398    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
399    fn ScaleSelf(
400        &self,
401        scaleX: f64,
402        scaleY: Option<f64>,
403        scaleZ: f64,
404        originX: f64,
405        originY: f64,
406        originZ: f64,
407    ) -> DomRoot<DOMMatrix> {
408        // Steps 1-6.
409        self.upcast::<DOMMatrixReadOnly>()
410            .scale_self(scaleX, scaleY, scaleZ, originX, originY, originZ);
411        // Step 7.
412        DomRoot::from_ref(self)
413    }
414
415    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scale3dself
416    fn Scale3dSelf(
417        &self,
418        scale: f64,
419        originX: f64,
420        originY: f64,
421        originZ: f64,
422    ) -> DomRoot<DOMMatrix> {
423        // Steps 1-4.
424        self.upcast::<DOMMatrixReadOnly>()
425            .scale_3d_self(scale, originX, originY, originZ);
426        // Step 5.
427        DomRoot::from_ref(self)
428    }
429
430    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateself
431    fn RotateSelf(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> {
432        // Steps 1-7.
433        self.upcast::<DOMMatrixReadOnly>()
434            .rotate_self(rotX, rotY, rotZ);
435        // Step 8.
436        DomRoot::from_ref(self)
437    }
438
439    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotatefromvectorself
440    fn RotateFromVectorSelf(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> {
441        // Step 1.
442        self.upcast::<DOMMatrixReadOnly>()
443            .rotate_from_vector_self(x, y);
444        // Step 2.
445        DomRoot::from_ref(self)
446    }
447
448    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateaxisangleself
449    fn RotateAxisAngleSelf(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> {
450        // Steps 1-2.
451        self.upcast::<DOMMatrixReadOnly>()
452            .rotate_axis_angle_self(x, y, z, angle);
453        // Step 3.
454        DomRoot::from_ref(self)
455    }
456
457    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-skewxself
458    fn SkewXSelf(&self, sx: f64) -> DomRoot<DOMMatrix> {
459        // Step 1.
460        self.upcast::<DOMMatrixReadOnly>().skew_x_self(sx);
461        // Step 2.
462        DomRoot::from_ref(self)
463    }
464
465    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-skewyself
466    fn SkewYSelf(&self, sy: f64) -> DomRoot<DOMMatrix> {
467        // Step 1.
468        self.upcast::<DOMMatrixReadOnly>().skew_y_self(sy);
469        // Step 2.
470        DomRoot::from_ref(self)
471    }
472
473    // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-invertself
474    fn InvertSelf(&self) -> DomRoot<DOMMatrix> {
475        // Steps 1-2.
476        self.upcast::<DOMMatrixReadOnly>().invert_self();
477        // Step 3.
478        DomRoot::from_ref(self)
479    }
480
481    /// <https://drafts.fxtf.org/geometry-1/#dom-dommatrix-setmatrixvalue>
482    fn SetMatrixValue(&self, transformList: DOMString) -> Fallible<DomRoot<DOMMatrix>> {
483        // 1. Parse transformList into an abstract matrix, and let
484        // matrix and 2dTransform be the result. If the result is failure,
485        // then throw a "SyntaxError" DOMException.
486        match transform_to_matrix(transformList.to_string()) {
487            Ok(tuple) => {
488                // 2. Set is 2D to the value of 2dTransform.
489                self.parent.set_is2D(tuple.0);
490                // 3. Set m11 element through m44 element to the element values of matrix in column-major order.
491                self.parent.set_matrix(tuple.1);
492            },
493            Err(error) => return Err(error),
494        }
495
496        // 4. Return the current matrix.
497        Ok(DomRoot::from_ref(self))
498    }
499}
500
501impl Serializable for DOMMatrix {
502    type Index = DomMatrixIndex;
503    type Data = DomMatrix;
504
505    fn serialize(&self) -> Result<(DomMatrixId, Self::Data), ()> {
506        let serialized = if self.parent.is2D() {
507            DomMatrix {
508                matrix: Transform3D::new(
509                    self.M11(),
510                    self.M12(),
511                    f64::NAN,
512                    f64::NAN,
513                    self.M21(),
514                    self.M22(),
515                    f64::NAN,
516                    f64::NAN,
517                    f64::NAN,
518                    f64::NAN,
519                    f64::NAN,
520                    f64::NAN,
521                    self.M41(),
522                    self.M42(),
523                    f64::NAN,
524                    f64::NAN,
525                ),
526                is_2d: true,
527            }
528        } else {
529            DomMatrix {
530                matrix: *self.parent.matrix(),
531                is_2d: false,
532            }
533        };
534        Ok((DomMatrixId::new(), serialized))
535    }
536
537    fn deserialize(
538        owner: &GlobalScope,
539        serialized: Self::Data,
540        can_gc: CanGc,
541    ) -> Result<DomRoot<Self>, ()>
542    where
543        Self: Sized,
544    {
545        if serialized.is_2d {
546            Ok(Self::new(
547                owner,
548                true,
549                Transform3D::new(
550                    serialized.matrix.m11,
551                    serialized.matrix.m12,
552                    0.0,
553                    0.0,
554                    serialized.matrix.m21,
555                    serialized.matrix.m22,
556                    0.0,
557                    0.0,
558                    0.0,
559                    0.0,
560                    1.0,
561                    0.0,
562                    serialized.matrix.m41,
563                    serialized.matrix.m42,
564                    0.0,
565                    1.0,
566                ),
567                can_gc,
568            ))
569        } else {
570            Ok(Self::new(owner, false, serialized.matrix, can_gc))
571        }
572    }
573
574    fn serialized_storage<'a>(
575        data: StructuredData<'a, '_>,
576    ) -> &'a mut Option<FxHashMap<DomMatrixId, Self::Data>> {
577        match data {
578            StructuredData::Reader(reader) => &mut reader.matrices,
579            StructuredData::Writer(writer) => &mut writer.matrices,
580        }
581    }
582}