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}