Back to index

lightning-sunbird  0.9+nobinonly
nsSVGGlyphFrame.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 "nsFrame.h"
00040 #include "nsISVGRendererGlyphGeometry.h"
00041 #include "nsISVGRendererGlyphMetrics.h"
00042 #include "nsISVGRenderer.h"
00043 #include "nsISVGGlyphGeometrySource.h"
00044 #include "nsISVGGlyphFragmentLeaf.h"
00045 #include "nsITextContent.h"
00046 #include "nsISVGChildFrame.h"
00047 #include "nsISVGOuterSVGFrame.h"
00048 #include "nsISVGTextFrame.h"
00049 #include "nsISVGRendererRegion.h"
00050 #include "nsISVGContainerFrame.h"
00051 #include "nsISVGTextContainerFrame.h"
00052 #include "nsSVGGradient.h"
00053 #include "nsISVGValueUtils.h"
00054 #include "nsReadableUtils.h"
00055 #include "nsCRT.h"
00056 #include "prdtoa.h"
00057 #include "nsIDOMSVGRect.h"
00058 #include "nsILookAndFeel.h"
00059 #include "nsTextFragment.h"
00060 #include "nsSVGRect.h"
00061 #include "nsSVGPoint.h"
00062 #include "nsSVGAtoms.h"
00063 #include "nsIViewManager.h"
00064 #include "nsINameSpaceManager.h"
00065 #include "nsContainerFrame.h"
00066 #include "nsLayoutAtoms.h"
00067 #include "nsSVGUtils.h"
00068 #include "nsISVGPathFlatten.h"
00069 
00070 typedef nsFrame nsSVGGlyphFrameBase;
00071 
00072 class nsSVGGlyphFrame : public nsSVGGlyphFrameBase,
00073                         public nsISVGValueObserver,
00074                         public nsSupportsWeakReference,
00075                         public nsISVGGlyphGeometrySource, // : nsISVGGlyphMetricsSource : nsISVGGeometrySource
00076                         public nsISVGGlyphFragmentLeaf, // : nsISVGGlyphFragmentNode
00077                         public nsISVGChildFrame
00078 {
00079 protected:
00080   friend nsresult
00081   NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00082                       nsIFrame* parentFrame, nsIFrame** aNewFrame);
00083   nsSVGGlyphFrame();
00084   virtual ~nsSVGGlyphFrame();
00085 
00086 public:
00087    // nsISupports interface:
00088   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00089   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00090   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00091 
00092   // nsIFrame interface:
00093   NS_IMETHOD
00094   Init(nsPresContext*  aPresContext,
00095        nsIContent*      aContent,
00096        nsIFrame*        aParent,
00097        nsStyleContext*  aContext,
00098        nsIFrame*        aPrevInFlow);
00099 
00100   NS_IMETHOD  CharacterDataChanged(nsPresContext* aPresContext,
00101                                    nsIContent*     aChild,
00102                                    PRBool          aAppend);
00103 
00104   NS_IMETHOD  DidSetStyleContext(nsPresContext* aPresContext);
00105 
00106   NS_IMETHOD  SetSelected(nsPresContext* aPresContext,
00107                           nsIDOMRange*    aRange,
00108                           PRBool          aSelected,
00109                           nsSpread        aSpread);
00110   NS_IMETHOD  GetSelected(PRBool *aSelected) const;
00111   NS_IMETHOD  IsSelectable(PRBool* aIsSelectable, PRUint8* aSelectStyle);
00112 
00118   virtual nsIAtom* GetType() const;
00119   virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
00120 
00121 #ifdef DEBUG
00122   NS_IMETHOD GetFrameName(nsAString& aResult) const
00123   {
00124     return MakeFrameName(NS_LITERAL_STRING("SVGGlyph"), aResult);
00125   }
00126 #endif
00127 
00128   // nsISVGValueObserver
00129   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00130                                      nsISVGValue::modificationType aModType);
00131   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00132                                      nsISVGValue::modificationType aModType);
00133 
00134   // nsISVGChildFrame interface:
00135   NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00136   NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
00137   NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
00138   NS_IMETHOD InitialUpdate();
00139   NS_IMETHOD NotifyCanvasTMChanged();
00140   NS_IMETHOD NotifyRedrawSuspended();
00141   NS_IMETHOD NotifyRedrawUnsuspended();
00142   NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_OK; }
00143   NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
00144   
00145   // nsISVGGeometrySource interface: 
00146   NS_DECL_NSISVGGEOMETRYSOURCE
00147 
00148   // nsISVGGlyphMetricsSource interface:
00149   NS_DECL_NSISVGGLYPHMETRICSSOURCE
00150 
00151   // nsISVGGlyphGeometrySource interface:
00152   NS_DECL_NSISVGGLYPHGEOMETRYSOURCE
00153 
00154   // nsISVGGlyphFragmentLeaf interface:
00155   NS_IMETHOD_(void) SetGlyphPosition(float x, float y);
00156   NS_IMETHOD_(float) GetGlyphPositionX();
00157   NS_IMETHOD_(float) GetGlyphPositionY();  
00158   NS_IMETHOD GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics);
00159   NS_IMETHOD_(PRBool) IsStartOfChunk(); // == is new absolutely positioned chunk.
00160   NS_IMETHOD_(void) GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y);
00161   NS_IMETHOD_(PRUint32) GetNumberOfChars();
00162   NS_IMETHOD_(PRUint32) GetCharNumberOffset();
00163 
00164   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetX();
00165   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetY();
00166   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDx();
00167   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDy();
00168   NS_IMETHOD_(PRUint16) GetTextAnchor();
00169   NS_IMETHOD_(PRBool) IsAbsolutelyPositioned();
00170 
00171   // nsISVGGlyphFragmentNode interface:
00172   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment();
00173   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment();
00174   NS_IMETHOD_(PRUint32) BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch);
00175   NS_IMETHOD_(void) NotifyMetricsSuspended();
00176   NS_IMETHOD_(void) NotifyMetricsUnsuspended();
00177   NS_IMETHOD_(void) NotifyGlyphFragmentTreeSuspended();
00178   NS_IMETHOD_(void) NotifyGlyphFragmentTreeUnsuspended();
00179   
00180 protected:
00181   void UpdateGeometry(PRUint32 flags, PRBool bRedraw=PR_TRUE);
00182   void UpdateMetrics(PRUint32 flags);
00183   void UpdateFragmentTree();
00184   nsISVGOuterSVGFrame *GetOuterSVGFrame();
00185   nsISVGTextFrame *GetTextFrame();
00186   NS_IMETHOD Update(PRUint32 aFlags);
00187   
00188   nsCOMPtr<nsISVGRendererGlyphGeometry> mGeometry;
00189   nsCOMPtr<nsISVGRendererGlyphMetrics> mMetrics;
00190   float mX, mY;
00191   PRUint32 mGeometryUpdateFlags;
00192   PRUint32 mMetricsUpdateFlags;
00193   PRUint32 mCharOffset;
00194   PRBool mFragmentTreeDirty;
00195   nsString mCharacterData;
00196   nsCOMPtr<nsISVGGradient> mFillGradient;
00197   nsCOMPtr<nsISVGGradient> mStrokeGradient;
00198 };
00199 
00200 //----------------------------------------------------------------------
00201 // Implementation
00202 
00203 nsresult
00204 NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* parentFrame,
00205                     nsIFrame** aNewFrame)
00206 {
00207   *aNewFrame = nsnull;
00208 
00209 #ifdef DEBUG
00210   NS_ASSERTION(parentFrame, "null parent");
00211   nsISVGTextContainerFrame *text_container;
00212   parentFrame->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame), (void**)&text_container);
00213   NS_ASSERTION(text_container, "trying to construct an SVGGlyphFrame for an invalid container");
00214   
00215   nsCOMPtr<nsITextContent> tc = do_QueryInterface(aContent);
00216   NS_ASSERTION(tc, "trying to construct an SVGGlyphFrame for wrong content element");
00217 #endif
00218   
00219   nsSVGGlyphFrame* it = new (aPresShell) nsSVGGlyphFrame;
00220   if (nsnull == it)
00221     return NS_ERROR_OUT_OF_MEMORY;
00222 
00223   *aNewFrame = it;
00224 
00225   return NS_OK;
00226 }
00227 
00228 nsSVGGlyphFrame::nsSVGGlyphFrame()
00229     : mGeometryUpdateFlags(0), mMetricsUpdateFlags(0),
00230       mCharOffset(0), mFragmentTreeDirty(PR_FALSE)
00231 {
00232 }
00233 
00234 nsSVGGlyphFrame::~nsSVGGlyphFrame()
00235 {
00236   if (mFillGradient) {
00237     NS_ADD_SVGVALUE_OBSERVER(mFillGradient);
00238   }
00239   if (mStrokeGradient) {
00240     NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient);
00241   }
00242 }
00243 
00244 
00245 //----------------------------------------------------------------------
00246 // nsISupports methods
00247 
00248 NS_INTERFACE_MAP_BEGIN(nsSVGGlyphFrame)
00249   NS_INTERFACE_MAP_ENTRY(nsISVGGeometrySource)
00250   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphMetricsSource)
00251   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphGeometrySource)
00252   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentLeaf)
00253   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentNode)
00254   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00255   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00256   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00257 NS_INTERFACE_MAP_END_INHERITING(nsSVGGlyphFrameBase)
00258 
00259 //----------------------------------------------------------------------
00260 // nsIFrame methods
00261 
00262 NS_IMETHODIMP
00263 nsSVGGlyphFrame::Init(nsPresContext*  aPresContext,
00264                       nsIContent*      aContent,
00265                       nsIFrame*        aParent,
00266                       nsStyleContext*  aContext,
00267                       nsIFrame*        aPrevInFlow)
00268 {
00269 //  rv = nsSVGGlyphFrameBase::Init(aPresContext, aContent, aParent,
00270 //                                 aContext, aPrevInFlow);
00271 
00272   mContent = aContent;
00273   NS_IF_ADDREF(mContent);
00274   mParent = aParent;
00275 
00276   if (mContent) {
00277     mContent->SetMayHaveFrame(PR_TRUE);
00278   }
00279   
00280   // construct our glyphmetrics & glyphgeometry objects:
00281   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00282   if (!outerSVGFrame) {
00283     NS_ERROR("No outerSVGFrame");
00284     SetStyleContext(aPresContext, aContext);
00285     return NS_ERROR_FAILURE;
00286   }
00287   nsCOMPtr<nsISVGRenderer> renderer;
00288   outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
00289   if (renderer) {
00290     renderer->CreateGlyphMetrics(this, getter_AddRefs(mMetrics));
00291     renderer->CreateGlyphGeometry(this, getter_AddRefs(mGeometry));
00292   }
00293   
00294   SetStyleContext(aPresContext, aContext);
00295 
00296   if (!renderer || !mMetrics || !mGeometry)
00297     return NS_ERROR_FAILURE;
00298     
00299   return NS_OK;
00300 }
00301 
00302 NS_IMETHODIMP
00303 nsSVGGlyphFrame::CharacterDataChanged(nsPresContext* aPresContext,
00304                                       nsIContent*     aChild,
00305                                       PRBool          aAppend)
00306 {
00307        return Update(nsISVGGeometrySource::UPDATEMASK_ALL);
00308 }
00309 
00310 NS_IMETHODIMP
00311 nsSVGGlyphFrame::Update(PRUint32 aFlags)
00312 {
00313 #ifdef DEBUG
00314 //  printf("** nsSVGGlyphFrame::Update\n");
00315 #endif
00316   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00317   if (!outerSVGFrame) {
00318     NS_ERROR("No outerSVGFrame");
00319     return NS_ERROR_FAILURE;
00320   }
00321   
00322   outerSVGFrame->SuspendRedraw();
00323   UpdateFragmentTree();
00324   UpdateMetrics(aFlags);
00325   UpdateGeometry(aFlags);
00326   outerSVGFrame->UnsuspendRedraw();
00327 
00328   return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsSVGGlyphFrame::DidSetStyleContext(nsPresContext* aPresContext)
00333 {
00334   // One of the styles that might have been changed are the urls that
00335   // point to gradients, etc.  Drop our cached values to those
00336   if (mFillGradient) {
00337     NS_ADD_SVGVALUE_OBSERVER(mFillGradient);
00338     mFillGradient = nsnull;
00339   }
00340   if (mStrokeGradient) {
00341     NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient);
00342     mStrokeGradient = nsnull;
00343   }
00344 
00345   return CharacterDataChanged(aPresContext, nsnull, PR_FALSE);
00346 }
00347 
00348 NS_IMETHODIMP
00349 nsSVGGlyphFrame::SetSelected(nsPresContext* aPresContext,
00350                              nsIDOMRange*    aRange,
00351                              PRBool          aSelected,
00352                              nsSpread        aSpread)
00353 {
00354 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00355   printf("nsSVGGlyphFrame(%p)::SetSelected()\n", this);
00356 #endif
00357 //  return nsSVGGlyphFrameBase::SetSelected(aPresContext, aRange, aSelected, aSpread);
00358 
00359   // check whether style allows selection
00360   PRBool  selectable;
00361   IsSelectable(&selectable, nsnull);
00362   if (!selectable)
00363     return NS_OK;
00364   
00365   if ( aSelected ){
00366     mState |=  NS_FRAME_SELECTED_CONTENT;
00367   }
00368   else
00369     mState &= ~NS_FRAME_SELECTED_CONTENT;
00370 
00371   UpdateGeometry(nsISVGGlyphGeometrySource::UPDATEMASK_HIGHLIGHT |
00372                  nsISVGGlyphGeometrySource::UPDATEMASK_HAS_HIGHLIGHT,
00373                  PR_FALSE);  
00374 
00375   return NS_OK;
00376 }
00377 
00378 NS_IMETHODIMP
00379 nsSVGGlyphFrame::GetSelected(PRBool *aSelected) const
00380 {
00381   nsresult rv = nsSVGGlyphFrameBase::GetSelected(aSelected);
00382 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00383   printf("nsSVGGlyphFrame(%p)::GetSelected()=%d\n", this, *aSelected);
00384 #endif
00385   return rv;
00386 }
00387 
00388 NS_IMETHODIMP
00389 nsSVGGlyphFrame::IsSelectable(PRBool* aIsSelectable,
00390                               PRUint8* aSelectStyle)
00391 {
00392   nsresult rv = nsSVGGlyphFrameBase::IsSelectable(aIsSelectable, aSelectStyle);
00393 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00394   printf("nsSVGGlyphFrame(%p)::IsSelectable()=(%d,%d)\n", this, *aIsSelectable, aSelectStyle);
00395 #endif
00396   return rv;
00397 }
00398 
00399 nsIAtom *
00400 nsSVGGlyphFrame::GetType() const
00401 {
00402   return nsLayoutAtoms::svgGlyphFrame;
00403 }
00404 
00405 PRBool
00406 nsSVGGlyphFrame::IsFrameOfType(PRUint32 aFlags) const
00407 {
00408   return !(aFlags & ~nsIFrame::eSVG);
00409 }
00410 
00411 //----------------------------------------------------------------------
00412 // nsISVGValueObserver methods:
00413 
00414 NS_IMETHODIMP
00415 nsSVGGlyphFrame::WillModifySVGObservable(nsISVGValue* observable,
00416                                          nsISVGValue::modificationType aModType)
00417 {
00418   return NS_OK;
00419 }
00420 
00421 
00422 NS_IMETHODIMP
00423 nsSVGGlyphFrame::DidModifySVGObservable (nsISVGValue* observable,
00424                                          nsISVGValue::modificationType aModType)
00425 {
00426   // Is this a gradient?
00427   nsCOMPtr<nsISVGGradient>val = do_QueryInterface(observable);
00428   if (val) {
00429     // Yes, we need to handle this differently
00430     nsCOMPtr<nsISVGGradient>fill = do_QueryInterface(mFillGradient);
00431     if (fill == val) {
00432       if (aModType == nsISVGValue::mod_die) {
00433         mFillGradient = nsnull;
00434       }
00435       return Update(nsISVGGeometrySource::UPDATEMASK_FILL_PAINT);
00436     } else {
00437       // No real harm in assuming a stroke gradient at this point
00438       if (aModType == nsISVGValue::mod_die) {
00439         mStrokeGradient = nsnull;
00440       }
00441       return Update(nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT);
00442     }
00443   } else {
00444     // No, all of our other observables update the canvastm by default
00445     return Update(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM);
00446   }
00447   return NS_OK;
00448 }
00449 
00450 //----------------------------------------------------------------------
00451 // nsISVGChildFrame methods
00452 
00453 NS_IMETHODIMP
00454 nsSVGGlyphFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00455 {
00456 #ifdef DEBUG
00457   //printf("nsSVGGlyphFrame(%p)::Paint\n", this);
00458 #endif
00459   if (!GetStyleVisibility()->IsVisible())
00460     return NS_OK;
00461 
00462   mGeometry->Render(canvas);
00463   return NS_OK;
00464 }
00465 
00466 NS_IMETHODIMP
00467 nsSVGGlyphFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00468 {
00469 #ifdef DEBUG
00470   //printf("nsSVGGlyphFrame(%p)::GetFrameForPoint\n", this);
00471 #endif
00472   // test for hit:
00473   *hit = nsnull;
00474 
00475   PRBool events = PR_FALSE;
00476   switch (GetStyleSVG()->mPointerEvents) {
00477     case NS_STYLE_POINTER_EVENTS_NONE:
00478       break;
00479     case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
00480       if (GetStyleVisibility()->IsVisible() &&
00481           (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None ||
00482            GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None))
00483         events = PR_TRUE;
00484       break;
00485     case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
00486     case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
00487     case NS_STYLE_POINTER_EVENTS_VISIBLE:
00488       if (GetStyleVisibility()->IsVisible())
00489         events = PR_TRUE;
00490       break;
00491     case NS_STYLE_POINTER_EVENTS_PAINTED:
00492       if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None ||
00493           GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
00494         events = PR_TRUE;
00495       break;
00496     case NS_STYLE_POINTER_EVENTS_FILL:
00497     case NS_STYLE_POINTER_EVENTS_STROKE:
00498     case NS_STYLE_POINTER_EVENTS_ALL:
00499       events = PR_TRUE;
00500       break;
00501     default:
00502       NS_ERROR("not reached");
00503       break;
00504   }
00505 
00506   if (!events)
00507     return NS_OK;
00508 
00509   PRBool isHit;
00510   mGeometry->ContainsPoint(x, y, &isHit);
00511   if (isHit) 
00512     *hit = this;
00513   
00514   return NS_OK;
00515 }
00516 
00517 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00518 nsSVGGlyphFrame::GetCoveredRegion()
00519 {
00520   nsISVGRendererRegion *region = nsnull;
00521   if (mGeometry)
00522     mGeometry->GetCoveredRegion(&region);
00523   return region;
00524 }
00525 
00526 NS_IMETHODIMP
00527 nsSVGGlyphFrame::InitialUpdate()
00528 {
00529   return Update(nsISVGGeometrySource::UPDATEMASK_ALL);
00530 }  
00531 
00532 NS_IMETHODIMP
00533 nsSVGGlyphFrame::NotifyCanvasTMChanged()
00534 {
00535   UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM);
00536   
00537   return NS_OK;
00538 }
00539 
00540 NS_IMETHODIMP
00541 nsSVGGlyphFrame::NotifyRedrawSuspended()
00542 {
00543   // XXX should we cache the fact that redraw is suspended?
00544   return NS_OK;
00545 }
00546 
00547 NS_IMETHODIMP
00548 nsSVGGlyphFrame::NotifyRedrawUnsuspended()
00549 {
00550   NS_ASSERTION(!mMetricsUpdateFlags, "dirty metrics in nsSVGGlyphFrame::NotifyRedrawUnsuspended");
00551   NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::NotifyRedrawUnsuspended");
00552     
00553   if (mGeometryUpdateFlags != 0) {
00554     nsCOMPtr<nsISVGRendererRegion> dirty_region;
00555     mGeometry->Update(mGeometryUpdateFlags, getter_AddRefs(dirty_region));
00556     if (dirty_region) {
00557       nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00558       if (outerSVGFrame)
00559         outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00560     }
00561     mGeometryUpdateFlags = 0;
00562   }
00563   return NS_OK;
00564 }
00565 
00566 NS_IMETHODIMP
00567 nsSVGGlyphFrame::GetBBox(nsIDOMSVGRect **_retval)
00568 {
00569   *_retval = nsnull;
00570 
00571   if (mGeometry)
00572     return mGeometry->GetBoundingBox(_retval);
00573   return NS_ERROR_FAILURE;
00574 }
00575 
00576 //----------------------------------------------------------------------
00577 // nsISVGGeometrySource methods:
00578 
00579 /* [noscript] readonly attribute nsPresContext presContext; */
00580 NS_IMETHODIMP
00581 nsSVGGlyphFrame::GetPresContext(nsPresContext * *aPresContext)
00582 {
00583   // XXX gcc 3.2.2 requires the explicit 'nsSVGGlyphFrameBase::' qualification
00584   *aPresContext = nsSVGGlyphFrameBase::GetPresContext();
00585   NS_ADDREF(*aPresContext);
00586   return NS_OK;
00587 }
00588 
00589 /* readonly attribute nsIDOMSVGMatrix canvasTM; */
00590 NS_IMETHODIMP
00591 nsSVGGlyphFrame::GetCanvasTM(nsIDOMSVGMatrix * *aCTM)
00592 {
00593   NS_ASSERTION(mParent, "null parent");
00594   
00595   nsISVGContainerFrame *containerFrame;
00596   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00597   if (!containerFrame) {
00598     NS_ERROR("invalid container");
00599     return NS_ERROR_FAILURE;
00600   }
00601   nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
00602   *aCTM = parentTM.get();
00603   NS_ADDREF(*aCTM);
00604   return NS_OK;
00605 }
00606 
00607 /* readonly attribute float strokeOpacity; */
00608 NS_IMETHODIMP
00609 nsSVGGlyphFrame::GetStrokeOpacity(float *aStrokeOpacity)
00610 {
00611   *aStrokeOpacity =
00612     GetStyleSVG()->mStrokeOpacity * GetStyleDisplay()->mOpacity;
00613   return NS_OK;
00614 }
00615 
00616 /* readonly attribute float strokeWidth; */
00617 NS_IMETHODIMP
00618 nsSVGGlyphFrame::GetStrokeWidth(float *aStrokeWidth)
00619 {
00620   // We use mContent->GetParent() rather than mContent because we're
00621   // looking for the containing text container rather than the text node
00622   *aStrokeWidth =
00623     nsSVGUtils::CoordToFloat(nsSVGGlyphFrameBase::GetPresContext(),
00624                              mContent->GetParent(),
00625                              GetStyleSVG()->mStrokeWidth);
00626   return NS_OK;
00627 }
00628 
00629 /* void getStrokeDashArray ([array, size_is (count)] out float arr, out unsigned long count); */
00630 NS_IMETHODIMP
00631 nsSVGGlyphFrame::GetStrokeDashArray(float **arr, PRUint32 *count)
00632 {
00633   const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray;
00634   nsPresContext *presContext = nsSVGGlyphFrameBase::GetPresContext();
00635   float totalLength = 0.0f;
00636 
00637   *count = GetStyleSVG()->mStrokeDasharrayLength;
00638   *arr = nsnull;
00639 
00640   if (*count) {
00641     *arr = (float *) nsMemory::Alloc(*count * sizeof(float));
00642     if (*arr) {
00643       for (PRUint32 i = 0; i < *count; i++) {
00644         (*arr)[i] = nsSVGUtils::CoordToFloat(presContext, mContent, dasharray[i]);
00645         if ((*arr)[i] < 0.0f) {
00646           nsMemory::Free(*arr);
00647           *count = 0;
00648           *arr = nsnull;
00649           return NS_OK;
00650         }
00651         totalLength += (*arr)[i];
00652       }
00653     } else {
00654       *count = 0;
00655       *arr = nsnull;
00656       return NS_ERROR_OUT_OF_MEMORY;
00657     }
00658 
00659     if (totalLength == 0.0f) {
00660       nsMemory::Free(*arr);
00661       *count = 0;
00662     }
00663   }
00664 
00665   return NS_OK;
00666 }
00667 
00668 /* readonly attribute float strokeDashoffset; */
00669 NS_IMETHODIMP
00670 nsSVGGlyphFrame::GetStrokeDashoffset(float *aStrokeDashoffset)
00671 {
00672   *aStrokeDashoffset = 
00673     nsSVGUtils::CoordToFloat(nsSVGGlyphFrameBase::GetPresContext(),
00674                              mContent, GetStyleSVG()->mStrokeDashoffset);
00675   return NS_OK;
00676 }
00677 
00678 /* readonly attribute unsigned short strokeLinecap; */
00679 NS_IMETHODIMP
00680 nsSVGGlyphFrame::GetStrokeLinecap(PRUint16 *aStrokeLinecap)
00681 {
00682   *aStrokeLinecap = GetStyleSVG()->mStrokeLinecap;
00683   return NS_OK;
00684 }
00685 
00686 /* readonly attribute unsigned short strokeLinejoin; */
00687 NS_IMETHODIMP
00688 nsSVGGlyphFrame::GetStrokeLinejoin(PRUint16 *aStrokeLinejoin)
00689 {
00690   *aStrokeLinejoin = GetStyleSVG()->mStrokeLinejoin;
00691   return NS_OK;
00692 }
00693 
00694 /* readonly attribute float strokeMiterlimit; */
00695 NS_IMETHODIMP
00696 nsSVGGlyphFrame::GetStrokeMiterlimit(float *aStrokeMiterlimit)
00697 {
00698   *aStrokeMiterlimit = GetStyleSVG()->mStrokeMiterlimit; 
00699   return NS_OK;
00700 }
00701 
00702 /* readonly attribute float fillOpacity; */
00703 NS_IMETHODIMP
00704 nsSVGGlyphFrame::GetFillOpacity(float *aFillOpacity)
00705 {
00706   *aFillOpacity =
00707     GetStyleSVG()->mFillOpacity * GetStyleDisplay()->mOpacity;
00708   return NS_OK;
00709 }
00710 
00711 /* readonly attribute unsigned short fillRule; */
00712 NS_IMETHODIMP
00713 nsSVGGlyphFrame::GetFillRule(PRUint16 *aFillRule)
00714 {
00715   *aFillRule = GetStyleSVG()->mFillRule;
00716   return NS_OK;
00717 }
00718 
00719 /* readonly attribute unsigned short clipRule; */
00720 NS_IMETHODIMP
00721 nsSVGGlyphFrame::GetClipRule(PRUint16 *aClipRule)
00722 {
00723   *aClipRule = GetStyleSVG()->mClipRule;
00724   return NS_OK;
00725 }
00726 
00727 /* readonly attribute unsigned short strokePaintType; */
00728 NS_IMETHODIMP
00729 nsSVGGlyphFrame::GetStrokePaintType(PRUint16 *aStrokePaintType)
00730 {
00731   float strokeWidth;
00732   GetStrokeWidth(&strokeWidth);
00733 
00734   // cairo will stop rendering if stroke-width is less than or equal to zero
00735   *aStrokePaintType = strokeWidth <= 0 ?
00736                       nsISVGGeometrySource::PAINT_TYPE_NONE :
00737                       GetStyleSVG()->mStroke.mType;
00738   return NS_OK;
00739 }
00740 
00741 /* readonly attribute unsigned short strokePaintServerType; */
00742 NS_IMETHODIMP
00743 nsSVGGlyphFrame::GetStrokePaintServerType(PRUint16 *aStrokePaintServerType)
00744 {
00745   return nsSVGUtils::GetPaintType(aStrokePaintServerType, GetStyleSVG()->mStroke, mContent,
00746                                   nsSVGGlyphFrameBase::GetPresContext()->PresShell());
00747 }
00748 
00749 /* [noscript] readonly attribute nscolor strokePaint; */
00750 NS_IMETHODIMP
00751 nsSVGGlyphFrame::GetStrokePaint(nscolor *aStrokePaint)
00752 {
00753   *aStrokePaint = GetStyleSVG()->mStroke.mPaint.mColor;
00754   return NS_OK;
00755 }
00756 
00757 /* [noscript] void GetStrokeGradient(nsISVGGradient **aGrad); */
00758 NS_IMETHODIMP
00759 nsSVGGlyphFrame::GetStrokeGradient(nsISVGGradient **aGrad)
00760 {
00761   nsresult rv = NS_OK;
00762   if (!mStrokeGradient) {
00763     nsIURI *aServer;
00764     aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer;
00765     if (aServer == nsnull)
00766       return NS_ERROR_FAILURE;
00767     // Now have the URI.  Get the gradient 
00768     rv = NS_GetSVGGradient(getter_AddRefs(mStrokeGradient), aServer, mContent, 
00769                            nsSVGGlyphFrameBase::GetPresContext()->PresShell());
00770     NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient);
00771   }
00772   *aGrad = mStrokeGradient;
00773   return rv;
00774 }
00775 
00776 /* readonly attribute unsigned short fillPaintType; */
00777 NS_IMETHODIMP
00778 nsSVGGlyphFrame::GetFillPaintType(PRUint16 *aFillPaintType)
00779 {
00780   *aFillPaintType = GetStyleSVG()->mFill.mType;
00781   return NS_OK;
00782 }
00783 
00784 /* readonly attribute unsigned short fillPaintServerType; */
00785 NS_IMETHODIMP
00786 nsSVGGlyphFrame::GetFillPaintServerType(PRUint16 *aFillPaintServerType)
00787 {
00788   return nsSVGUtils::GetPaintType(aFillPaintServerType, GetStyleSVG()->mFill, mContent,
00789                                   nsSVGGlyphFrameBase::GetPresContext()->PresShell());
00790 }
00791 
00792 /* [noscript] readonly attribute nscolor fillPaint; */
00793 NS_IMETHODIMP
00794 nsSVGGlyphFrame::GetFillPaint(nscolor *aFillPaint)
00795 {
00796   *aFillPaint = GetStyleSVG()->mFill.mPaint.mColor;
00797   return NS_OK;
00798 }
00799 
00800 /* [noscript] void GetFillGradient(nsISVGGradient **aGrad); */
00801 NS_IMETHODIMP
00802 nsSVGGlyphFrame::GetFillGradient(nsISVGGradient **aGrad)
00803 {
00804   nsresult rv = NS_OK;
00805   if (!mFillGradient) {
00806     nsIURI *aServer;
00807     aServer = GetStyleSVG()->mFill.mPaint.mPaintServer;
00808     if (aServer == nsnull)
00809       return NS_ERROR_FAILURE;
00810     // Now have the URI.  Get the gradient 
00811     rv = NS_GetSVGGradient(getter_AddRefs(mFillGradient), aServer, mContent, 
00812                            nsSVGGlyphFrameBase::GetPresContext()->PresShell());
00813     NS_ADD_SVGVALUE_OBSERVER(mFillGradient);
00814   }
00815   *aGrad = mFillGradient;
00816   return rv;
00817 }
00818 
00819 /* [noscript] boolean isClipChild; */
00820 NS_IMETHODIMP
00821 nsSVGGlyphFrame::IsClipChild(PRBool *_retval)
00822 {
00823   *_retval = PR_FALSE;
00824   nsCOMPtr<nsIContent> node(mContent);
00825 
00826   do {
00827     if (node->Tag() == nsSVGAtoms::clipPath) {
00828       *_retval = PR_TRUE;
00829       break;
00830     }
00831     node = node->GetParent();
00832   } while (node);
00833     
00834   return NS_OK;
00835 }
00836 
00837 //----------------------------------------------------------------------
00838 // nsISVGGlyphMetricsSource methods:
00839 
00840 /* [noscript] readonly attribute nsFont font; */
00841 NS_IMETHODIMP
00842 nsSVGGlyphFrame::GetFont(nsFont *aFont)
00843 {
00844   *aFont = GetStyleFont()->mFont;
00845 
00846   // XXX eventually we will have to treat decorations separately from
00847   // fonts, because they can have a different color than the current
00848   // glyph.
00849   
00850   NS_ASSERTION(mParent, "no parent");
00851   nsStyleContext *parentContext = mParent->GetStyleContext();
00852   NS_ASSERTION(parentContext, "no style context on parent");
00853   
00854   PRUint8 styleDecorations =
00855     parentContext->GetStyleTextReset()->mTextDecoration;
00856   if (styleDecorations & NS_STYLE_TEXT_DECORATION_UNDERLINE)
00857     aFont->decorations |= NS_FONT_DECORATION_UNDERLINE;
00858   if (styleDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE)
00859     aFont->decorations |= NS_FONT_DECORATION_OVERLINE;
00860   if (styleDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH)
00861     aFont->decorations |= NS_FONT_DECORATION_LINE_THROUGH;    
00862   
00863   return NS_OK;
00864 }
00865 
00866 /* readonly attribute DOMString characterData; */
00867 NS_IMETHODIMP
00868 nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
00869 {
00870   aCharacterData = mCharacterData;
00871   return NS_OK;
00872 }
00873 
00874 void
00875 NS_SVGFindPointOnPath(nsSVGPathData *data,
00876                       float aX, float aY, float aAdvance,
00877                       nsSVGCharacterPosition *aCP)
00878 {
00879   float x, y, length = 0;
00880   float midpoint = aX + aAdvance/2;
00881   for (PRUint32 i = 0; i < data->count; i++) {
00882     if (data->type[i] == NS_SVGPATHFLATTEN_LINE) {
00883       float dx = data->x[i] - x;
00884       float dy = data->y[i] - y;
00885       float sublength = sqrt(dx*dx + dy*dy);
00886       
00887       if (sublength != 0 && length + sublength >= midpoint) {
00888         float ratio = (aX - length)/sublength;
00889         aCP->x = x * (1.0f - ratio) + data->x[i] * ratio;
00890         aCP->y = y * (1.0f - ratio) + data->y[i] * ratio;
00891 
00892         float dx = data->x[i] - x;
00893         float dy = data->y[i] - y;
00894         aCP->angle = atan2(dy, dx);
00895 
00896         float normalization = 1.0/sqrt(dx*dx+dy*dy);
00897         aCP->x += - aY * dy * normalization;
00898         aCP->y +=   aY * dx * normalization;
00899         return;
00900       }
00901       length += sublength;
00902     }
00903     x = data->x[i];
00904     y = data->y[i];
00905   }
00906 }
00907 
00908 /* readonly attribute nsSVGCharacterPostion characterPosition; */
00909 NS_IMETHODIMP
00910 nsSVGGlyphFrame::GetCharacterPosition(nsSVGCharacterPosition **aCharacterPosition)
00911 {
00912   *aCharacterPosition = nsnull;
00913   nsISVGPathFlatten *textPath = nsnull;
00914 
00915   /* check if we're the child of a textPath */
00916   for (nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent())
00917     if (frame->GetType() == nsLayoutAtoms::svgTextPathFrame) {
00918       frame->QueryInterface(NS_GET_IID(nsISVGPathFlatten), (void **)&textPath);
00919       break;
00920     }
00921 
00922   /* we're an ordinary fragment - return */
00923   /* XXX: we might want to use this for individual x/y/dx/dy adjustment */
00924   if (!textPath)
00925     return NS_OK;
00926 
00927   nsSVGPathData *data;
00928   textPath->GetFlattenedPath(&data);
00929 
00930   /* textPath frame, but invalid target */
00931   if (!data)
00932     return NS_ERROR_FAILURE;
00933 
00934   float length = data->Length();
00935   PRUint32 strLength = mCharacterData.Length();
00936 
00937   nsSVGCharacterPosition *cp = new nsSVGCharacterPosition[strLength];
00938 
00939   for (PRUint32 k = 0; k < strLength; k++)
00940       cp[k].draw = PR_FALSE;
00941 
00942   float x = mX;
00943   for (PRUint32 i = 0; i < strLength; i++) {
00944     float advance;
00945     mMetrics->GetAdvanceOfChar(i, &advance);
00946 
00947     /* have we run off the end of the path? */
00948     if (x + advance/2 > length)
00949       break;
00950 
00951     /* check that we've advanced to the start of the path */
00952     if (x + advance/2 >= 0.0f) {
00953       cp[i].draw = PR_TRUE;
00954 
00955       // add y (normal)
00956       // add rotation
00957       // move point back along tangent
00958       NS_SVGFindPointOnPath(data, x, mY, advance, &(cp[i]));
00959     }
00960     x += advance;
00961   }
00962 
00963   *aCharacterPosition = cp;
00964 
00965   delete data;
00966 
00967   return NS_OK;
00968 }
00969 
00970 /* readonly attribute unsigned short textRendering; */
00971 NS_IMETHODIMP
00972 nsSVGGlyphFrame::GetTextRendering(PRUint16 *aTextRendering)
00973 {
00974   *aTextRendering = GetStyleSVG()->mTextRendering;
00975   return NS_OK;
00976 }
00977 
00978 //----------------------------------------------------------------------
00979 // nsISVGGlyphGeometrySource methods:
00980 
00981 /* readonly attribute nsISVGRendererGlyphMetrics metrics; */
00982 NS_IMETHODIMP
00983 nsSVGGlyphFrame::GetMetrics(nsISVGRendererGlyphMetrics * *aMetrics)
00984 {
00985   *aMetrics = mMetrics;
00986   NS_ADDREF(*aMetrics);
00987   return NS_OK;
00988 }
00989 
00990 /* readonly attribute float x; */
00991 NS_IMETHODIMP
00992 nsSVGGlyphFrame::GetX(float *aX)
00993 {
00994   *aX = mX;
00995   return NS_OK;
00996 }
00997 
00998 /* readonly attribute float y; */
00999 NS_IMETHODIMP
01000 nsSVGGlyphFrame::GetY(float *aY)
01001 {
01002   *aY = mY;
01003   return NS_OK;
01004 }
01005 
01006 /* readonly attribute boolean hasHighlight; */
01007 NS_IMETHODIMP
01008 nsSVGGlyphFrame::GetHasHighlight(PRBool *aHasHighlight)
01009 {
01010   *aHasHighlight = (mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
01011 
01012   return NS_OK;
01013 }
01014 
01015 
01016 // Utilities for converting from indices in the uncompressed content
01017 // element strings to compressed frame string and back:
01018 int CompressIndex(int index, const nsTextFragment*fragment)
01019 {
01020   int ci=0;
01021   if (fragment->Is2b()) {
01022     const PRUnichar *data=fragment->Get2b();
01023     while(*data && index) {
01024       if (XP_IS_SPACE_W(*data)){
01025         do {
01026           ++data;
01027           --index;
01028         }while(XP_IS_SPACE_W(*data) && index);
01029       }
01030       else {
01031         ++data;
01032         --index;
01033       }
01034       ++ci;
01035     }
01036   }
01037   else {
01038     const char *data=fragment->Get1b();
01039     while(*data && index) {
01040       if (XP_IS_SPACE_W(*data)){
01041         do {
01042           ++data;
01043           --index;
01044         }while(XP_IS_SPACE_W(*data) && index);
01045       }
01046       else {
01047         ++data;
01048         --index;
01049       }
01050       ++ci;
01051     }
01052   }
01053     
01054   return ci;
01055 }
01056 
01057 int UncompressIndex(int index, PRBool bRightAffinity, const nsTextFragment*fragment)
01058 {
01059   // XXX
01060   return index;
01061 }
01062 
01063 /* [noscript] void getHighlight (out unsigned long charnum, out unsigned long nchars, out nscolor foreground, out nscolor background); */
01064 NS_IMETHODIMP
01065 nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars, nscolor *foreground, nscolor *background)
01066 {
01067   *foreground = NS_RGB(255,255,255);
01068   *background = NS_RGB(0,0,0); 
01069   *charnum=0;
01070   *nchars=0;
01071 
01072     PRBool hasHighlight;
01073   GetHasHighlight(&hasHighlight);
01074 
01075   if (!hasHighlight) {
01076     NS_ERROR("nsSVGGlyphFrame::GetHighlight() called by renderer when there is no highlight");
01077     return NS_ERROR_FAILURE;
01078   }
01079 
01080   // XXX gcc 3.2.2 requires the explicit 'nsSVGGlyphFrameBase::' qualification
01081   nsPresContext *presContext = nsSVGGlyphFrameBase::GetPresContext();
01082 
01083   nsCOMPtr<nsITextContent> tc = do_QueryInterface(mContent);
01084   NS_ASSERTION(tc, "no textcontent interface");
01085 
01086   // The selection ranges are relative to the uncompressed text in
01087   // the content element. We'll need the text fragment:
01088   const nsTextFragment *fragment = tc->Text();
01089   
01090   // get the selection details 
01091   SelectionDetails *details = nsnull;
01092   {
01093     nsCOMPtr<nsIFrameSelection> frameSelection;
01094     {
01095       nsCOMPtr<nsISelectionController> controller;
01096       GetSelectionController(presContext, getter_AddRefs(controller));
01097       
01098       if (!controller) {
01099         NS_ERROR("no selection controller");
01100         return NS_ERROR_FAILURE;
01101       }
01102       frameSelection = do_QueryInterface(controller);
01103     }
01104     if (!frameSelection) {
01105       frameSelection = presContext->PresShell()->FrameSelection();
01106     }
01107     if (!frameSelection) {
01108       NS_ERROR("no frameselection interface");
01109       return NS_ERROR_FAILURE;
01110     }
01111 
01112     frameSelection->LookUpSelection(mContent, 0, fragment->GetLength(),
01113                                     &details, PR_FALSE);
01114   }
01115 
01116 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
01117   {
01118     SelectionDetails *dp = details;
01119     printf("nsSVGGlyphFrame(%p)::GetHighlight() [\n", this);
01120     while (dp) {
01121       printf("selection detail: %d(%d)->%d(%d) type %d\n",
01122              dp->mStart, CompressIndex(dp->mStart, fragment),
01123              dp->mEnd, CompressIndex(dp->mEnd, fragment),
01124              dp->mType);
01125       dp = dp->mNext;
01126     }
01127     printf("]\n");
01128       
01129   }
01130 #endif
01131   
01132   if (details) {
01133     NS_ASSERTION(details->mNext==nsnull, "can't do multiple selection ranges");
01134 
01135     *charnum=CompressIndex(details->mStart, fragment);
01136     *nchars=CompressIndex(details->mEnd, fragment)-*charnum;  
01137     
01138     nsILookAndFeel *look = presContext->LookAndFeel();
01139 
01140     look->GetColor(nsILookAndFeel::eColor_TextSelectBackground, *background);
01141     look->GetColor(nsILookAndFeel::eColor_TextSelectForeground, *foreground);
01142 
01143     SelectionDetails *dp = details;
01144     while ((dp=details->mNext) != nsnull) {
01145       delete details;
01146       details = dp;
01147     }
01148     delete details;
01149   }
01150   
01151   return NS_OK;
01152 }
01153 
01154 
01155 //----------------------------------------------------------------------
01156 // nsISVGGlyphFragmentLeaf interface:
01157 
01158 NS_IMETHODIMP_(void)
01159 nsSVGGlyphFrame::SetGlyphPosition(float x, float y)
01160 {
01161   mX = x;
01162   mY = y;
01163   UpdateGeometry(nsISVGGlyphGeometrySource::UPDATEMASK_X |
01164                  nsISVGGlyphGeometrySource::UPDATEMASK_Y);
01165 }
01166 
01167 NS_IMETHODIMP_(float)
01168 nsSVGGlyphFrame::GetGlyphPositionX()
01169 {
01170   return mX;
01171 }
01172 
01173 NS_IMETHODIMP_(float)
01174 nsSVGGlyphFrame::GetGlyphPositionY()
01175 {
01176   return mY;
01177 }
01178 
01179 
01180 NS_IMETHODIMP
01181 nsSVGGlyphFrame::GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics)
01182 {
01183   *metrics = mMetrics;
01184   NS_IF_ADDREF(*metrics);
01185   return NS_OK;
01186 }
01187 
01188 NS_IMETHODIMP_(PRBool)
01189 nsSVGGlyphFrame::IsStartOfChunk()
01190 {
01191   // this fragment is a chunk if it has a corresponding absolute
01192   // position adjustment in an ancestors' x or y array. (At the moment
01193   // we don't map the full arrays, but only the first elements.)
01194 
01195   return PR_FALSE;
01196 }
01197 
01198 NS_IMETHODIMP_(void)
01199 nsSVGGlyphFrame::GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y)
01200 {
01201 }
01202 
01203 NS_IMETHODIMP_(PRUint32)
01204 nsSVGGlyphFrame::GetNumberOfChars()
01205 {
01206   return mCharacterData.Length();
01207 }
01208 
01209 NS_IMETHODIMP_(PRUint32)
01210 nsSVGGlyphFrame::GetCharNumberOffset()
01211 {
01212   return mCharOffset;
01213 }
01214 
01215 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01216 nsSVGGlyphFrame::GetX()
01217 {
01218   nsISVGTextContainerFrame *containerFrame;
01219   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame),
01220                           (void**)&containerFrame);
01221   if (containerFrame)
01222     return containerFrame->GetX();
01223   return nsnull;
01224 }
01225 
01226 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01227 nsSVGGlyphFrame::GetY()
01228 {
01229   nsISVGTextContainerFrame *containerFrame;
01230   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame),
01231                           (void**)&containerFrame);
01232   if (containerFrame)
01233     return containerFrame->GetY();
01234   return nsnull;
01235 }
01236 
01237 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01238 nsSVGGlyphFrame::GetDx()
01239 {
01240   nsISVGTextContainerFrame *containerFrame;
01241   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame),
01242                           (void**)&containerFrame);
01243   if (containerFrame)
01244     return containerFrame->GetDx();
01245   return nsnull;
01246 }
01247 
01248 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
01249 nsSVGGlyphFrame::GetDy()
01250 {
01251   nsISVGTextContainerFrame *containerFrame;
01252   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame),
01253                           (void**)&containerFrame);
01254   if (containerFrame)
01255     return containerFrame->GetDy();
01256   return nsnull;
01257 }
01258 
01259 NS_IMETHODIMP_(PRUint16)
01260 nsSVGGlyphFrame::GetTextAnchor()
01261 {
01262   return GetStyleSVG()->mTextAnchor;
01263 }
01264 
01265 NS_IMETHODIMP_(PRBool)
01266 nsSVGGlyphFrame::IsAbsolutelyPositioned()
01267 {
01268   nsIFrame *lastFrame = this;
01269 
01270   for (nsIFrame *frame = this->GetParent();
01271        frame != nsnull;
01272        lastFrame = frame, frame = frame->GetParent()) {
01273 
01274     /* need to be the first child if we are absolutely positioned */
01275     if (!frame ||
01276         frame->GetFirstChild(nsnull) != lastFrame)
01277       break;
01278 
01279     // textPath is always absolutely positioned for our purposes
01280     if (frame->GetType() == nsLayoutAtoms::svgTextPathFrame)
01281       return PR_TRUE;
01282         
01283     if (frame &&
01284         (frame->GetContent()->HasAttr(kNameSpaceID_None, nsSVGAtoms::x) ||
01285          frame->GetContent()->HasAttr(kNameSpaceID_None, nsSVGAtoms::y)))
01286         return PR_TRUE;
01287 
01288     if (frame->GetType() == nsLayoutAtoms::svgTextFrame)
01289       break;
01290   }
01291 
01292   return PR_FALSE;
01293 }
01294 
01295 
01296 //----------------------------------------------------------------------
01297 // nsISVGGlyphFragmentNode interface:
01298 
01299 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
01300 nsSVGGlyphFrame::GetFirstGlyphFragment()
01301 {
01302   return this;
01303 }
01304 
01305 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
01306 nsSVGGlyphFrame::GetNextGlyphFragment()
01307 {
01308   nsIFrame* sibling = mNextSibling;
01309   while (sibling) {
01310     nsISVGGlyphFragmentNode *node = nsnull;
01311     sibling->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
01312     if (node)
01313       return node->GetFirstGlyphFragment();
01314     sibling = sibling->GetNextSibling();
01315   }
01316 
01317   // no more siblings. go back up the tree.
01318   
01319   NS_ASSERTION(mParent, "null parent");
01320   nsISVGGlyphFragmentNode *node = nsnull;
01321   mParent->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
01322   return node ? node->GetNextGlyphFragment() : nsnull;
01323 }
01324 
01325 NS_IMETHODIMP_(PRUint32)
01326 nsSVGGlyphFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch)
01327 {
01328   // XXX actually we should be building a new fragment for each chunk here...
01329 
01330 
01331   mCharOffset = charNum;
01332   nsCOMPtr<nsITextContent> tc = do_QueryInterface(mContent);
01333 
01334   if (tc->TextLength() == 0) {
01335 #ifdef DEBUG
01336     printf("Glyph frame with zero length text\n");
01337 #endif
01338     mCharacterData.AssignLiteral("");
01339     return charNum;
01340   }
01341 
01342   mCharacterData.Truncate();
01343   tc->AppendTextTo(mCharacterData);
01344   mCharacterData.CompressWhitespace(charNum==0, lastBranch);
01345 
01346   return charNum+mCharacterData.Length();
01347 }
01348 
01349 NS_IMETHODIMP_(void)
01350 nsSVGGlyphFrame::NotifyMetricsSuspended()
01351 {
01352   // do nothing
01353 }
01354 
01355 NS_IMETHODIMP_(void)
01356 nsSVGGlyphFrame::NotifyMetricsUnsuspended()
01357 {
01358   NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::NotifyMetricsUnsuspended");
01359 
01360   if (mMetricsUpdateFlags != 0) {
01361     PRBool metricsDirty = PR_FALSE;
01362     if (mMetrics)
01363       mMetrics->Update(mMetricsUpdateFlags, &metricsDirty);
01364     if (metricsDirty) {
01365       mGeometryUpdateFlags |= nsISVGGlyphGeometrySource::UPDATEMASK_METRICS;
01366       nsISVGTextFrame* text_frame = GetTextFrame();
01367       NS_ASSERTION(text_frame, "null text frame");
01368       if (text_frame)
01369         text_frame->NotifyGlyphMetricsChange(this);
01370     }
01371     mMetricsUpdateFlags = 0;
01372   }   
01373 }
01374 
01375 NS_IMETHODIMP_(void)
01376 nsSVGGlyphFrame::NotifyGlyphFragmentTreeSuspended()
01377 {
01378   // do nothing
01379 }
01380 
01381 NS_IMETHODIMP_(void)
01382 nsSVGGlyphFrame::NotifyGlyphFragmentTreeUnsuspended()
01383 {
01384   if (mFragmentTreeDirty) {
01385     nsISVGTextFrame* text_frame = GetTextFrame();
01386     NS_ASSERTION(text_frame, "null text frame");
01387     if (text_frame)
01388       text_frame->NotifyGlyphFragmentTreeChange(this);
01389     mFragmentTreeDirty = PR_FALSE;
01390   }
01391 }
01392 
01393 
01394 
01395 //----------------------------------------------------------------------
01396 //
01397 
01398 void nsSVGGlyphFrame::UpdateGeometry(PRUint32 flags, PRBool bRedraw)
01399 {
01400   mGeometryUpdateFlags |= flags;
01401   
01402   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
01403   if (!outerSVGFrame) {
01404     NS_ERROR("null outerSVGFrame");
01405     return;
01406   }
01407   
01408   PRBool suspended;
01409   outerSVGFrame->IsRedrawSuspended(&suspended);
01410   if (!suspended) {
01411     NS_ASSERTION(!mMetricsUpdateFlags, "dirty metrics in nsSVGGlyphFrame::UpdateGeometry");
01412     NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::UpdateGeometry");
01413     nsCOMPtr<nsISVGRendererRegion> dirty_region;
01414     if (mGeometry)
01415       mGeometry->Update(mGeometryUpdateFlags, getter_AddRefs(dirty_region));
01416     if (dirty_region) {
01417       // if we're being used as a clippath, this will get called
01418       // during the paint - don't need to invalidate (which causes
01419       // us to loop busy-painting)
01420 
01421       nsIView *view = GetClosestView();
01422       if (!view) return;
01423       nsIViewManager *vm = view->GetViewManager();
01424       PRBool painting;
01425       vm->IsPainting(painting);
01426 
01427       if (!painting)
01428         outerSVGFrame->InvalidateRegion(dirty_region, bRedraw);
01429     }
01430     mGeometryUpdateFlags = 0;
01431   }  
01432 }
01433 
01434 void nsSVGGlyphFrame::UpdateMetrics(PRUint32 flags)
01435 {
01436   mMetricsUpdateFlags |= flags;
01437 
01438   nsISVGTextFrame* text_frame = GetTextFrame();
01439   if (!text_frame) {
01440     NS_ERROR("null text_frame");
01441     return;
01442   }
01443   
01444   PRBool suspended = text_frame->IsMetricsSuspended();
01445   if (!suspended) {
01446     NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::UpdateMetrics");
01447     PRBool metricsDirty;
01448     mMetrics->Update(mMetricsUpdateFlags, &metricsDirty);
01449     if (metricsDirty) {
01450       mGeometryUpdateFlags |= nsISVGGlyphGeometrySource::UPDATEMASK_METRICS;
01451       text_frame->NotifyGlyphMetricsChange(this);
01452     }
01453     mMetricsUpdateFlags = 0;
01454   }
01455 }
01456 
01457 void nsSVGGlyphFrame::UpdateFragmentTree()
01458 {
01459   mFragmentTreeDirty = PR_TRUE;
01460     
01461   nsISVGTextFrame* text_frame = GetTextFrame();
01462   if (!text_frame) {
01463     NS_ERROR("null text_frame");
01464     return;
01465   }
01466   
01467   PRBool suspended = text_frame->IsGlyphFragmentTreeSuspended();
01468   if (!suspended) {
01469     text_frame->NotifyGlyphFragmentTreeChange(this);
01470     mFragmentTreeDirty = PR_FALSE;
01471   }
01472 }
01473 
01474 nsISVGOuterSVGFrame *
01475 nsSVGGlyphFrame::GetOuterSVGFrame()
01476 {
01477   NS_ASSERTION(mParent, "null parent");
01478   
01479   nsISVGContainerFrame *containerFrame;
01480   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
01481   if (!containerFrame) {
01482     NS_ERROR("invalid container");
01483     return nsnull;
01484   }
01485 
01486   return containerFrame->GetOuterSVGFrame();  
01487 }
01488 
01489 nsISVGTextFrame *
01490 nsSVGGlyphFrame::GetTextFrame()
01491 {
01492   NS_ASSERTION(mParent, "null parent");
01493 
01494   nsISVGTextContainerFrame *containerFrame;
01495   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame), (void**)&containerFrame);
01496   if (!containerFrame) {
01497     NS_ERROR("invalid container");
01498     return nsnull;
01499   }
01500 
01501   return containerFrame->GetTextFrame();
01502 }