Back to index

lightning-sunbird  0.9+nobinonly
nsSVGTSpanFrame.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.fritze@crocodile-clips.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or 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 "nsSVGTSpanFrame.h"
00040 #include "nsSVGUtils.h"
00041 
00042 //----------------------------------------------------------------------
00043 // Implementation
00044 
00045 nsresult
00046 NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00047                     nsIFrame* parentFrame, nsIFrame** aNewFrame)
00048 {
00049   *aNewFrame = nsnull;
00050 
00051   NS_ASSERTION(parentFrame, "null parent");
00052   nsISVGTextContainerFrame *text_container;
00053   parentFrame->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame),
00054                               (void**)&text_container);
00055   if (!text_container) {
00056     NS_ERROR("trying to construct an SVGTSpanFrame for an invalid container");
00057     return NS_ERROR_FAILURE;
00058   }
00059   
00060   nsCOMPtr<nsIDOMSVGTSpanElement> tspan_elem = do_QueryInterface(aContent);
00061   if (!tspan_elem) {
00062     NS_ERROR("Trying to construct an SVGTSpanFrame for a "
00063              "content element that doesn't support the right interfaces");
00064     return NS_ERROR_FAILURE;
00065   }
00066   
00067   nsSVGTSpanFrame* it = new (aPresShell) nsSVGTSpanFrame;
00068   if (nsnull == it)
00069     return NS_ERROR_OUT_OF_MEMORY;
00070 
00071   *aNewFrame = it;
00072   
00073   return NS_OK;
00074 }
00075 
00076 nsSVGTSpanFrame::nsSVGTSpanFrame()
00077   : mCharOffset(0), mFragmentTreeDirty(PR_FALSE), mPropagateTransform(PR_TRUE)
00078 {
00079 }
00080 
00081 nsSVGTSpanFrame::~nsSVGTSpanFrame()
00082 {
00083   nsCOMPtr<nsIDOMSVGTextPositioningElement> element = do_QueryInterface(mContent);
00084 
00085   // clean up our listener refs:
00086   if (element) {
00087     nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00088     element->GetX(getter_AddRefs(animLengthList));
00089     if (animLengthList) {
00090       nsCOMPtr<nsIDOMSVGLengthList> lengthList;
00091       animLengthList->GetAnimVal(getter_AddRefs(lengthList));
00092       if (lengthList)
00093         NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00094     }
00095   }
00096  
00097   if (element) {
00098     nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00099     element->GetY(getter_AddRefs(animLengthList));
00100     if (animLengthList) {
00101       nsCOMPtr<nsIDOMSVGLengthList> lengthList;
00102       animLengthList->GetAnimVal(getter_AddRefs(lengthList));
00103       if (lengthList)
00104         NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00105     }
00106   }
00107 
00108   {
00109     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDy();
00110     if (lengthList)
00111       NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00112   }
00113 }
00114 
00115 nsresult nsSVGTSpanFrame::InitSVG()
00116 {
00117   nsCOMPtr<nsIDOMSVGTextPositioningElement> element = do_QueryInterface(mContent);
00118 
00119   // set us up as a listener for various <tspan>-properties: 
00120   {
00121   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00122   element->GetX(getter_AddRefs(animLengthList));
00123   if (animLengthList) {
00124     nsCOMPtr<nsIDOMSVGLengthList> lengthList;
00125     animLengthList->GetAnimVal(getter_AddRefs(lengthList));
00126     if (lengthList)
00127       NS_ADD_SVGVALUE_OBSERVER(lengthList);
00128     }
00129   }
00130  
00131   {
00132     nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00133     element->GetY(getter_AddRefs(animLengthList));
00134     if (animLengthList) {
00135       nsCOMPtr<nsIDOMSVGLengthList> lengthList;
00136       animLengthList->GetAnimVal(getter_AddRefs(lengthList));
00137       if (lengthList)
00138         NS_ADD_SVGVALUE_OBSERVER(lengthList);
00139     }
00140   }
00141     
00142 
00143   {
00144     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDx();
00145     if (lengthList)
00146       NS_ADD_SVGVALUE_OBSERVER(lengthList);
00147   }
00148 
00149   {
00150     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDy();
00151     if (lengthList)
00152       NS_ADD_SVGVALUE_OBSERVER(lengthList);
00153   }
00154 
00155   return NS_OK;
00156 }
00157 
00158 nsIAtom *
00159 nsSVGTSpanFrame::GetType() const
00160 {
00161   return nsLayoutAtoms::svgTSpanFrame;
00162 }
00163 
00164 PRBool
00165 nsSVGTSpanFrame::IsFrameOfType(PRUint32 aFlags) const
00166 {
00167   return !(aFlags & ~nsIFrame::eSVG);
00168 }
00169 
00170 //----------------------------------------------------------------------
00171 // nsISupports methods
00172 
00173 NS_INTERFACE_MAP_BEGIN(nsSVGTSpanFrame)
00174   NS_INTERFACE_MAP_ENTRY(nsISVGTextContainerFrame)
00175   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentNode)
00176   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00177   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00178   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00179   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00180 NS_INTERFACE_MAP_END_INHERITING(nsSVGTSpanFrameBase)
00181 
00182 
00183 //----------------------------------------------------------------------
00184 // nsIFrame methods
00185 NS_IMETHODIMP
00186 nsSVGTSpanFrame::Init(nsPresContext*  aPresContext,
00187                       nsIContent*      aContent,
00188                       nsIFrame*        aParent,
00189                       nsStyleContext*  aContext,
00190                       nsIFrame*        aPrevInFlow)
00191 {
00192   nsresult rv;
00193   rv = nsSVGTSpanFrameBase::Init(aPresContext, aContent, aParent,
00194                                  aContext, aPrevInFlow);
00195 
00196   InitSVG();
00197   
00198   return rv;
00199 }
00200 
00201 NS_IMETHODIMP
00202 nsSVGTSpanFrame::AppendFrames(nsIAtom*        aListName,
00203                               nsIFrame*       aFrameList)
00204 {
00205   // append == insert at end:
00206   return InsertFrames(aListName, mFrames.LastChild(), aFrameList);  
00207 }
00208 
00209 NS_IMETHODIMP
00210 nsSVGTSpanFrame::InsertFrames(nsIAtom*        aListName,
00211                               nsIFrame*       aPrevFrame,
00212                               nsIFrame*       aFrameList)
00213 {
00214   // memorize last new frame
00215   nsIFrame* lastNewFrame = nsnull;
00216   {
00217     nsFrameList tmpList(aFrameList);
00218     lastNewFrame = tmpList.LastChild();
00219   }
00220   
00221   // Insert the new frames
00222   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
00223 
00224   // call InitialUpdate() on all new frames:
00225   nsIFrame* kid = aFrameList;
00226   nsIFrame* end = nsnull;
00227   if (lastNewFrame)
00228     end = lastNewFrame->GetNextSibling();
00229   
00230   while (kid != end) {
00231     nsISVGChildFrame* SVGFrame=nsnull;
00232     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00233     if (SVGFrame) {
00234       SVGFrame->InitialUpdate(); 
00235     }
00236     kid = kid->GetNextSibling();
00237   }
00238   
00239   return NS_OK;
00240 }
00241 
00242 NS_IMETHODIMP
00243 nsSVGTSpanFrame::RemoveFrame(nsIAtom*        aListName,
00244                              nsIFrame*       aOldFrame)
00245 {
00246   nsCOMPtr<nsISVGRendererRegion> dirty_region;
00247 
00248   nsISVGChildFrame* SVGFrame=nsnull;
00249   aOldFrame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00250 
00251   if (SVGFrame)
00252     dirty_region = SVGFrame->GetCoveredRegion();
00253   
00254   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00255 
00256   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00257   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
00258 
00259   if (SVGFrame && outerSVGFrame) {
00260     // XXX We need to rebuild the fragment tree starting from the
00261     // removed frame. Let's just rebuild the whole tree for now
00262     outerSVGFrame->SuspendRedraw();
00263     mFragmentTreeDirty = PR_TRUE;
00264     
00265     if (dirty_region) {
00266       outerSVGFrame->InvalidateRegion(dirty_region, PR_FALSE);
00267     }
00268 
00269     outerSVGFrame->UnsuspendRedraw();
00270   }
00271   
00272   NS_ASSERTION(result, "didn't find frame to delete");
00273   return result ? NS_OK : NS_ERROR_FAILURE;
00274 }
00275 
00276 NS_IMETHODIMP
00277 nsSVGTSpanFrame::ReplaceFrame(nsIAtom*        aListName,
00278                               nsIFrame*       aOldFrame,
00279                               nsIFrame*       aNewFrame)
00280 {
00281   NS_NOTYETIMPLEMENTED("nsSVGTSpanFrame::ReplaceFrame");
00282   return NS_ERROR_NOT_IMPLEMENTED;
00283 }
00284 
00285 //----------------------------------------------------------------------
00286 // nsISVGValueObserver methods:
00287 
00288 NS_IMETHODIMP
00289 nsSVGTSpanFrame::WillModifySVGObservable(nsISVGValue* observable,
00290                                          nsISVGValue::modificationType aModType)
00291 {
00292   return NS_OK;
00293 }
00294 
00295 
00296 NS_IMETHODIMP
00297 nsSVGTSpanFrame::DidModifySVGObservable (nsISVGValue* observable,
00298                                          nsISVGValue::modificationType aModType)
00299 {
00300   nsISVGTextFrame* text_frame = GetTextFrame();
00301   if (text_frame)
00302     text_frame->NotifyGlyphMetricsChange(this);
00303   
00304   return NS_OK;
00305 }
00306 
00307 
00308 //----------------------------------------------------------------------
00309 // nsISVGChildFrame methods
00310 
00311 NS_IMETHODIMP
00312 nsSVGTSpanFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00313 {
00314 #ifdef DEBUG
00315 //  printf("nsSVGTSpanFrame(%p)::Paint\n", this);
00316 #endif
00317 
00318   nsIFrame* kid = mFrames.FirstChild();
00319   while (kid) {
00320     nsISVGChildFrame* SVGFrame=0;
00321     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00322     if (SVGFrame)
00323       SVGFrame->PaintSVG(canvas, dirtyRectTwips);
00324     kid = kid->GetNextSibling();
00325   }
00326 
00327   return NS_OK;
00328 }
00329 
00330 NS_IMETHODIMP
00331 nsSVGTSpanFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00332 {
00333 #ifdef DEBUG
00334 //  printf("nsSVGTSpanFrame(%p)::GetFrameForPoint\n", this);
00335 #endif
00336   *hit = nsnull;
00337   nsIFrame* kid = mFrames.FirstChild();
00338   while (kid) {
00339     nsISVGChildFrame* SVGFrame=0;
00340     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00341     if (SVGFrame) {
00342       nsIFrame* temp=nsnull;
00343       nsresult rv = SVGFrame->GetFrameForPointSVG(x, y, &temp);
00344       if (NS_SUCCEEDED(rv) && temp) {
00345         *hit = temp;
00346         // return NS_OK; can't return. we need reverse order but only
00347         // have a singly linked list...
00348       }
00349     }
00350     kid = kid->GetNextSibling();
00351   }
00352   
00353   return *hit ? NS_OK : NS_ERROR_FAILURE;
00354 }
00355 
00356 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00357 nsSVGTSpanFrame::GetCoveredRegion()
00358 {
00359   nsISVGRendererRegion *accu_region=nsnull;
00360   
00361   nsIFrame* kid = mFrames.FirstChild();
00362   while (kid) {
00363     nsISVGChildFrame* SVGFrame=0;
00364     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00365     if (SVGFrame) {
00366       nsCOMPtr<nsISVGRendererRegion> dirty_region = SVGFrame->GetCoveredRegion();
00367       if (accu_region) {
00368         if (dirty_region) {
00369           nsCOMPtr<nsISVGRendererRegion> temp = dont_AddRef(accu_region);
00370           dirty_region->Combine(temp, &accu_region);
00371         }
00372       }
00373       else {
00374         accu_region = dirty_region;
00375         NS_IF_ADDREF(accu_region);
00376       }
00377     }
00378     kid = kid->GetNextSibling();
00379   }
00380   
00381   return accu_region;
00382 }
00383 
00384 NS_IMETHODIMP
00385 nsSVGTSpanFrame::InitialUpdate()
00386 {
00387   nsIFrame* kid = mFrames.FirstChild();
00388   while (kid) {
00389     nsISVGChildFrame* SVGFrame=0;
00390     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00391     if (SVGFrame) {
00392       SVGFrame->InitialUpdate();
00393     }
00394     kid = kid->GetNextSibling();
00395   }
00396   return NS_OK;
00397 }  
00398 
00399 NS_IMETHODIMP
00400 nsSVGTSpanFrame::NotifyCanvasTMChanged()
00401 {
00402   nsIFrame* kid = mFrames.FirstChild();
00403   while (kid) {
00404     nsISVGChildFrame* SVGFrame=0;
00405     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00406     if (SVGFrame) {
00407       SVGFrame->NotifyCanvasTMChanged();
00408     }
00409     kid = kid->GetNextSibling();
00410   }
00411   return NS_OK;
00412 }
00413 
00414 NS_IMETHODIMP
00415 nsSVGTSpanFrame::NotifyRedrawSuspended()
00416 {
00417   nsIFrame* kid = mFrames.FirstChild();
00418   while (kid) {
00419     nsISVGChildFrame* SVGFrame=0;
00420     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00421     if (SVGFrame) {
00422       SVGFrame->NotifyRedrawSuspended();
00423     }
00424     kid = kid->GetNextSibling();
00425   }
00426   return NS_OK;
00427 }
00428 
00429 NS_IMETHODIMP
00430 nsSVGTSpanFrame::NotifyRedrawUnsuspended()
00431 {
00432   nsIFrame* kid = mFrames.FirstChild();
00433   while (kid) {
00434     nsISVGChildFrame* SVGFrame=0;
00435     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00436     if (SVGFrame) {
00437       SVGFrame->NotifyRedrawUnsuspended();
00438     }
00439     kid = kid->GetNextSibling();
00440   }
00441   return NS_OK;
00442 }
00443 
00444 NS_IMETHODIMP
00445 nsSVGTSpanFrame::SetMatrixPropagation(PRBool aPropagate)
00446 {
00447   mPropagateTransform = aPropagate;
00448   return NS_OK;
00449 }
00450 
00451 NS_IMETHODIMP
00452 nsSVGTSpanFrame::GetBBox(nsIDOMSVGRect **_retval)
00453 {
00454   return nsSVGUtils::GetBBox(&mFrames, _retval);
00455 }
00456 
00457 //----------------------------------------------------------------------
00458 // nsISVGContainerFrame methods:
00459 
00460 nsISVGOuterSVGFrame *
00461 nsSVGTSpanFrame::GetOuterSVGFrame()
00462 {
00463   NS_ASSERTION(mParent, "null parent");
00464   
00465   nsISVGContainerFrame *containerFrame;
00466   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00467   if (!containerFrame) {
00468     NS_ERROR("invalid container");
00469     return nsnull;
00470   }
00471 
00472   return containerFrame->GetOuterSVGFrame();  
00473 }
00474 
00475 already_AddRefed<nsIDOMSVGMatrix>
00476 nsSVGTSpanFrame::GetCanvasTM()
00477 {
00478   if (!mPropagateTransform) {
00479     nsIDOMSVGMatrix *retval;
00480     NS_NewSVGMatrix(&retval);
00481     return retval;
00482   }
00483 
00484   NS_ASSERTION(mParent, "null parent");
00485   
00486   nsISVGContainerFrame *containerFrame;
00487   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00488   if (!containerFrame) {
00489     NS_ERROR("invalid container");
00490     return nsnull;
00491   }
00492 
00493   return containerFrame->GetCanvasTM();  
00494 }
00495 
00496 already_AddRefed<nsSVGCoordCtxProvider>
00497 nsSVGTSpanFrame::GetCoordContextProvider()
00498 {
00499   NS_ASSERTION(mParent, "null parent");
00500   
00501   nsISVGContainerFrame *containerFrame;
00502   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00503   if (!containerFrame) {
00504     NS_ERROR("invalid container");
00505     return nsnull;
00506   }
00507 
00508   return containerFrame->GetCoordContextProvider();  
00509 }
00510 
00511 
00512 //----------------------------------------------------------------------
00513 // nsISVGTextContainerFrame methods:
00514 
00515 NS_IMETHODIMP_(nsISVGTextFrame *)
00516 nsSVGTSpanFrame::GetTextFrame()
00517 {
00518   NS_ASSERTION(mParent, "null parent");
00519   nsISVGTextContainerFrame *containerFrame;
00520   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame), (void**)&containerFrame);
00521   if (!containerFrame) {
00522     return nsnull;
00523   }
00524 
00525   return containerFrame->GetTextFrame();  
00526 }
00527 
00528 NS_IMETHODIMP_(PRBool)
00529 nsSVGTSpanFrame::GetAbsolutePositionAdjustmentX(float &x, PRUint32 charNum)
00530 {
00531   return PR_FALSE;  
00532 }
00533 
00534 NS_IMETHODIMP_(PRBool)
00535 nsSVGTSpanFrame::GetAbsolutePositionAdjustmentY(float &y, PRUint32 charNum)
00536 {
00537   return PR_FALSE;    
00538 }
00539 
00540 NS_IMETHODIMP_(PRBool)
00541 nsSVGTSpanFrame::GetRelativePositionAdjustmentX(float &dx, PRUint32 charNum)
00542 {
00543   return PR_FALSE;    
00544 }
00545 
00546 NS_IMETHODIMP_(PRBool)
00547 nsSVGTSpanFrame::GetRelativePositionAdjustmentY(float &dy, PRUint32 charNum)
00548 {
00549   return PR_FALSE;    
00550 }
00551 
00552 
00553 //----------------------------------------------------------------------
00554 // nsISVGGlyphFragmentNode methods:
00555 
00556 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
00557 nsSVGTSpanFrame::GetFirstGlyphFragment()
00558 {
00559   // try children first:
00560   nsIFrame* kid = mFrames.FirstChild();
00561   while (kid) {
00562     nsISVGGlyphFragmentNode *node = nsnull;
00563     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&node);
00564     if (node)
00565       return node->GetFirstGlyphFragment();
00566     kid = kid->GetNextSibling();
00567   }
00568 
00569   // nope. try siblings:
00570   return GetNextGlyphFragment();
00571 
00572 }
00573 
00574 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
00575 nsSVGTSpanFrame::GetNextGlyphFragment()
00576 {
00577   nsIFrame* sibling = mNextSibling;
00578   while (sibling) {
00579     nsISVGGlyphFragmentNode *node = nsnull;
00580     sibling->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00581     if (node)
00582       return node->GetFirstGlyphFragment();
00583     sibling = sibling->GetNextSibling();
00584   }
00585 
00586   // no more siblings. go back up the tree.
00587   
00588   NS_ASSERTION(mParent, "null parent");
00589   nsISVGGlyphFragmentNode *node = nsnull;
00590   mParent->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00591   return node ? node->GetNextGlyphFragment() : nsnull;
00592 }
00593 
00594 NS_IMETHODIMP_(PRUint32)
00595 nsSVGTSpanFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch)
00596 {
00597   mCharOffset = charNum;
00598 
00599   // init children:
00600   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
00601   nsISVGGlyphFragmentNode* next;
00602   while (node) {
00603     next = GetNextGlyphFragmentChildNode(node);
00604     charNum = node->BuildGlyphFragmentTree(charNum, lastBranch && !next);
00605     node = next;
00606   }
00607   
00608   return charNum;
00609 }
00610 
00611 
00612 NS_IMETHODIMP_(void)
00613 nsSVGTSpanFrame::NotifyMetricsSuspended()
00614 {
00615   nsIFrame* kid = mFrames.FirstChild();
00616   while (kid) {
00617     nsISVGGlyphFragmentNode *node = nsnull;
00618     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00619     if (node)
00620       node->NotifyMetricsSuspended();
00621     kid = kid->GetNextSibling();
00622   }
00623 }
00624 
00625 NS_IMETHODIMP_(void)
00626 nsSVGTSpanFrame::NotifyMetricsUnsuspended()
00627 {
00628   nsIFrame* kid = mFrames.FirstChild();
00629   while (kid) {
00630     nsISVGGlyphFragmentNode *node = nsnull;
00631     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00632     if (node)
00633       node->NotifyMetricsUnsuspended();
00634     kid = kid->GetNextSibling();
00635   }
00636 }
00637 
00638 NS_IMETHODIMP_(void)
00639 nsSVGTSpanFrame::NotifyGlyphFragmentTreeSuspended()
00640 {
00641   nsIFrame* kid = mFrames.FirstChild();
00642   while (kid) {
00643     nsISVGGlyphFragmentNode *node = nsnull;
00644     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00645     if (node)
00646       node->NotifyGlyphFragmentTreeSuspended();
00647     kid = kid->GetNextSibling();
00648   }
00649 }
00650 
00651 NS_IMETHODIMP_(void)
00652 nsSVGTSpanFrame::NotifyGlyphFragmentTreeUnsuspended()
00653 {
00654   if (mFragmentTreeDirty) {
00655     nsISVGTextFrame* text_frame = GetTextFrame();
00656     NS_ASSERTION(text_frame, "null text frame");
00657     if (text_frame)
00658       text_frame->NotifyGlyphFragmentTreeChange(this);
00659     mFragmentTreeDirty = PR_FALSE;
00660   }    
00661   
00662   nsIFrame* kid = mFrames.FirstChild();
00663   while (kid) {
00664     nsISVGGlyphFragmentNode *node = nsnull;
00665     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00666     if (node)
00667       node->NotifyGlyphFragmentTreeUnsuspended();
00668     kid = kid->GetNextSibling();
00669   }
00670 }
00671 
00672 
00673 //----------------------------------------------------------------------
00674 //
00675 
00676 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00677 nsSVGTSpanFrame::GetX()
00678 {
00679   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
00680   if (!tpElement)
00681     return nsnull;
00682 
00683   if (!mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::x))
00684       return nsnull;
00685 
00686   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00687   tpElement->GetX(getter_AddRefs(animLengthList));
00688   nsIDOMSVGLengthList *retval;
00689   animLengthList->GetAnimVal(&retval);
00690   return retval;
00691 }
00692 
00693 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00694 nsSVGTSpanFrame::GetY()
00695 {
00696   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
00697   if (!tpElement)
00698     return nsnull;
00699 
00700   if (!mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::y))
00701       return nsnull;
00702 
00703   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00704   tpElement->GetY(getter_AddRefs(animLengthList));
00705   nsIDOMSVGLengthList *retval;
00706   animLengthList->GetAnimVal(&retval);
00707   return retval;
00708 }
00709 
00710 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00711 nsSVGTSpanFrame::GetDx()
00712 {
00713   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
00714   if (!tpElement)
00715     return nsnull;
00716 
00717   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00718   tpElement->GetDx(getter_AddRefs(animLengthList));
00719   nsIDOMSVGLengthList *retval;
00720   animLengthList->GetAnimVal(&retval);
00721   return retval;
00722 }
00723 
00724 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00725 nsSVGTSpanFrame::GetDy()
00726 {
00727   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
00728   if (!tpElement)
00729     return nsnull;
00730 
00731   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
00732   tpElement->GetDy(getter_AddRefs(animLengthList));
00733   nsIDOMSVGLengthList *retval;
00734   animLengthList->GetAnimVal(&retval);
00735   return retval;
00736 }
00737 
00738 nsISVGGlyphFragmentNode *
00739 nsSVGTSpanFrame::GetFirstGlyphFragmentChildNode()
00740 {
00741   nsISVGGlyphFragmentNode* retval = nsnull;
00742   nsIFrame* frame = mFrames.FirstChild();
00743   while (frame) {
00744     frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval);
00745     if (retval) break;
00746     frame = frame->GetNextSibling();
00747   }
00748   return retval;
00749 }
00750 
00751 nsISVGGlyphFragmentNode *
00752 nsSVGTSpanFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node)
00753 {
00754   nsISVGGlyphFragmentNode* retval = nsnull;
00755   nsIFrame* frame = nsnull;
00756   node->QueryInterface(NS_GET_IID(nsIFrame), (void**)&frame);
00757   NS_ASSERTION(frame, "interface not implemented");
00758   frame = frame->GetNextSibling();
00759   while (frame) {
00760     frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval);
00761     if (retval) break;
00762     frame = frame->GetNextSibling();
00763   }
00764   return retval;
00765 }