Bumping manifests a=b2g-bump
[gecko.git] / dom / svg / SVGRectElement.cpp
blob5b00e54b31175d03fdeec92a0cf658fc3b9218e6
1 /* -*- Mode: C++; tab-width: 2; 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/. */
6 #include "mozilla/dom/SVGRectElement.h"
7 #include "nsGkAtoms.h"
8 #include "mozilla/dom/SVGRectElementBinding.h"
9 #include "mozilla/gfx/2D.h"
10 #include "mozilla/gfx/Matrix.h"
11 #include "mozilla/gfx/Rect.h"
12 #include "mozilla/gfx/PathHelpers.h"
13 #include <algorithm>
15 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
17 using namespace mozilla::gfx;
19 namespace mozilla {
20 namespace dom {
22 class SVGAnimatedLength;
24 JSObject*
25 SVGRectElement::WrapNode(JSContext *aCx)
27 return SVGRectElementBinding::Wrap(aCx, this);
30 nsSVGElement::LengthInfo SVGRectElement::sLengthInfo[6] =
32 { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
33 { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
34 { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
35 { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
36 { &nsGkAtoms::rx, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
37 { &nsGkAtoms::ry, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y }
40 //----------------------------------------------------------------------
41 // Implementation
43 SVGRectElement::SVGRectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
44 : SVGRectElementBase(aNodeInfo)
48 //----------------------------------------------------------------------
49 // nsIDOMNode methods
51 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGRectElement)
53 //----------------------------------------------------------------------
55 already_AddRefed<SVGAnimatedLength>
56 SVGRectElement::X()
58 return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
61 already_AddRefed<SVGAnimatedLength>
62 SVGRectElement::Y()
64 return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
67 already_AddRefed<SVGAnimatedLength>
68 SVGRectElement::Width()
70 return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
73 already_AddRefed<SVGAnimatedLength>
74 SVGRectElement::Height()
76 return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
79 already_AddRefed<SVGAnimatedLength>
80 SVGRectElement::Rx()
82 return mLengthAttributes[ATTR_RX].ToDOMAnimatedLength(this);
85 already_AddRefed<SVGAnimatedLength>
86 SVGRectElement::Ry()
88 return mLengthAttributes[ATTR_RY].ToDOMAnimatedLength(this);
91 //----------------------------------------------------------------------
92 // nsSVGElement methods
94 /* virtual */ bool
95 SVGRectElement::HasValidDimensions() const
97 return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() &&
98 mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
99 mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() &&
100 mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0;
103 nsSVGElement::LengthAttributesInfo
104 SVGRectElement::GetLengthInfo()
106 return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
107 ArrayLength(sLengthInfo));
110 //----------------------------------------------------------------------
111 // nsSVGPathGeometryElement methods
113 bool
114 SVGRectElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
115 const Matrix& aTransform)
117 Rect rect;
118 Float rx, ry;
119 GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
120 &rect.height, &rx, &ry, nullptr);
122 if (rect.IsEmpty()) {
123 // Rendering of the element disabled
124 rect.SetEmpty(); // Make sure width/height are zero and not negative
125 *aBounds = rect; // We still want the x/y position from 'rect'
126 return true;
129 if (!aTransform.IsRectilinear()) {
130 // We can't ignore the radii in this case if we want tight bounds
131 rx = std::max(rx, 0.0f);
132 ry = std::max(ry, 0.0f);
134 if (rx != 0 || ry != 0) {
135 return false;
139 if (aStrokeWidth > 0.f) {
140 rect.Inflate(aStrokeWidth / 2.f);
143 *aBounds = aTransform.TransformBounds(rect);
144 return true;
147 void
148 SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath)
150 float x, y, width, height, rx, ry;
151 GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
153 if (width <= 0 || height <= 0) {
154 aSimplePath->Reset();
155 return;
158 rx = std::max(rx, 0.0f);
159 ry = std::max(ry, 0.0f);
161 if (rx != 0 || ry != 0) {
162 aSimplePath->Reset();
163 return;
166 aSimplePath->SetRect(x, y, width, height);
169 TemporaryRef<Path>
170 SVGRectElement::BuildPath(PathBuilder* aBuilder)
172 float x, y, width, height, rx, ry;
173 GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
175 if (width <= 0 || height <= 0) {
176 return nullptr;
179 rx = std::max(rx, 0.0f);
180 ry = std::max(ry, 0.0f);
182 if (rx == 0 && ry == 0) {
183 // Optimization for the no rounded corners case.
184 Rect r(x, y, width, height);
185 aBuilder->MoveTo(r.TopLeft());
186 aBuilder->LineTo(r.TopRight());
187 aBuilder->LineTo(r.BottomRight());
188 aBuilder->LineTo(r.BottomLeft());
189 aBuilder->Close();
190 } else {
191 // If either the 'rx' or the 'ry' attribute isn't set, then we have to
192 // set it to the value of the other:
193 bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
194 bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
195 MOZ_ASSERT(hasRx || hasRy);
197 if (hasRx && !hasRy) {
198 ry = rx;
199 } else if (hasRy && !hasRx) {
200 rx = ry;
203 // Clamp rx and ry to half the rect's width and height respectively:
204 rx = std::min(rx, width / 2);
205 ry = std::min(ry, height / 2);
207 RectCornerRadii radii(rx, ry);
208 AppendRoundedRectToPath(aBuilder, Rect(x, y, width, height), radii);
211 return aBuilder->Finish();
214 } // namespace dom
215 } // namespace mozilla