1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla SVG Project code.
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #ifndef MOZILLA_SVGLENGTH_H__
38 : #define MOZILLA_SVGLENGTH_H__
39 :
40 : #include "nsDebug.h"
41 : #include "nsIDOMSVGLength.h"
42 : #include "nsMathUtils.h"
43 :
44 : class nsSVGElement;
45 :
46 : namespace mozilla {
47 :
48 : /**
49 : * This SVGLength class is currently used for SVGLength *list* attributes only.
50 : * The class that is currently used for <length> attributes is nsSVGLength2.
51 : *
52 : * The member mUnit should always be valid, but the member mValue may be
53 : * numeric_limits<float>::quiet_NaN() under one circumstances (see the comment
54 : * in SetValueAndUnit below). Even if mValue is valid, some methods may return
55 : * numeric_limits<float>::quiet_NaN() if they involve a unit conversion that
56 : * fails - see comments below.
57 : *
58 : * The DOM wrapper class for this class is DOMSVGLength.
59 : */
60 : class SVGLength
61 0 : {
62 : public:
63 :
64 0 : SVGLength()
65 : #ifdef DEBUG
66 : : mValue(0.0f)
67 0 : , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN) // caught by IsValid()
68 : #endif
69 0 : {}
70 :
71 0 : SVGLength(float aValue, PRUint8 aUnit)
72 : : mValue(aValue)
73 0 : , mUnit(aUnit)
74 : {
75 0 : NS_ASSERTION(IsValid(), "Constructed an invalid length");
76 0 : }
77 :
78 0 : SVGLength(const SVGLength &aOther)
79 : : mValue(aOther.mValue)
80 0 : , mUnit(aOther.mUnit)
81 0 : {}
82 :
83 0 : SVGLength& operator=(const SVGLength &rhs) {
84 0 : mValue = rhs.mValue;
85 0 : mUnit = rhs.mUnit;
86 0 : return *this;
87 : }
88 :
89 0 : bool operator==(const SVGLength &rhs) const {
90 0 : return mValue == rhs.mValue && mUnit == rhs.mUnit;
91 : }
92 :
93 : void GetValueAsString(nsAString& aValue) const;
94 :
95 : /**
96 : * This method returns true, unless there was a parse failure, in which
97 : * case it returns false (and the length is left unchanged).
98 : */
99 : bool SetValueFromString(const nsAString& aValue);
100 :
101 : /**
102 : * This will usually return a valid, finite number. There is one exception
103 : * though - see the comment in SetValueAndUnit().
104 : */
105 0 : float GetValueInCurrentUnits() const {
106 0 : return mValue;
107 : }
108 :
109 0 : PRUint8 GetUnit() const {
110 0 : return mUnit;
111 : }
112 :
113 0 : void SetValueInCurrentUnits(float aValue) {
114 0 : mValue = aValue;
115 0 : NS_ASSERTION(IsValid(), "Set invalid SVGLength");
116 0 : }
117 :
118 0 : void SetValueAndUnit(float aValue, PRUint8 aUnit) {
119 0 : mValue = aValue;
120 0 : mUnit = aUnit;
121 :
122 : // IsValid() should always be true, with one exception: if
123 : // SVGLengthListSMILType has to convert between unit types and the unit
124 : // conversion is undefined, it will end up passing in and setting
125 : // numeric_limits<float>::quiet_NaN(). Because of that we only check the
126 : // unit here, and allow mValue to be invalid. The painting code has to be
127 : // able to handle NaN anyway, since conversion to user units may fail in
128 : // general.
129 :
130 0 : NS_ASSERTION(IsValidUnitType(mUnit), "Set invalid SVGLength");
131 0 : }
132 :
133 : /**
134 : * If it's not possible to convert this length's value to user units, then
135 : * this method will return numeric_limits<float>::quiet_NaN().
136 : */
137 0 : float GetValueInUserUnits(const nsSVGElement *aElement, PRUint8 aAxis) const {
138 0 : return mValue * GetUserUnitsPerUnit(aElement, aAxis);
139 : }
140 :
141 : /**
142 : * Sets this length's value, converting the supplied user unit value to this
143 : * lengths *current* unit (i.e. leaving the length's unit unchanged).
144 : *
145 : * This method returns true, unless the user unit value couldn't be
146 : * converted to this length's current unit, in which case it returns false
147 : * (and the length is left unchanged).
148 : */
149 0 : bool SetFromUserUnitValue(float aUserUnitValue,
150 : nsSVGElement *aElement,
151 : PRUint8 aAxis) {
152 0 : float uuPerUnit = GetUserUnitsPerUnit(aElement, aAxis);
153 0 : float value = aUserUnitValue / uuPerUnit;
154 0 : if (uuPerUnit > 0 && NS_finite(value)) {
155 0 : mValue = value;
156 0 : NS_ASSERTION(IsValid(), "Set invalid SVGLength");
157 0 : return true;
158 : }
159 0 : return false;
160 : }
161 :
162 : /**
163 : * Get this length's value in the units specified.
164 : *
165 : * This method returns numeric_limits<float>::quiet_NaN() if it is not
166 : * possible to convert the value to the specified unit.
167 : */
168 : float GetValueInSpecifiedUnit(PRUint8 aUnit,
169 : const nsSVGElement *aElement,
170 : PRUint8 aAxis) const;
171 :
172 : /**
173 : * Convert this length's value to the unit specified.
174 : *
175 : * This method returns true, unless it isn't possible to convert the
176 : * length to the specified unit. In that case the length is left unchanged
177 : * and this method returns false.
178 : */
179 0 : bool ConvertToUnit(PRUint32 aUnit, nsSVGElement *aElement, PRUint8 aAxis) {
180 0 : float val = GetValueInSpecifiedUnit(aUnit, aElement, aAxis);
181 0 : if (NS_finite(val)) {
182 0 : mValue = val;
183 0 : mUnit = aUnit;
184 0 : NS_ASSERTION(IsValid(), "Set invalid SVGLength");
185 0 : return true;
186 : }
187 0 : return false;
188 : }
189 :
190 : bool IsPercentage() const {
191 : return mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE;
192 : }
193 :
194 0 : static bool IsValidUnitType(PRUint16 unit) {
195 : return unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
196 0 : unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC;
197 : }
198 :
199 : private:
200 :
201 : #ifdef DEBUG
202 0 : bool IsValid() const {
203 0 : return NS_finite(mValue) && IsValidUnitType(mUnit);
204 : }
205 : #endif
206 :
207 : /**
208 : * Returns the number of user units per current unit.
209 : *
210 : * This method returns numeric_limits<float>::quiet_NaN() if the conversion
211 : * factor between the length's current unit and user units is undefined (see
212 : * the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent).
213 : */
214 : float GetUserUnitsPerUnit(const nsSVGElement *aElement, PRUint8 aAxis) const;
215 :
216 : /**
217 : * The conversion factor between user units (CSS px) and CSS inches is
218 : * constant: 96 px per inch.
219 : */
220 0 : static float GetUserUnitsPerInch()
221 : {
222 0 : return 96.0;
223 : }
224 :
225 : /**
226 : * The conversion factor between user units and percentage units depends on
227 : * aElement being non-null, and on aElement having a viewport element
228 : * ancestor with only appropriate SVG elements between aElement and that
229 : * ancestor. If that's not the case, then the conversion factor is undefined.
230 : *
231 : * This function returns a non-negative value if the conversion factor is
232 : * defined, otherwise it returns numeric_limits<float>::quiet_NaN().
233 : */
234 : static float GetUserUnitsPerPercent(const nsSVGElement *aElement, PRUint8 aAxis);
235 :
236 : float mValue;
237 : PRUint8 mUnit;
238 : };
239 :
240 : } // namespace mozilla
241 :
242 : #endif // MOZILLA_SVGLENGTH_H__
|