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 IBM Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2004
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either of the GNU General Public License Version 2 or later (the "GPL"),
25 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "mozilla/Util.h"
38 :
39 : #include "nsGkAtoms.h"
40 : #include "nsCOMPtr.h"
41 : #include "SVGAnimatedPreserveAspectRatio.h"
42 : #include "nsDOMError.h"
43 : #include "nsSVGUtils.h"
44 : #include "nsSVGMarkerElement.h"
45 : #include "gfxMatrix.h"
46 : #include "nsContentUtils.h" // NS_ENSURE_FINITE
47 :
48 : using namespace mozilla;
49 :
50 : nsSVGElement::LengthInfo nsSVGMarkerElement::sLengthInfo[4] =
51 : {
52 : { &nsGkAtoms::refX, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
53 : { &nsGkAtoms::refY, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
54 : { &nsGkAtoms::markerWidth, 3, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
55 : { &nsGkAtoms::markerHeight, 3, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
56 : };
57 :
58 : nsSVGEnumMapping nsSVGMarkerElement::sUnitsMap[] = {
59 : {&nsGkAtoms::strokeWidth, nsIDOMSVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH},
60 : {&nsGkAtoms::userSpaceOnUse, nsIDOMSVGMarkerElement::SVG_MARKERUNITS_USERSPACEONUSE},
61 : {nsnull, 0}
62 : };
63 :
64 : nsSVGElement::EnumInfo nsSVGMarkerElement::sEnumInfo[1] =
65 : {
66 : { &nsGkAtoms::markerUnits,
67 : sUnitsMap,
68 : nsIDOMSVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH
69 : }
70 : };
71 :
72 : nsSVGElement::AngleInfo nsSVGMarkerElement::sAngleInfo[1] =
73 : {
74 : { &nsGkAtoms::orient, 0, nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED }
75 : };
76 :
77 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(Marker)
78 :
79 : //----------------------------------------------------------------------
80 : // nsISupports methods
81 :
82 1464 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGOrientType::DOMAnimatedEnum, mSVGElement)
83 :
84 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGOrientType::DOMAnimatedEnum)
85 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGOrientType::DOMAnimatedEnum)
86 :
87 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGOrientType::DOMAnimatedEnum)
88 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedEnumeration)
89 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
90 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedEnumeration)
91 0 : NS_INTERFACE_MAP_END
92 :
93 0 : NS_IMPL_ADDREF_INHERITED(nsSVGMarkerElement,nsSVGMarkerElementBase)
94 0 : NS_IMPL_RELEASE_INHERITED(nsSVGMarkerElement,nsSVGMarkerElementBase)
95 :
96 0 : DOMCI_NODE_DATA(SVGMarkerElement, nsSVGMarkerElement)
97 :
98 0 : NS_INTERFACE_TABLE_HEAD(nsSVGMarkerElement)
99 0 : NS_NODE_INTERFACE_TABLE5(nsSVGMarkerElement, nsIDOMNode, nsIDOMElement,
100 : nsIDOMSVGElement, nsIDOMSVGFitToViewBox,
101 : nsIDOMSVGMarkerElement)
102 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGMarkerElement)
103 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGMarkerElementBase)
104 :
105 : //----------------------------------------------------------------------
106 : // Implementation
107 :
108 : nsresult
109 0 : nsSVGOrientType::SetBaseValue(PRUint16 aValue,
110 : nsSVGElement *aSVGElement)
111 : {
112 0 : if (aValue == nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_AUTO ||
113 : aValue == nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {
114 0 : SetBaseValue(aValue);
115 : aSVGElement->SetAttr(
116 : kNameSpaceID_None, nsGkAtoms::orient, nsnull,
117 : (aValue ==nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_AUTO ?
118 0 : NS_LITERAL_STRING("auto") : NS_LITERAL_STRING("0")),
119 0 : true);
120 0 : return NS_OK;
121 : }
122 0 : return NS_ERROR_DOM_SYNTAX_ERR;
123 : }
124 :
125 : nsresult
126 0 : nsSVGOrientType::ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
127 : nsSVGElement *aSVGElement)
128 : {
129 0 : *aResult = new DOMAnimatedEnum(this, aSVGElement);
130 0 : if (!*aResult)
131 0 : return NS_ERROR_OUT_OF_MEMORY;
132 :
133 0 : NS_ADDREF(*aResult);
134 0 : return NS_OK;
135 : }
136 :
137 0 : nsSVGMarkerElement::nsSVGMarkerElement(already_AddRefed<nsINodeInfo> aNodeInfo)
138 0 : : nsSVGMarkerElementBase(aNodeInfo), mCoordCtx(nsnull)
139 : {
140 0 : }
141 :
142 : //----------------------------------------------------------------------
143 : // nsIDOMNode methods
144 :
145 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGMarkerElement)
146 :
147 : //----------------------------------------------------------------------
148 : // nsIDOMSVGFitToViewBox methods
149 :
150 : /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
151 0 : NS_IMETHODIMP nsSVGMarkerElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
152 : {
153 0 : return mViewBox.ToDOMAnimatedRect(aViewBox, this);
154 : }
155 :
156 : /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
157 : NS_IMETHODIMP
158 0 : nsSVGMarkerElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
159 : **aPreserveAspectRatio)
160 : {
161 0 : return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
162 : }
163 :
164 : //----------------------------------------------------------------------
165 : // nsIDOMSVGMarkerElement methods
166 :
167 : /* readonly attribute nsIDOMSVGAnimatedLength refX; */
168 0 : NS_IMETHODIMP nsSVGMarkerElement::GetRefX(nsIDOMSVGAnimatedLength * *aRefX)
169 : {
170 0 : return mLengthAttributes[REFX].ToDOMAnimatedLength(aRefX, this);
171 : }
172 :
173 : /* readonly attribute nsIDOMSVGAnimatedLength refY; */
174 0 : NS_IMETHODIMP nsSVGMarkerElement::GetRefY(nsIDOMSVGAnimatedLength * *aRefY)
175 : {
176 0 : return mLengthAttributes[REFY].ToDOMAnimatedLength(aRefY, this);
177 : }
178 :
179 : /* readonly attribute nsIDOMSVGAnimatedEnumeration markerUnits; */
180 0 : NS_IMETHODIMP nsSVGMarkerElement::GetMarkerUnits(nsIDOMSVGAnimatedEnumeration * *aMarkerUnits)
181 : {
182 0 : return mEnumAttributes[MARKERUNITS].ToDOMAnimatedEnum(aMarkerUnits, this);
183 : }
184 :
185 : /* readonly attribute nsIDOMSVGAnimatedLength markerWidth; */
186 0 : NS_IMETHODIMP nsSVGMarkerElement::GetMarkerWidth(nsIDOMSVGAnimatedLength * *aMarkerWidth)
187 : {
188 0 : return mLengthAttributes[MARKERWIDTH].ToDOMAnimatedLength(aMarkerWidth, this);
189 : }
190 :
191 : /* readonly attribute nsIDOMSVGAnimatedLength markerHeight; */
192 0 : NS_IMETHODIMP nsSVGMarkerElement::GetMarkerHeight(nsIDOMSVGAnimatedLength * *aMarkerHeight)
193 : {
194 0 : return mLengthAttributes[MARKERHEIGHT].ToDOMAnimatedLength(aMarkerHeight, this);
195 : }
196 :
197 : /* readonly attribute nsIDOMSVGAnimatedEnumeration orientType; */
198 0 : NS_IMETHODIMP nsSVGMarkerElement::GetOrientType(nsIDOMSVGAnimatedEnumeration * *aOrientType)
199 : {
200 0 : return mOrientType.ToDOMAnimatedEnum(aOrientType, this);
201 : }
202 :
203 : /* readonly attribute nsIDOMSVGAnimatedLength orientAngle; */
204 0 : NS_IMETHODIMP nsSVGMarkerElement::GetOrientAngle(nsIDOMSVGAnimatedAngle * *aOrientAngle)
205 : {
206 0 : return mAngleAttributes[ORIENT].ToDOMAnimatedAngle(aOrientAngle, this);
207 : }
208 :
209 : /* void setOrientToAuto (); */
210 0 : NS_IMETHODIMP nsSVGMarkerElement::SetOrientToAuto()
211 : {
212 : SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nsnull,
213 0 : NS_LITERAL_STRING("auto"), true);
214 0 : return NS_OK;
215 : }
216 :
217 : /* void setOrientToAngle (in nsIDOMSVGAngle angle); */
218 0 : NS_IMETHODIMP nsSVGMarkerElement::SetOrientToAngle(nsIDOMSVGAngle *angle)
219 : {
220 0 : if (!angle)
221 0 : return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
222 :
223 : float f;
224 0 : nsresult rv = angle->GetValue(&f);
225 0 : NS_ENSURE_SUCCESS(rv, rv);
226 0 : NS_ENSURE_FINITE(f, NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
227 0 : mAngleAttributes[ORIENT].SetBaseValue(f, this, true);
228 :
229 0 : return NS_OK;
230 : }
231 :
232 : //----------------------------------------------------------------------
233 : // nsIContent methods
234 :
235 : NS_IMETHODIMP_(bool)
236 0 : nsSVGMarkerElement::IsAttributeMapped(const nsIAtom* name) const
237 : {
238 : static const MappedAttributeEntry* const map[] = {
239 : sFEFloodMap,
240 : sFiltersMap,
241 : sFontSpecificationMap,
242 : sGradientStopMap,
243 : sLightingEffectsMap,
244 : sMarkersMap,
245 : sTextContentElementsMap,
246 : sViewportsMap
247 : };
248 :
249 0 : return FindAttributeDependence(name, map) ||
250 0 : nsSVGMarkerElementBase::IsAttributeMapped(name);
251 : }
252 :
253 : //----------------------------------------------------------------------
254 : // nsSVGElement methods
255 :
256 : bool
257 0 : nsSVGMarkerElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
258 : nsAString &aResult) const
259 : {
260 0 : if (aNameSpaceID == kNameSpaceID_None &&
261 : aName == nsGkAtoms::orient &&
262 0 : mOrientType.GetBaseValue() == SVG_MARKER_ORIENT_AUTO) {
263 0 : aResult.AssignLiteral("auto");
264 0 : return true;
265 : }
266 0 : return nsSVGMarkerElementBase::GetAttr(aNameSpaceID, aName, aResult);
267 : }
268 :
269 : bool
270 0 : nsSVGMarkerElement::ParseAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
271 : const nsAString& aValue,
272 : nsAttrValue& aResult)
273 : {
274 0 : if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::orient) {
275 0 : if (aValue.EqualsLiteral("auto")) {
276 0 : mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO);
277 0 : aResult.SetTo(aValue);
278 0 : return true;
279 : }
280 0 : mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
281 : }
282 : return nsSVGMarkerElementBase::ParseAttribute(aNameSpaceID, aName,
283 0 : aValue, aResult);
284 : }
285 :
286 : nsresult
287 0 : nsSVGMarkerElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
288 : bool aNotify)
289 : {
290 0 : if (aNamespaceID == kNameSpaceID_None) {
291 0 : if (aName == nsGkAtoms::orient) {
292 0 : mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
293 : }
294 : }
295 :
296 0 : return nsSVGMarkerElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
297 : }
298 :
299 : //----------------------------------------------------------------------
300 : // nsSVGElement methods
301 :
302 : void
303 0 : nsSVGMarkerElement::SetParentCoordCtxProvider(nsSVGSVGElement *aContext)
304 : {
305 0 : mCoordCtx = aContext;
306 0 : mViewBoxToViewportTransform = nsnull;
307 0 : }
308 :
309 : /* virtual */ bool
310 0 : nsSVGMarkerElement::HasValidDimensions() const
311 : {
312 0 : return (!mLengthAttributes[MARKERWIDTH].IsExplicitlySet() ||
313 0 : mLengthAttributes[MARKERWIDTH].GetAnimValInSpecifiedUnits() > 0) &&
314 0 : (!mLengthAttributes[MARKERHEIGHT].IsExplicitlySet() ||
315 0 : mLengthAttributes[MARKERHEIGHT].GetAnimValInSpecifiedUnits() > 0);
316 : }
317 :
318 : nsSVGElement::LengthAttributesInfo
319 0 : nsSVGMarkerElement::GetLengthInfo()
320 : {
321 : return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
322 0 : ArrayLength(sLengthInfo));
323 : }
324 :
325 : nsSVGElement::AngleAttributesInfo
326 0 : nsSVGMarkerElement::GetAngleInfo()
327 : {
328 : return AngleAttributesInfo(mAngleAttributes, sAngleInfo,
329 0 : ArrayLength(sAngleInfo));
330 : }
331 :
332 : nsSVGElement::EnumAttributesInfo
333 0 : nsSVGMarkerElement::GetEnumInfo()
334 : {
335 : return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
336 0 : ArrayLength(sEnumInfo));
337 : }
338 :
339 : nsSVGViewBox *
340 0 : nsSVGMarkerElement::GetViewBox()
341 : {
342 0 : return &mViewBox;
343 : }
344 :
345 : SVGAnimatedPreserveAspectRatio *
346 0 : nsSVGMarkerElement::GetPreserveAspectRatio()
347 : {
348 0 : return &mPreserveAspectRatio;
349 : }
350 :
351 : //----------------------------------------------------------------------
352 : // public helpers
353 :
354 : gfxMatrix
355 0 : nsSVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
356 : float aX, float aY, float aAutoAngle)
357 : {
358 0 : gfxFloat scale = mEnumAttributes[MARKERUNITS].GetAnimValue() ==
359 0 : SVG_MARKERUNITS_STROKEWIDTH ? aStrokeWidth : 1.0;
360 :
361 0 : gfxFloat angle = mOrientType.GetAnimValue() == SVG_MARKER_ORIENT_AUTO ?
362 : aAutoAngle :
363 0 : mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0;
364 :
365 0 : return gfxMatrix(cos(angle) * scale, sin(angle) * scale,
366 0 : -sin(angle) * scale, cos(angle) * scale,
367 0 : aX, aY);
368 : }
369 :
370 : nsSVGViewBoxRect
371 0 : nsSVGMarkerElement::GetViewBoxRect()
372 : {
373 0 : if (mViewBox.IsValid()) {
374 0 : return mViewBox.GetAnimValue();
375 : }
376 : return nsSVGViewBoxRect(
377 : 0, 0,
378 : mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
379 0 : mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
380 : }
381 :
382 : gfxMatrix
383 0 : nsSVGMarkerElement::GetViewBoxTransform()
384 : {
385 0 : if (!mViewBoxToViewportTransform) {
386 : float viewportWidth =
387 0 : mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx);
388 : float viewportHeight =
389 0 : mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx);
390 :
391 0 : nsSVGViewBoxRect viewbox = GetViewBoxRect();
392 :
393 0 : NS_ABORT_IF_FALSE(viewbox.width > 0.0f && viewbox.height > 0.0f,
394 : "Rendering should be disabled");
395 :
396 : gfxMatrix viewBoxTM =
397 : nsSVGUtils::GetViewBoxTransform(this,
398 : viewportWidth, viewportHeight,
399 : viewbox.x, viewbox.y,
400 : viewbox.width, viewbox.height,
401 0 : mPreserveAspectRatio);
402 :
403 0 : float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
404 0 : float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
405 :
406 0 : gfxPoint ref = viewBoxTM.Transform(gfxPoint(refX, refY));
407 :
408 0 : gfxMatrix TM = viewBoxTM * gfxMatrix().Translate(gfxPoint(-ref.x, -ref.y));
409 :
410 0 : mViewBoxToViewportTransform = new gfxMatrix(TM);
411 : }
412 :
413 0 : return *mViewBoxToViewportTransform;
414 4392 : }
415 :
416 :
|