1use 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 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 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 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 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 fn M11(&self) -> f64 {
153 self.upcast::<DOMMatrixReadOnly>().M11()
154 }
155
156 fn SetM11(&self, value: f64) {
158 self.upcast::<DOMMatrixReadOnly>().set_m11(value);
159 }
160
161 fn M12(&self) -> f64 {
163 self.upcast::<DOMMatrixReadOnly>().M12()
164 }
165
166 fn SetM12(&self, value: f64) {
168 self.upcast::<DOMMatrixReadOnly>().set_m12(value);
169 }
170
171 fn M13(&self) -> f64 {
173 self.upcast::<DOMMatrixReadOnly>().M13()
174 }
175
176 fn SetM13(&self, value: f64) {
178 self.upcast::<DOMMatrixReadOnly>().set_m13(value);
179 }
180
181 fn M14(&self) -> f64 {
183 self.upcast::<DOMMatrixReadOnly>().M14()
184 }
185
186 fn SetM14(&self, value: f64) {
188 self.upcast::<DOMMatrixReadOnly>().set_m14(value);
189 }
190
191 fn M21(&self) -> f64 {
193 self.upcast::<DOMMatrixReadOnly>().M21()
194 }
195
196 fn SetM21(&self, value: f64) {
198 self.upcast::<DOMMatrixReadOnly>().set_m21(value);
199 }
200
201 fn M22(&self) -> f64 {
203 self.upcast::<DOMMatrixReadOnly>().M22()
204 }
205
206 fn SetM22(&self, value: f64) {
208 self.upcast::<DOMMatrixReadOnly>().set_m22(value);
209 }
210
211 fn M23(&self) -> f64 {
213 self.upcast::<DOMMatrixReadOnly>().M23()
214 }
215
216 fn SetM23(&self, value: f64) {
218 self.upcast::<DOMMatrixReadOnly>().set_m23(value);
219 }
220
221 fn M24(&self) -> f64 {
223 self.upcast::<DOMMatrixReadOnly>().M24()
224 }
225
226 fn SetM24(&self, value: f64) {
228 self.upcast::<DOMMatrixReadOnly>().set_m24(value);
229 }
230
231 fn M31(&self) -> f64 {
233 self.upcast::<DOMMatrixReadOnly>().M31()
234 }
235
236 fn SetM31(&self, value: f64) {
238 self.upcast::<DOMMatrixReadOnly>().set_m31(value);
239 }
240
241 fn M32(&self) -> f64 {
243 self.upcast::<DOMMatrixReadOnly>().M32()
244 }
245
246 fn SetM32(&self, value: f64) {
248 self.upcast::<DOMMatrixReadOnly>().set_m32(value);
249 }
250
251 fn M33(&self) -> f64 {
253 self.upcast::<DOMMatrixReadOnly>().M33()
254 }
255
256 fn SetM33(&self, value: f64) {
258 self.upcast::<DOMMatrixReadOnly>().set_m33(value);
259 }
260
261 fn M34(&self) -> f64 {
263 self.upcast::<DOMMatrixReadOnly>().M34()
264 }
265
266 fn SetM34(&self, value: f64) {
268 self.upcast::<DOMMatrixReadOnly>().set_m34(value);
269 }
270
271 fn M41(&self) -> f64 {
273 self.upcast::<DOMMatrixReadOnly>().M41()
274 }
275
276 fn SetM41(&self, value: f64) {
278 self.upcast::<DOMMatrixReadOnly>().set_m41(value);
279 }
280
281 fn M42(&self) -> f64 {
283 self.upcast::<DOMMatrixReadOnly>().M42()
284 }
285
286 fn SetM42(&self, value: f64) {
288 self.upcast::<DOMMatrixReadOnly>().set_m42(value);
289 }
290
291 fn M43(&self) -> f64 {
293 self.upcast::<DOMMatrixReadOnly>().M43()
294 }
295
296 fn SetM43(&self, value: f64) {
298 self.upcast::<DOMMatrixReadOnly>().set_m43(value);
299 }
300
301 fn M44(&self) -> f64 {
303 self.upcast::<DOMMatrixReadOnly>().M44()
304 }
305
306 fn SetM44(&self, value: f64) {
308 self.upcast::<DOMMatrixReadOnly>().set_m44(value);
309 }
310
311 fn A(&self) -> f64 {
313 self.upcast::<DOMMatrixReadOnly>().A()
314 }
315
316 fn SetA(&self, value: f64) {
318 self.upcast::<DOMMatrixReadOnly>().set_m11(value);
319 }
320
321 fn B(&self) -> f64 {
323 self.upcast::<DOMMatrixReadOnly>().B()
324 }
325
326 fn SetB(&self, value: f64) {
328 self.upcast::<DOMMatrixReadOnly>().set_m12(value);
329 }
330
331 fn C(&self) -> f64 {
333 self.upcast::<DOMMatrixReadOnly>().C()
334 }
335
336 fn SetC(&self, value: f64) {
338 self.upcast::<DOMMatrixReadOnly>().set_m21(value);
339 }
340
341 fn D(&self) -> f64 {
343 self.upcast::<DOMMatrixReadOnly>().D()
344 }
345
346 fn SetD(&self, value: f64) {
348 self.upcast::<DOMMatrixReadOnly>().set_m22(value);
349 }
350
351 fn E(&self) -> f64 {
353 self.upcast::<DOMMatrixReadOnly>().E()
354 }
355
356 fn SetE(&self, value: f64) {
358 self.upcast::<DOMMatrixReadOnly>().set_m41(value);
359 }
360
361 fn F(&self) -> f64 {
363 self.upcast::<DOMMatrixReadOnly>().F()
364 }
365
366 fn SetF(&self, value: f64) {
368 self.upcast::<DOMMatrixReadOnly>().set_m42(value);
369 }
370
371 fn MultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
373 self.upcast::<DOMMatrixReadOnly>()
375 .multiply_self(other)
376 .and(Ok(DomRoot::from_ref(self)))
378 }
379
380 fn PreMultiplySelf(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
382 self.upcast::<DOMMatrixReadOnly>()
384 .pre_multiply_self(other)
385 .and(Ok(DomRoot::from_ref(self)))
387 }
388
389 fn TranslateSelf(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> {
391 self.upcast::<DOMMatrixReadOnly>()
393 .translate_self(tx, ty, tz);
394 DomRoot::from_ref(self)
396 }
397
398 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 self.upcast::<DOMMatrixReadOnly>()
410 .scale_self(scaleX, scaleY, scaleZ, originX, originY, originZ);
411 DomRoot::from_ref(self)
413 }
414
415 fn Scale3dSelf(
417 &self,
418 scale: f64,
419 originX: f64,
420 originY: f64,
421 originZ: f64,
422 ) -> DomRoot<DOMMatrix> {
423 self.upcast::<DOMMatrixReadOnly>()
425 .scale_3d_self(scale, originX, originY, originZ);
426 DomRoot::from_ref(self)
428 }
429
430 fn RotateSelf(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> {
432 self.upcast::<DOMMatrixReadOnly>()
434 .rotate_self(rotX, rotY, rotZ);
435 DomRoot::from_ref(self)
437 }
438
439 fn RotateFromVectorSelf(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> {
441 self.upcast::<DOMMatrixReadOnly>()
443 .rotate_from_vector_self(x, y);
444 DomRoot::from_ref(self)
446 }
447
448 fn RotateAxisAngleSelf(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> {
450 self.upcast::<DOMMatrixReadOnly>()
452 .rotate_axis_angle_self(x, y, z, angle);
453 DomRoot::from_ref(self)
455 }
456
457 fn SkewXSelf(&self, sx: f64) -> DomRoot<DOMMatrix> {
459 self.upcast::<DOMMatrixReadOnly>().skew_x_self(sx);
461 DomRoot::from_ref(self)
463 }
464
465 fn SkewYSelf(&self, sy: f64) -> DomRoot<DOMMatrix> {
467 self.upcast::<DOMMatrixReadOnly>().skew_y_self(sy);
469 DomRoot::from_ref(self)
471 }
472
473 fn InvertSelf(&self) -> DomRoot<DOMMatrix> {
475 self.upcast::<DOMMatrixReadOnly>().invert_self();
477 DomRoot::from_ref(self)
479 }
480
481 fn SetMatrixValue(&self, transformList: DOMString) -> Fallible<DomRoot<DOMMatrix>> {
483 match transform_to_matrix(transformList.to_string()) {
487 Ok(tuple) => {
488 self.parent.set_is2D(tuple.0);
490 self.parent.set_matrix(tuple.1);
492 },
493 Err(error) => return Err(error),
494 }
495
496 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}