Back to index

lightning-sunbird  0.9+nobinonly
nsSVGUseElement.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 IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nsSVGGraphicElement.h"
00038 #include "nsIDOMSVGGElement.h"
00039 #include "nsSVGAtoms.h"
00040 #include "nsIDOMSVGAnimatedLength.h"
00041 #include "nsSVGLength.h"
00042 #include "nsISVGSVGElement.h"
00043 #include "nsSVGCoordCtxProvider.h"
00044 #include "nsIDOMSVGURIReference.h"
00045 #include "nsIDOMSVGAnimatedString.h"
00046 #include "nsIDOMSVGUseElement.h"
00047 #include "nsSVGAnimatedLength.h"
00048 #include "nsSVGAnimatedString.h"
00049 #include "nsIDOMDocument.h"
00050 #include "nsIDOMSVGSVGElement.h"
00051 #include "nsIDOMSVGSymbolElement.h"
00052 #include "nsIDocument.h"
00053 #include "nsIDOMMutationListener.h"
00054 #include "nsISupportsArray.h"
00055 #include "nsIPresShell.h"
00056 #include "nsIAnonymousContentCreator.h"
00057 
00058 #define NS_SVG_USE_ELEMENT_IMPL_CID \
00059 { 0xa95c13d3, 0xc193, 0x465f, {0x81, 0xf0, 0x02, 0x6d, 0x67, 0x05, 0x54, 0x58 } }
00060 
00061 nsresult
00062 NS_NewSVGSVGElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
00063 
00064 typedef nsSVGGraphicElement nsSVGUseElementBase;
00065 
00066 class nsSVGUseElement : public nsSVGUseElementBase,
00067                         public nsIDOMSVGURIReference,
00068                         public nsIDOMSVGUseElement,
00069                         public nsIDOMMutationListener,
00070                         public nsIAnonymousContentCreator
00071 {
00072 protected:
00073   friend nsresult NS_NewSVGUseElement(nsIContent **aResult,
00074                                       nsINodeInfo *aNodeInfo);
00075   nsSVGUseElement(nsINodeInfo *aNodeInfo);
00076   virtual ~nsSVGUseElement();
00077   virtual nsresult Init();
00078   
00079 public:
00080   NS_DEFINE_STATIC_IID_ACCESSOR(NS_SVG_USE_ELEMENT_IMPL_CID);
00081 
00082   // interfaces:
00083   
00084   NS_DECL_ISUPPORTS_INHERITED
00085   NS_DECL_NSIDOMSVGUSEELEMENT
00086   NS_DECL_NSIDOMSVGURIREFERENCE
00087 
00088   // xxx I wish we could use virtual inheritance
00089   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGUseElementBase::)
00090   NS_FORWARD_NSIDOMELEMENT(nsSVGUseElementBase::)
00091   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGUseElementBase::)
00092 
00093   // nsISVGContent specializations:
00094   virtual void ParentChainChanged();
00095 
00096   // nsISVGValueObserver specializations:
00097   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00098                                      nsISVGValue::modificationType aModType);
00099   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00100                                      nsISVGValue::modificationType aModType);
00101 
00102   // nsIDOMMutationListener
00103   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
00104   NS_IMETHOD SubtreeModified(nsIDOMEvent* aMutationEvent);
00105   NS_IMETHOD NodeInserted(nsIDOMEvent* aMutationEvent);
00106   NS_IMETHOD NodeRemoved(nsIDOMEvent* aMutationEvent);
00107   NS_IMETHOD NodeRemovedFromDocument(nsIDOMEvent* aMutationEvent);
00108   NS_IMETHOD NodeInsertedIntoDocument(nsIDOMEvent* aMutationEvent);
00109   NS_IMETHOD AttrModified(nsIDOMEvent* aMutationEvent);
00110   NS_IMETHOD CharacterDataModified(nsIDOMEvent* aMutationEvent);
00111 
00112   // nsIAnonymousContentCreator
00113   NS_IMETHOD CreateAnonymousContent(nsPresContext* aPresContext,
00114                                     nsISupportsArray& aAnonymousItems);
00115   NS_IMETHOD CreateFrameFor(nsPresContext *aPresContext,
00116                             nsIContent *aContent,
00117                             nsIFrame **aFrame);
00118 
00119 protected:
00120 
00121   nsresult LookupHref(nsIDOMSVGElement **aElement);
00122   void TriggerReclone();
00123   void RemoveListeners();
00124 
00125   nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
00126   nsCOMPtr<nsIDOMSVGAnimatedLength> mX;
00127   nsCOMPtr<nsIDOMSVGAnimatedLength> mY;
00128   nsCOMPtr<nsIDOMSVGAnimatedLength> mWidth;
00129   nsCOMPtr<nsIDOMSVGAnimatedLength> mHeight;
00130 
00131   nsCOMPtr<nsIContent> mOriginal; // if we've been cloned, our "real" copy
00132   nsCOMPtr<nsIContent> mClone;  // cloned tree
00133 };
00134 
00136 // implementation
00137 
00138 
00139 NS_IMPL_NS_NEW_SVG_ELEMENT(Use)
00140 
00141 
00142 //----------------------------------------------------------------------
00143 // nsISupports methods
00144 
00145 NS_IMPL_ADDREF_INHERITED(nsSVGUseElement,nsSVGUseElementBase)
00146 NS_IMPL_RELEASE_INHERITED(nsSVGUseElement,nsSVGUseElementBase)
00147 
00148 NS_INTERFACE_MAP_BEGIN(nsSVGUseElement)
00149   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
00150   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
00151   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGElement)
00152   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGURIReference)
00153   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGUseElement)
00154   NS_INTERFACE_MAP_ENTRY(nsIDOMMutationListener)
00155   NS_INTERFACE_MAP_ENTRY(nsIAnonymousContentCreator)
00156   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGUseElement)
00157   if (aIID.Equals(NS_GET_IID(nsSVGUseElement)))
00158     foundInterface = NS_REINTERPRET_CAST(nsISupports*, this);
00159   else
00160 NS_INTERFACE_MAP_END_INHERITING(nsSVGUseElementBase)
00161 
00162 //----------------------------------------------------------------------
00163 // Implementation
00164 
00165 nsSVGUseElement::nsSVGUseElement(nsINodeInfo *aNodeInfo)
00166   : nsSVGUseElementBase(aNodeInfo)
00167 {
00168 }
00169 
00170 nsSVGUseElement::~nsSVGUseElement()
00171 {
00172   RemoveListeners();
00173 }
00174 
00175 nsresult
00176 nsSVGUseElement::Init()
00177 {
00178   nsresult rv = nsSVGUseElementBase::Init();
00179   NS_ENSURE_SUCCESS(rv,rv);
00180 
00181   // Create mapped properties:
00182 
00183   // DOM property: x ,  #IMPLIED attrib: x
00184   {
00185     nsCOMPtr<nsISVGLength> length;
00186     rv = NS_NewSVGLength(getter_AddRefs(length),
00187                          0.0f);
00188     NS_ENSURE_SUCCESS(rv,rv);
00189     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mX), length);
00190     NS_ENSURE_SUCCESS(rv,rv);
00191     rv = AddMappedSVGValue(nsSVGAtoms::x, mX);
00192     NS_ENSURE_SUCCESS(rv,rv);
00193   }
00194 
00195   // DOM property: y ,  #IMPLIED attrib: y
00196   {
00197     nsCOMPtr<nsISVGLength> length;
00198     rv = NS_NewSVGLength(getter_AddRefs(length),
00199                          0.0f);
00200     NS_ENSURE_SUCCESS(rv,rv);
00201     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mY), length);
00202     NS_ENSURE_SUCCESS(rv,rv);
00203     rv = AddMappedSVGValue(nsSVGAtoms::y, mY);
00204     NS_ENSURE_SUCCESS(rv,rv);
00205   }
00206 
00207   // DOM property: width ,  #REQUIRED  attrib: width
00208   // XXX: enforce requiredness
00209   {
00210     nsCOMPtr<nsISVGLength> length;
00211     rv = NS_NewSVGLength(getter_AddRefs(length),
00212                          100.0f, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
00213     NS_ENSURE_SUCCESS(rv,rv);
00214     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mWidth), length);
00215     NS_ENSURE_SUCCESS(rv,rv);
00216     rv = AddMappedSVGValue(nsSVGAtoms::width, mWidth);
00217     NS_ENSURE_SUCCESS(rv,rv);
00218   }
00219 
00220   // DOM property: height ,  #REQUIRED  attrib: height
00221   // XXX: enforce requiredness
00222   {
00223     nsCOMPtr<nsISVGLength> length;
00224     rv = NS_NewSVGLength(getter_AddRefs(length),
00225                          100.0f, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
00226     NS_ENSURE_SUCCESS(rv,rv);
00227     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mHeight), length);
00228     NS_ENSURE_SUCCESS(rv,rv);
00229     rv = AddMappedSVGValue(nsSVGAtoms::height, mHeight);
00230     NS_ENSURE_SUCCESS(rv,rv);
00231   }
00232 
00233 
00234   // DOM property: href , #REQUIRED attrib: xlink:href
00235   // XXX: enforce requiredness
00236   {
00237     rv = NS_NewSVGAnimatedString(getter_AddRefs(mHref));
00238     NS_ENSURE_SUCCESS(rv,rv);
00239     rv = AddMappedSVGValue(nsSVGAtoms::href, mHref, kNameSpaceID_XLink);
00240     NS_ENSURE_SUCCESS(rv,rv);
00241   }
00242 
00243   return rv;
00244 }
00245 
00246 //----------------------------------------------------------------------
00247 // nsISVGContent methods
00248 
00249 void nsSVGUseElement::ParentChainChanged()
00250 {
00251   // set new context information on our length-properties:
00252   
00253   nsCOMPtr<nsIDOMSVGSVGElement> svg_elem;
00254   GetOwnerSVGElement(getter_AddRefs(svg_elem));
00255   if (!svg_elem) return;
00256 
00257   nsCOMPtr<nsSVGCoordCtxProvider> ctx = do_QueryInterface(svg_elem);
00258   NS_ASSERTION(ctx, "<svg> element missing interface");
00259 
00260   // x:
00261   {
00262     nsCOMPtr<nsIDOMSVGLength> dom_length;
00263     mX->GetAnimVal(getter_AddRefs(dom_length));
00264     nsCOMPtr<nsISVGLength> length = do_QueryInterface(dom_length);
00265     NS_ASSERTION(length, "svg length missing interface");
00266     
00267     length->SetContext(nsRefPtr<nsSVGCoordCtx>(ctx->GetContextX()));
00268   }
00269 
00270   // y:
00271   {
00272     nsCOMPtr<nsIDOMSVGLength> dom_length;
00273     mY->GetAnimVal(getter_AddRefs(dom_length));
00274     nsCOMPtr<nsISVGLength> length = do_QueryInterface(dom_length);
00275     NS_ASSERTION(length, "svg length missing interface");
00276     
00277     length->SetContext(nsRefPtr<nsSVGCoordCtx>(ctx->GetContextY()));
00278   }
00279 
00280   // width:
00281   {
00282     nsCOMPtr<nsIDOMSVGLength> dom_length;
00283     mWidth->GetAnimVal(getter_AddRefs(dom_length));
00284     nsCOMPtr<nsISVGLength> length = do_QueryInterface(dom_length);
00285     NS_ASSERTION(length, "svg length missing interface");
00286     
00287     length->SetContext(nsRefPtr<nsSVGCoordCtx>(ctx->GetContextX()));
00288   }
00289 
00290   // height:
00291   {
00292     nsCOMPtr<nsIDOMSVGLength> dom_length;
00293     mHeight->GetAnimVal(getter_AddRefs(dom_length));
00294     nsCOMPtr<nsISVGLength> length = do_QueryInterface(dom_length);
00295     NS_ASSERTION(length, "svg length missing interface");
00296     
00297     length->SetContext(nsRefPtr<nsSVGCoordCtx>(ctx->GetContextY()));
00298   }
00299 }
00300 
00301 //----------------------------------------------------------------------
00302 // nsIDOMNode methods
00303 
00304 nsresult
00305 nsSVGUseElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult)
00306 {
00307   *aResult = nsnull;
00308 
00309   nsSVGUseElement *it = new nsSVGUseElement(mNodeInfo);
00310   if (!it) {
00311     return NS_ERROR_OUT_OF_MEMORY;
00312   }
00313 
00314   nsCOMPtr<nsIDOMNode> kungFuDeathGrip(it);
00315   nsresult rv = it->Init();
00316   rv |= CopyInnerTo(it, aDeep);
00317 
00318   // nsSVGUseElement specific portion - record who we cloned from
00319   it->mOriginal = NS_CONST_CAST(nsSVGUseElement*, this);
00320 
00321   if (NS_SUCCEEDED(rv)) {
00322     kungFuDeathGrip.swap(*aResult);
00323   }
00324 
00325   return rv;
00326 }
00327 
00328 //----------------------------------------------------------------------
00329 // nsIDOMSVGURIReference methods
00330 
00331 /* readonly attribute nsIDOMSVGAnimatedString href; */
00332   NS_IMETHODIMP nsSVGUseElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
00333 {
00334   *aHref = mHref;
00335   NS_IF_ADDREF(*aHref);
00336   return NS_OK;
00337 }
00338 
00339 //----------------------------------------------------------------------
00340 // nsIDOMSVGUseElement methods
00341 
00342 /* readonly attribute nsIDOMSVGAnimatedLength x; */
00343 NS_IMETHODIMP nsSVGUseElement::GetX(nsIDOMSVGAnimatedLength * *aX)
00344 {
00345   *aX = mX;
00346   NS_IF_ADDREF(*aX);
00347   return NS_OK;
00348 }
00349 
00350 /* readonly attribute nsIDOMSVGAnimatedLength y; */
00351 NS_IMETHODIMP nsSVGUseElement::GetY(nsIDOMSVGAnimatedLength * *aY)
00352 {
00353   *aY = mY;
00354   NS_IF_ADDREF(*aY);
00355   return NS_OK;
00356 }
00357 
00358 /* readonly attribute nsIDOMSVGAnimatedLength width; */
00359 NS_IMETHODIMP nsSVGUseElement::GetWidth(nsIDOMSVGAnimatedLength * *aWidth)
00360 {
00361   *aWidth = mWidth;
00362   NS_IF_ADDREF(*aWidth);
00363   return NS_OK;
00364 }
00365 
00366 /* readonly attribute nsIDOMSVGAnimatedLength height; */
00367 NS_IMETHODIMP nsSVGUseElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
00368 {
00369   *aHeight = mHeight;
00370   NS_IF_ADDREF(*aHeight);
00371   return NS_OK;
00372 }
00373 
00374 //----------------------------------------------------------------------
00375 // nsISVGValueObserver methods
00376 
00377 NS_IMETHODIMP
00378 nsSVGUseElement::WillModifySVGObservable(nsISVGValue* aObservable,
00379                                          nsISVGValue::modificationType aModType)
00380 {
00381   nsCOMPtr<nsIDOMSVGAnimatedString> s = do_QueryInterface(aObservable);
00382 
00383   // we're about to point at some other reference geometry, so
00384   // remove all the handlers we stuck on the old one.
00385   if (s && mHref == s)
00386     RemoveListeners();
00387 
00388   return nsSVGUseElementBase::WillModifySVGObservable(aObservable, aModType);
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsSVGUseElement::DidModifySVGObservable(nsISVGValue* aObservable,
00393                                         nsISVGValue::modificationType aModType)
00394 {
00395   nsCOMPtr<nsIDOMSVGAnimatedString> s = do_QueryInterface(aObservable);
00396 
00397   if (s && mHref == s) {
00398     // we're changing our nature, clear out the clone information
00399     mOriginal = nsnull;
00400 
00401     TriggerReclone();
00402     nsCOMPtr<nsIDOMSVGElement> element;
00403     LookupHref(getter_AddRefs(element));
00404     if (element) {
00405       nsresult rv;
00406       nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(element));
00407       NS_ASSERTION(target, "No dom event target for use reference");
00408       rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeInserted"),
00409                                     this, PR_TRUE);
00410       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
00411       rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeRemoved"),
00412                                     this, PR_TRUE);
00413       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
00414       rv = target->AddEventListener(NS_LITERAL_STRING("DOMAttrModified"),
00415                                     this, PR_TRUE);
00416       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
00417       rv = target->AddEventListener(NS_LITERAL_STRING("DOMCharacterDataModified"),
00418                                     this, PR_TRUE);
00419       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
00420     }
00421   }
00422 
00423   if (mClone) {
00424     nsCOMPtr<nsIDOMSVGAnimatedLength> l = do_QueryInterface(aObservable);
00425     nsCOMPtr<nsIDOMSVGSymbolElement> symbol = do_QueryInterface(mClone);
00426     nsCOMPtr<nsIDOMSVGSVGElement>    svg    = do_QueryInterface(mClone);
00427 
00428     if (l && (symbol || svg)) {
00429       if (l == mWidth) {
00430         nsAutoString width;
00431         GetAttr(kNameSpaceID_None, nsSVGAtoms::width, width);
00432         mClone->SetAttr(kNameSpaceID_None, nsSVGAtoms::width, width, PR_FALSE);
00433       }
00434 
00435       if (l == mHeight) {
00436         nsAutoString height;
00437         GetAttr(kNameSpaceID_None, nsSVGAtoms::height, height);
00438         mClone->SetAttr(kNameSpaceID_None, nsSVGAtoms::height, height, PR_FALSE);
00439       }
00440     }
00441   }
00442 
00443   return nsSVGUseElementBase::DidModifySVGObservable(aObservable, aModType);
00444 }
00445 
00446 //----------------------------------------------------------------------
00447 // nsIDOMMutationListener methods
00448 
00449 NS_IMETHODIMP nsSVGUseElement::HandleEvent(nsIDOMEvent* aEvent)
00450 {
00451   return NS_OK;
00452 }
00453 
00454 NS_IMETHODIMP nsSVGUseElement::SubtreeModified(nsIDOMEvent* aEvent)
00455 {
00456   return NS_OK;
00457 }
00458 
00459 NS_IMETHODIMP nsSVGUseElement::NodeInserted(nsIDOMEvent* aEvent)
00460 {
00461   TriggerReclone();
00462   return NS_OK;
00463 }
00464 
00465 NS_IMETHODIMP nsSVGUseElement::NodeRemoved(nsIDOMEvent* aEvent)
00466 {
00467   TriggerReclone();
00468   return NS_OK;
00469 }
00470 
00471 NS_IMETHODIMP nsSVGUseElement::NodeRemovedFromDocument(nsIDOMEvent* aMutationEvent)
00472 {
00473   return NS_OK;
00474 }
00475 
00476 NS_IMETHODIMP nsSVGUseElement::NodeInsertedIntoDocument(nsIDOMEvent* aMutationEvent)
00477 {
00478   return NS_OK;
00479 }
00480 
00481 NS_IMETHODIMP nsSVGUseElement::AttrModified(nsIDOMEvent* aMutationEvent)
00482 {
00483   TriggerReclone();
00484   return NS_OK;
00485 }
00486 
00487 NS_IMETHODIMP nsSVGUseElement::CharacterDataModified(nsIDOMEvent* aMutationEvent)
00488 {
00489   TriggerReclone();
00490   return NS_OK;
00491 }
00492 
00493 //----------------------------------------------------------------------
00494 // nsIAnonymousContentCreator methods
00495 
00496 NS_IMETHODIMP
00497 nsSVGUseElement::CreateAnonymousContent(nsPresContext*    aPresContext,
00498                                         nsISupportsArray& aAnonymousItems)
00499 {
00500 #ifdef DEBUG_tor
00501   nsAutoString href;
00502   mHref->GetAnimVal(href);
00503   fprintf(stderr, "<svg:use> reclone of \"%s\"\n", ToNewCString(href));
00504 #endif
00505 
00506   mClone = nsnull;
00507 
00508   nsCOMPtr<nsIDOMSVGElement> element;
00509   nsresult rv = LookupHref(getter_AddRefs(element));
00510 
00511   if (!element)
00512     return rv;
00513 
00514   // make sure target is valid type for <use>
00515   // QIable nsSVGGraphicsElement would eliminate enumerating all elements
00516   nsCOMPtr<nsIContent> targetContent = do_QueryInterface(element);
00517   nsIAtom *tag = targetContent->Tag();
00518   if (tag != nsSVGAtoms::svg &&
00519       tag != nsSVGAtoms::symbol &&
00520       tag != nsSVGAtoms::g &&
00521       tag != nsSVGAtoms::path &&
00522       tag != nsSVGAtoms::text &&
00523       tag != nsSVGAtoms::rect &&
00524       tag != nsSVGAtoms::circle &&
00525       tag != nsSVGAtoms::ellipse &&
00526       tag != nsSVGAtoms::line &&
00527       tag != nsSVGAtoms::polyline &&
00528       tag != nsSVGAtoms::polygon &&
00529       tag != nsSVGAtoms::image &&
00530       tag != nsSVGAtoms::use)
00531     return NS_ERROR_FAILURE;
00532 
00533   // circular loop detection
00534 
00535   // check 1 - check if we're a document descendent of the target
00536   if (nsContentUtils::ContentIsDescendantOf(this, targetContent))
00537     return NS_ERROR_FAILURE;
00538 
00539   // check 2 - check if we're a clone, and if we already exist in the hierarchy
00540   if (this->GetParent() && mOriginal) {
00541     for (nsCOMPtr<nsIContent> content = this->GetParent();
00542          content;
00543          content = content->GetParent()) {
00544       nsCOMPtr<nsIDOMSVGUseElement> useElement = do_QueryInterface(content);
00545 
00546       if (useElement) {
00547         nsRefPtr<nsSVGUseElement> useImpl;
00548         useElement->QueryInterface(NS_GET_IID(nsSVGUseElement),
00549                                    getter_AddRefs(useImpl));
00550 
00551         if (useImpl && useImpl->mOriginal == mOriginal)
00552           return NS_ERROR_FAILURE;
00553       }
00554     }
00555   }
00556 
00557   nsCOMPtr<nsIDOMNode> newchild;
00558   element->CloneNode(PR_TRUE, getter_AddRefs(newchild));
00559 
00560   if (!newchild)
00561     return NS_ERROR_FAILURE;
00562   
00563   nsCOMPtr<nsIContent>             newcontent = do_QueryInterface(newchild);
00564   nsCOMPtr<nsIDOMSVGSymbolElement> symbol     = do_QueryInterface(newchild);
00565   nsCOMPtr<nsIDOMSVGSVGElement>    svg        = do_QueryInterface(newchild);
00566 
00567   if (symbol) {
00568     nsIDocument *document = GetCurrentDoc();
00569     if (!document)
00570       return NS_ERROR_FAILURE;
00571 
00572     nsNodeInfoManager *nodeInfoManager = document->NodeInfoManager();
00573     if (!nodeInfoManager)
00574       return NS_ERROR_FAILURE;
00575 
00576     nsCOMPtr<nsINodeInfo> nodeInfo;
00577     nodeInfoManager->GetNodeInfo(nsSVGAtoms::svg, nsnull, kNameSpaceID_SVG,
00578                                  getter_AddRefs(nodeInfo));
00579     if (!nodeInfo)
00580       return NS_ERROR_FAILURE;
00581 
00582     nsCOMPtr<nsIContent> svgNode;
00583     NS_NewSVGSVGElement(getter_AddRefs(svgNode), nodeInfo);
00584 
00585     if (!svgNode)
00586       return NS_ERROR_FAILURE;
00587     
00588     if (newcontent->HasAttr(kNameSpaceID_None, nsSVGAtoms::viewBox)) {
00589       nsAutoString viewbox;
00590       newcontent->GetAttr(kNameSpaceID_None, nsSVGAtoms::viewBox, viewbox);
00591       svgNode->SetAttr(kNameSpaceID_None, nsSVGAtoms::viewBox, viewbox, PR_FALSE);
00592     }
00593 
00594     // copy attributes
00595     PRUint32 i;
00596     for (i = 0; i < newcontent->GetAttrCount(); i++) {
00597       PRInt32 nsID;
00598       nsCOMPtr<nsIAtom> name;
00599       nsCOMPtr<nsIAtom> prefix;
00600       nsAutoString value;
00601 
00602       newcontent->GetAttrNameAt(i, &nsID,
00603                                 getter_AddRefs(name),
00604                                 getter_AddRefs(prefix));
00605       newcontent->GetAttr(nsID, name, value);
00606       svgNode->SetAttr(nsID, name, prefix, value, PR_FALSE);
00607     }
00608 
00609     // move the children over
00610     PRUint32 num = newcontent->GetChildCount();
00611     for (i = 0; i < num; i++) {
00612       nsCOMPtr<nsIContent> child = newcontent->GetChildAt(0);
00613       newcontent->RemoveChildAt(0, PR_FALSE);
00614       svgNode->InsertChildAt(child, i, PR_TRUE);
00615     }
00616 
00617     newcontent = svgNode;
00618   }
00619 
00620   if (symbol || svg) {
00621     if (HasAttr(kNameSpaceID_None, nsSVGAtoms::width)) {
00622       nsAutoString width;
00623       GetAttr(kNameSpaceID_None, nsSVGAtoms::width, width);
00624       newcontent->SetAttr(kNameSpaceID_None, nsSVGAtoms::width, width, PR_FALSE);
00625     }
00626 
00627     if (HasAttr(kNameSpaceID_None, nsSVGAtoms::height)) {
00628       nsAutoString height;
00629       GetAttr(kNameSpaceID_None, nsSVGAtoms::height, height);
00630       newcontent->SetAttr(kNameSpaceID_None, nsSVGAtoms::height, height, PR_FALSE);
00631     }
00632   }
00633 
00634   aAnonymousItems.AppendElement(newcontent);
00635   mClone = newcontent;
00636 
00637   return NS_OK;
00638 }
00639 
00640 NS_IMETHODIMP
00641 nsSVGUseElement::CreateFrameFor(nsPresContext *aPresContext,
00642                                 nsIContent *aContent,
00643                                 nsIFrame **aFrame)
00644 {
00645   *aFrame = nsnull;
00646   return NS_ERROR_FAILURE;
00647 }
00648 
00649 
00650 //----------------------------------------------------------------------
00651 // implementation helpers
00652 
00653 nsresult
00654 nsSVGUseElement::LookupHref(nsIDOMSVGElement **aResult)
00655 {
00656   *aResult = nsnull;
00657 
00658   nsresult rv;
00659   nsAutoString href;
00660   mHref->GetAnimVal(href);
00661   if (href.IsEmpty())
00662     return NS_OK;
00663 
00664   // Get ID from spec
00665   PRInt32 pos = href.FindChar('#');
00666   if (pos == -1) {
00667     NS_WARNING("URI Spec not a reference");
00668     return NS_ERROR_FAILURE;
00669   } else if (pos > 0) {
00670     // XXX we don't support external <use> yet
00671     NS_WARNING("URI Spec not a local URI reference");
00672     return NS_ERROR_FAILURE;
00673   }
00674 
00675   // Strip off hash and get name
00676   nsAutoString id;
00677   href.Right(id, href.Length() - (pos + 1));
00678 
00679   // Get document
00680   nsCOMPtr<nsIDOMDocument> document;
00681   rv = GetOwnerDocument(getter_AddRefs(document));
00682   if (!NS_SUCCEEDED(rv) || !document)
00683     return rv;
00684 
00685   // Get element
00686   nsCOMPtr<nsIDOMElement> element;
00687   rv = document->GetElementById(id, getter_AddRefs(element));
00688   if (!NS_SUCCEEDED(rv) || !element)
00689     return rv;
00690 
00691   CallQueryInterface(element, aResult);
00692 
00693   return NS_OK;
00694 }
00695 
00696 void
00697 nsSVGUseElement::TriggerReclone()
00698 {
00699   nsIDocument *doc = GetCurrentDoc();
00700   if (!doc) return;
00701   nsIPresShell *presShell = doc->GetShellAt(0);
00702   if (!presShell) return;
00703   presShell->RecreateFramesFor(this);
00704 }
00705 
00706 void
00707 nsSVGUseElement::RemoveListeners()
00708 {
00709   nsCOMPtr<nsIDOMSVGElement> element;
00710   LookupHref(getter_AddRefs(element));
00711   if (element) {
00712     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(element));
00713     NS_ASSERTION(target, "No dom event target for use reference");
00714     
00715     target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeInserted"),
00716                                 this, PR_TRUE);
00717     target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeRemoved"),
00718                                 this, PR_TRUE);
00719     target->RemoveEventListener(NS_LITERAL_STRING("DOMAttrModified"),
00720                                 this, PR_TRUE);
00721     target->RemoveEventListener(NS_LITERAL_STRING("DOMCharacterDataModifed"),
00722                                 this, PR_TRUE);
00723   }
00724 }