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 "SVGViewBoxSMILType.h"
8 #include "nsSMILValue.h"
9 #include "nsSVGViewBox.h"
10 #include "nsDebug.h"
11 #include <math.h>
12 
13 namespace mozilla {
14 
15 /*static*/ SVGViewBoxSMILType SVGViewBoxSMILType::sSingleton;
16 
Init(nsSMILValue & aValue) const17 void SVGViewBoxSMILType::Init(nsSMILValue& aValue) const {
18   MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
19 
20   aValue.mU.mPtr = new nsSVGViewBoxRect();
21   aValue.mType = this;
22 }
23 
Destroy(nsSMILValue & aValue) const24 void SVGViewBoxSMILType::Destroy(nsSMILValue& aValue) const {
25   NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
26   delete static_cast<nsSVGViewBoxRect*>(aValue.mU.mPtr);
27   aValue.mU.mPtr = nullptr;
28   aValue.mType = nsSMILNullType::Singleton();
29 }
30 
Assign(nsSMILValue & aDest,const nsSMILValue & aSrc) const31 nsresult SVGViewBoxSMILType::Assign(nsSMILValue& aDest,
32                                     const nsSMILValue& aSrc) const {
33   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
34   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
35 
36   const nsSVGViewBoxRect* src =
37       static_cast<const nsSVGViewBoxRect*>(aSrc.mU.mPtr);
38   nsSVGViewBoxRect* dst = static_cast<nsSVGViewBoxRect*>(aDest.mU.mPtr);
39   *dst = *src;
40   return NS_OK;
41 }
42 
IsEqual(const nsSMILValue & aLeft,const nsSMILValue & aRight) const43 bool SVGViewBoxSMILType::IsEqual(const nsSMILValue& aLeft,
44                                  const nsSMILValue& aRight) const {
45   NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
46   NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
47 
48   const nsSVGViewBoxRect* leftBox =
49       static_cast<const nsSVGViewBoxRect*>(aLeft.mU.mPtr);
50   const nsSVGViewBoxRect* rightBox =
51       static_cast<nsSVGViewBoxRect*>(aRight.mU.mPtr);
52   return *leftBox == *rightBox;
53 }
54 
Add(nsSMILValue & aDest,const nsSMILValue & aValueToAdd,uint32_t aCount) const55 nsresult SVGViewBoxSMILType::Add(nsSMILValue& aDest,
56                                  const nsSMILValue& aValueToAdd,
57                                  uint32_t aCount) const {
58   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
59                   "Trying to add invalid types");
60   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
61 
62   // See https://bugzilla.mozilla.org/show_bug.cgi?id=541884#c3 and the two
63   // comments that follow that one for arguments for and against allowing
64   // viewBox to be additive.
65 
66   return NS_ERROR_FAILURE;
67 }
68 
ComputeDistance(const nsSMILValue & aFrom,const nsSMILValue & aTo,double & aDistance) const69 nsresult SVGViewBoxSMILType::ComputeDistance(const nsSMILValue& aFrom,
70                                              const nsSMILValue& aTo,
71                                              double& aDistance) const {
72   NS_PRECONDITION(aFrom.mType == aTo.mType,
73                   "Trying to compare different types");
74   NS_PRECONDITION(aFrom.mType == this, "Unexpected source type");
75 
76   const nsSVGViewBoxRect* from =
77       static_cast<const nsSVGViewBoxRect*>(aFrom.mU.mPtr);
78   const nsSVGViewBoxRect* to =
79       static_cast<const nsSVGViewBoxRect*>(aTo.mU.mPtr);
80 
81   if (from->none || to->none) {
82     return NS_ERROR_FAILURE;
83   }
84 
85   // We use the distances between the edges rather than the difference between
86   // the x, y, width and height for the "distance". This is necessary in
87   // order for the "distance" result that we calculate to be the same for a
88   // given change in the left side as it is for an equal change in the opposite
89   // side. See https://bugzilla.mozilla.org/show_bug.cgi?id=541884#c12
90 
91   float dLeft = to->x - from->x;
92   float dTop = to->y - from->y;
93   float dRight = (to->x + to->width) - (from->x + from->width);
94   float dBottom = (to->y + to->height) - (from->y + from->height);
95 
96   aDistance =
97       sqrt(dLeft * dLeft + dTop * dTop + dRight * dRight + dBottom * dBottom);
98 
99   return NS_OK;
100 }
101 
Interpolate(const nsSMILValue & aStartVal,const nsSMILValue & aEndVal,double aUnitDistance,nsSMILValue & aResult) const102 nsresult SVGViewBoxSMILType::Interpolate(const nsSMILValue& aStartVal,
103                                          const nsSMILValue& aEndVal,
104                                          double aUnitDistance,
105                                          nsSMILValue& aResult) const {
106   NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
107                   "Trying to interpolate different types");
108   NS_PRECONDITION(aStartVal.mType == this,
109                   "Unexpected types for interpolation");
110   NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
111 
112   const nsSVGViewBoxRect* start =
113       static_cast<const nsSVGViewBoxRect*>(aStartVal.mU.mPtr);
114   const nsSVGViewBoxRect* end =
115       static_cast<const nsSVGViewBoxRect*>(aEndVal.mU.mPtr);
116 
117   if (start->none || end->none) {
118     return NS_ERROR_FAILURE;
119   }
120 
121   nsSVGViewBoxRect* current = static_cast<nsSVGViewBoxRect*>(aResult.mU.mPtr);
122 
123   float x = (start->x + (end->x - start->x) * aUnitDistance);
124   float y = (start->y + (end->y - start->y) * aUnitDistance);
125   float width = (start->width + (end->width - start->width) * aUnitDistance);
126   float height =
127       (start->height + (end->height - start->height) * aUnitDistance);
128 
129   *current = nsSVGViewBoxRect(x, y, width, height);
130 
131   return NS_OK;
132 }
133 
134 }  // namespace mozilla
135