View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.dom;
16  
17  import org.htmlunit.corejs.javascript.Context;
18  import org.htmlunit.corejs.javascript.Function;
19  import org.htmlunit.corejs.javascript.VarScope;
20  import org.htmlunit.javascript.configuration.JsxClass;
21  import org.htmlunit.javascript.configuration.JsxConstructor;
22  import org.htmlunit.javascript.configuration.JsxConstructorAlias;
23  import org.htmlunit.javascript.configuration.JsxFunction;
24  import org.htmlunit.javascript.configuration.JsxGetter;
25  import org.htmlunit.javascript.configuration.JsxSetter;
26  
27  /**
28   * A JavaScript object for {@code DOMMatrix}.
29   *
30   * @author Ahmed Ashour
31   * @author Ronald Brill
32   *
33   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix">MDN Documentation</a>
34   */
35  @JsxClass
36  public class DOMMatrix extends DOMMatrixReadOnly {
37  
38      /**
39       * JavaScript constructor.
40       * @param cx the current context
41       * @param scope the scope
42       * @param args the arguments to the WebSocket constructor
43       * @param ctorObj the function object
44       * @param inNewExpr Is new or not
45       * @return the java object to allow JavaScript to access
46       */
47      @JsxConstructor
48      @JsxConstructorAlias(alias = "WebKitCSSMatrix")
49      public static DOMMatrix jsConstructor(final Context cx, final VarScope scope,
50              final Object[] args, final Function ctorObj, final boolean inNewExpr) {
51  
52          final DOMMatrix matrix = new DOMMatrix();
53          matrix.init(args, scope, ctorObj);
54          return matrix;
55      }
56  
57      /**
58       * {@inheritDoc}
59       */
60      @Override
61      @JsxGetter
62      public double getM11() {
63          return super.getM11();
64      }
65  
66      /**
67       * {@inheritDoc}
68       */
69      @Override
70      @JsxSetter
71      public void setM11(final double m11) {
72          super.setM11(m11);
73      }
74  
75      /**
76       * {@inheritDoc}
77       */
78      @Override
79      @JsxGetter
80      public double getM12() {
81          return super.getM12();
82      }
83  
84      /**
85       * {@inheritDoc}
86       */
87      @Override
88      @JsxSetter
89      public void setM12(final double m12) {
90          super.setM12(m12);
91      }
92  
93      /**
94       * {@inheritDoc}
95       */
96      @Override
97      @JsxGetter
98      public double getM13() {
99          return super.getM13();
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     @JsxSetter
107     public void setM13(final double m13) {
108         super.setM13(m13);
109     }
110 
111     /**
112      * {@inheritDoc}
113      */
114     @Override
115     @JsxGetter
116     public double getM14() {
117         return super.getM14();
118     }
119 
120     /**
121      * {@inheritDoc}
122      */
123     @Override
124     @JsxSetter
125     public void setM14(final double m14) {
126         super.setM14(m14);
127     }
128 
129     /**
130      * {@inheritDoc}
131      */
132     @Override
133     @JsxGetter
134     public double getM21() {
135         return super.getM21();
136     }
137 
138     /**
139      * {@inheritDoc}
140      */
141     @Override
142     @JsxSetter
143     public void setM21(final double m21) {
144         super.setM21(m21);
145     }
146 
147     /**
148      * {@inheritDoc}
149      */
150     @Override
151     @JsxGetter
152     public double getM22() {
153         return super.getM22();
154     }
155 
156     /**
157      * {@inheritDoc}
158      */
159     @Override
160     @JsxSetter
161     public void setM22(final double m22) {
162         super.setM22(m22);
163     }
164 
165     /**
166      * {@inheritDoc}
167      */
168     @Override
169     @JsxGetter
170     public double getM23() {
171         return super.getM23();
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     @Override
178     @JsxSetter
179     public void setM23(final double m23) {
180         super.setM23(m23);
181     }
182 
183     /**
184      * {@inheritDoc}
185      */
186     @Override
187     @JsxGetter
188     public double getM24() {
189         return super.getM24();
190     }
191 
192     /**
193      * {@inheritDoc}
194      */
195     @Override
196     @JsxSetter
197     public void setM24(final double m24) {
198         super.setM24(m24);
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     @Override
205     @JsxGetter
206     public double getM31() {
207         return super.getM31();
208     }
209 
210     /**
211      * {@inheritDoc}
212      */
213     @Override
214     @JsxSetter
215     public void setM31(final double m31) {
216         super.setM31(m31);
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     @JsxGetter
224     public double getM32() {
225         return super.getM32();
226     }
227 
228     /**
229      * {@inheritDoc}
230      */
231     @Override
232     @JsxSetter
233     public void setM32(final double m32) {
234         super.setM32(m32);
235     }
236 
237     /**
238      * {@inheritDoc}
239      */
240     @Override
241     @JsxGetter
242     public double getM33() {
243         return super.getM33();
244     }
245 
246     /**
247      * {@inheritDoc}
248      */
249     @Override
250     @JsxSetter
251     public void setM33(final double m33) {
252         super.setM33(m33);
253     }
254 
255     /**
256      * {@inheritDoc}
257      */
258     @Override
259     @JsxGetter
260     public double getM34() {
261         return super.getM34();
262     }
263 
264     /**
265      * {@inheritDoc}
266      */
267     @Override
268     @JsxSetter
269     public void setM34(final double m34) {
270         super.setM34(m34);
271     }
272 
273     /**
274      * {@inheritDoc}
275      */
276     @Override
277     @JsxGetter
278     public double getM41() {
279         return super.getM41();
280     }
281 
282     /**
283      * {@inheritDoc}
284      */
285     @Override
286     @JsxSetter
287     public void setM41(final double m41) {
288         super.setM41(m41);
289     }
290 
291     /**
292      * {@inheritDoc}
293      */
294     @Override
295     @JsxGetter
296     public double getM42() {
297         return super.getM42();
298     }
299 
300     /**
301      * {@inheritDoc}
302      */
303     @Override
304     @JsxSetter
305     public void setM42(final double m42) {
306         super.setM42(m42);
307     }
308 
309     /**
310      * {@inheritDoc}
311      */
312     @Override
313     @JsxGetter
314     public double getM43() {
315         return super.getM43();
316     }
317 
318     /**
319      * {@inheritDoc}
320      */
321     @Override
322     @JsxSetter
323     public void setM43(final double m43) {
324         super.setM43(m43);
325     }
326 
327     /**
328      * {@inheritDoc}
329      */
330     @Override
331     @JsxGetter
332     public double getM44() {
333         return super.getM44();
334     }
335 
336     /**
337      * {@inheritDoc}
338      */
339     @Override
340     @JsxSetter
341     public void setM44(final double m44) {
342         super.setM44(m44);
343     }
344 
345     /**
346      * {@inheritDoc}
347      */
348     @Override
349     @JsxGetter
350     public double getA() {
351         return super.getA();
352     }
353 
354     /**
355      * Sets the {@code a} property.
356      * @param a the new value
357      */
358     @JsxSetter
359     public void setA(final double a) {
360         super.setM11(a);
361     }
362 
363     /**
364      * {@inheritDoc}
365      */
366     @Override
367     @JsxGetter
368     public double getB() {
369         return super.getB();
370     }
371 
372     /**
373      * Sets the {@code b} property.
374      * @param b the new value
375      */
376     @JsxSetter
377     public void setB(final double b) {
378         super.setM12(b);
379     }
380 
381     /**
382      * {@inheritDoc}
383      */
384     @Override
385     @JsxGetter
386     public double getC() {
387         return super.getC();
388     }
389 
390     /**
391      * Sets the {@code c} property.
392      * @param c the new value
393      */
394     @JsxSetter
395     public void setC(final double c) {
396         super.setM21(c);
397     }
398 
399     /**
400      * {@inheritDoc}
401      */
402     @Override
403     @JsxGetter
404     public double getD() {
405         return super.getD();
406     }
407 
408     /**
409      * Sets the {@code d} property.
410      * @param d the new value
411      */
412     @JsxSetter
413     public void setD(final double d) {
414         super.setM22(d);
415     }
416 
417     /**
418      * {@inheritDoc}
419      */
420     @Override
421     @JsxGetter
422     public double getE() {
423         return super.getE();
424     }
425 
426     /**
427      * Sets the {@code e} property.
428      * @param e the new value
429      */
430     @JsxSetter
431     public void setE(final double e) {
432         super.setM41(e);
433     }
434 
435     /**
436      * {@inheritDoc}
437      */
438     @Override
439     @JsxGetter
440     public double getF() {
441         return super.getF();
442     }
443 
444     /**
445      * Sets the {@code f} property.
446      * @param f the new value
447      */
448     @JsxSetter
449     public void setF(final double f) {
450         super.setM42(f);
451     }
452 
453     /**
454      * Inverts the original matrix. If the matrix cannot be inverted,
455      * the new matrix's components are all set to NaN and its is2D property is set to false.
456      * @return this matrix, inverted
457      */
458     @JsxFunction
459     public DOMMatrix invertSelf() {
460         if (isIs2D()) {
461             final double det = getM11() * getM22() - getM12() * getM21();
462             if (det == 0) {
463                 // Not invertible: set all to NaN, is2D_ = false
464                 initWithNan();
465                 return this;
466             }
467 
468             final double[] inv = new double[6];
469             inv[0] = getM22() / det;
470             inv[1] = -getM12() / det;
471 
472             inv[2] = -getM21() / det;
473             inv[3] = getM11() / det;
474 
475             inv[4] = (getM21() * getM42() - getM22() * getM41()) / det;
476             inv[5] = (getM12() * getM41() - getM11() * getM42()) / det;
477 
478             setM11(inv[0]);
479             setM12(inv[1]);
480             setM21(inv[2]);
481             setM22(inv[3]);
482             setM41(inv[4]);
483             setM42(inv[5]);
484             setIs2D(true);
485             return this;
486         }
487 
488         final double[] inv = new double[16];
489         inv[0] = getM22() * getM33() * getM44()
490                 - getM22() * getM34() * getM43()
491                 - getM32() * getM23() * getM44()
492                 + getM32() * getM24() * getM43()
493                 + getM42() * getM23() * getM34()
494                 - getM42() * getM24() * getM33();
495 
496         inv[4] = -getM21() * getM33() * getM44()
497                 + getM21() * getM34() * getM43()
498                 + getM31() * getM23() * getM44()
499                 - getM31() * getM24() * getM43()
500                 - getM41() * getM23() * getM34()
501                 + getM41() * getM24() * getM33();
502 
503         inv[8] = getM21() * getM32() * getM44()
504                 - getM21() * getM34() * getM42()
505                 - getM31() * getM22() * getM44()
506                 + getM31() * getM24() * getM42()
507                 + getM41() * getM22() * getM34()
508                 - getM41() * getM24() * getM32();
509 
510         inv[12] = -getM21() * getM32() * getM43()
511                 + getM21() * getM33() * getM42()
512                 + getM31() * getM22() * getM43()
513                 - getM31() * getM23() * getM42()
514                 - getM41() * getM22() * getM33()
515                 + getM41() * getM23() * getM32();
516 
517         inv[1] = -getM12() * getM33() * getM44()
518                 + getM12() * getM34() * getM43()
519                 + getM32() * getM13() * getM44()
520                 - getM32() * getM14() * getM43()
521                 - getM42() * getM13() * getM34()
522                 + getM42() * getM14() * getM33();
523 
524         inv[5] = getM11() * getM33() * getM44()
525                 - getM11() * getM34() * getM43()
526                 - getM31() * getM13() * getM44()
527                 + getM31() * getM14() * getM43()
528                 + getM41() * getM13() * getM34()
529                 - getM41() * getM14() * getM33();
530 
531         inv[9] = -getM11() * getM32() * getM44()
532                 + getM11() * getM34() * getM42()
533                 + getM31() * getM12() * getM44()
534                 - getM31() * getM14() * getM42()
535                 - getM41() * getM12() * getM34()
536                 + getM41() * getM14() * getM32();
537 
538         inv[13] = getM11() * getM32() * getM43()
539                 - getM11() * getM33() * getM42()
540                 - getM31() * getM12() * getM43()
541                 + getM31() * getM13() * getM42()
542                 + getM41() * getM12() * getM33()
543                 - getM41() * getM13() * getM32();
544 
545         inv[2] = getM12() * getM23() * getM44()
546                 - getM12() * getM24() * getM43()
547                 - getM22() * getM13() * getM44()
548                 + getM22() * getM14() * getM43()
549                 + getM42() * getM13() * getM24()
550                 - getM42() * getM14() * getM23();
551 
552         inv[6] = -getM11() * getM23() * getM44()
553                 + getM11() * getM24() * getM43()
554                 + getM21() * getM13() * getM44()
555                 - getM21() * getM14() * getM43()
556                 - getM41() * getM13() * getM24()
557                 + getM41() * getM14() * getM23();
558 
559         inv[10] = getM11() * getM22() * getM44()
560                 - getM11() * getM24() * getM42()
561                 - getM21() * getM12() * getM44()
562                 + getM21() * getM14() * getM42()
563                 + getM41() * getM12() * getM24()
564                 - getM41() * getM14() * getM22();
565 
566         inv[14] = -getM11() * getM22() * getM43()
567                 + getM11() * getM23() * getM42()
568                 + getM21() * getM12() * getM43()
569                 - getM21() * getM13() * getM42()
570                 - getM41() * getM12() * getM23()
571                 + getM41() * getM13() * getM22();
572 
573         inv[3] = -getM12() * getM23() * getM34()
574                 + getM12() * getM24() * getM33()
575                 + getM22() * getM13() * getM34()
576                 - getM22() * getM14() * getM33()
577                 - getM32() * getM13() * getM24()
578                 + getM32() * getM14() * getM23();
579 
580         inv[7] = getM11() * getM23() * getM34()
581                 - getM11() * getM24() * getM33()
582                 - getM21() * getM13() * getM34()
583                 + getM21() * getM14() * getM33()
584                 + getM31() * getM13() * getM24()
585                 - getM31() * getM14() * getM23();
586 
587         inv[11] = -getM11() * getM22() * getM34()
588                 + getM11() * getM24() * getM32()
589                 + getM21() * getM12() * getM34()
590                 - getM21() * getM14() * getM32()
591                 - getM31() * getM12() * getM24()
592                 + getM31() * getM14() * getM22();
593 
594         inv[15] = getM11() * getM22() * getM33()
595                 - getM11() * getM23() * getM32()
596                 - getM21() * getM12() * getM33()
597                 + getM21() * getM13() * getM32()
598                 + getM31() * getM12() * getM23()
599                 - getM31() * getM13() * getM22();
600 
601         double det = getM11() * inv[0] + getM12() * inv[4] + getM13() * inv[8] + getM14() * inv[12];
602 
603         if (det == 0) {
604             // Not invertible: set all to NaN, is2D_ = false
605             initWithNan();
606             return this;
607         }
608 
609         det = 1.0 / det;
610 
611         setM11(inv[0] * det);
612         setM12(inv[1] * det);
613         setM13(inv[2] * det);
614         setM14(inv[3] * det);
615 
616         setM21(inv[4] * det);
617         setM22(inv[5] * det);
618         setM23(inv[6] * det);
619         setM24(inv[7] * det);
620 
621         setM31(inv[8] * det);
622         setM32(inv[9] * det);
623         setM33(inv[10] * det);
624         setM34(inv[11] * det);
625 
626         setM41(inv[12] * det);
627         setM42(inv[13] * det);
628         setM43(inv[14] * det);
629         setM44(inv[15] * det);
630 
631         setIs2D(false);
632         return this;
633     }
634 
635     private void initWithNan() {
636         setM11(Double.NaN);
637         setM12(Double.NaN);
638         setM13(Double.NaN);
639         setM14(Double.NaN);
640         setM21(Double.NaN);
641         setM22(Double.NaN);
642         setM23(Double.NaN);
643         setM24(Double.NaN);
644         setM31(Double.NaN);
645         setM32(Double.NaN);
646         setM33(Double.NaN);
647         setM34(Double.NaN);
648         setM41(Double.NaN);
649         setM42(Double.NaN);
650         setM43(Double.NaN);
651         setM44(Double.NaN);
652         setIs2D(false);
653     }
654 }