SVGLength.h 5.1 KB

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