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) 2003
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "mozilla/Util.h"
40 :
41 : #include "nsSVGImageElement.h"
42 : #include "nsCOMPtr.h"
43 : #include "nsIURI.h"
44 : #include "nsNetUtil.h"
45 : #include "imgIContainer.h"
46 : #include "imgIDecoderObserver.h"
47 : #include "gfxContext.h"
48 :
49 : using namespace mozilla;
50 :
51 : nsSVGElement::LengthInfo nsSVGImageElement::sLengthInfo[4] =
52 : {
53 : { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
54 : { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
55 : { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
56 : { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
57 : };
58 :
59 : nsSVGElement::StringInfo nsSVGImageElement::sStringInfo[1] =
60 : {
61 : { &nsGkAtoms::href, kNameSpaceID_XLink, true }
62 : };
63 :
64 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(Image)
65 :
66 : //----------------------------------------------------------------------
67 : // nsISupports methods
68 :
69 0 : NS_IMPL_ADDREF_INHERITED(nsSVGImageElement,nsSVGImageElementBase)
70 0 : NS_IMPL_RELEASE_INHERITED(nsSVGImageElement,nsSVGImageElementBase)
71 :
72 0 : DOMCI_NODE_DATA(SVGImageElement, nsSVGImageElement)
73 :
74 0 : NS_INTERFACE_TABLE_HEAD(nsSVGImageElement)
75 0 : NS_NODE_INTERFACE_TABLE8(nsSVGImageElement, nsIDOMNode, nsIDOMElement,
76 : nsIDOMSVGElement, nsIDOMSVGTests,
77 : nsIDOMSVGImageElement,
78 : nsIDOMSVGURIReference, imgIDecoderObserver,
79 : nsIImageLoadingContent)
80 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGImageElement)
81 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGImageElementBase)
82 :
83 : //----------------------------------------------------------------------
84 : // Implementation
85 :
86 0 : nsSVGImageElement::nsSVGImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
87 0 : : nsSVGImageElementBase(aNodeInfo)
88 : {
89 : // We start out broken
90 0 : AddStatesSilently(NS_EVENT_STATE_BROKEN);
91 0 : }
92 :
93 0 : nsSVGImageElement::~nsSVGImageElement()
94 : {
95 0 : DestroyImageLoadingContent();
96 0 : }
97 :
98 : //----------------------------------------------------------------------
99 : // nsIDOMNode methods
100 :
101 :
102 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGImageElement)
103 :
104 :
105 : //----------------------------------------------------------------------
106 : // nsIDOMSVGImageElement methods:
107 :
108 : /* readonly attribute nsIDOMSVGAnimatedLength x; */
109 0 : NS_IMETHODIMP nsSVGImageElement::GetX(nsIDOMSVGAnimatedLength * *aX)
110 : {
111 0 : return mLengthAttributes[X].ToDOMAnimatedLength(aX, this);
112 : }
113 :
114 : /* readonly attribute nsIDOMSVGAnimatedLength y; */
115 0 : NS_IMETHODIMP nsSVGImageElement::GetY(nsIDOMSVGAnimatedLength * *aY)
116 : {
117 0 : return mLengthAttributes[Y].ToDOMAnimatedLength(aY, this);
118 : }
119 :
120 : /* readonly attribute nsIDOMSVGAnimatedLength width; */
121 0 : NS_IMETHODIMP nsSVGImageElement::GetWidth(nsIDOMSVGAnimatedLength * *aWidth)
122 : {
123 0 : return mLengthAttributes[WIDTH].ToDOMAnimatedLength(aWidth, this);
124 : }
125 :
126 : /* readonly attribute nsIDOMSVGAnimatedLength height; */
127 0 : NS_IMETHODIMP nsSVGImageElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
128 : {
129 0 : return mLengthAttributes[HEIGHT].ToDOMAnimatedLength(aHeight, this);
130 : }
131 :
132 : /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
133 : NS_IMETHODIMP
134 0 : nsSVGImageElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
135 : **aPreserveAspectRatio)
136 : {
137 0 : return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
138 : }
139 :
140 : //----------------------------------------------------------------------
141 : // nsIDOMSVGURIReference methods:
142 :
143 : /* readonly attribute nsIDOMSVGAnimatedString href; */
144 : NS_IMETHODIMP
145 0 : nsSVGImageElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
146 : {
147 0 : return mStringAttributes[HREF].ToDOMAnimatedString(aHref, this);
148 : }
149 :
150 : //----------------------------------------------------------------------
151 :
152 : nsresult
153 0 : nsSVGImageElement::LoadSVGImage(bool aForce, bool aNotify)
154 : {
155 : // resolve href attribute
156 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
157 :
158 0 : nsAutoString href;
159 0 : mStringAttributes[HREF].GetAnimValue(href, this);
160 0 : href.Trim(" \t\n\r");
161 :
162 0 : if (baseURI && !href.IsEmpty())
163 0 : NS_MakeAbsoluteURI(href, href, baseURI);
164 :
165 0 : return LoadImage(href, aForce, aNotify);
166 : }
167 :
168 : //----------------------------------------------------------------------
169 : // nsIContent methods:
170 :
171 : nsresult
172 0 : nsSVGImageElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
173 : const nsAttrValue* aValue, bool aNotify)
174 : {
175 0 : if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
176 :
177 : // If there isn't a frame we still need to load the image in case
178 : // the frame is created later e.g. by attaching to a document.
179 : // If there is a frame then it should deal with loading as the image
180 : // url may be animated
181 0 : if (!GetPrimaryFrame()) {
182 :
183 : // Prevent setting image.src by exiting early
184 0 : if (nsContentUtils::IsImageSrcSetDisabled()) {
185 0 : return NS_OK;
186 : }
187 :
188 0 : if (aValue) {
189 0 : LoadSVGImage(true, aNotify);
190 : } else {
191 0 : CancelImageRequests(aNotify);
192 : }
193 : }
194 : }
195 : return nsSVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
196 0 : aValue, aNotify);
197 : }
198 :
199 : void
200 0 : nsSVGImageElement::MaybeLoadSVGImage()
201 : {
202 0 : if (mStringAttributes[HREF].IsExplicitlySet() &&
203 0 : (NS_FAILED(LoadSVGImage(false, true)) ||
204 0 : !LoadingEnabled())) {
205 0 : CancelImageRequests(true);
206 : }
207 0 : }
208 :
209 : nsresult
210 0 : nsSVGImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
211 : nsIContent* aBindingParent,
212 : bool aCompileEventHandlers)
213 : {
214 : nsresult rv = nsSVGImageElementBase::BindToTree(aDocument, aParent,
215 : aBindingParent,
216 0 : aCompileEventHandlers);
217 0 : NS_ENSURE_SUCCESS(rv, rv);
218 :
219 0 : if (mStringAttributes[HREF].IsExplicitlySet()) {
220 : // FIXME: Bug 660963 it would be nice if we could just have
221 : // ClearBrokenState update our state and do it fast...
222 0 : ClearBrokenState();
223 0 : RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
224 : nsContentUtils::AddScriptRunner(
225 0 : NS_NewRunnableMethod(this, &nsSVGImageElement::MaybeLoadSVGImage));
226 : }
227 :
228 0 : return rv;
229 : }
230 :
231 : nsEventStates
232 0 : nsSVGImageElement::IntrinsicState() const
233 : {
234 : return nsSVGImageElementBase::IntrinsicState() |
235 0 : nsImageLoadingContent::ImageState();
236 : }
237 :
238 : NS_IMETHODIMP_(bool)
239 0 : nsSVGImageElement::IsAttributeMapped(const nsIAtom* name) const
240 : {
241 : static const MappedAttributeEntry* const map[] = {
242 : sViewportsMap,
243 : };
244 :
245 0 : return FindAttributeDependence(name, map) ||
246 0 : nsSVGImageElementBase::IsAttributeMapped(name);
247 : }
248 :
249 : //----------------------------------------------------------------------
250 : // nsSVGPathGeometryElement methods
251 :
252 : /* For the purposes of the update/invalidation logic pretend to
253 : be a rectangle. */
254 : void
255 0 : nsSVGImageElement::ConstructPath(gfxContext *aCtx)
256 : {
257 : float x, y, width, height;
258 :
259 0 : GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
260 :
261 0 : if (width <= 0 || height <= 0)
262 0 : return;
263 :
264 0 : aCtx->Rectangle(gfxRect(x, y, width, height));
265 : }
266 :
267 : //----------------------------------------------------------------------
268 : // nsSVGElement methods
269 :
270 : /* virtual */ bool
271 0 : nsSVGImageElement::HasValidDimensions() const
272 : {
273 0 : return mLengthAttributes[WIDTH].IsExplicitlySet() &&
274 0 : mLengthAttributes[WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
275 0 : mLengthAttributes[HEIGHT].IsExplicitlySet() &&
276 0 : mLengthAttributes[HEIGHT].GetAnimValInSpecifiedUnits() > 0;
277 : }
278 :
279 : nsSVGElement::LengthAttributesInfo
280 0 : nsSVGImageElement::GetLengthInfo()
281 : {
282 : return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
283 0 : ArrayLength(sLengthInfo));
284 : }
285 :
286 : SVGAnimatedPreserveAspectRatio *
287 0 : nsSVGImageElement::GetPreserveAspectRatio()
288 : {
289 0 : return &mPreserveAspectRatio;
290 : }
291 :
292 : nsSVGElement::StringAttributesInfo
293 0 : nsSVGImageElement::GetStringInfo()
294 : {
295 : return StringAttributesInfo(mStringAttributes, sStringInfo,
296 0 : ArrayLength(sStringInfo));
297 : }
298 :
299 : nsresult
300 0 : nsSVGImageElement::CopyInnerTo(nsGenericElement* aDest) const
301 : {
302 0 : if (aDest->OwnerDoc()->IsStaticDocument()) {
303 0 : CreateStaticImageClone(static_cast<nsSVGImageElement*>(aDest));
304 : }
305 0 : return nsSVGImageElementBase::CopyInnerTo(aDest);
306 : }
|