SVGRectElement.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. #include "mozilla/dom/SVGRectElement.h"
  6. #include "nsGkAtoms.h"
  7. #include "mozilla/dom/SVGRectElementBinding.h"
  8. #include "mozilla/gfx/2D.h"
  9. #include "mozilla/gfx/Matrix.h"
  10. #include "mozilla/gfx/Rect.h"
  11. #include "mozilla/gfx/PathHelpers.h"
  12. #include <algorithm>
  13. NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
  14. using namespace mozilla::gfx;
  15. namespace mozilla {
  16. namespace dom {
  17. class SVGAnimatedLength;
  18. JSObject*
  19. SVGRectElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
  20. {
  21. return SVGRectElementBinding::Wrap(aCx, this, aGivenProto);
  22. }
  23. nsSVGElement::LengthInfo SVGRectElement::sLengthInfo[6] =
  24. {
  25. { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
  26. { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
  27. { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
  28. { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
  29. { &nsGkAtoms::rx, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
  30. { &nsGkAtoms::ry, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y }
  31. };
  32. //----------------------------------------------------------------------
  33. // Implementation
  34. SVGRectElement::SVGRectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
  35. : SVGRectElementBase(aNodeInfo)
  36. {
  37. }
  38. //----------------------------------------------------------------------
  39. // nsIDOMNode methods
  40. NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGRectElement)
  41. //----------------------------------------------------------------------
  42. already_AddRefed<SVGAnimatedLength>
  43. SVGRectElement::X()
  44. {
  45. return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
  46. }
  47. already_AddRefed<SVGAnimatedLength>
  48. SVGRectElement::Y()
  49. {
  50. return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
  51. }
  52. already_AddRefed<SVGAnimatedLength>
  53. SVGRectElement::Width()
  54. {
  55. return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
  56. }
  57. already_AddRefed<SVGAnimatedLength>
  58. SVGRectElement::Height()
  59. {
  60. return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
  61. }
  62. already_AddRefed<SVGAnimatedLength>
  63. SVGRectElement::Rx()
  64. {
  65. return mLengthAttributes[ATTR_RX].ToDOMAnimatedLength(this);
  66. }
  67. already_AddRefed<SVGAnimatedLength>
  68. SVGRectElement::Ry()
  69. {
  70. return mLengthAttributes[ATTR_RY].ToDOMAnimatedLength(this);
  71. }
  72. //----------------------------------------------------------------------
  73. // nsSVGElement methods
  74. /* virtual */ bool
  75. SVGRectElement::HasValidDimensions() const
  76. {
  77. return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() &&
  78. mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
  79. mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() &&
  80. mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0;
  81. }
  82. nsSVGElement::LengthAttributesInfo
  83. SVGRectElement::GetLengthInfo()
  84. {
  85. return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
  86. ArrayLength(sLengthInfo));
  87. }
  88. //----------------------------------------------------------------------
  89. // nsSVGPathGeometryElement methods
  90. bool
  91. SVGRectElement::GetGeometryBounds(Rect* aBounds,
  92. const StrokeOptions& aStrokeOptions,
  93. const Matrix& aToBoundsSpace,
  94. const Matrix* aToNonScalingStrokeSpace)
  95. {
  96. Rect rect;
  97. Float rx, ry;
  98. GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
  99. &rect.height, &rx, &ry, nullptr);
  100. if (rect.IsEmpty()) {
  101. // Rendering of the element disabled
  102. rect.SetEmpty(); // Make sure width/height are zero and not negative
  103. // We still want the x/y position from 'rect'
  104. *aBounds = aToBoundsSpace.TransformBounds(rect);
  105. return true;
  106. }
  107. if (!aToBoundsSpace.IsRectilinear()) {
  108. // We can't ignore the radii in this case if we want tight bounds
  109. rx = std::max(rx, 0.0f);
  110. ry = std::max(ry, 0.0f);
  111. if (rx != 0 || ry != 0) {
  112. return false;
  113. }
  114. }
  115. if (aStrokeOptions.mLineWidth > 0.f) {
  116. if (aToNonScalingStrokeSpace) {
  117. if (aToNonScalingStrokeSpace->IsRectilinear()) {
  118. MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
  119. rect = aToNonScalingStrokeSpace->TransformBounds(rect);
  120. // Note that, in principle, an author could cause the corners of the
  121. // rect to be beveled by specifying stroke-linejoin or setting
  122. // stroke-miterlimit to be less than sqrt(2). In that very unlikely
  123. // event the bounds that we calculate here may be too big if
  124. // aToBoundsSpace is non-rectilinear. This is likely to be so rare it's
  125. // not worth handling though.
  126. rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
  127. Matrix nonScalingToBounds =
  128. aToNonScalingStrokeSpace->Inverse() * aToBoundsSpace;
  129. *aBounds = nonScalingToBounds.TransformBounds(rect);
  130. return true;
  131. }
  132. return false;
  133. }
  134. // The "beveled" comment above applies here too
  135. rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
  136. }
  137. *aBounds = aToBoundsSpace.TransformBounds(rect);
  138. return true;
  139. }
  140. void
  141. SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath)
  142. {
  143. float x, y, width, height, rx, ry;
  144. GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
  145. if (width <= 0 || height <= 0) {
  146. aSimplePath->Reset();
  147. return;
  148. }
  149. rx = std::max(rx, 0.0f);
  150. ry = std::max(ry, 0.0f);
  151. if (rx != 0 || ry != 0) {
  152. aSimplePath->Reset();
  153. return;
  154. }
  155. aSimplePath->SetRect(x, y, width, height);
  156. }
  157. already_AddRefed<Path>
  158. SVGRectElement::BuildPath(PathBuilder* aBuilder)
  159. {
  160. float x, y, width, height, rx, ry;
  161. GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
  162. if (width <= 0 || height <= 0) {
  163. return nullptr;
  164. }
  165. rx = std::max(rx, 0.0f);
  166. ry = std::max(ry, 0.0f);
  167. if (rx == 0 && ry == 0) {
  168. // Optimization for the no rounded corners case.
  169. Rect r(x, y, width, height);
  170. aBuilder->MoveTo(r.TopLeft());
  171. aBuilder->LineTo(r.TopRight());
  172. aBuilder->LineTo(r.BottomRight());
  173. aBuilder->LineTo(r.BottomLeft());
  174. aBuilder->Close();
  175. } else {
  176. // If either the 'rx' or the 'ry' attribute isn't set, then we have to
  177. // set it to the value of the other:
  178. bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
  179. bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
  180. MOZ_ASSERT(hasRx || hasRy);
  181. if (hasRx && !hasRy) {
  182. ry = rx;
  183. } else if (hasRy && !hasRx) {
  184. rx = ry;
  185. }
  186. // Clamp rx and ry to half the rect's width and height respectively:
  187. rx = std::min(rx, width / 2);
  188. ry = std::min(ry, height / 2);
  189. RectCornerRadii radii(rx, ry);
  190. AppendRoundedRectToPath(aBuilder, Rect(x, y, width, height), radii);
  191. }
  192. return aBuilder->Finish();
  193. }
  194. } // namespace dom
  195. } // namespace mozilla