1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/DOMQuad.h"
8 
9 #include <algorithm>
10 #include "mozilla/FloatingPoint.h"
11 #include "mozilla/MacroForEach.h"
12 #include "mozilla/dom/BindingDeclarations.h"
13 #include "mozilla/dom/DOMPoint.h"
14 #include "mozilla/dom/DOMQuadBinding.h"
15 #include "mozilla/dom/DOMRect.h"
16 #include "mozilla/dom/DOMRectBinding.h"
17 #include "mozilla/gfx/BasePoint.h"
18 #include "mozilla/gfx/MatrixFwd.h"
19 #include "nsIGlobalObject.h"
20 
21 using namespace mozilla;
22 using namespace mozilla::dom;
23 using namespace mozilla::gfx;
24 
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad,mParent,mPoints[0],mPoints[1],mPoints[2],mPoints[3])25 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad, mParent, mPoints[0], mPoints[1],
26                                       mPoints[2], mPoints[3])
27 
28 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMQuad, AddRef)
29 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMQuad, Release)
30 
31 DOMQuad::DOMQuad(nsISupports* aParent, CSSPoint aPoints[4]) : mParent(aParent) {
32   for (uint32_t i = 0; i < 4; ++i) {
33     mPoints[i] = new DOMPoint(aParent, aPoints[i].x, aPoints[i].y);
34   }
35 }
36 
DOMQuad(nsISupports * aParent)37 DOMQuad::DOMQuad(nsISupports* aParent) : mParent(aParent) {}
38 
39 DOMQuad::~DOMQuad() = default;
40 
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)41 JSObject* DOMQuad::WrapObject(JSContext* aCx,
42                               JS::Handle<JSObject*> aGivenProto) {
43   return DOMQuad_Binding::Wrap(aCx, this, aGivenProto);
44 }
45 
FromRect(const GlobalObject & aGlobal,const DOMRectInit & aInit)46 already_AddRefed<DOMQuad> DOMQuad::FromRect(const GlobalObject& aGlobal,
47                                             const DOMRectInit& aInit) {
48   nsISupports* parent = aGlobal.GetAsSupports();
49   RefPtr<DOMQuad> obj = new DOMQuad(parent);
50   obj->mPoints[0] = new DOMPoint(parent, aInit.mX, aInit.mY, 0, 1);
51   obj->mPoints[1] =
52       new DOMPoint(parent, aInit.mX + aInit.mWidth, aInit.mY, 0, 1);
53   obj->mPoints[2] = new DOMPoint(parent, aInit.mX + aInit.mWidth,
54                                  aInit.mY + aInit.mHeight, 0, 1);
55   obj->mPoints[3] =
56       new DOMPoint(parent, aInit.mX, aInit.mY + aInit.mHeight, 0, 1);
57   return obj.forget();
58 }
59 
FromQuad(const GlobalObject & aGlobal,const DOMQuadInit & aInit)60 already_AddRefed<DOMQuad> DOMQuad::FromQuad(const GlobalObject& aGlobal,
61                                             const DOMQuadInit& aInit) {
62   RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
63   obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aInit.mP1);
64   obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aInit.mP2);
65   obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aInit.mP3);
66   obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aInit.mP4);
67   return obj.forget();
68 }
69 
Constructor(const GlobalObject & aGlobal,const DOMPointInit & aP1,const DOMPointInit & aP2,const DOMPointInit & aP3,const DOMPointInit & aP4)70 already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
71                                                const DOMPointInit& aP1,
72                                                const DOMPointInit& aP2,
73                                                const DOMPointInit& aP3,
74                                                const DOMPointInit& aP4) {
75   RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
76   obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aP1);
77   obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aP2);
78   obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aP3);
79   obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aP4);
80   return obj.forget();
81 }
82 
Constructor(const GlobalObject & aGlobal,const DOMRectReadOnly & aRect)83 already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal,
84                                                const DOMRectReadOnly& aRect) {
85   CSSPoint points[4];
86   Float x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height();
87   points[0] = CSSPoint(x, y);
88   points[1] = CSSPoint(x + w, y);
89   points[2] = CSSPoint(x + w, y + h);
90   points[3] = CSSPoint(x, y + h);
91   RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports(), points);
92   return obj.forget();
93 }
94 
GetHorizontalMinMax(double * aX1,double * aX2) const95 void DOMQuad::GetHorizontalMinMax(double* aX1, double* aX2) const {
96   double x1, x2;
97   x1 = x2 = Point(0)->X();
98   for (uint32_t i = 1; i < 4; ++i) {
99     double x = Point(i)->X();
100     x1 = NaNSafeMin(x1, x);
101     x2 = NaNSafeMax(x2, x);
102   }
103   *aX1 = x1;
104   *aX2 = x2;
105 }
106 
GetVerticalMinMax(double * aY1,double * aY2) const107 void DOMQuad::GetVerticalMinMax(double* aY1, double* aY2) const {
108   double y1, y2;
109   y1 = y2 = Point(0)->Y();
110   for (uint32_t i = 1; i < 4; ++i) {
111     double y = Point(i)->Y();
112     y1 = NaNSafeMin(y1, y);
113     y2 = NaNSafeMax(y2, y);
114   }
115   *aY1 = y1;
116   *aY2 = y2;
117 }
118 
GetBounds() const119 already_AddRefed<DOMRectReadOnly> DOMQuad::GetBounds() const {
120   double x1, x2;
121   double y1, y2;
122 
123   GetHorizontalMinMax(&x1, &x2);
124   GetVerticalMinMax(&y1, &y2);
125 
126   RefPtr<DOMRectReadOnly> rval =
127       new DOMRectReadOnly(GetParentObject(), x1, y1, x2 - x1, y2 - y1);
128   return rval.forget();
129 }
130 
131 // https://drafts.fxtf.org/geometry/#structured-serialization
WriteStructuredClone(JSContext * aCx,JSStructuredCloneWriter * aWriter) const132 bool DOMQuad::WriteStructuredClone(JSContext* aCx,
133                                    JSStructuredCloneWriter* aWriter) const {
134   for (const auto& point : mPoints) {
135     if (!point->WriteStructuredClone(aCx, aWriter)) {
136       return false;
137     }
138   }
139   return true;
140 }
141 
142 // static
ReadStructuredClone(JSContext * aCx,nsIGlobalObject * aGlobal,JSStructuredCloneReader * aReader)143 already_AddRefed<DOMQuad> DOMQuad::ReadStructuredClone(
144     JSContext* aCx, nsIGlobalObject* aGlobal,
145     JSStructuredCloneReader* aReader) {
146   RefPtr<DOMQuad> quad = new DOMQuad(aGlobal);
147   for (auto& point : quad->mPoints) {
148     point = DOMPoint::ReadStructuredClone(aCx, aGlobal, aReader);
149     if (!point) {
150       return nullptr;
151     }
152   }
153   return quad.forget();
154 }
155