1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef MOZILLA_GFX_SCALEFACTORS2D_H_
7 #define MOZILLA_GFX_SCALEFACTORS2D_H_
8 
9 #include <ostream>
10 
11 #include "mozilla/Attributes.h"
12 #include "mozilla/FloatingPoint.h"
13 #include "mozilla/gfx/ScaleFactor.h"
14 
15 #include "gfxPoint.h"
16 
17 namespace mozilla {
18 namespace gfx {
19 
20 /*
21  * This class is like ScaleFactor, but allows different scales on the x and
22  * y axes.
23  */
24 template<class src, class dst>
25 struct ScaleFactors2D {
26   float xScale;
27   float yScale;
28 
ScaleFactors2DScaleFactors2D29   constexpr ScaleFactors2D() : xScale(1.0), yScale(1.0) {}
ScaleFactors2DScaleFactors2D30   constexpr ScaleFactors2D(const ScaleFactors2D<src, dst>& aCopy)
31     : xScale(aCopy.xScale), yScale(aCopy.yScale) {}
ScaleFactors2DScaleFactors2D32   constexpr ScaleFactors2D(float aXScale, float aYScale)
33     : xScale(aXScale), yScale(aYScale) {}
34   // Layout code often uses gfxSize to represent a pair of x/y scales.
ScaleFactors2DScaleFactors2D35   explicit constexpr ScaleFactors2D(const gfxSize& aSize)
36     : xScale(aSize.width), yScale(aSize.height) {}
37 
38   // "Upgrade" from a ScaleFactor.
39   // This is deliberately 'explicit' so that the treatment of a single scale
40   // number as both the x- and y-scale in a context where they are allowed to
41   // be different, is more visible.
ScaleFactors2DScaleFactors2D42   explicit constexpr ScaleFactors2D(const ScaleFactor<src, dst>& aScale)
43     : xScale(aScale.scale), yScale(aScale.scale) {}
44 
AreScalesSameScaleFactors2D45   bool AreScalesSame() const {
46     return FuzzyEqualsMultiplicative(xScale, yScale);
47   }
48 
49   // Convert to a ScaleFactor. Asserts that the scales are, in fact, equal.
ToScaleFactorScaleFactors2D50   ScaleFactor<src, dst> ToScaleFactor() const {
51     MOZ_ASSERT(AreScalesSame());
52     return ScaleFactor<src, dst>(xScale);
53   }
54 
55   bool operator==(const ScaleFactors2D<src, dst>& aOther) const {
56     return xScale == aOther.xScale && yScale == aOther.yScale;
57   }
58 
59   bool operator!=(const ScaleFactors2D<src, dst>& aOther) const {
60     return !(*this == aOther);
61   }
62 
63   friend std::ostream& operator<<(std::ostream& aStream,
64                                   const ScaleFactors2D<src, dst>& aScale) {
65     if (aScale.AreScalesSame()) {
66       return aStream << aScale.xScale;
67     } else {
68       return aStream << '(' << aScale.xScale << ',' << aScale.yScale << ')';
69     }
70   }
71 
72   template<class other>
73   ScaleFactors2D<other, dst> operator/(const ScaleFactors2D<src, other>& aOther) const {
74     return ScaleFactors2D<other, dst>(xScale / aOther.xScale, yScale / aOther.yScale);
75   }
76 
77   template<class other>
78   ScaleFactors2D<src, other> operator/(const ScaleFactors2D<other, dst>& aOther) const {
79     return ScaleFactors2D<src, other>(xScale / aOther.xScale, yScale / aOther.yScale);
80   }
81 
82   template<class other>
83   ScaleFactors2D<src, other> operator*(const ScaleFactors2D<dst, other>& aOther) const {
84     return ScaleFactors2D<src, other>(xScale * aOther.xScale, yScale * aOther.yScale);
85   }
86 
87   template<class other>
88   ScaleFactors2D<other, dst> operator*(const ScaleFactors2D<other, src>& aOther) const {
89     return ScaleFactors2D<other, dst>(xScale * aOther.xScale, yScale * aOther.yScale);
90   }
91 
92   template<class other>
93   ScaleFactors2D<src, other> operator*(const ScaleFactor<dst, other>& aOther) const {
94     return *this * ScaleFactors2D<dst, other>(aOther);
95   }
96 
97   template<class other>
98   ScaleFactors2D<other, dst> operator*(const ScaleFactor<other, src>& aOther) const {
99     return *this * ScaleFactors2D<other, src>(aOther);
100   }
101 
102   template<class other>
103   ScaleFactors2D<src, other> operator/(const ScaleFactor<other, dst>& aOther) const {
104     return *this / ScaleFactors2D<other, dst>(aOther);
105   }
106 
107   template<class other>
108   ScaleFactors2D<other, dst> operator/(const ScaleFactor<src, other>& aOther) const {
109     return *this / ScaleFactors2D<src, other>(aOther);
110   }
111 
112   template<class other>
113   friend ScaleFactors2D<other, dst> operator*(const ScaleFactor<other, src>& aA,
114                                               const ScaleFactors2D<src, dst>& aB) {
115     return ScaleFactors2D<other, src>(aA) * aB;
116   }
117 
118   template<class other>
119   friend ScaleFactors2D<other, src> operator/(const ScaleFactor<other, dst>& aA,
120                                               const ScaleFactors2D<src, dst>& aB) {
121     return ScaleFactors2D<other, src>(aA) / aB;
122   }
123 
124   // Divide two scales of the same units, yielding a scale with no units,
125   // represented as a gfxSize. This can mean e.g. the cahnge in a particular
126   // scale from one frame to the next.
127   gfxSize operator/(const ScaleFactors2D& aOther) const {
128     return gfxSize(xScale / aOther.xScale, yScale / aOther.yScale);
129   }
130 };
131 
132 } // namespace gfx
133 } // namespace mozilla
134 
135 #endif /* MOZILLA_GFX_SCALEFACTORS2D_H_ */
136