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 the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Crocodile Clips Ltd..
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * William Cook <william.cook@crocodile-clips.com> (original author)
24 : * Alex Fritze <alex.fritze@crocodile-clips.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "mozilla/Util.h"
41 :
42 : #include "nsSVGPathGeometryElement.h"
43 : #include "nsIDOMSVGRectElement.h"
44 : #include "nsSVGLength2.h"
45 : #include "nsGkAtoms.h"
46 : #include "gfxContext.h"
47 :
48 : using namespace mozilla;
49 :
50 : typedef nsSVGPathGeometryElement nsSVGRectElementBase;
51 :
52 : class nsSVGRectElement : public nsSVGRectElementBase,
53 : public nsIDOMSVGRectElement
54 0 : {
55 : protected:
56 : friend nsresult NS_NewSVGRectElement(nsIContent **aResult,
57 : already_AddRefed<nsINodeInfo> aNodeInfo);
58 : nsSVGRectElement(already_AddRefed<nsINodeInfo> aNodeInfo);
59 :
60 : public:
61 : // interfaces:
62 : NS_DECL_ISUPPORTS_INHERITED
63 : NS_DECL_NSIDOMSVGRECTELEMENT
64 :
65 : // xxx I wish we could use virtual inheritance
66 0 : NS_FORWARD_NSIDOMNODE(nsSVGRectElementBase::)
67 0 : NS_FORWARD_NSIDOMELEMENT(nsSVGRectElementBase::)
68 0 : NS_FORWARD_NSIDOMSVGELEMENT(nsSVGRectElementBase::)
69 :
70 : // nsSVGSVGElement methods:
71 : virtual bool HasValidDimensions() const;
72 :
73 : // nsSVGPathGeometryElement methods:
74 : virtual void ConstructPath(gfxContext *aCtx);
75 :
76 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
77 :
78 : virtual nsXPCClassInfo* GetClassInfo();
79 : protected:
80 :
81 : virtual LengthAttributesInfo GetLengthInfo();
82 :
83 : enum { X, Y, WIDTH, HEIGHT, RX, RY };
84 : nsSVGLength2 mLengthAttributes[6];
85 : static LengthInfo sLengthInfo[6];
86 : };
87 :
88 : nsSVGElement::LengthInfo nsSVGRectElement::sLengthInfo[6] =
89 : {
90 : { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
91 : { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
92 : { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
93 : { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
94 : { &nsGkAtoms::rx, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
95 : { &nsGkAtoms::ry, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y }
96 : };
97 :
98 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(Rect)
99 :
100 : //----------------------------------------------------------------------
101 : // nsISupports methods
102 :
103 0 : NS_IMPL_ADDREF_INHERITED(nsSVGRectElement,nsSVGRectElementBase)
104 0 : NS_IMPL_RELEASE_INHERITED(nsSVGRectElement,nsSVGRectElementBase)
105 :
106 0 : DOMCI_NODE_DATA(SVGRectElement, nsSVGRectElement)
107 :
108 0 : NS_INTERFACE_TABLE_HEAD(nsSVGRectElement)
109 0 : NS_NODE_INTERFACE_TABLE5(nsSVGRectElement, nsIDOMNode, nsIDOMElement,
110 : nsIDOMSVGElement, nsIDOMSVGTests,
111 : nsIDOMSVGRectElement)
112 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGRectElement)
113 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGRectElementBase)
114 :
115 : //----------------------------------------------------------------------
116 : // Implementation
117 :
118 0 : nsSVGRectElement::nsSVGRectElement(already_AddRefed<nsINodeInfo> aNodeInfo)
119 0 : : nsSVGRectElementBase(aNodeInfo)
120 : {
121 0 : }
122 :
123 : //----------------------------------------------------------------------
124 : // nsIDOMNode methods
125 :
126 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGRectElement)
127 :
128 : //----------------------------------------------------------------------
129 : // nsIDOMSVGRectElement methods
130 :
131 : /* readonly attribute nsIDOMSVGAnimatedLength x; */
132 0 : NS_IMETHODIMP nsSVGRectElement::GetX(nsIDOMSVGAnimatedLength * *aX)
133 : {
134 0 : return mLengthAttributes[X].ToDOMAnimatedLength(aX, this);
135 : }
136 :
137 : /* readonly attribute nsIDOMSVGAnimatedLength y; */
138 0 : NS_IMETHODIMP nsSVGRectElement::GetY(nsIDOMSVGAnimatedLength * *aY)
139 : {
140 0 : return mLengthAttributes[Y].ToDOMAnimatedLength(aY, this);
141 : }
142 :
143 : /* readonly attribute nsIDOMSVGAnimatedLength width; */
144 0 : NS_IMETHODIMP nsSVGRectElement::GetWidth(nsIDOMSVGAnimatedLength * *aWidth)
145 : {
146 0 : return mLengthAttributes[WIDTH].ToDOMAnimatedLength(aWidth, this);
147 : }
148 :
149 : /* readonly attribute nsIDOMSVGAnimatedLength height; */
150 0 : NS_IMETHODIMP nsSVGRectElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
151 : {
152 0 : return mLengthAttributes[HEIGHT].ToDOMAnimatedLength(aHeight, this);
153 : }
154 :
155 : /* readonly attribute nsIDOMSVGAnimatedLength rx; */
156 0 : NS_IMETHODIMP nsSVGRectElement::GetRx(nsIDOMSVGAnimatedLength * *aRx)
157 : {
158 0 : return mLengthAttributes[RX].ToDOMAnimatedLength(aRx, this);
159 : }
160 :
161 : /* readonly attribute nsIDOMSVGAnimatedLength ry; */
162 0 : NS_IMETHODIMP nsSVGRectElement::GetRy(nsIDOMSVGAnimatedLength * *aRy)
163 : {
164 0 : return mLengthAttributes[RY].ToDOMAnimatedLength(aRy, this);
165 : }
166 :
167 : //----------------------------------------------------------------------
168 : // nsSVGElement methods
169 :
170 : /* virtual */ bool
171 0 : nsSVGRectElement::HasValidDimensions() const
172 : {
173 0 : return mLengthAttributes[WIDTH].IsExplicitlySet() &&
174 0 : mLengthAttributes[WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
175 0 : mLengthAttributes[HEIGHT].IsExplicitlySet() &&
176 0 : mLengthAttributes[HEIGHT].GetAnimValInSpecifiedUnits() > 0;
177 : }
178 :
179 : nsSVGElement::LengthAttributesInfo
180 0 : nsSVGRectElement::GetLengthInfo()
181 : {
182 : return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
183 0 : ArrayLength(sLengthInfo));
184 : }
185 :
186 : //----------------------------------------------------------------------
187 : // nsSVGPathGeometryElement methods
188 :
189 : void
190 0 : nsSVGRectElement::ConstructPath(gfxContext *aCtx)
191 : {
192 : float x, y, width, height, rx, ry;
193 :
194 0 : GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nsnull);
195 :
196 : /* In a perfect world, this would be handled by the DOM, and
197 : return a DOM exception. */
198 0 : if (width <= 0 || height <= 0)
199 0 : return;
200 :
201 0 : rx = NS_MAX(rx, 0.0f);
202 0 : ry = NS_MAX(ry, 0.0f);
203 :
204 : /* optimize the no rounded corners case */
205 0 : if (rx == 0 && ry == 0) {
206 0 : aCtx->Rectangle(gfxRect(x, y, width, height));
207 0 : return;
208 : }
209 :
210 : /* If either the 'rx' or the 'ry' attribute isn't set, then we
211 : have to set it to the value of the other. */
212 0 : bool hasRx = mLengthAttributes[RX].IsExplicitlySet();
213 0 : bool hasRy = mLengthAttributes[RY].IsExplicitlySet();
214 0 : if (hasRx && !hasRy)
215 0 : ry = rx;
216 0 : else if (hasRy && !hasRx)
217 0 : rx = ry;
218 :
219 : /* Clamp rx and ry to half the rect's width and height respectively. */
220 0 : float halfWidth = width/2;
221 0 : float halfHeight = height/2;
222 0 : if (rx > halfWidth)
223 0 : rx = halfWidth;
224 0 : if (ry > halfHeight)
225 0 : ry = halfHeight;
226 :
227 0 : gfxSize corner(rx, ry);
228 : aCtx->RoundedRectangle(gfxRect(x, y, width, height),
229 0 : gfxCornerSizes(corner, corner, corner, corner));
230 : }
|