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 the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Daniel Holbert <dholbert@mozilla.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "mozilla/Util.h"
39 :
40 : #include "nsSVGMpathElement.h"
41 : #include "nsAutoPtr.h"
42 : #include "nsDebug.h"
43 : #include "nsSVGPathElement.h"
44 : #include "nsSVGAnimateMotionElement.h"
45 : #include "nsContentUtils.h"
46 :
47 : using namespace mozilla;
48 : using namespace mozilla::dom;
49 :
50 : nsSVGElement::StringInfo nsSVGMpathElement::sStringInfo[1] =
51 : {
52 : { &nsGkAtoms::href, kNameSpaceID_XLink, false }
53 : };
54 :
55 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(Mpath)
56 :
57 : // Cycle collection magic -- based on nsSVGUseElement
58 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGMpathElement)
59 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsSVGMpathElement,
60 : nsSVGMpathElementBase)
61 0 : tmp->UnlinkHrefTarget(false);
62 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
63 :
64 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsSVGMpathElement,
65 : nsSVGMpathElementBase)
66 0 : tmp->mHrefTarget.Traverse(&cb);
67 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
68 :
69 : //----------------------------------------------------------------------
70 : // nsISupports methods
71 :
72 0 : NS_IMPL_ADDREF_INHERITED(nsSVGMpathElement,nsSVGMpathElementBase)
73 0 : NS_IMPL_RELEASE_INHERITED(nsSVGMpathElement,nsSVGMpathElementBase)
74 :
75 0 : DOMCI_NODE_DATA(SVGMpathElement, nsSVGMpathElement)
76 :
77 0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsSVGMpathElement)
78 0 : NS_NODE_INTERFACE_TABLE6(nsSVGMpathElement, nsIDOMNode, nsIDOMElement,
79 : nsIDOMSVGElement, nsIDOMSVGURIReference,
80 : nsIDOMSVGMpathElement, nsIMutationObserver)
81 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGMpathElement)
82 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGMpathElementBase)
83 :
84 : // Constructor
85 : #ifdef _MSC_VER
86 : // Disable "warning C4355: 'this' : used in base member initializer list".
87 : // We can ignore that warning because we know that mHrefTarget's constructor
88 : // doesn't dereference the pointer passed to it.
89 : #pragma warning(push)
90 : #pragma warning(disable:4355)
91 : #endif
92 0 : nsSVGMpathElement::nsSVGMpathElement(already_AddRefed<nsINodeInfo> aNodeInfo)
93 : : nsSVGMpathElementBase(aNodeInfo),
94 0 : mHrefTarget(this)
95 : #ifdef _MSC_VER
96 : #pragma warning(pop)
97 : #endif
98 : {
99 0 : }
100 :
101 0 : nsSVGMpathElement::~nsSVGMpathElement()
102 : {
103 0 : UnlinkHrefTarget(false);
104 0 : }
105 :
106 : //----------------------------------------------------------------------
107 : // nsIDOMNode methods
108 :
109 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGMpathElement)
110 :
111 : //----------------------------------------------------------------------
112 : // nsIDOMSVGURIReference methods
113 :
114 : /* readonly attribute nsIDOMSVGAnimatedString href; */
115 : NS_IMETHODIMP
116 0 : nsSVGMpathElement::GetHref(nsIDOMSVGAnimatedString** aHref)
117 : {
118 0 : return mStringAttributes[HREF].ToDOMAnimatedString(aHref, this);
119 : }
120 :
121 : //----------------------------------------------------------------------
122 : // nsIContent methods
123 :
124 : nsresult
125 0 : nsSVGMpathElement::BindToTree(nsIDocument* aDocument,
126 : nsIContent* aParent,
127 : nsIContent* aBindingParent,
128 : bool aCompileEventHandlers)
129 : {
130 0 : NS_ABORT_IF_FALSE(!mHrefTarget.get(),
131 : "Shouldn't have href-target yet "
132 : "(or it should've been cleared)");
133 : nsresult rv = nsSVGMpathElementBase::BindToTree(aDocument, aParent,
134 : aBindingParent,
135 0 : aCompileEventHandlers);
136 0 : NS_ENSURE_SUCCESS(rv,rv);
137 :
138 0 : if (aDocument) {
139 : const nsAttrValue* hrefAttrValue =
140 0 : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
141 0 : if (hrefAttrValue) {
142 0 : UpdateHrefTarget(aParent, hrefAttrValue->GetStringValue());
143 : }
144 : }
145 :
146 0 : return NS_OK;
147 : }
148 :
149 : void
150 0 : nsSVGMpathElement::UnbindFromTree(bool aDeep, bool aNullParent)
151 : {
152 0 : UnlinkHrefTarget(true);
153 0 : nsSVGMpathElementBase::UnbindFromTree(aDeep, aNullParent);
154 0 : }
155 :
156 : bool
157 0 : nsSVGMpathElement::ParseAttribute(PRInt32 aNamespaceID,
158 : nsIAtom* aAttribute,
159 : const nsAString& aValue,
160 : nsAttrValue& aResult)
161 : {
162 : bool returnVal =
163 : nsSVGMpathElementBase::ParseAttribute(aNamespaceID, aAttribute,
164 0 : aValue, aResult);
165 0 : if (aNamespaceID == kNameSpaceID_XLink &&
166 : aAttribute == nsGkAtoms::href &&
167 0 : IsInDoc()) {
168 : // NOTE: If we fail the IsInDoc call, it's ok -- we'll update the target
169 : // on next BindToTree call.
170 0 : UpdateHrefTarget(GetParent(), aValue);
171 : }
172 0 : return returnVal;
173 : }
174 :
175 : nsresult
176 0 : nsSVGMpathElement::UnsetAttr(PRInt32 aNamespaceID,
177 : nsIAtom* aAttribute, bool aNotify)
178 : {
179 : nsresult rv = nsSVGMpathElementBase::UnsetAttr(aNamespaceID, aAttribute,
180 0 : aNotify);
181 0 : NS_ENSURE_SUCCESS(rv, rv);
182 :
183 0 : if (aNamespaceID == kNameSpaceID_XLink &&
184 : aAttribute == nsGkAtoms::href) {
185 0 : UnlinkHrefTarget(true);
186 : }
187 :
188 0 : return NS_OK;
189 : }
190 :
191 : //----------------------------------------------------------------------
192 : // nsSVGElement methods
193 :
194 : nsSVGElement::StringAttributesInfo
195 0 : nsSVGMpathElement::GetStringInfo()
196 : {
197 : return StringAttributesInfo(mStringAttributes, sStringInfo,
198 0 : ArrayLength(sStringInfo));
199 : }
200 :
201 : //----------------------------------------------------------------------
202 : // nsIMutationObserver methods
203 :
204 : void
205 0 : nsSVGMpathElement::AttributeChanged(nsIDocument* aDocument,
206 : Element* aElement,
207 : PRInt32 aNameSpaceID,
208 : nsIAtom* aAttribute,
209 : PRInt32 aModType)
210 : {
211 0 : if (aNameSpaceID == kNameSpaceID_None) {
212 0 : if (aAttribute == nsGkAtoms::d) {
213 0 : NotifyParentOfMpathChange(GetParent());
214 : }
215 : }
216 0 : }
217 :
218 : //----------------------------------------------------------------------
219 : // Public helper methods
220 :
221 : nsSVGPathElement*
222 0 : nsSVGMpathElement::GetReferencedPath()
223 : {
224 0 : if (!HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)) {
225 0 : NS_ABORT_IF_FALSE(!mHrefTarget.get(),
226 : "We shouldn't have an xlink:href target "
227 : "if we don't have an xlink:href attribute");
228 0 : return nsnull;
229 : }
230 :
231 0 : nsIContent* genericTarget = mHrefTarget.get();
232 0 : if (genericTarget && genericTarget->IsSVG(nsGkAtoms::path)) {
233 0 : return static_cast<nsSVGPathElement*>(genericTarget);
234 : }
235 0 : return nsnull;
236 : }
237 :
238 : //----------------------------------------------------------------------
239 : // Protected helper methods
240 :
241 : void
242 0 : nsSVGMpathElement::UpdateHrefTarget(nsIContent* aParent,
243 : const nsAString& aHrefStr)
244 : {
245 0 : nsCOMPtr<nsIURI> targetURI;
246 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
247 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
248 0 : aHrefStr, OwnerDoc(), baseURI);
249 :
250 : // Stop observing old target (if any)
251 0 : if (mHrefTarget.get()) {
252 0 : mHrefTarget.get()->RemoveMutationObserver(this);
253 : }
254 :
255 0 : if (aParent) {
256 : // Pass in |aParent| instead of |this| -- first argument is only used
257 : // for a call to GetCurrentDoc(), and |this| might not have a current
258 : // document yet (if our caller is BindToTree).
259 0 : mHrefTarget.Reset(aParent, targetURI);
260 : } else {
261 : // if we don't have a parent, then there's no animateMotion element
262 : // depending on our target, so there's no point tracking it right now.
263 0 : mHrefTarget.Unlink();
264 : }
265 :
266 : // Start observing new target (if any)
267 0 : if (mHrefTarget.get()) {
268 0 : mHrefTarget.get()->AddMutationObserver(this);
269 : }
270 :
271 0 : NotifyParentOfMpathChange(aParent);
272 0 : }
273 :
274 : void
275 0 : nsSVGMpathElement::UnlinkHrefTarget(bool aNotifyParent)
276 : {
277 : // Stop observing old target (if any)
278 0 : if (mHrefTarget.get()) {
279 0 : mHrefTarget.get()->RemoveMutationObserver(this);
280 : }
281 0 : mHrefTarget.Unlink();
282 :
283 0 : if (aNotifyParent) {
284 0 : NotifyParentOfMpathChange(GetParent());
285 : }
286 0 : }
287 :
288 : void
289 0 : nsSVGMpathElement::NotifyParentOfMpathChange(nsIContent* aParent)
290 : {
291 0 : if (aParent && aParent->IsSVG(nsGkAtoms::animateMotion)) {
292 :
293 : nsSVGAnimateMotionElement* animateMotionParent =
294 0 : static_cast<nsSVGAnimateMotionElement*>(aParent);
295 :
296 0 : animateMotionParent->MpathChanged();
297 0 : AnimationNeedsResample();
298 : }
299 4392 : }
|