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 http://mozilla.org/MPL/2.0/. */
4 
5 use dom::bindings::cell::DomRefCell;
6 use dom::bindings::codegen::Bindings::DOMMatrixBinding::{DOMMatrixInit, DOMMatrixMethods};
7 use dom::bindings::codegen::Bindings::DOMMatrixReadOnlyBinding::{DOMMatrixReadOnlyMethods, Wrap};
8 use dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
9 use dom::bindings::error;
10 use dom::bindings::error::Fallible;
11 use dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
12 use dom::bindings::root::DomRoot;
13 use dom::dommatrix::DOMMatrix;
14 use dom::dompoint::DOMPoint;
15 use dom::globalscope::GlobalScope;
16 use dom_struct::dom_struct;
17 use euclid::{Transform3D, Angle};
18 use std::cell::{Cell, Ref};
19 use std::f64;
20 
21 #[dom_struct]
22 pub struct DOMMatrixReadOnly {
23     reflector_: Reflector,
24     matrix: DomRefCell<Transform3D<f64>>,
25     is2D: Cell<bool>,
26 }
27 
28 impl DOMMatrixReadOnly {
29     #[allow(unrooted_must_root)]
new(global: &GlobalScope, is2D: bool, matrix: Transform3D<f64>) -> DomRoot<Self>30     pub fn new(global: &GlobalScope, is2D: bool, matrix: Transform3D<f64>) -> DomRoot<Self> {
31         let dommatrix = Self::new_inherited(is2D, matrix);
32         reflect_dom_object(Box::new(dommatrix), global, Wrap)
33     }
34 
new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self35     pub fn new_inherited(is2D: bool, matrix: Transform3D<f64>) -> Self {
36         DOMMatrixReadOnly {
37             reflector_: Reflector::new(),
38             matrix: DomRefCell::new(matrix),
39             is2D: Cell::new(is2D),
40         }
41     }
42 
43     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly
Constructor(global: &GlobalScope) -> Fallible<DomRoot<Self>>44     pub fn Constructor(global: &GlobalScope) -> Fallible<DomRoot<Self>> {
45         Ok(Self::new(global, true, Transform3D::identity()))
46     }
47 
48     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>>49     pub fn Constructor_(global: &GlobalScope, entries: Vec<f64>) -> Fallible<DomRoot<Self>> {
50         entries_to_matrix(&entries[..])
51             .map(|(is2D, matrix)| {
52                 Self::new(global, is2D, matrix)
53             })
54     }
55 
56     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-frommatrix
FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>>57     pub fn FromMatrix(global: &GlobalScope, other: &DOMMatrixInit) -> Fallible<DomRoot<Self>> {
58         dommatrixinit_to_matrix(&other)
59             .map(|(is2D, matrix)| {
60                 Self::new(global, is2D, matrix)
61             })
62     }
63 
matrix(&self) -> Ref<Transform3D<f64>>64     pub fn matrix(&self) -> Ref<Transform3D<f64>> {
65         self.matrix.borrow()
66     }
67 
is_2d(&self) -> bool68     pub fn is_2d(&self) -> bool {
69         self.is2D.get()
70     }
71 
72     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
set_m11(&self, value: f64)73     pub fn set_m11(&self, value: f64) {
74         self.matrix.borrow_mut().m11 = value;
75     }
76 
77     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m12
set_m12(&self, value: f64)78     pub fn set_m12(&self, value: f64) {
79         self.matrix.borrow_mut().m12 = value;
80     }
81 
82     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m13
set_m13(&self, value: f64)83     pub fn set_m13(&self, value: f64) {
84         self.matrix.borrow_mut().m13 = value;
85     }
86 
87     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m14
set_m14(&self, value: f64)88     pub fn set_m14(&self, value: f64) {
89         self.matrix.borrow_mut().m14 = value;
90     }
91 
92     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m21
set_m21(&self, value: f64)93     pub fn set_m21(&self, value: f64) {
94         self.matrix.borrow_mut().m21 = value;
95     }
96 
97     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m22
set_m22(&self, value: f64)98     pub fn set_m22(&self, value: f64) {
99         self.matrix.borrow_mut().m22 = value;
100     }
101 
102     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m23
set_m23(&self, value: f64)103     pub fn set_m23(&self, value: f64) {
104         self.matrix.borrow_mut().m23 = value;
105     }
106 
107     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m24
set_m24(&self, value: f64)108     pub fn set_m24(&self, value: f64) {
109         self.matrix.borrow_mut().m24 = value;
110     }
111 
112     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m31
set_m31(&self, value: f64)113     pub fn set_m31(&self, value: f64) {
114         self.matrix.borrow_mut().m31 = value;
115     }
116 
117     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m32
set_m32(&self, value: f64)118     pub fn set_m32(&self, value: f64) {
119         self.matrix.borrow_mut().m32 = value;
120     }
121 
122     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m33
set_m33(&self, value: f64)123     pub fn set_m33(&self, value: f64) {
124         self.matrix.borrow_mut().m33 = value;
125     }
126 
127     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m34
set_m34(&self, value: f64)128     pub fn set_m34(&self, value: f64) {
129         self.matrix.borrow_mut().m34 = value;
130     }
131 
132     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m41
set_m41(&self, value: f64)133     pub fn set_m41(&self, value: f64) {
134         self.matrix.borrow_mut().m41 = value;
135     }
136 
137     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m42
set_m42(&self, value: f64)138     pub fn set_m42(&self, value: f64) {
139         self.matrix.borrow_mut().m42 = value;
140     }
141 
142     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m43
set_m43(&self, value: f64)143     pub fn set_m43(&self, value: f64) {
144         self.matrix.borrow_mut().m43 = value;
145     }
146 
147     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m44
set_m44(&self, value: f64)148     pub fn set_m44(&self, value: f64) {
149         self.matrix.borrow_mut().m44 = value;
150     }
151 
152 
153     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-multiplyself
multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()>154     pub fn multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
155         // Step 1.
156         dommatrixinit_to_matrix(&other).map(|(is2D, other_matrix)| {
157             // Step 2.
158             let mut matrix = self.matrix.borrow_mut();
159             *matrix = other_matrix.post_mul(&matrix);
160             // Step 3.
161             if !is2D {
162                 self.is2D.set(false);
163             }
164             // Step 4 in DOMMatrix.MultiplySelf
165         })
166     }
167 
168     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-premultiplyself
pre_multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()>169     pub fn pre_multiply_self(&self, other: &DOMMatrixInit) -> Fallible<()> {
170         // Step 1.
171         dommatrixinit_to_matrix(&other).map(|(is2D, other_matrix)| {
172             // Step 2.
173             let mut matrix = self.matrix.borrow_mut();
174             *matrix = other_matrix.pre_mul(&matrix);
175             // Step 3.
176             if !is2D {
177                 self.is2D.set(false);
178             }
179             // Step 4 in DOMMatrix.PreMultiplySelf
180         })
181     }
182 
183     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-translateself
translate_self(&self, tx: f64, ty: f64, tz: f64)184     pub fn translate_self(&self, tx: f64, ty: f64, tz: f64) {
185         // Step 1.
186         let translation = Transform3D::create_translation(tx, ty, tz);
187         let mut matrix = self.matrix.borrow_mut();
188         *matrix = translation.post_mul(&matrix);
189         // Step 2.
190         if tz != 0.0 {
191             self.is2D.set(false);
192         }
193         // Step 3 in DOMMatrix.TranslateSelf
194     }
195 
196     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scaleself
scale_self(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64, mut originX: f64, mut originY: f64, mut originZ: f64)197     pub fn scale_self(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
198                       mut originX: f64, mut originY: f64, mut originZ: f64) {
199         // Step 1.
200         self.translate_self(originX, originY, originZ);
201         // Step 2.
202         let scaleY = scaleY.unwrap_or(scaleX);
203         // Step 3.
204         {
205             let scale3D = Transform3D::create_scale(scaleX, scaleY, scaleZ);
206             let mut matrix = self.matrix.borrow_mut();
207             *matrix = scale3D.post_mul(&matrix);
208         }
209         // Step 4.
210         originX = -originX;
211         originY = -originY;
212         originZ = -originZ;
213         // Step 5.
214         self.translate_self(originX, originY, originZ);
215         // Step 6.
216         if scaleZ != 1.0 || originZ != 0.0 {
217             self.is2D.set(false);
218         }
219         // Step 7 in DOMMatrix.ScaleSelf
220     }
221 
222     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-scale3dself
scale_3d_self(&self, scale: f64, originX: f64, originY: f64, originZ: f64)223     pub fn scale_3d_self(&self, scale: f64, originX: f64, originY: f64, originZ: f64) {
224         // Step 1.
225         self.translate_self(originX, originY, originZ);
226         // Step 2.
227         {
228             let scale3D = Transform3D::create_scale(scale, scale, scale);
229             let mut matrix = self.matrix.borrow_mut();
230             *matrix = scale3D.post_mul(&matrix);
231         }
232         // Step 3.
233         self.translate_self(-originX, -originY, -originZ);
234         // Step 4.
235         if scale != 1.0 {
236             self.is2D.set(false);
237         }
238         // Step 5 in DOMMatrix.Scale3dSelf
239     }
240 
241     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateself
rotate_self(&self, mut rotX: f64, mut rotY: Option<f64>, mut rotZ: Option<f64>)242     pub fn rotate_self(&self, mut rotX: f64, mut rotY: Option<f64>, mut rotZ: Option<f64>) {
243         // Step 1.
244         if rotY.is_none() && rotZ.is_none() {
245             rotZ = Some(rotX);
246             rotX = 0.0;
247             rotY = Some(0.0);
248         }
249         // Step 2.
250         let rotY = rotY.unwrap_or(0.0);
251         // Step 3.
252         let rotZ = rotZ.unwrap_or(0.0);
253         // Step 4.
254         if rotX != 0.0 || rotY != 0.0 {
255             self.is2D.set(false);
256         }
257         if rotZ != 0.0 {
258             // Step 5.
259             let rotation = Transform3D::create_rotation(0.0, 0.0, 1.0, Angle::radians(rotZ.to_radians()));
260             let mut matrix = self.matrix.borrow_mut();
261             *matrix = rotation.post_mul(&matrix);
262         }
263         if rotY != 0.0 {
264             // Step 6.
265             let rotation = Transform3D::create_rotation(0.0, 1.0, 0.0, Angle::radians(rotY.to_radians()));
266             let mut matrix = self.matrix.borrow_mut();
267             *matrix = rotation.post_mul(&matrix);
268         }
269         if rotX != 0.0 {
270             // Step 7.
271             let rotation = Transform3D::create_rotation(1.0, 0.0, 0.0, Angle::radians(rotX.to_radians()));
272             let mut matrix = self.matrix.borrow_mut();
273             *matrix = rotation.post_mul(&matrix);
274         }
275         // Step 8 in DOMMatrix.RotateSelf
276     }
277 
278     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotatefromvectorself
rotate_from_vector_self(&self, x: f64, y: f64)279     pub fn rotate_from_vector_self(&self, x: f64, y: f64) {
280         // don't do anything when the rotation angle is zero or undefined
281         if y != 0.0 || x < 0.0 {
282             // Step 1.
283             let rotZ = Angle::radians(f64::atan2(y, x));
284             let rotation = Transform3D::create_rotation(0.0, 0.0, 1.0, rotZ);
285             let mut matrix = self.matrix.borrow_mut();
286             *matrix = rotation.post_mul(&matrix);
287         }
288         // Step 2 in DOMMatrix.RotateFromVectorSelf
289     }
290 
291     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-rotateaxisangleself
rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64)292     pub fn rotate_axis_angle_self(&self, x: f64, y: f64, z: f64, angle: f64) {
293         // Step 1.
294         let (norm_x, norm_y, norm_z) = normalize_point(x, y, z);
295         let rotation = Transform3D::create_rotation(norm_x, norm_y, norm_z, Angle::radians(angle.to_radians()));
296         let mut matrix = self.matrix.borrow_mut();
297         *matrix = rotation.post_mul(&matrix);
298         // Step 2.
299         if x != 0.0 || y != 0.0 {
300             self.is2D.set(false);
301         }
302         // Step 3 in DOMMatrix.RotateAxisAngleSelf
303     }
304 
305     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-skewxself
skew_x_self(&self, sx: f64)306     pub fn skew_x_self(&self, sx: f64) {
307         // Step 1.
308         let skew = Transform3D::create_skew(Angle::radians(sx.to_radians()), Angle::radians(0.0));
309         let mut matrix = self.matrix.borrow_mut();
310         *matrix = skew.post_mul(&matrix);
311         // Step 2 in DOMMatrix.SkewXSelf
312     }
313 
314     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-skewyself
skew_y_self(&self, sy: f64)315     pub fn skew_y_self(&self, sy: f64) {
316         // Step 1.
317         let skew = Transform3D::create_skew(Angle::radians(0.0), Angle::radians(sy.to_radians()));
318         let mut matrix = self.matrix.borrow_mut();
319         *matrix = skew.post_mul(&matrix);
320         // Step 2 in DOMMatrix.SkewYSelf
321     }
322 
323     // https://drafts.fxtf.org/geometry-1/#dom-dommatrix-invertself
invert_self(&self)324     pub fn invert_self(&self) {
325         let mut matrix = self.matrix.borrow_mut();
326         // Step 1.
327         *matrix = matrix.inverse().unwrap_or_else(|| {
328             // Step 2.
329             self.is2D.set(false);
330             Transform3D::row_major(f64::NAN, f64::NAN, f64::NAN, f64::NAN,
331                                 f64::NAN, f64::NAN, f64::NAN, f64::NAN,
332                                 f64::NAN, f64::NAN, f64::NAN, f64::NAN,
333                                 f64::NAN, f64::NAN, f64::NAN, f64::NAN)
334         })
335         // Step 3 in DOMMatrix.InvertSelf
336     }
337 }
338 
339 
340 impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
341     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m11
M11(&self) -> f64342     fn M11(&self) -> f64 {
343         self.matrix.borrow().m11
344     }
345 
346     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m12
M12(&self) -> f64347     fn M12(&self) -> f64 {
348         self.matrix.borrow().m12
349     }
350 
351     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m13
M13(&self) -> f64352     fn M13(&self) -> f64 {
353         self.matrix.borrow().m13
354     }
355 
356     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m14
M14(&self) -> f64357     fn M14(&self) -> f64 {
358         self.matrix.borrow().m14
359     }
360 
361     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m21
M21(&self) -> f64362     fn M21(&self) -> f64 {
363         self.matrix.borrow().m21
364     }
365 
366     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m22
M22(&self) -> f64367     fn M22(&self) -> f64 {
368         self.matrix.borrow().m22
369     }
370 
371     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m23
M23(&self) -> f64372     fn M23(&self) -> f64 {
373         self.matrix.borrow().m23
374     }
375 
376     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m24
M24(&self) -> f64377     fn M24(&self) -> f64 {
378         self.matrix.borrow().m24
379     }
380 
381     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m31
M31(&self) -> f64382     fn M31(&self) -> f64 {
383         self.matrix.borrow().m31
384     }
385 
386     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m32
M32(&self) -> f64387     fn M32(&self) -> f64 {
388         self.matrix.borrow().m32
389     }
390 
391     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m33
M33(&self) -> f64392     fn M33(&self) -> f64 {
393         self.matrix.borrow().m33
394     }
395 
396     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m34
M34(&self) -> f64397     fn M34(&self) -> f64 {
398         self.matrix.borrow().m34
399     }
400 
401     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m41
M41(&self) -> f64402     fn M41(&self) -> f64 {
403         self.matrix.borrow().m41
404     }
405 
406     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m42
M42(&self) -> f64407     fn M42(&self) -> f64 {
408         self.matrix.borrow().m42
409     }
410 
411     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m43
M43(&self) -> f64412     fn M43(&self) -> f64 {
413         self.matrix.borrow().m43
414     }
415 
416     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-m44
M44(&self) -> f64417     fn M44(&self) -> f64 {
418         self.matrix.borrow().m44
419     }
420 
421     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-a
A(&self) -> f64422     fn A(&self) -> f64 {
423         self.M11()
424     }
425 
426     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-b
B(&self) -> f64427     fn B(&self) -> f64 {
428         self.M12()
429     }
430 
431     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-c
C(&self) -> f64432     fn C(&self) -> f64 {
433         self.M21()
434     }
435 
436     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-d
D(&self) -> f64437     fn D(&self) -> f64 {
438         self.M22()
439     }
440 
441     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-e
E(&self) -> f64442     fn E(&self) -> f64 {
443         self.M41()
444     }
445 
446     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-f
F(&self) -> f64447     fn F(&self) -> f64 {
448         self.M42()
449     }
450 
451     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-is2d
Is2D(&self) -> bool452     fn Is2D(&self) -> bool {
453         self.is2D.get()
454     }
455 
456     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-isidentity
IsIdentity(&self) -> bool457     fn IsIdentity(&self) -> bool {
458         let matrix = self.matrix.borrow();
459         matrix.m12 == 0.0 && matrix.m13 == 0.0 && matrix.m14 == 0.0 && matrix.m21 == 0.0 &&
460             matrix.m23 == 0.0 && matrix.m24 == 0.0 && matrix.m31 == 0.0 && matrix.m32 == 0.0 &&
461             matrix.m34 == 0.0 && matrix.m41 == 0.0 && matrix.m42 == 0.0 && matrix.m43 == 0.0 &&
462             matrix.m11 == 1.0 && matrix.m22 == 1.0 && matrix.m33 == 1.0 && matrix.m44 == 1.0
463     }
464 
465     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-translate
Translate(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix>466     fn Translate(&self, tx: f64, ty: f64, tz: f64) -> DomRoot<DOMMatrix> {
467         DOMMatrix::from_readonly(&self.global(), self).TranslateSelf(tx, ty, tz)
468     }
469 
470     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale
Scale(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix>471     fn Scale(&self, scaleX: f64, scaleY: Option<f64>, scaleZ: f64,
472                     originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
473         DOMMatrix::from_readonly(&self.global(), self)
474             .ScaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
475     }
476 
477     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-scale3d
Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix>478     fn Scale3d(&self, scale: f64, originX: f64, originY: f64, originZ: f64) -> DomRoot<DOMMatrix> {
479         DOMMatrix::from_readonly(&self.global(), self)
480             .Scale3dSelf(scale, originX, originY, originZ)
481     }
482 
483     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotate
Rotate(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix>484     fn Rotate(&self, rotX: f64, rotY: Option<f64>, rotZ: Option<f64>) -> DomRoot<DOMMatrix> {
485         DOMMatrix::from_readonly(&self.global(), self).RotateSelf(rotX, rotY, rotZ)
486     }
487 
488     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotatefromvector
RotateFromVector(&self, x: f64, y: f64) -> DomRoot<DOMMatrix>489     fn RotateFromVector(&self, x: f64, y: f64) -> DomRoot<DOMMatrix> {
490         DOMMatrix::from_readonly(&self.global(), self).RotateFromVectorSelf(x, y)
491     }
492 
493     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-rotateaxisangle
RotateAxisAngle(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix>494     fn RotateAxisAngle(&self, x: f64, y: f64, z: f64, angle: f64) -> DomRoot<DOMMatrix> {
495         DOMMatrix::from_readonly(&self.global(), self).RotateAxisAngleSelf(x, y, z, angle)
496     }
497 
498     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-skewx
SkewX(&self, sx: f64) -> DomRoot<DOMMatrix>499     fn SkewX(&self, sx: f64) -> DomRoot<DOMMatrix> {
500         DOMMatrix::from_readonly(&self.global(), self).SkewXSelf(sx)
501     }
502 
503     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-skewy
SkewY(&self, sy: f64) -> DomRoot<DOMMatrix>504     fn SkewY(&self, sy: f64) -> DomRoot<DOMMatrix> {
505         DOMMatrix::from_readonly(&self.global(), self).SkewYSelf(sy)
506     }
507 
508     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-multiply
Multiply(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>>509     fn Multiply(&self, other: &DOMMatrixInit) -> Fallible<DomRoot<DOMMatrix>> {
510         DOMMatrix::from_readonly(&self.global(), self).MultiplySelf(&other)
511     }
512 
513     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipx
FlipX(&self) -> DomRoot<DOMMatrix>514     fn FlipX(&self) -> DomRoot<DOMMatrix> {
515         let is2D = self.is2D.get();
516         let flip = Transform3D::row_major(-1.0, 0.0, 0.0, 0.0,
517                                         0.0, 1.0, 0.0, 0.0,
518                                         0.0, 0.0, 1.0, 0.0,
519                                         0.0, 0.0, 0.0, 1.0);
520         let matrix = flip.post_mul(&self.matrix.borrow());
521         DOMMatrix::new(&self.global(), is2D, matrix)
522     }
523 
524     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-flipy
FlipY(&self) -> DomRoot<DOMMatrix>525     fn FlipY(&self) -> DomRoot<DOMMatrix> {
526         let is2D = self.is2D.get();
527         let flip = Transform3D::row_major(1.0,  0.0, 0.0, 0.0,
528                                        0.0, -1.0, 0.0, 0.0,
529                                        0.0,  0.0, 1.0, 0.0,
530                                        0.0,  0.0, 0.0, 1.0);
531         let matrix = flip.post_mul(&self.matrix.borrow());
532         DOMMatrix::new(&self.global(), is2D, matrix)
533     }
534 
535     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-inverse
Inverse(&self) -> DomRoot<DOMMatrix>536     fn Inverse(&self) -> DomRoot<DOMMatrix> {
537         DOMMatrix::from_readonly(&self.global(), self).InvertSelf()
538     }
539 
540     // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-transformpoint
TransformPoint(&self, point: &DOMPointInit) -> DomRoot<DOMPoint>541     fn TransformPoint(&self, point: &DOMPointInit) -> DomRoot<DOMPoint> {
542         // Euclid always normalizes the homogeneous coordinate which is usually the right
543         // thing but may (?) not be compliant with the CSS matrix spec (or at least is
544         // probably not the behavior web authors will expect even if it is mathematically
545         // correct in the context of geometry computations).
546         // Since this is the only place where this is needed, better implement it here
547         // than in euclid (which does not have a notion of 4d points).
548         let mat = self.matrix.borrow();
549         let x = point.x * mat.m11 + point.y * mat.m21 + point.z * mat.m31 + point.w * mat.m41;
550         let y = point.x * mat.m12 + point.y * mat.m22 + point.z * mat.m32 + point.w * mat.m42;
551         let z = point.x * mat.m13 + point.y * mat.m23 + point.z * mat.m33 + point.w * mat.m43;
552         let w = point.x * mat.m14 + point.y * mat.m24 + point.z * mat.m34 + point.w * mat.m44;
553 
554         DOMPoint::new(&self.global(), x, y, z, w)
555     }
556 }
557 
558 
559 // https://drafts.fxtf.org/geometry-1/#create-a-2d-matrix
create_2d_matrix(entries: &[f64]) -> Transform3D<f64>560 fn create_2d_matrix(entries: &[f64]) -> Transform3D<f64> {
561     Transform3D::row_major(entries[0], entries[1], 0.0, 0.0,
562                         entries[2], entries[3], 0.0, 0.0,
563                         0.0,        0.0,        1.0, 0.0,
564                         entries[4], entries[5], 0.0, 1.0)
565 }
566 
567 
568 // https://drafts.fxtf.org/geometry-1/#create-a-3d-matrix
create_3d_matrix(entries: &[f64]) -> Transform3D<f64>569 fn create_3d_matrix(entries: &[f64]) -> Transform3D<f64> {
570     Transform3D::row_major(entries[0],  entries[1],  entries[2],  entries[3],
571                         entries[4],  entries[5],  entries[6],  entries[7],
572                         entries[8],  entries[9],  entries[10], entries[11],
573                         entries[12], entries[13], entries[14], entries[15])
574 }
575 
576 // https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-dommatrixreadonly-numbersequence
entries_to_matrix(entries: &[f64]) -> Fallible<(bool, Transform3D<f64>)>577 pub fn entries_to_matrix(entries: &[f64]) -> Fallible<(bool, Transform3D<f64>)> {
578     if entries.len() == 6 {
579         Ok((true, create_2d_matrix(&entries)))
580     } else if entries.len() == 16 {
581         Ok((false, create_3d_matrix(&entries)))
582     } else {
583         let err_msg = format!("Expected 6 or 16 entries, but found {}.", entries.len());
584         Err(error::Error::Type(err_msg.to_owned()))
585     }
586 }
587 
588 
589 // https://drafts.fxtf.org/geometry-1/#validate-and-fixup
dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)>590 pub fn dommatrixinit_to_matrix(dict: &DOMMatrixInit) -> Fallible<(bool, Transform3D<f64>)> {
591     // Step 1.
592     if dict.a.is_some() && dict.m11.is_some() && dict.a.unwrap() != dict.m11.unwrap() ||
593        dict.b.is_some() && dict.m12.is_some() && dict.b.unwrap() != dict.m12.unwrap() ||
594        dict.c.is_some() && dict.m21.is_some() && dict.c.unwrap() != dict.m21.unwrap() ||
595        dict.d.is_some() && dict.m22.is_some() && dict.d.unwrap() != dict.m22.unwrap() ||
596        dict.e.is_some() && dict.m41.is_some() && dict.e.unwrap() != dict.m41.unwrap() ||
597        dict.f.is_some() && dict.m42.is_some() && dict.f.unwrap() != dict.m42.unwrap() ||
598        dict.is2D.is_some() && dict.is2D.unwrap() &&
599        (dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 || dict.m23 != 0.0 ||
600         dict.m43 != 0.0 || dict.m14 != 0.0 || dict.m24 != 0.0 || dict.m34 != 0.0 ||
601         dict.m33 != 1.0 || dict.m44 != 1.0) {
602             Err(error::Error::Type("Invalid matrix initializer.".to_owned()))
603     } else {
604         let mut is2D = dict.is2D;
605         // Step 2.
606         let m11 = dict.m11.unwrap_or(dict.a.unwrap_or(1.0));
607         // Step 3.
608         let m12 = dict.m12.unwrap_or(dict.b.unwrap_or(0.0));
609         // Step 4.
610         let m21 = dict.m21.unwrap_or(dict.c.unwrap_or(0.0));
611         // Step 5.
612         let m22 = dict.m22.unwrap_or(dict.d.unwrap_or(1.0));
613         // Step 6.
614         let m41 = dict.m41.unwrap_or(dict.e.unwrap_or(0.0));
615         // Step 7.
616         let m42 = dict.m42.unwrap_or(dict.f.unwrap_or(0.0));
617         // Step 8.
618         if is2D.is_none() &&
619             (dict.m31 != 0.0 || dict.m32 != 0.0 || dict.m13 != 0.0 ||
620              dict.m23 != 0.0 || dict.m43 != 0.0 || dict.m14 != 0.0 ||
621              dict.m24 != 0.0 || dict.m34 != 0.0 ||
622              dict.m33 != 1.0 || dict.m44 != 1.0) {
623                  is2D = Some(false);
624         }
625         // Step 9.
626         if is2D.is_none() {
627             is2D = Some(true);
628         }
629         let matrix = Transform3D::row_major(m11,      m12,      dict.m13, dict.m14,
630                                          m21,      m22,      dict.m23, dict.m24,
631                                          dict.m31, dict.m32, dict.m33, dict.m34,
632                                          m41,      m42,      dict.m43, dict.m44);
633         Ok((is2D.unwrap(), matrix))
634     }
635 }
636 
637 
638 #[inline]
normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64)639 fn normalize_point(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
640     let len = (x * x + y * y + z * z).sqrt();
641     if len == 0.0 {
642         (0.0, 0.0, 0.0)
643     } else {
644         (x / len, y / len, z / len)
645     }
646 }
647