Back to index

lightning-sunbird  0.9+nobinonly
nsSVGScriptElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Mozilla SVG project.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Crocodile Clips Ltd..
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alex Fritze <alex@croczilla.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsSVGElement.h"
00040 #include "nsSVGAtoms.h"
00041 #include "nsIDOMSVGScriptElement.h"
00042 #include "nsIDOMSVGURIReference.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsSVGAnimatedString.h"
00045 #include "nsIDocument.h"
00046 #include "nsIURI.h"
00047 #include "nsNetUtil.h"
00048 #include "nsIScriptElement.h"
00049 #include "nsIScriptLoader.h"
00050 #include "nsIScriptLoaderObserver.h"
00051 #include "nsIPresShell.h"
00052 #include "nsPresContext.h"
00053 #include "nsGUIEvent.h"
00054 #include "nsIDOMText.h"
00055 
00056 typedef nsSVGElement nsSVGScriptElementBase;
00057 
00058 class nsSVGScriptElement : public nsSVGScriptElementBase,
00059                            public nsIDOMSVGScriptElement, 
00060                            public nsIDOMSVGURIReference,
00061                            public nsIScriptLoaderObserver,
00062                            public nsIScriptElement
00063 {
00064 protected:
00065   friend nsresult NS_NewSVGScriptElement(nsIContent **aResult,
00066                                          nsINodeInfo *aNodeInfo);
00067   nsSVGScriptElement(nsINodeInfo *aNodeInfo);
00068   virtual ~nsSVGScriptElement();
00069   virtual nsresult Init();
00070   
00071 public:
00072   // interfaces:
00073   
00074   NS_DECL_ISUPPORTS_INHERITED
00075   NS_DECL_NSIDOMSVGSCRIPTELEMENT
00076   NS_DECL_NSIDOMSVGURIREFERENCE
00077   NS_DECL_NSISCRIPTLOADEROBSERVER
00078 
00079   // xxx If xpcom allowed virtual inheritance we wouldn't need to
00080   // forward here :-(
00081   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGScriptElementBase::)
00082   NS_FORWARD_NSIDOMELEMENT(nsSVGScriptElementBase::)
00083   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGScriptElementBase::)
00084 
00085   // nsIScriptElement
00086   virtual void GetScriptType(nsAString& type);
00087   virtual already_AddRefed<nsIURI> GetScriptURI();
00088   virtual void GetScriptText(nsAString& text);
00089   virtual void GetScriptCharset(nsAString& charset); 
00090   virtual void SetScriptLineNumber(PRUint32 aLineNumber);
00091   virtual PRUint32 GetScriptLineNumber();
00092 
00093   // nsISVGValueObserver specializations:
00094   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00095                                      nsISVGValue::modificationType aModType);
00096 
00097   // nsIContent specializations:
00098   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
00099                               nsIContent* aBindingParent,
00100                               PRBool aCompileEventHandlers);
00101   virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
00102                                  PRBool aNotify);
00103   virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify);
00104     
00105 protected:
00119   void MaybeProcessScript();
00120   
00121   nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
00122   PRUint32 mLineNumber;
00123   PRPackedBool mIsEvaluated;
00124   PRPackedBool mEvaluating;
00125 };
00126 
00127 NS_IMPL_NS_NEW_SVG_ELEMENT(Script)
00128 
00129 //----------------------------------------------------------------------
00130 // nsISupports methods
00131 
00132 NS_IMPL_ADDREF_INHERITED(nsSVGScriptElement,nsSVGScriptElementBase)
00133 NS_IMPL_RELEASE_INHERITED(nsSVGScriptElement,nsSVGScriptElementBase)
00134 
00135 NS_INTERFACE_MAP_BEGIN(nsSVGScriptElement)
00136   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
00137   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
00138   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGElement)
00139   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGScriptElement)
00140   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGURIReference)
00141   NS_INTERFACE_MAP_ENTRY(nsIScriptLoaderObserver)
00142   NS_INTERFACE_MAP_ENTRY(nsIScriptElement)
00143   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGScriptElement)
00144 NS_INTERFACE_MAP_END_INHERITING(nsSVGScriptElementBase)
00145 
00146 //----------------------------------------------------------------------
00147 // Implementation
00148 
00149 nsSVGScriptElement::nsSVGScriptElement(nsINodeInfo *aNodeInfo)
00150   : nsSVGScriptElementBase(aNodeInfo),
00151     mLineNumber(0),
00152     mIsEvaluated(PR_FALSE),
00153     mEvaluating(PR_FALSE)
00154 {
00155 
00156 }
00157 
00158 nsSVGScriptElement::~nsSVGScriptElement()
00159 {
00160 }
00161 
00162   
00163 nsresult
00164 nsSVGScriptElement::Init()
00165 {
00166   nsresult rv;
00167 
00168   // nsIDOMSVGURIReference properties
00169 
00170   // DOM property: href , #REQUIRED attrib: xlink:href
00171   // XXX: enforce requiredness
00172   {
00173     rv = NS_NewSVGAnimatedString(getter_AddRefs(mHref));
00174     NS_ENSURE_SUCCESS(rv,rv);
00175     rv = AddMappedSVGValue(nsSVGAtoms::href, mHref, kNameSpaceID_XLink);
00176     NS_ENSURE_SUCCESS(rv,rv);
00177   }
00178 
00179   return NS_OK;
00180 }
00181 
00182 //----------------------------------------------------------------------
00183 // nsIDOMNode methods
00184 
00185 NS_IMPL_DOM_CLONENODE_WITH_INIT(nsSVGScriptElement)
00186 
00187 //----------------------------------------------------------------------
00188 // nsIDOMSVGScriptElement methods
00189 
00190 /* attribute DOMString type; */
00191 NS_IMETHODIMP
00192 nsSVGScriptElement::GetType(nsAString & aType)
00193 {
00194   return GetAttr(kNameSpaceID_None, nsSVGAtoms::type, aType);
00195 }
00196 NS_IMETHODIMP
00197 nsSVGScriptElement::SetType(const nsAString & aType)
00198 {
00199   NS_ERROR("write me!");
00200   return NS_ERROR_NOT_IMPLEMENTED;
00201 }
00202 
00203 //----------------------------------------------------------------------
00204 // nsIDOMSVGURIReference methods
00205 
00206 /* readonly attribute nsIDOMSVGAnimatedString href; */
00207 NS_IMETHODIMP
00208 nsSVGScriptElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
00209 {
00210   *aHref = mHref;
00211   NS_IF_ADDREF(*aHref);
00212   return NS_OK;
00213 }
00214 
00215 //----------------------------------------------------------------------
00216 // nsIScriptLoaderObserver methods
00217 
00218 // variation of this code in nsHTMLScriptElement - check if changes
00219 // need to be transfered when modifying
00220 
00221 /* void scriptAvailable (in nsresult aResult, in nsIScriptElement aElement , in nsIURI aURI, in PRInt32 aLineNo, in PRUint32 aScriptLength, [size_is (aScriptLength)] in wstring aScript); */
00222 NS_IMETHODIMP
00223 nsSVGScriptElement::ScriptAvailable(nsresult aResult,
00224                                     nsIScriptElement *aElement,
00225                                     PRBool aIsInline,
00226                                     PRBool aWasPending,
00227                                     nsIURI *aURI,
00228                                     PRInt32 aLineNo,
00229                                     const nsAString& aScript)
00230 {
00231   if (!aIsInline && NS_FAILED(aResult)) {
00232     nsCOMPtr<nsPresContext> presContext;
00233     nsIDocument* doc = GetCurrentDoc();
00234     if (doc) {
00235       nsIPresShell *presShell = doc->GetShellAt(0);
00236       if (presShell)
00237         presContext = presShell->GetPresContext();
00238     }
00239 
00240     nsEventStatus status = nsEventStatus_eIgnore;
00241     nsScriptErrorEvent event(PR_TRUE, NS_SCRIPT_ERROR);
00242 
00243     event.lineNr = aLineNo;
00244 
00245     NS_NAMED_LITERAL_STRING(errorString, "Error loading script");
00246     event.errorMsg = errorString.get();
00247 
00248     nsCAutoString spec;
00249     aURI->GetSpec(spec);
00250 
00251     NS_ConvertUTF8toUCS2 fileName(spec);
00252     event.fileName = fileName.get();
00253 
00254     HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT,
00255                    &status);
00256   }
00257 
00258   return NS_OK;
00259 }
00260 
00261 // variation of this code in nsHTMLScriptElement - check if changes
00262 // need to be transfered when modifying
00263 
00264 /* void scriptEvaluated (in nsresult aResult, in nsIScriptElement aElement); */
00265 NS_IMETHODIMP
00266 nsSVGScriptElement::ScriptEvaluated(nsresult aResult,
00267                                     nsIScriptElement *aElement,
00268                                     PRBool aIsInline,
00269                                     PRBool aWasPending)
00270 {
00271   nsresult rv = NS_OK;
00272   if (!aIsInline) {
00273     nsCOMPtr<nsPresContext> presContext;
00274     nsIDocument* doc = GetCurrentDoc();
00275     if (doc) {
00276       nsIPresShell *presShell = doc->GetShellAt(0);
00277       if (presShell)
00278         presContext = presShell->GetPresContext();
00279     }
00280 
00281     nsEventStatus status = nsEventStatus_eIgnore;
00282     nsEvent event(PR_TRUE,
00283                   NS_SUCCEEDED(aResult) ? NS_SCRIPT_LOAD : NS_SCRIPT_ERROR);
00284     rv = HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT,
00285                         &status);
00286   }
00287 
00288   return rv;
00289 }
00290 
00291 //----------------------------------------------------------------------
00292 // nsIScriptElement methods
00293 
00294 void
00295 nsSVGScriptElement::GetScriptType(nsAString& type)
00296 {
00297   GetType(type);
00298 }
00299 
00300 // variation of this code in nsHTMLScriptElement - check if changes
00301 // need to be transfered when modifying
00302 
00303 already_AddRefed<nsIURI>
00304 nsSVGScriptElement::GetScriptURI()
00305 {
00306   nsIURI *uri = nsnull;
00307   nsAutoString src;
00308   mHref->GetAnimVal(src);
00309   if (!src.IsEmpty()) {
00310     nsCOMPtr<nsIURI> baseURI = GetBaseURI();
00311     NS_NewURI(&uri, src, nsnull, baseURI);
00312   }
00313   return uri;
00314 }
00315 
00316 void
00317 nsSVGScriptElement::GetScriptText(nsAString& text)
00318 {
00319   GetContentsAsText(text);
00320 }
00321 
00322 void
00323 nsSVGScriptElement::GetScriptCharset(nsAString& charset)
00324 {
00325   charset.Truncate();
00326 }
00327 
00328 void 
00329 nsSVGScriptElement::SetScriptLineNumber(PRUint32 aLineNumber)
00330 {
00331   mLineNumber = aLineNumber;
00332 }
00333 
00334 PRUint32
00335 nsSVGScriptElement::GetScriptLineNumber()
00336 {
00337   return mLineNumber;
00338 }
00339 
00340 
00341 //----------------------------------------------------------------------
00342 // nsISVGValueObserver methods
00343 
00344 NS_IMETHODIMP
00345 nsSVGScriptElement::DidModifySVGObservable(nsISVGValue* aObservable,
00346                                            nsISVGValue::modificationType aModType)
00347 {
00348   nsresult rv = nsSVGScriptElementBase::DidModifySVGObservable(aObservable,
00349                                                                aModType);
00350   
00351   // if aObservable==mHref:
00352   MaybeProcessScript();
00353   
00354   return rv;
00355 }
00356 
00357 //----------------------------------------------------------------------
00358 // nsIContent methods
00359 
00360 nsresult
00361 nsSVGScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
00362                                nsIContent* aBindingParent,
00363                                PRBool aCompileEventHandlers)
00364 {
00365   nsresult rv = nsSVGScriptElementBase::BindToTree(aDocument, aParent,
00366                                                    aBindingParent,
00367                                                    aCompileEventHandlers);
00368   NS_ENSURE_SUCCESS(rv, rv);
00369 
00370   if (aDocument) {
00371     MaybeProcessScript();
00372   }
00373 
00374   return rv;
00375 }
00376 
00377 nsresult
00378 nsSVGScriptElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
00379                                   PRBool aNotify)
00380 {
00381   nsresult rv = nsSVGScriptElementBase::InsertChildAt(aKid, aIndex, aNotify);
00382   if (NS_SUCCEEDED(rv) && aNotify) {
00383     MaybeProcessScript();
00384   }
00385 
00386   return rv;
00387 }
00388 
00389 nsresult
00390 nsSVGScriptElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
00391 {
00392   nsresult rv = nsSVGScriptElementBase::AppendChildTo(aKid, aNotify);
00393   if (NS_SUCCEEDED(rv) && aNotify) {
00394     MaybeProcessScript();
00395   }
00396 
00397   return rv;
00398 }
00399 
00400 //----------------------------------------------------------------------
00401 // implementation helpers
00402 
00403 // variation of this code in nsHTMLScriptElement - check if changes
00404 // need to be transfered when modifying
00405 void
00406 nsSVGScriptElement::MaybeProcessScript()
00407 {
00408   if (mIsEvaluated || mEvaluating || !IsInDoc()) {
00409     return;
00410   }
00411 
00412   // We'll always call this to make sure that
00413   // ScriptAvailable/ScriptEvaluated gets called. See bug 153600
00414   nsresult rv = NS_OK;
00415   nsCOMPtr<nsIScriptLoader> loader = GetOwnerDoc()->GetScriptLoader();
00416   if (loader) {
00417     mEvaluating = PR_TRUE;
00418     rv = loader->ProcessScriptElement(this, this);
00419     mEvaluating = PR_FALSE;
00420   }
00421 
00422   // But we'll only set mIsEvaluated if we did really load or evaluate
00423   // something
00424   if (HasAttr(kNameSpaceID_XLink, nsSVGAtoms::href) ||
00425       mAttrsAndChildren.ChildCount()) {
00426     mIsEvaluated = PR_TRUE;
00427   }
00428 }