Back to index

lightning-sunbird  0.9+nobinonly
nsSVGTextFrame.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 "nsContainerFrame.h"
00040 #include "nsIDOMSVGTextElement.h"
00041 #include "nsPresContext.h"
00042 #include "nsISVGTextFrame.h"
00043 #include "nsISVGRendererCanvas.h"
00044 #include "nsWeakReference.h"
00045 #include "nsISVGValue.h"
00046 #include "nsISVGValueObserver.h"
00047 #include "nsIDOMSVGTransformable.h"
00048 #include "nsIDOMSVGAnimTransformList.h"
00049 #include "nsIDOMSVGSVGElement.h"
00050 #include "nsIDOMSVGMatrix.h"
00051 #include "nsIDOMSVGLengthList.h"
00052 #include "nsIDOMSVGLength.h"
00053 #include "nsISVGValueUtils.h"
00054 #include "nsIDOMSVGAnimatedLengthList.h"
00055 #include "nsIDOMSVGTransformList.h"
00056 #include "nsISVGContainerFrame.h"
00057 #include "nsISVGChildFrame.h"
00058 #include "nsISVGGlyphFragmentNode.h"
00059 #include "nsISVGGlyphFragmentLeaf.h"
00060 #include "nsISVGRendererGlyphMetrics.h"
00061 #include "nsISVGOuterSVGFrame.h"
00062 #include "nsIDOMSVGRect.h"
00063 #include "nsISVGTextContentMetrics.h"
00064 #include "nsSVGRect.h"
00065 #include "nsSVGMatrix.h"
00066 #include "nsLayoutAtoms.h"
00067 #include "nsISVGPathFlatten.h"
00068 #include "nsSVGUtils.h"
00069 
00070 typedef nsContainerFrame nsSVGTextFrameBase;
00071 
00072 class nsSVGTextFrame : public nsSVGTextFrameBase,
00073                        public nsISVGTextFrame, // : nsISVGTextContainerFrame
00074                        public nsISVGChildFrame,
00075                        public nsISVGContainerFrame,
00076                        public nsISVGValueObserver,
00077                        public nsISVGTextContentMetrics,
00078                        public nsSupportsWeakReference
00079 {
00080   friend nsresult
00081   NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00082                      nsIFrame** aNewFrame);
00083 protected:
00084   nsSVGTextFrame();
00085   virtual ~nsSVGTextFrame();
00086   nsresult Init();
00087   
00088    // nsISupports interface:
00089   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00090 private:
00091   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00092   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }  
00093 public:
00094   // nsIFrame:
00095 
00096   NS_IMETHOD  AppendFrames(nsIAtom*        aListName,
00097                            nsIFrame*       aFrameList);
00098   NS_IMETHOD  InsertFrames(nsIAtom*        aListName,
00099                            nsIFrame*       aPrevFrame,
00100                            nsIFrame*       aFrameList);
00101   NS_IMETHOD  RemoveFrame(nsIAtom*        aListName,
00102                           nsIFrame*       aOldFrame);
00103   NS_IMETHOD  ReplaceFrame(nsIAtom*        aListName,
00104                            nsIFrame*       aOldFrame,
00105                            nsIFrame*       aNewFrame);
00106   
00107   NS_IMETHOD Init(nsPresContext*  aPresContext,
00108                   nsIContent*      aContent,
00109                   nsIFrame*        aParent,
00110                   nsStyleContext*  aContext,
00111                   nsIFrame*        aPrevInFlow);
00112 
00113   NS_IMETHOD  AttributeChanged(nsIContent*     aChild,
00114                                PRInt32         aNameSpaceID,
00115                                nsIAtom*        aAttribute,
00116                                PRInt32         aModType);
00117 
00118   NS_IMETHOD DidSetStyleContext(nsPresContext* aPresContext);
00119 
00125   virtual nsIAtom* GetType() const;
00126   virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
00127 
00128 #ifdef DEBUG
00129   NS_IMETHOD GetFrameName(nsAString& aResult) const
00130   {
00131     return MakeFrameName(NS_LITERAL_STRING("SVGText"), aResult);
00132   }
00133 #endif
00134 
00135   // nsISVGValueObserver
00136   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00137                                      nsISVGValue::modificationType aModType);
00138   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00139                                      nsISVGValue::modificationType aModType);
00140 
00141   // nsISVGTextContentMetrics
00142   NS_IMETHOD GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval);
00143   
00144   // nsISupportsWeakReference
00145   // implementation inherited from nsSupportsWeakReference
00146   
00147   // nsISVGChildFrame interface:
00148   NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00149   NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
00150   NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
00151   NS_IMETHOD InitialUpdate();
00152   NS_IMETHOD NotifyCanvasTMChanged();
00153   NS_IMETHOD NotifyRedrawSuspended();
00154   NS_IMETHOD NotifyRedrawUnsuspended();
00155   NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
00156   NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
00157   
00158   // nsISVGContainerFrame interface:
00159   nsISVGOuterSVGFrame *GetOuterSVGFrame();
00160   already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
00161   already_AddRefed<nsSVGCoordCtxProvider> GetCoordContextProvider();
00162   
00163   // nsISVGTextFrame interface:
00164   NS_IMETHOD_(void) NotifyGlyphMetricsChange(nsISVGGlyphFragmentNode* caller);
00165   NS_IMETHOD_(void) NotifyGlyphFragmentTreeChange(nsISVGGlyphFragmentNode* caller);
00166   NS_IMETHOD_(PRBool) IsMetricsSuspended();
00167   NS_IMETHOD_(PRBool) IsGlyphFragmentTreeSuspended();
00168 
00169   // nsISVGTextContainerFrame interface:
00170   NS_IMETHOD_(nsISVGTextFrame *) GetTextFrame();
00171   NS_IMETHOD_(PRBool) GetAbsolutePositionAdjustmentX(float &x, PRUint32 charNum);
00172   NS_IMETHOD_(PRBool) GetAbsolutePositionAdjustmentY(float &y, PRUint32 charNum);
00173   NS_IMETHOD_(PRBool) GetRelativePositionAdjustmentX(float &dx, PRUint32 charNum);
00174   NS_IMETHOD_(PRBool) GetRelativePositionAdjustmentY(float &dy, PRUint32 charNum);
00175   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetX();
00176   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetY();
00177   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDx();
00178   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDy();
00179 
00180 protected:
00181   void EnsureFragmentTreeUpToDate();
00182   void UpdateFragmentTree();
00183   void UpdateGlyphPositioning();
00184   already_AddRefed<nsIDOMSVGAnimatedTransformList> GetTransform();
00185   nsISVGGlyphFragmentNode *GetFirstGlyphFragmentChildNode();
00186   nsISVGGlyphFragmentNode *GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node);
00187   nsISVGGlyphFragmentLeaf *GetGlyphFragmentAtCharNum(PRUint32 charnum);
00188 
00189   enum UpdateState{
00190     unsuspended,
00191     suspended,
00192     updating};
00193   UpdateState mFragmentTreeState;
00194   UpdateState mMetricsState;
00195   PRBool mFragmentTreeDirty;
00196   PRBool mPositioningDirty;
00197 
00198   nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
00199   PRBool mPropagateTransform;
00200 };
00201 
00202 //----------------------------------------------------------------------
00203 // Implementation
00204 
00205 nsresult
00206 NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00207                    nsIFrame** aNewFrame)
00208 {
00209   *aNewFrame = nsnull;
00210 
00211   nsCOMPtr<nsIDOMSVGTextElement> text_elem = do_QueryInterface(aContent);
00212   if (!text_elem) {
00213 #ifdef DEBUG
00214     printf("warning: trying to construct an SVGTextFrame for a "
00215            "content element that doesn't support the right interfaces\n");
00216 #endif
00217     return NS_ERROR_FAILURE;
00218   }
00219   
00220   nsSVGTextFrame* it = new (aPresShell) nsSVGTextFrame;
00221   if (nsnull == it)
00222     return NS_ERROR_OUT_OF_MEMORY;
00223 
00224   *aNewFrame = it;
00225   
00226   return NS_OK;
00227 }
00228 
00229 nsSVGTextFrame::nsSVGTextFrame()
00230     : mFragmentTreeState(suspended), mMetricsState(suspended),
00231       mFragmentTreeDirty(PR_FALSE), mPositioningDirty(PR_FALSE),
00232       mPropagateTransform(PR_TRUE)
00233 {
00234 }
00235 
00236 nsSVGTextFrame::~nsSVGTextFrame()
00237 {
00238   // clean up our listener refs:
00239   {
00240     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetX();
00241     NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00242   }
00243 
00244   {
00245     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetY();
00246     NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00247   }
00248 
00249   {
00250     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDx();
00251     NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00252   }
00253 
00254   {
00255     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDy();
00256     NS_REMOVE_SVGVALUE_OBSERVER(lengthList);
00257   }
00258 
00259   {
00260     nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00261     NS_ASSERTION(transformable, "wrong content element");
00262     nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00263     transformable->GetTransform(getter_AddRefs(transforms));
00264     NS_REMOVE_SVGVALUE_OBSERVER(transforms);
00265   }
00266 }
00267 
00268 nsresult nsSVGTextFrame::Init()
00269 {
00270   // set us up as a listener for various <text>-properties: 
00271   {
00272     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetX();
00273     NS_ADD_SVGVALUE_OBSERVER(lengthList);
00274   }
00275 
00276   {
00277     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetY();
00278     NS_ADD_SVGVALUE_OBSERVER(lengthList);
00279   }
00280 
00281   {
00282     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDx();
00283     NS_ADD_SVGVALUE_OBSERVER(lengthList);
00284   }
00285 
00286   {
00287     nsCOMPtr<nsIDOMSVGLengthList> lengthList = GetDy();
00288     NS_ADD_SVGVALUE_OBSERVER(lengthList);
00289   }
00290 
00291   {
00292     nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms = GetTransform();
00293     NS_ADD_SVGVALUE_OBSERVER(transforms);
00294   }
00295   
00296   return NS_OK;
00297 }
00298 
00299 //----------------------------------------------------------------------
00300 // nsISupports methods
00301 
00302 NS_INTERFACE_MAP_BEGIN(nsSVGTextFrame)
00303   NS_INTERFACE_MAP_ENTRY(nsISVGTextFrame)
00304   NS_INTERFACE_MAP_ENTRY(nsISVGTextContainerFrame)
00305   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00306   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00307   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00308   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00309   NS_INTERFACE_MAP_ENTRY(nsISVGTextContentMetrics)
00310 NS_INTERFACE_MAP_END_INHERITING(nsSVGTextFrameBase)
00311 
00312 
00313 //----------------------------------------------------------------------
00314 // nsIFrame methods
00315 NS_IMETHODIMP
00316 nsSVGTextFrame::Init(nsPresContext*   aPresContext,
00317                      nsIContent*      aContent,
00318                      nsIFrame*        aParent,
00319                      nsStyleContext*  aContext,
00320                      nsIFrame*        aPrevInFlow)
00321 {
00322   nsresult rv;
00323   rv = nsSVGTextFrameBase::Init(aPresContext, aContent, aParent,
00324                                 aContext, aPrevInFlow);
00325 
00326   Init();
00327   
00328   return rv;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsSVGTextFrame::AttributeChanged(nsIContent*     aChild,
00333                                  PRInt32         aNameSpaceID,
00334                                  nsIAtom*        aAttribute,
00335                                  PRInt32         aModType)
00336 {
00337   // we don't use this notification mechanism
00338   
00339 #ifdef DEBUG
00340   printf("** nsSVGTextFrame::AttributeChanged(");
00341   nsAutoString str;
00342   aAttribute->ToString(str);
00343   printf(NS_ConvertUTF16toUTF8(str).get());
00344   printf(")\n");
00345 #endif
00346   
00347   return NS_OK;
00348 }
00349 
00350 NS_IMETHODIMP
00351 nsSVGTextFrame::DidSetStyleContext(nsPresContext* aPresContext)
00352 {
00353 #ifdef DEBUG
00354   printf("** nsSVGTextFrame::DidSetStyleContext\n");
00355 #endif
00356 
00357   return NS_OK;
00358 }
00359 
00360 nsIAtom *
00361 nsSVGTextFrame::GetType() const
00362 {
00363   return nsLayoutAtoms::svgTextFrame;
00364 }
00365 
00366 PRBool
00367 nsSVGTextFrame::IsFrameOfType(PRUint32 aFlags) const
00368 {
00369   return !(aFlags & ~nsIFrame::eSVG);
00370 }
00371 
00372 NS_IMETHODIMP
00373 nsSVGTextFrame::AppendFrames(nsIAtom*        aListName,
00374                              nsIFrame*       aFrameList)
00375 {
00376   // append == insert at end:
00377   return InsertFrames(aListName, mFrames.LastChild(), aFrameList);  
00378 }
00379 
00380 NS_IMETHODIMP
00381 nsSVGTextFrame::InsertFrames(nsIAtom*        aListName,
00382                              nsIFrame*       aPrevFrame,
00383                              nsIFrame*       aFrameList)
00384 {
00385   // memorize last new frame
00386   nsIFrame* lastNewFrame = nsnull;
00387   {
00388     nsFrameList tmpList(aFrameList);
00389     lastNewFrame = tmpList.LastChild();
00390   }
00391   
00392   // Insert the new frames
00393   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
00394 
00395   // call InitialUpdate() on all new frames:
00396   nsIFrame* kid = aFrameList;
00397   nsIFrame* end = nsnull;
00398   if (lastNewFrame)
00399     end = lastNewFrame->GetNextSibling();
00400   
00401   while (kid != end) {
00402     nsISVGChildFrame* SVGFrame=nsnull;
00403     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00404     if (SVGFrame) {
00405       SVGFrame->InitialUpdate(); 
00406     }
00407     kid = kid->GetNextSibling();
00408   }
00409   
00410   return NS_OK;
00411 }
00412 
00413 NS_IMETHODIMP
00414 nsSVGTextFrame::RemoveFrame(nsIAtom*        aListName,
00415                             nsIFrame*       aOldFrame)
00416 {
00417   nsCOMPtr<nsISVGRendererRegion> dirty_region;
00418 
00419   nsISVGChildFrame* SVGFrame=nsnull;
00420   aOldFrame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00421 
00422   if (SVGFrame)
00423     dirty_region = SVGFrame->GetCoveredRegion();
00424   
00425   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00426 
00427   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00428   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
00429 
00430   if (SVGFrame && outerSVGFrame) {
00431     // XXX We need to rebuild the fragment tree starting from the
00432     // removed frame. Let's just rebuild the whole tree for now
00433     outerSVGFrame->SuspendRedraw();
00434     mFragmentTreeDirty = PR_TRUE;
00435     
00436     if (dirty_region) {
00437       outerSVGFrame->InvalidateRegion(dirty_region, PR_FALSE);
00438     }
00439 
00440     outerSVGFrame->UnsuspendRedraw();
00441   }
00442   
00443   NS_ASSERTION(result, "didn't find frame to delete");
00444   return result ? NS_OK : NS_ERROR_FAILURE;
00445 }
00446 
00447 NS_IMETHODIMP
00448 nsSVGTextFrame::ReplaceFrame(nsIAtom*        aListName,
00449                              nsIFrame*       aOldFrame,
00450                              nsIFrame*       aNewFrame)
00451 {
00452   NS_NOTYETIMPLEMENTED("nsSVGTextFrame::ReplaceFrame");
00453   return NS_ERROR_NOT_IMPLEMENTED;
00454 }
00455 
00456 //----------------------------------------------------------------------
00457 // nsISVGValueObserver methods:
00458 
00459 NS_IMETHODIMP
00460 nsSVGTextFrame::WillModifySVGObservable(nsISVGValue* observable,
00461                                         nsISVGValue::modificationType aModType)
00462 {
00463   return NS_OK;
00464 }
00465 
00466 
00467 NS_IMETHODIMP
00468 nsSVGTextFrame::DidModifySVGObservable (nsISVGValue* observable,
00469                                         nsISVGValue::modificationType aModType)
00470 {  
00471   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms = GetTransform();
00472   if (SameCOMIdentity(observable, transforms)) {
00473     // transform has changed
00474 
00475     // make sure our cached transform matrix gets (lazily) updated
00476     mCanvasTM = nsnull;
00477     
00478     nsIFrame* kid = mFrames.FirstChild();
00479     while (kid) {
00480       nsISVGChildFrame* SVGFrame=0;
00481       kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00482       if (SVGFrame)
00483         SVGFrame->NotifyCanvasTMChanged();
00484       kid = kid->GetNextSibling();
00485     }
00486   }
00487   else {
00488     // x, y have changed
00489     mPositioningDirty = PR_TRUE;
00490     if (mMetricsState == unsuspended) {
00491       UpdateGlyphPositioning();
00492     }
00493   }
00494   return NS_OK;
00495 }
00496 
00497 //----------------------------------------------------------------------
00498 // nsISVGTextContentMetrics
00499 NS_IMETHODIMP
00500 nsSVGTextFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
00501 {
00502   *_retval = nsnull;
00503   
00504   EnsureFragmentTreeUpToDate();
00505 
00506   nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(charnum);
00507   if (!fragment) return NS_ERROR_FAILURE; // xxx return some index-out-of-range error
00508   
00509   // query the renderer metrics for the bounds of the character
00510   nsCOMPtr<nsISVGRendererGlyphMetrics> metrics;
00511   fragment->GetGlyphMetrics(getter_AddRefs(metrics));
00512   if (!metrics) return NS_ERROR_FAILURE;
00513   nsresult rv = metrics->GetExtentOfChar(charnum-fragment->GetCharNumberOffset(),
00514                                          _retval);
00515   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00516 
00517   // offset the bounds by the position of the fragment:
00518   float x,y;
00519   (*_retval)->GetX(&x);
00520   (*_retval)->GetY(&y);
00521   (*_retval)->SetX(x+fragment->GetGlyphPositionX());
00522   (*_retval)->SetY(y+fragment->GetGlyphPositionY());
00523 
00524   return NS_OK;
00525 }
00526 
00527 
00528 //----------------------------------------------------------------------
00529 // nsISVGChildFrame methods
00530 
00531 NS_IMETHODIMP
00532 nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00533 {
00534 #ifdef DEBUG
00535 //  printf("nsSVGTextFrame(%p)::Paint\n", this);
00536 #endif
00537 
00538   nsIFrame* kid = mFrames.FirstChild();
00539   while (kid) {
00540     nsISVGChildFrame* SVGFrame=0;
00541     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00542     if (SVGFrame)
00543       SVGFrame->PaintSVG(canvas, dirtyRectTwips);
00544     kid = kid->GetNextSibling();
00545   }
00546 
00547   return NS_OK;
00548 }
00549 
00550 NS_IMETHODIMP
00551 nsSVGTextFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00552 {
00553 #ifdef DEBUG
00554 //  printf("nsSVGTextFrame(%p)::GetFrameForPoint\n", this);
00555 #endif
00556   *hit = nsnull;
00557   nsIFrame* kid = mFrames.FirstChild();
00558   while (kid) {
00559     nsISVGChildFrame* SVGFrame=0;
00560     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00561     if (SVGFrame) {
00562       nsIFrame* temp=nsnull;
00563       nsresult rv = SVGFrame->GetFrameForPointSVG(x, y, &temp);
00564       if (NS_SUCCEEDED(rv) && temp) {
00565         *hit = temp;
00566         // return NS_OK; can't return. we need reverse order but only
00567         // have a singly linked list...
00568       }
00569     }
00570     kid = kid->GetNextSibling();
00571   }
00572   
00573   return *hit ? NS_OK : NS_ERROR_FAILURE;
00574 }
00575 
00576 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00577 nsSVGTextFrame::GetCoveredRegion()
00578 {
00579   nsISVGRendererRegion *accu_region=nsnull;
00580   
00581   nsIFrame* kid = mFrames.FirstChild();
00582   while (kid) {
00583     nsISVGChildFrame* SVGFrame=0;
00584     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00585     if (SVGFrame) {
00586       nsCOMPtr<nsISVGRendererRegion> dirty_region = SVGFrame->GetCoveredRegion();
00587       if (dirty_region) {
00588         if (accu_region) {
00589           nsCOMPtr<nsISVGRendererRegion> temp = dont_AddRef(accu_region);
00590           dirty_region->Combine(temp, &accu_region);
00591         }
00592         else {
00593           accu_region = dirty_region;
00594           NS_IF_ADDREF(accu_region);
00595         }
00596       }
00597     }
00598     kid = kid->GetNextSibling();
00599   }
00600   
00601   return accu_region;
00602 }
00603 
00604 NS_IMETHODIMP
00605 nsSVGTextFrame::InitialUpdate()
00606 {
00607   nsIFrame* kid = mFrames.FirstChild();
00608   while (kid) {
00609     nsISVGChildFrame* SVGFrame=0;
00610     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00611     if (SVGFrame) {
00612       SVGFrame->InitialUpdate();
00613     }
00614     kid = kid->GetNextSibling();
00615   }
00616 
00617 #ifdef DEBUG
00618   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00619   if (!outerSVGFrame) {
00620     NS_ERROR("null outerSVGFrame");
00621     return NS_ERROR_FAILURE;
00622   }
00623   
00624   PRBool suspended;
00625   outerSVGFrame->IsRedrawSuspended(&suspended);
00626   if (!suspended) NS_ERROR("initialupdate while redraw not suspended! need to update fragment tree");
00627   //XXX
00628 #endif
00629 
00630   return NS_OK;
00631 }
00632 
00633 NS_IMETHODIMP
00634 nsSVGTextFrame::NotifyCanvasTMChanged()
00635 {
00636   // make sure our cached transform matrix gets (lazily) updated
00637   mCanvasTM = nsnull;
00638   
00639   nsIFrame* kid = mFrames.FirstChild();
00640   while (kid) {
00641     nsISVGChildFrame* SVGFrame=0;
00642     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00643     if (SVGFrame) {
00644       SVGFrame->NotifyCanvasTMChanged();
00645     }
00646     kid = kid->GetNextSibling();
00647   }
00648   return NS_OK;
00649 }
00650 
00651 NS_IMETHODIMP
00652 nsSVGTextFrame::NotifyRedrawSuspended()
00653 {
00654   mMetricsState = suspended;
00655   mFragmentTreeState = suspended;
00656   
00657   nsIFrame* kid = mFrames.FirstChild();
00658   while (kid) {
00659     nsISVGChildFrame* SVGFrame=nsnull;
00660     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00661     if (SVGFrame) {
00662       SVGFrame->NotifyRedrawSuspended();
00663     }
00664     nsISVGGlyphFragmentNode* fragmentNode=nsnull;
00665     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&fragmentNode);
00666     if (fragmentNode) {
00667       fragmentNode->NotifyMetricsSuspended();
00668       fragmentNode->NotifyGlyphFragmentTreeSuspended();
00669     }
00670     kid = kid->GetNextSibling();
00671   }
00672   return NS_OK;
00673 }
00674 
00675 NS_IMETHODIMP
00676 nsSVGTextFrame::NotifyRedrawUnsuspended()
00677 {
00678   NS_ASSERTION(mMetricsState == suspended, "metrics state not suspended during redraw");
00679   NS_ASSERTION(mFragmentTreeState == suspended, "fragment tree not suspended during redraw");
00680 
00681   // 3 passes:
00682   mFragmentTreeState = updating;
00683   nsIFrame* kid = mFrames.FirstChild();
00684   while (kid) {
00685     nsISVGGlyphFragmentNode* node=nsnull;
00686     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00687     if (node)
00688       node->NotifyGlyphFragmentTreeUnsuspended();
00689     kid = kid->GetNextSibling();
00690   }
00691 
00692   mFragmentTreeState = unsuspended;
00693   if (mFragmentTreeDirty)
00694     UpdateFragmentTree();
00695   
00696   mMetricsState = updating;
00697   kid = mFrames.FirstChild();
00698   while (kid) {
00699     nsISVGGlyphFragmentNode* node=nsnull;
00700     kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00701     if (node)
00702       node->NotifyMetricsUnsuspended();
00703     kid = kid->GetNextSibling();
00704   }
00705 
00706   mMetricsState = unsuspended;
00707   if (mPositioningDirty)
00708     UpdateGlyphPositioning();
00709   
00710   kid = mFrames.FirstChild();
00711   while (kid) {
00712     nsISVGChildFrame* SVGFrame=nsnull;
00713     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00714     if (SVGFrame) {
00715       SVGFrame->NotifyRedrawUnsuspended();
00716     }
00717     kid = kid->GetNextSibling();
00718   }
00719   
00720   return NS_OK;
00721 }
00722 
00723 NS_IMETHODIMP
00724 nsSVGTextFrame::SetMatrixPropagation(PRBool aPropagate)
00725 {
00726   mPropagateTransform = aPropagate;
00727   return NS_OK;
00728 }
00729 
00730 NS_IMETHODIMP
00731 nsSVGTextFrame::GetBBox(nsIDOMSVGRect **_retval)
00732 {
00733   EnsureFragmentTreeUpToDate();
00734   return nsSVGUtils::GetBBox(&mFrames, _retval);
00735 }
00736 
00737 //----------------------------------------------------------------------
00738 // nsISVGContainerFrame methods:
00739 
00740 nsISVGOuterSVGFrame *
00741 nsSVGTextFrame::GetOuterSVGFrame()
00742 {
00743   NS_ASSERTION(mParent, "null parent");
00744   
00745   nsISVGContainerFrame *containerFrame;
00746   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00747   if (!containerFrame) {
00748     NS_ERROR("invalid container");
00749     return nsnull;
00750   }
00751 
00752   return containerFrame->GetOuterSVGFrame();  
00753 }
00754 
00755 already_AddRefed<nsIDOMSVGMatrix>
00756 nsSVGTextFrame::GetCanvasTM()
00757 {
00758   if (!mCanvasTM) {
00759     if (!mPropagateTransform) {
00760       nsIDOMSVGMatrix *retval;
00761       NS_NewSVGMatrix(&retval);
00762       return retval;
00763     }
00764 
00765     // get our parent's tm and append local transforms (if any):
00766     NS_ASSERTION(mParent, "null parent");
00767     nsISVGContainerFrame *containerFrame;
00768     mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00769     if (!containerFrame) {
00770       NS_ERROR("invalid parent");
00771       return nsnull;
00772     }
00773     nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
00774     NS_ASSERTION(parentTM, "null TM");
00775 
00776     // got the parent tm, now check for local tm:
00777     nsCOMPtr<nsIDOMSVGMatrix> localTM;
00778     {
00779       nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00780       NS_ASSERTION(transformable, "wrong content element");
00781       nsCOMPtr<nsIDOMSVGAnimatedTransformList> atl;
00782       transformable->GetTransform(getter_AddRefs(atl));
00783       NS_ASSERTION(atl, "null animated transform list");
00784       nsCOMPtr<nsIDOMSVGTransformList> transforms;
00785       atl->GetAnimVal(getter_AddRefs(transforms));
00786       NS_ASSERTION(transforms, "null transform list");
00787       PRUint32 numberOfItems;
00788       transforms->GetNumberOfItems(&numberOfItems);
00789       if (numberOfItems>0)
00790         transforms->GetConsolidationMatrix(getter_AddRefs(localTM));
00791     }
00792     
00793     if (localTM)
00794       parentTM->Multiply(localTM, getter_AddRefs(mCanvasTM));
00795     else
00796       mCanvasTM = parentTM;
00797   }
00798 
00799   nsIDOMSVGMatrix* retval = mCanvasTM.get();
00800   NS_IF_ADDREF(retval);
00801   return retval;
00802 }
00803 
00804 already_AddRefed<nsSVGCoordCtxProvider>
00805 nsSVGTextFrame::GetCoordContextProvider()
00806 {
00807   NS_ASSERTION(mParent, "null parent");
00808   
00809   nsISVGContainerFrame *containerFrame;
00810   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00811   if (!containerFrame) {
00812     NS_ERROR("invalid container");
00813     return nsnull;
00814   }
00815 
00816   return containerFrame->GetCoordContextProvider();  
00817 }
00818 
00819 
00820 //----------------------------------------------------------------------
00821 // nsISVGTextFrame methods
00822 
00823 NS_IMETHODIMP_(void)
00824 nsSVGTextFrame::NotifyGlyphMetricsChange(nsISVGGlyphFragmentNode* caller)
00825 {
00826   NS_ASSERTION(mMetricsState!=suspended, "notification during suspension");
00827   mPositioningDirty = PR_TRUE;
00828   if (mMetricsState == unsuspended) {
00829     UpdateGlyphPositioning();
00830   }
00831 }
00832 
00833 NS_IMETHODIMP_(void)
00834 nsSVGTextFrame::NotifyGlyphFragmentTreeChange(nsISVGGlyphFragmentNode* caller)
00835 {
00836   NS_ASSERTION(mFragmentTreeState!=suspended, "notification during suspension");
00837   mFragmentTreeDirty = PR_TRUE;
00838   if (mFragmentTreeState == unsuspended) {
00839     UpdateFragmentTree();
00840   }
00841 }
00842 
00843 NS_IMETHODIMP_(PRBool)
00844 nsSVGTextFrame::IsMetricsSuspended()
00845 {
00846   return (mMetricsState != unsuspended);
00847 }
00848 
00849 NS_IMETHODIMP_(PRBool)
00850 nsSVGTextFrame::IsGlyphFragmentTreeSuspended()
00851 {
00852   return (mFragmentTreeState != unsuspended);
00853 }
00854 
00855 //----------------------------------------------------------------------
00856 // nsISVGTextContainerFrame methods:
00857 
00858 NS_IMETHODIMP_(nsISVGTextFrame *)
00859 nsSVGTextFrame::GetTextFrame()
00860 {
00861   return this;
00862 }
00863 
00864 NS_IMETHODIMP_(PRBool)
00865 nsSVGTextFrame::GetAbsolutePositionAdjustmentX(float &x, PRUint32 charNum)
00866 {
00867   return PR_FALSE;
00868 }
00869 
00870 NS_IMETHODIMP_(PRBool)
00871 nsSVGTextFrame::GetAbsolutePositionAdjustmentY(float &y, PRUint32 charNum)
00872 {
00873   return PR_FALSE;
00874 }
00875 
00876 NS_IMETHODIMP_(PRBool)
00877 nsSVGTextFrame::GetRelativePositionAdjustmentX(float &dx, PRUint32 charNum)
00878 {
00879   return PR_FALSE;
00880 }
00881 
00882 NS_IMETHODIMP_(PRBool)
00883 nsSVGTextFrame::GetRelativePositionAdjustmentY(float &dy, PRUint32 charNum)
00884 {
00885   return PR_FALSE;  
00886 }
00887 
00888 //----------------------------------------------------------------------
00889 //
00890 
00891 // ensure that the tree and positioning of the nodes is up-to-date
00892 void
00893 nsSVGTextFrame::EnsureFragmentTreeUpToDate()
00894 {
00895   PRBool resuspend_fragmenttree = PR_FALSE;
00896   PRBool resuspend_metrics = PR_FALSE;
00897   
00898   // give children a chance to flush their change notifications:
00899   
00900   if (mFragmentTreeState == suspended) {
00901     resuspend_fragmenttree = PR_TRUE;
00902     mFragmentTreeState = updating;
00903     nsIFrame* kid = mFrames.FirstChild();
00904     while (kid) {
00905       nsISVGGlyphFragmentNode* node=nsnull;
00906       kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00907       if (node)
00908         node->NotifyGlyphFragmentTreeUnsuspended();
00909       kid = kid->GetNextSibling();
00910     }
00911     
00912     mFragmentTreeState = unsuspended;
00913   }
00914 
00915   if (mFragmentTreeDirty)
00916     UpdateFragmentTree();
00917 
00918   if (mMetricsState == suspended) {
00919     resuspend_metrics = PR_TRUE;
00920     mMetricsState = updating;
00921     nsIFrame* kid = mFrames.FirstChild();
00922     while (kid) {
00923       nsISVGGlyphFragmentNode* node=nsnull;
00924       kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00925       if (node)
00926         node->NotifyMetricsUnsuspended();
00927       kid = kid->GetNextSibling();
00928     }
00929 
00930     mMetricsState = unsuspended;
00931   }
00932   
00933   if (mPositioningDirty)
00934     UpdateGlyphPositioning();
00935 
00936   if (resuspend_fragmenttree || resuspend_metrics) {
00937     mMetricsState = suspended;
00938     mFragmentTreeState = suspended;
00939   
00940     nsIFrame* kid = mFrames.FirstChild();
00941     while (kid) {
00942       nsISVGGlyphFragmentNode* fragmentNode=nsnull;
00943       kid->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&fragmentNode);
00944       if (fragmentNode) {
00945         fragmentNode->NotifyMetricsSuspended();
00946         fragmentNode->NotifyGlyphFragmentTreeSuspended();
00947       }
00948       kid = kid->GetNextSibling();
00949     }
00950   } 
00951 }
00952 
00953 void
00954 nsSVGTextFrame::UpdateFragmentTree()
00955 {
00956   NS_ASSERTION(mFragmentTreeState == unsuspended, "updating during suspension!");
00957 
00958   PRUint32 charNum = 0;
00959   
00960   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
00961   nsISVGGlyphFragmentNode* next;
00962   while (node) {
00963     next = GetNextGlyphFragmentChildNode(node);
00964     charNum = node->BuildGlyphFragmentTree(charNum, !next);
00965     node = next;
00966   }
00967 
00968   mFragmentTreeDirty = PR_FALSE;
00969   
00970   mPositioningDirty = PR_TRUE;
00971   if (mMetricsState == unsuspended)
00972     UpdateGlyphPositioning();
00973 }
00974 
00975 static void
00976 GetSingleValue(nsISVGGlyphFragmentLeaf *fragment,
00977                nsIDOMSVGLengthList *list, float *val)
00978 {
00979   if (!list)
00980     return;
00981 
00982   PRUint32 count = 0;
00983   list->GetNumberOfItems(&count);
00984 #ifdef DEBUG
00985   if (count > 1)
00986     NS_WARNING("multiple lengths for x/y attributes on <text> elements not implemented yet!");
00987 #endif
00988   if (count) {
00989     nsCOMPtr<nsIDOMSVGLength> length;
00990     list->GetItem(0, getter_AddRefs(length));
00991     length->GetValue(val);
00992 
00993     /* check for % sizing of textpath */
00994     PRUint16 type;
00995     length->GetUnitType(&type);
00996     if (type == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
00997       nsIFrame *glyph;
00998       CallQueryInterface(fragment, &glyph);
00999 
01000       nsISVGPathFlatten *textPath = nsnull;
01001       /* check if we're the child of a textPath */
01002       for (nsIFrame *frame = glyph; frame != nsnull; frame = frame->GetParent())
01003         if (frame->GetType() == nsLayoutAtoms::svgTextPathFrame) {
01004           frame->QueryInterface(NS_GET_IID(nsISVGPathFlatten), 
01005                                 (void **)&textPath);
01006           break;
01007         }
01008 
01009       if (textPath) {
01010         nsSVGPathData *data;
01011         textPath->GetFlattenedPath(&data);
01012 
01013         if (!data)
01014           return;
01015 
01016         float percent;
01017         length->GetValueInSpecifiedUnits(&percent);
01018 
01019         *val = data->Length()*percent/100.0f;
01020         delete data;
01021       }
01022     }
01023   }
01024 }
01025 
01026 void
01027 nsSVGTextFrame::UpdateGlyphPositioning()
01028 {
01029   NS_ASSERTION(mMetricsState == unsuspended, "updating during suspension");
01030 
01031   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
01032   if (!node) return;
01033 
01034   // we'll align every fragment in this chunk on the dominant-baseline:
01035   // XXX should actually inspect 'alignment-baseline' for each fragment
01036   
01037   PRUint8 baseline;
01038   switch(GetStyleSVGReset()->mDominantBaseline) {
01039     case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
01040       baseline = nsISVGRendererGlyphMetrics::BASELINE_TEXT_BEFORE_EDGE;
01041       break;
01042     case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
01043       baseline = nsISVGRendererGlyphMetrics::BASELINE_TEXT_AFTER_EDGE;
01044       break;
01045     case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
01046       baseline = nsISVGRendererGlyphMetrics::BASELINE_MIDDLE;
01047       break;
01048     case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
01049       baseline = nsISVGRendererGlyphMetrics::BASELINE_CENTRAL;
01050       break;
01051     case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
01052       baseline = nsISVGRendererGlyphMetrics::BASELINE_MATHEMATICAL;
01053       break;
01054     case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
01055       baseline = nsISVGRendererGlyphMetrics::BASELINE_IDEOGRAPHC;
01056       break;
01057     case NS_STYLE_DOMINANT_BASELINE_HANGING:
01058       baseline = nsISVGRendererGlyphMetrics::BASELINE_HANGING;
01059       break;
01060     case NS_STYLE_DOMINANT_BASELINE_AUTO:
01061     case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
01062     case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
01063     default:
01064       baseline = nsISVGRendererGlyphMetrics::BASELINE_ALPHABETIC;
01065       break;
01066   }
01067 
01068   nsISVGGlyphFragmentLeaf *fragment, *firstFragment;
01069 
01070   firstFragment = node->GetFirstGlyphFragment();
01071   if (!firstFragment) {
01072     mPositioningDirty = PR_FALSE;
01073     return;
01074   }
01075 
01076   float x = 0, y = 0;
01077 
01078   {
01079     nsCOMPtr<nsIDOMSVGLengthList> list = GetX();
01080     GetSingleValue(firstFragment, list, &x);
01081   }
01082   {
01083     nsCOMPtr<nsIDOMSVGLengthList> list = GetY();
01084     GetSingleValue(firstFragment, list, &y);
01085   }
01086 
01087   // loop over chunks
01088   while (firstFragment) {
01089     {
01090       nsCOMPtr<nsIDOMSVGLengthList> list = firstFragment->GetX();
01091       GetSingleValue(firstFragment, list, &x);
01092     }
01093     {
01094       nsCOMPtr<nsIDOMSVGLengthList> list = firstFragment->GetY();
01095       GetSingleValue(firstFragment, list, &y);
01096     }
01097 
01098     // determine x offset based on text_anchor:
01099   
01100     PRUint8 anchor = firstFragment->GetTextAnchor();
01101 
01102     float chunkLength = 0.0f;
01103     if (anchor != NS_STYLE_TEXT_ANCHOR_START) {
01104       // need to get the total chunk length
01105     
01106       fragment = firstFragment;
01107       while (fragment) {
01108         nsCOMPtr<nsISVGRendererGlyphMetrics> metrics;
01109         fragment->GetGlyphMetrics(getter_AddRefs(metrics));
01110         if (!metrics) continue;
01111 
01112         float advance, dx = 0.0f;
01113         nsCOMPtr<nsIDOMSVGLengthList> list = fragment->GetDx();
01114         GetSingleValue(fragment, list, &dx);
01115         metrics->GetAdvance(&advance);
01116         chunkLength += advance + dx;
01117         fragment = fragment->GetNextGlyphFragment();
01118         if (fragment && fragment->IsAbsolutelyPositioned())
01119           break;
01120       }
01121     }
01122 
01123     if (anchor == NS_STYLE_TEXT_ANCHOR_MIDDLE)
01124       x -= chunkLength/2.0f;
01125     else if (anchor == NS_STYLE_TEXT_ANCHOR_END)
01126       x -= chunkLength;
01127   
01128     // set position of each fragment in this chunk:
01129   
01130     fragment = firstFragment;
01131     while (fragment) {
01132       nsCOMPtr<nsISVGRendererGlyphMetrics> metrics;
01133       fragment->GetGlyphMetrics(getter_AddRefs(metrics));
01134       if (!metrics) continue;
01135 
01136       float baseline_offset, dx = 0.0f, dy = 0.0f;
01137       metrics->GetBaselineOffset(baseline, &baseline_offset);
01138       {
01139         nsCOMPtr<nsIDOMSVGLengthList> list = fragment->GetDx();
01140         GetSingleValue(fragment, list, &dx);
01141       }
01142       {
01143         nsCOMPtr<nsIDOMSVGLengthList> list = fragment->GetDy();
01144         GetSingleValue(fragment, list, &dy);
01145       }
01146 
01147       fragment->SetGlyphPosition(x + dx, y + dy - baseline_offset);
01148 
01149       float advance;
01150       metrics->GetAdvance(&advance);
01151       x += dx + advance;
01152       y += dy;
01153       fragment = fragment->GetNextGlyphFragment();
01154       if (fragment && fragment->IsAbsolutelyPositioned())
01155         break;
01156     }
01157     firstFragment = fragment;
01158   }
01159 
01160   mPositioningDirty = PR_FALSE;
01161 }
01162 
01163 
01164 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01165 nsSVGTextFrame::GetX()
01166 {
01167   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
01168   NS_ASSERTION(tpElement, "wrong content element");
01169 
01170   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
01171   tpElement->GetX(getter_AddRefs(animLengthList));
01172   nsIDOMSVGLengthList *retval;
01173   animLengthList->GetAnimVal(&retval);
01174   return retval;
01175 }
01176 
01177 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01178 nsSVGTextFrame::GetY()
01179 {
01180   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
01181   NS_ASSERTION(tpElement, "wrong content element");
01182 
01183   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
01184   tpElement->GetY(getter_AddRefs(animLengthList));
01185   nsIDOMSVGLengthList *retval;
01186   animLengthList->GetAnimVal(&retval);
01187   return retval;
01188 }
01189 
01190 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01191 nsSVGTextFrame::GetDx()
01192 {
01193   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
01194   NS_ASSERTION(tpElement, "wrong content element");
01195 
01196   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
01197   tpElement->GetDx(getter_AddRefs(animLengthList));
01198   nsIDOMSVGLengthList *retval;
01199   animLengthList->GetAnimVal(&retval);
01200   return retval;
01201 }
01202 
01203 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01204 nsSVGTextFrame::GetDy()
01205 {
01206   nsCOMPtr<nsIDOMSVGTextPositioningElement> tpElement = do_QueryInterface(mContent);
01207   NS_ASSERTION(tpElement, "wrong content element");
01208 
01209   nsCOMPtr<nsIDOMSVGAnimatedLengthList> animLengthList;
01210   tpElement->GetDy(getter_AddRefs(animLengthList));
01211   nsIDOMSVGLengthList *retval;
01212   animLengthList->GetAnimVal(&retval);
01213   return retval;
01214 }
01215 
01216 already_AddRefed<nsIDOMSVGAnimatedTransformList>
01217 nsSVGTextFrame::GetTransform()
01218 {
01219   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
01220   NS_ASSERTION(transformable, "wrong content element");
01221   
01222   nsIDOMSVGAnimatedTransformList *retval;
01223   transformable->GetTransform(&retval);
01224   return retval;
01225 }
01226 
01227 nsISVGGlyphFragmentNode *
01228 nsSVGTextFrame::GetFirstGlyphFragmentChildNode()
01229 {
01230   nsISVGGlyphFragmentNode* retval = nsnull;
01231   nsIFrame* frame = mFrames.FirstChild();
01232   while (frame) {
01233     frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval);
01234     if (retval) break;
01235     frame = frame->GetNextSibling();
01236   }
01237   return retval;
01238 }
01239 
01240 nsISVGGlyphFragmentNode *
01241 nsSVGTextFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node)
01242 {
01243   nsISVGGlyphFragmentNode* retval = nsnull;
01244   nsIFrame* frame = nsnull;
01245   node->QueryInterface(NS_GET_IID(nsIFrame), (void**)&frame);
01246   NS_ASSERTION(frame, "interface not implemented");
01247   frame = frame->GetNextSibling();
01248   while (frame) {
01249     frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval);
01250     if (retval) break;
01251     frame = frame->GetNextSibling();
01252   }
01253   return retval;
01254 }
01255 
01256 nsISVGGlyphFragmentLeaf *
01257 nsSVGTextFrame::GetGlyphFragmentAtCharNum(PRUint32 charnum)
01258 {
01259   nsISVGGlyphFragmentLeaf *fragment = nsnull;
01260   {
01261     nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
01262     if (!node) return nsnull; 
01263     fragment = node->GetFirstGlyphFragment();
01264   }
01265   
01266   while(fragment) {
01267     PRUint32 count = fragment->GetNumberOfChars();
01268     if (count>charnum)
01269       return fragment;
01270     charnum-=count;
01271     fragment = fragment->GetNextGlyphFragment();
01272   }
01273 
01274   // not found
01275   return nsnull;
01276 }