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 #ifndef MOZILLA_SVGLENGTH_H__ 8 #define MOZILLA_SVGLENGTH_H__ 9 10 #include "nsDebug.h" 11 #include "nsMathUtils.h" 12 #include "mozilla/FloatingPoint.h" 13 #include "mozilla/dom/SVGLengthBinding.h" 14 15 namespace mozilla { 16 17 namespace dom { 18 class SVGElement; 19 } 20 21 /** 22 * This SVGLength class is currently used for SVGLength *list* attributes only. 23 * The class that is currently used for <length> attributes is 24 * SVGAnimatedLength. 25 * 26 * The member mUnit should always be valid, but the member mValue may be 27 * numeric_limits<float>::quiet_NaN() under one circumstances (see the comment 28 * in SetValueAndUnit below). Even if mValue is valid, some methods may return 29 * numeric_limits<float>::quiet_NaN() if they involve a unit conversion that 30 * fails - see comments below. 31 * 32 * The DOM wrapper class for this class is DOMSVGLength. 33 */ 34 class SVGLength { 35 public: SVGLength()36 SVGLength() 37 : mValue(0.0f), 38 mUnit(dom::SVGLength_Binding::SVG_LENGTHTYPE_UNKNOWN) // caught by 39 // IsValid() 40 {} 41 SVGLength(float aValue,uint8_t aUnit)42 SVGLength(float aValue, uint8_t aUnit) : mValue(aValue), mUnit(aUnit) { 43 NS_ASSERTION(IsValid(), "Constructed an invalid length"); 44 } 45 46 bool operator==(const SVGLength& rhs) const { 47 return mValue == rhs.mValue && mUnit == rhs.mUnit; 48 } 49 50 void GetValueAsString(nsAString& aValue) const; 51 52 /** 53 * This method returns true, unless there was a parse failure, in which 54 * case it returns false (and the length is left unchanged). 55 */ 56 bool SetValueFromString(const nsAString& aString); 57 58 /** 59 * This will usually return a valid, finite number. There is one exception 60 * though - see the comment in SetValueAndUnit(). 61 */ GetValueInCurrentUnits()62 float GetValueInCurrentUnits() const { return mValue; } 63 GetUnit()64 uint8_t GetUnit() const { return mUnit; } 65 SetValueInCurrentUnits(float aValue)66 void SetValueInCurrentUnits(float aValue) { 67 mValue = aValue; 68 NS_ASSERTION(IsValid(), "Set invalid SVGLength"); 69 } 70 SetValueAndUnit(float aValue,uint8_t aUnit)71 void SetValueAndUnit(float aValue, uint8_t aUnit) { 72 mValue = aValue; 73 mUnit = aUnit; 74 75 // IsValid() should always be true, with one exception: if 76 // SVGLengthListSMILType has to convert between unit types and the unit 77 // conversion is undefined, it will end up passing in and setting 78 // numeric_limits<float>::quiet_NaN(). Because of that we only check the 79 // unit here, and allow mValue to be invalid. The painting code has to be 80 // able to handle NaN anyway, since conversion to user units may fail in 81 // general. 82 83 NS_ASSERTION(IsValidUnitType(mUnit), "Set invalid SVGLength"); 84 } 85 86 /** 87 * If it's not possible to convert this length's value to user units, then 88 * this method will return numeric_limits<float>::quiet_NaN(). 89 */ GetValueInUserUnits(const dom::SVGElement * aElement,uint8_t aAxis)90 float GetValueInUserUnits(const dom::SVGElement* aElement, 91 uint8_t aAxis) const { 92 return mValue * GetUserUnitsPerUnit(aElement, aAxis); 93 } 94 95 /** 96 * Get this length's value in the units specified. 97 * 98 * This method returns numeric_limits<float>::quiet_NaN() if it is not 99 * possible to convert the value to the specified unit. 100 */ 101 float GetValueInSpecifiedUnit(uint8_t aUnit, const dom::SVGElement* aElement, 102 uint8_t aAxis) const; 103 IsPercentage()104 bool IsPercentage() const { 105 return mUnit == dom::SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE; 106 } 107 IsValidUnitType(uint16_t unit)108 static bool IsValidUnitType(uint16_t unit) { 109 return unit > dom::SVGLength_Binding::SVG_LENGTHTYPE_UNKNOWN && 110 unit <= dom::SVGLength_Binding::SVG_LENGTHTYPE_PC; 111 } 112 113 /** 114 * Returns the number of user units per current unit. 115 * 116 * This method returns numeric_limits<float>::quiet_NaN() if the conversion 117 * factor between the length's current unit and user units is undefined (see 118 * the comments for GetUserUnitsPerInch and GetUserUnitsPerPercent). 119 */ 120 float GetUserUnitsPerUnit(const dom::SVGElement* aElement, 121 uint8_t aAxis) const; 122 123 private: 124 #ifdef DEBUG IsValid()125 bool IsValid() const { return IsFinite(mValue) && IsValidUnitType(mUnit); } 126 #endif 127 128 /** 129 * The conversion factor between user units (CSS px) and CSS inches is 130 * constant: 96 px per inch. 131 */ GetUserUnitsPerInch()132 static float GetUserUnitsPerInch() { return 96.0; } 133 134 /** 135 * The conversion factor between user units and percentage units depends on 136 * aElement being non-null, and on aElement having a viewport element 137 * ancestor with only appropriate SVG elements between aElement and that 138 * ancestor. If that's not the case, then the conversion factor is undefined. 139 * 140 * This function returns a non-negative value if the conversion factor is 141 * defined, otherwise it returns numeric_limits<float>::quiet_NaN(). 142 */ 143 static float GetUserUnitsPerPercent(const dom::SVGElement* aElement, 144 uint8_t aAxis); 145 146 float mValue; 147 uint8_t mUnit; 148 }; 149 150 } // namespace mozilla 151 152 #endif // MOZILLA_SVGLENGTH_H__ 153