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 Mozilla SVG Project code.
16 : *
17 : * The Initial Developer of the Original Code is Jonathan Watt.
18 : * Portions created by the Initial Developer are Copyright (C) 2006
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Jonathan Watt <jwatt@jwatt.org> (original author)
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 "nsSVGAElement.h"
41 : #include "nsSVGGraphicElement.h"
42 : #include "nsIDOMSVGAElement.h"
43 : #include "nsIDOMSVGURIReference.h"
44 : #include "nsILink.h"
45 : #include "nsSVGString.h"
46 : #include "nsCOMPtr.h"
47 : #include "nsGkAtoms.h"
48 : #include "nsContentUtils.h"
49 :
50 : using namespace mozilla;
51 :
52 : nsSVGElement::StringInfo nsSVGAElement::sStringInfo[2] =
53 : {
54 : { &nsGkAtoms::href, kNameSpaceID_XLink, true },
55 : { &nsGkAtoms::target, kNameSpaceID_None, true }
56 : };
57 :
58 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(A)
59 :
60 :
61 : //----------------------------------------------------------------------
62 : // nsISupports methods
63 :
64 0 : NS_IMPL_ADDREF_INHERITED(nsSVGAElement, nsSVGAElementBase)
65 0 : NS_IMPL_RELEASE_INHERITED(nsSVGAElement, nsSVGAElementBase)
66 :
67 0 : DOMCI_NODE_DATA(SVGAElement, nsSVGAElement)
68 :
69 0 : NS_INTERFACE_TABLE_HEAD(nsSVGAElement)
70 0 : NS_NODE_INTERFACE_TABLE8(nsSVGAElement,
71 : nsIDOMNode,
72 : nsIDOMElement,
73 : nsIDOMSVGElement,
74 : nsIDOMSVGAElement,
75 : nsIDOMSVGTests,
76 : nsIDOMSVGURIReference,
77 : nsILink,
78 : Link)
79 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAElement)
80 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGAElementBase)
81 :
82 :
83 : //----------------------------------------------------------------------
84 : // Implementation
85 :
86 0 : nsSVGAElement::nsSVGAElement(already_AddRefed<nsINodeInfo> aNodeInfo)
87 : : nsSVGAElementBase(aNodeInfo),
88 0 : Link(this)
89 : {
90 0 : }
91 :
92 : //----------------------------------------------------------------------
93 : // nsIDOMSVGURIReference methods
94 :
95 : /* readonly attribute nsIDOMSVGAnimatedString href; */
96 : NS_IMETHODIMP
97 0 : nsSVGAElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
98 : {
99 0 : return mStringAttributes[HREF].ToDOMAnimatedString(aHref, this);
100 : }
101 :
102 :
103 : //----------------------------------------------------------------------
104 : // nsINode methods
105 :
106 : nsresult
107 0 : nsSVGAElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
108 : {
109 0 : nsresult rv = nsGenericElement::PreHandleEvent(aVisitor);
110 0 : NS_ENSURE_SUCCESS(rv, rv);
111 :
112 0 : return PreHandleEventForLinks(aVisitor);
113 : }
114 :
115 : nsresult
116 0 : nsSVGAElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
117 : {
118 0 : return PostHandleEventForLinks(aVisitor);
119 : }
120 :
121 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGAElement)
122 :
123 :
124 : //----------------------------------------------------------------------
125 : // nsIDOMSVGAElement methods
126 :
127 : /* readonly attribute nsIDOMSVGAnimatedString target; */
128 : NS_IMETHODIMP
129 0 : nsSVGAElement::GetTarget(nsIDOMSVGAnimatedString * *aTarget)
130 : {
131 0 : return mStringAttributes[TARGET].ToDOMAnimatedString(aTarget, this);
132 : }
133 :
134 :
135 : //----------------------------------------------------------------------
136 : // nsIContent methods
137 :
138 : nsresult
139 0 : nsSVGAElement::BindToTree(nsIDocument *aDocument, nsIContent *aParent,
140 : nsIContent *aBindingParent,
141 : bool aCompileEventHandlers)
142 : {
143 0 : Link::ResetLinkState(false);
144 :
145 : nsresult rv = nsSVGAElementBase::BindToTree(aDocument, aParent,
146 : aBindingParent,
147 0 : aCompileEventHandlers);
148 0 : NS_ENSURE_SUCCESS(rv, rv);
149 :
150 0 : if (aDocument) {
151 0 : aDocument->RegisterPendingLinkUpdate(this);
152 : }
153 :
154 0 : return NS_OK;
155 : }
156 :
157 : void
158 0 : nsSVGAElement::UnbindFromTree(bool aDeep, bool aNullParent)
159 : {
160 : // If this link is ever reinserted into a document, it might
161 : // be under a different xml:base, so forget the cached state now.
162 0 : Link::ResetLinkState(false);
163 :
164 0 : nsIDocument* doc = GetCurrentDoc();
165 0 : if (doc) {
166 0 : doc->UnregisterPendingLinkUpdate(this);
167 : }
168 :
169 0 : nsSVGAElementBase::UnbindFromTree(aDeep, aNullParent);
170 0 : }
171 :
172 : nsLinkState
173 0 : nsSVGAElement::GetLinkState() const
174 : {
175 0 : return Link::GetLinkState();
176 : }
177 :
178 : already_AddRefed<nsIURI>
179 0 : nsSVGAElement::GetHrefURI() const
180 : {
181 0 : nsCOMPtr<nsIURI> hrefURI;
182 0 : return IsLink(getter_AddRefs(hrefURI)) ? hrefURI.forget() : nsnull;
183 : }
184 :
185 :
186 : NS_IMETHODIMP_(bool)
187 0 : nsSVGAElement::IsAttributeMapped(const nsIAtom* name) const
188 : {
189 : static const MappedAttributeEntry* const map[] = {
190 : sFEFloodMap,
191 : sFiltersMap,
192 : sFontSpecificationMap,
193 : sGradientStopMap,
194 : sLightingEffectsMap,
195 : sMarkersMap,
196 : sTextContentElementsMap,
197 : sViewportsMap
198 : };
199 :
200 0 : return FindAttributeDependence(name, map) ||
201 0 : nsSVGAElementBase::IsAttributeMapped(name);
202 : }
203 :
204 : bool
205 0 : nsSVGAElement::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
206 : {
207 0 : nsCOMPtr<nsIURI> uri;
208 0 : if (IsLink(getter_AddRefs(uri))) {
209 0 : if (aTabIndex) {
210 0 : *aTabIndex = ((sTabFocusModel & eTabFocus_linksMask) == 0 ? -1 : 0);
211 : }
212 0 : return true;
213 : }
214 :
215 0 : if (aTabIndex) {
216 0 : *aTabIndex = -1;
217 : }
218 :
219 0 : return false;
220 : }
221 :
222 : bool
223 0 : nsSVGAElement::IsLink(nsIURI** aURI) const
224 : {
225 : // To be a clickable XLink for styling and interaction purposes, we require:
226 : //
227 : // xlink:href - must be set
228 : // xlink:type - must be unset or set to "" or set to "simple"
229 : // xlink:show - must be unset or set to "", "new" or "replace"
230 : // xlink:actuate - must be unset or set to "" or "onRequest"
231 : //
232 : // For any other values, we're either not a *clickable* XLink, or the end
233 : // result is poorly specified. Either way, we return false.
234 :
235 : static nsIContent::AttrValuesArray sTypeVals[] =
236 : { &nsGkAtoms::_empty, &nsGkAtoms::simple, nsnull };
237 :
238 : static nsIContent::AttrValuesArray sShowVals[] =
239 : { &nsGkAtoms::_empty, &nsGkAtoms::_new, &nsGkAtoms::replace, nsnull };
240 :
241 : static nsIContent::AttrValuesArray sActuateVals[] =
242 : { &nsGkAtoms::_empty, &nsGkAtoms::onRequest, nsnull };
243 :
244 : // Optimization: check for href first for early return
245 : const nsAttrValue* href = mAttrsAndChildren.GetAttr(nsGkAtoms::href,
246 0 : kNameSpaceID_XLink);
247 0 : if (href &&
248 : FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type,
249 0 : sTypeVals, eCaseMatters) !=
250 : nsIContent::ATTR_VALUE_NO_MATCH &&
251 : FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
252 0 : sShowVals, eCaseMatters) !=
253 : nsIContent::ATTR_VALUE_NO_MATCH &&
254 : FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate,
255 0 : sActuateVals, eCaseMatters) !=
256 : nsIContent::ATTR_VALUE_NO_MATCH) {
257 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
258 : // Get absolute URI
259 0 : nsAutoString str;
260 0 : mStringAttributes[HREF].GetAnimValue(str, this);
261 : nsContentUtils::NewURIWithDocumentCharset(aURI, str,
262 0 : OwnerDoc(), baseURI);
263 : // must promise out param is non-null if we return true
264 0 : return !!*aURI;
265 : }
266 :
267 0 : *aURI = nsnull;
268 0 : return false;
269 : }
270 :
271 : void
272 0 : nsSVGAElement::GetLinkTarget(nsAString& aTarget)
273 : {
274 0 : mStringAttributes[TARGET].GetAnimValue(aTarget, this);
275 0 : if (aTarget.IsEmpty()) {
276 :
277 : static nsIContent::AttrValuesArray sShowVals[] =
278 : { &nsGkAtoms::_new, &nsGkAtoms::replace, nsnull };
279 :
280 0 : switch (FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
281 0 : sShowVals, eCaseMatters)) {
282 : case 0:
283 0 : aTarget.AssignLiteral("_blank");
284 0 : return;
285 : case 1:
286 0 : return;
287 : }
288 0 : nsIDocument* ownerDoc = OwnerDoc();
289 0 : if (ownerDoc) {
290 0 : ownerDoc->GetBaseTarget(aTarget);
291 : }
292 : }
293 : }
294 :
295 : nsEventStates
296 0 : nsSVGAElement::IntrinsicState() const
297 : {
298 0 : return Link::LinkState() | nsSVGAElementBase::IntrinsicState();
299 : }
300 :
301 : nsresult
302 0 : nsSVGAElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
303 : nsIAtom* aPrefix, const nsAString& aValue,
304 : bool aNotify)
305 : {
306 : nsresult rv = nsSVGAElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
307 0 : aValue, aNotify);
308 :
309 : // The ordering of the parent class's SetAttr call and Link::ResetLinkState
310 : // is important here! The attribute is not set until SetAttr returns, and
311 : // we will need the updated attribute value because notifying the document
312 : // that content states have changed will call IntrinsicState, which will try
313 : // to get updated information about the visitedness from Link.
314 0 : if (aName == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
315 0 : Link::ResetLinkState(!!aNotify);
316 : }
317 :
318 0 : return rv;
319 : }
320 :
321 : nsresult
322 0 : nsSVGAElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
323 : bool aNotify)
324 : {
325 0 : nsresult rv = nsSVGAElementBase::UnsetAttr(aNameSpaceID, aAttr, aNotify);
326 :
327 : // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
328 : // is important here! The attribute is not unset until UnsetAttr returns, and
329 : // we will need the updated attribute value because notifying the document
330 : // that content states have changed will call IntrinsicState, which will try
331 : // to get updated information about the visitedness from Link.
332 0 : if (aAttr == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
333 0 : Link::ResetLinkState(!!aNotify);
334 : }
335 :
336 0 : return rv;
337 : }
338 :
339 : //----------------------------------------------------------------------
340 : // nsSVGElement methods
341 :
342 : nsSVGElement::StringAttributesInfo
343 0 : nsSVGAElement::GetStringInfo()
344 : {
345 : return StringAttributesInfo(mStringAttributes, sStringInfo,
346 0 : ArrayLength(sStringInfo));
347 : }
|