/layout/svg/base/src/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
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with 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 the GNU General Public License Version 2 or later (the "GPL"), or 
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the NPL, 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 "nsReadableUtils.h"
00053 #include "nsCRT.h"
00054 #include "prdtoa.h"
00055 #include "nsIDOMSVGRect.h"
00056 #include "nsILookAndFeel.h"
00057 #include "nsTextFragment.h"
00058 
00059 typedef nsFrame nsSVGGlyphFrameBase;
00060 
00061 class nsSVGGlyphFrame : public nsSVGGlyphFrameBase,
00062                         public nsISVGGlyphGeometrySource, // : nsISVGGlyphMetricsSource : nsISVGGeometrySource
00063                         public nsISVGGlyphFragmentLeaf, // : nsISVGGlyphFragmentNode
00064                         public nsISVGChildFrame
00065 {
00066 protected:
00067   friend nsresult
00068   NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00069                       nsIFrame* parentFrame, nsIFrame** aNewFrame);
00070   nsSVGGlyphFrame();
00071   virtual ~nsSVGGlyphFrame();
00072 
00073 public:
00074    // nsISupports interface:
00075   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00076   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00077   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00078 
00079   // nsIFrame interface:
00080   NS_IMETHOD
00081   Init(nsIPresContext*  aPresContext,
00082        nsIContent*      aContent,
00083        nsIFrame*        aParent,
00084        nsStyleContext* aContext,
00085        nsIFrame*        aPrevInFlow);
00086 
00087   NS_IMETHOD  ContentChanged(nsIPresContext* aPresContext,
00088                              nsIContent*     aChild,
00089                              nsISupports*    aSubContent);
00090 
00091   NS_IMETHOD  SetSelected(nsIPresContext* aPresContext,
00092                           nsIDOMRange*    aRange,
00093                           PRBool          aSelected,
00094                           nsSpread        aSpread);
00095   NS_IMETHOD  GetSelected(PRBool *aSelected) const;
00096   NS_IMETHOD  IsSelectable(PRBool* aIsSelectable, PRUint8* aSelectStyle);
00097 
00098   // nsISVGChildFrame interface:
00099   NS_IMETHOD Paint(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00100   NS_IMETHOD GetFrameForPoint(float x, float y, nsIFrame** hit);
00101   NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
00102   NS_IMETHOD InitialUpdate();
00103   NS_IMETHOD NotifyCTMChanged();
00104   NS_IMETHOD NotifyRedrawSuspended();
00105   NS_IMETHOD NotifyRedrawUnsuspended();
00106   NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
00107   
00108   // nsISVGGeometrySource interface: 
00109   NS_DECL_NSISVGGEOMETRYSOURCE
00110 
00111   // nsISVGGlyphMetricsSource interface:
00112   NS_DECL_NSISVGGLYPHMETRICSSOURCE
00113 
00114   // nsISVGGlyphGeometrySource interface:
00115   NS_DECL_NSISVGGLYPHGEOMETRYSOURCE
00116 
00117   // nsISVGGlyphFragmentLeaf interface:
00118   NS_IMETHOD_(void) SetGlyphPosition(float x, float y);
00119   NS_IMETHOD_(float) GetGlyphPositionX();
00120   NS_IMETHOD_(float) GetGlyphPositionY();  
00121   NS_IMETHOD GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics);
00122   NS_IMETHOD_(PRBool) IsStartOfChunk(); // == is new absolutely positioned chunk.
00123   NS_IMETHOD_(void) GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y);
00124   NS_IMETHOD_(PRUint32) GetNumberOfChars();
00125   NS_IMETHOD_(PRUint32) GetCharNumberOffset();
00126 
00127   // nsISVGGlyphFragmentNode interface:
00128   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment();
00129   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment();
00130   NS_IMETHOD_(PRUint32) BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch);
00131   NS_IMETHOD_(void) NotifyMetricsSuspended();
00132   NS_IMETHOD_(void) NotifyMetricsUnsuspended();
00133   NS_IMETHOD_(void) NotifyGlyphFragmentTreeSuspended();
00134   NS_IMETHOD_(void) NotifyGlyphFragmentTreeUnsuspended();
00135   
00136 protected:
00137   void UpdateGeometry(PRUint32 flags, PRBool bRedraw=PR_TRUE);
00138   void UpdateMetrics(PRUint32 flags);
00139   void UpdateFragmentTree();
00140   nsISVGOuterSVGFrame *GetOuterSVGFrame();
00141   nsISVGTextFrame *GetTextFrame();
00142   
00143   nsCOMPtr<nsISVGRendererGlyphGeometry> mGeometry;
00144   nsCOMPtr<nsISVGRendererGlyphMetrics> mMetrics;
00145   float mX, mY;
00146   PRUint32 mCharOffset;
00147   PRUint32 mGeometryUpdateFlags;
00148   PRUint32 mMetricsUpdateFlags;
00149   PRBool mFragmentTreeDirty;
00150   nsString mCharacterData;
00151 };
00152 
00153 //----------------------------------------------------------------------
00154 // Implementation
00155 
00156 nsresult
00157 NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* parentFrame,
00158                     nsIFrame** aNewFrame)
00159 {
00160   *aNewFrame = nsnull;
00161 
00162 #ifdef DEBUG
00163   NS_ASSERTION(parentFrame, "null parent");
00164   nsISVGTextContainerFrame *text_container;
00165   parentFrame->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame), (void**)&text_container);
00166   NS_ASSERTION(text_container, "trying to construct an SVGGlyphFrame for an invalid container");
00167   
00168   nsCOMPtr<nsITextContent> tc = do_QueryInterface(aContent);
00169   NS_ASSERTION(tc, "trying to construct an SVGGlyphFrame for wrong content element");
00170 #endif
00171   
00172   nsSVGGlyphFrame* it = new (aPresShell) nsSVGGlyphFrame;
00173   if (nsnull == it)
00174     return NS_ERROR_OUT_OF_MEMORY;
00175 
00176   *aNewFrame = it;
00177 
00178   return NS_OK;
00179 }
00180 
00181 nsSVGGlyphFrame::nsSVGGlyphFrame()
00182     : mGeometryUpdateFlags(0), mMetricsUpdateFlags(0),
00183       mCharOffset(0), mFragmentTreeDirty(PR_FALSE)
00184 {
00185 }
00186 
00187 nsSVGGlyphFrame::~nsSVGGlyphFrame()
00188 {
00189 
00190 }
00191 
00192 
00193 //----------------------------------------------------------------------
00194 // nsISupports methods
00195 
00196 NS_INTERFACE_MAP_BEGIN(nsSVGGlyphFrame)
00197   NS_INTERFACE_MAP_ENTRY(nsISVGGeometrySource)
00198   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphMetricsSource)
00199   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphGeometrySource)
00200   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentLeaf)
00201   NS_INTERFACE_MAP_ENTRY(nsISVGGlyphFragmentNode)
00202   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00203 NS_INTERFACE_MAP_END_INHERITING(nsSVGGlyphFrameBase)
00204 
00205 //----------------------------------------------------------------------
00206 // nsIFrame methods
00207 
00208 NS_IMETHODIMP
00209 nsSVGGlyphFrame::Init(nsIPresContext*  aPresContext,
00210                       nsIContent*      aContent,
00211                       nsIFrame*        aParent,
00212                       nsStyleContext*  aContext,
00213                       nsIFrame*        aPrevInFlow)
00214 {
00215 //  rv = nsSVGGlyphFrameBase::Init(aPresContext, aContent, aParent,
00216 //                                 aContext, aPrevInFlow);
00217 
00218   mContent = aContent;
00219   NS_IF_ADDREF(mContent);
00220   mParent = aParent;
00221 
00222   // construct our glyphmetrics & glyphgeometry objects:
00223   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00224   if (!outerSVGFrame) {
00225     NS_ERROR("No outerSVGFrame");
00226     return NS_ERROR_FAILURE;
00227   }
00228   nsCOMPtr<nsISVGRenderer> renderer;
00229   outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
00230 
00231   renderer->CreateGlyphMetrics(this, getter_AddRefs(mMetrics));
00232   if (!mMetrics) return NS_ERROR_FAILURE;
00233   
00234   renderer->CreateGlyphGeometry(this, getter_AddRefs(mGeometry));
00235   if (!mGeometry) return NS_ERROR_FAILURE;
00236   
00237   
00238   SetStyleContext(aPresContext, aContext);
00239     
00240   return NS_OK;
00241 }
00242 
00243 NS_IMETHODIMP
00244 nsSVGGlyphFrame::ContentChanged(nsIPresContext* aPresContext,
00245                                 nsIContent*     aChild,
00246                                 nsISupports*    aSubContent)
00247 {
00248 #ifdef DEBUG
00249 //  printf("** nsSVGGlyphFrame::ContentChanged\n");
00250 #endif
00251   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00252   if (!outerSVGFrame) {
00253     NS_ERROR("No outerSVGFrame");
00254     return NS_ERROR_FAILURE;
00255   }
00256   
00257   outerSVGFrame->SuspendRedraw();
00258   UpdateFragmentTree();
00259   UpdateMetrics(nsISVGGeometrySource::UPDATEMASK_ALL);
00260   UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_ALL);
00261   outerSVGFrame->UnsuspendRedraw();
00262 
00263   return NS_OK;
00264 }
00265 
00266 NS_IMETHODIMP
00267 nsSVGGlyphFrame::SetSelected(nsIPresContext* aPresContext,
00268                              nsIDOMRange*    aRange,
00269                              PRBool          aSelected,
00270                              nsSpread        aSpread)
00271 {
00272 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00273   printf("nsSVGGlyphFrame(%p)::SetSelected()\n", this);
00274 #endif
00275 //  return nsSVGGlyphFrameBase::SetSelected(aPresContext, aRange, aSelected, aSpread);
00276 
00277   // check whether style allows selection
00278   PRBool  selectable;
00279   IsSelectable(&selectable, nsnull);
00280   if (!selectable)
00281     return NS_OK;
00282   
00283   nsFrameState  frameState;
00284   GetFrameState(&frameState);
00285   if ( aSelected ){
00286     frameState |=  NS_FRAME_SELECTED_CONTENT;
00287   }
00288   else
00289     frameState &= ~NS_FRAME_SELECTED_CONTENT;
00290   SetFrameState(frameState);
00291 
00292   UpdateGeometry(nsISVGGlyphGeometrySource::UPDATEMASK_HIGHLIGHT |
00293                  nsISVGGlyphGeometrySource::UPDATEMASK_HAS_HIGHLIGHT,
00294                  PR_FALSE);  
00295 
00296   return NS_OK;
00297 }
00298 
00299 NS_IMETHODIMP
00300 nsSVGGlyphFrame::GetSelected(PRBool *aSelected) const
00301 {
00302   nsresult rv = nsSVGGlyphFrameBase::GetSelected(aSelected);
00303 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00304   printf("nsSVGGlyphFrame(%p)::GetSelected()=%d\n", this, *aSelected);
00305 #endif
00306   return rv;
00307 }
00308 
00309 NS_IMETHODIMP
00310 nsSVGGlyphFrame::IsSelectable(PRBool* aIsSelectable,
00311                               PRUint8* aSelectStyle)
00312 {
00313   nsresult rv = nsSVGGlyphFrameBase::IsSelectable(aIsSelectable, aSelectStyle);
00314 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00315   printf("nsSVGGlyphFrame(%p)::IsSelectable()=(%d,%d)\n", this, *aIsSelectable, aSelectStyle);
00316 #endif
00317   return rv;
00318 }
00319 
00320 
00321 //----------------------------------------------------------------------
00322 // nsISVGChildFrame methods
00323 
00324 NS_IMETHODIMP
00325 nsSVGGlyphFrame::Paint(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00326 {
00327 #ifdef DEBUG
00328   //printf("nsSVGGlyphFrame(%p)::Paint\n", this);
00329 #endif
00330   mGeometry->Render(canvas);
00331   return NS_OK;
00332 }
00333 
00334 NS_IMETHODIMP
00335 nsSVGGlyphFrame::GetFrameForPoint(float x, float y, nsIFrame** hit)
00336 {
00337 #ifdef DEBUG
00338   //printf("nsSVGGlyphFrame(%p)::GetFrameForPoint\n", this);
00339 #endif
00340   // test for hit:
00341   *hit = nsnull;
00342   PRBool isHit;
00343   mGeometry->ContainsPoint(x, y, &isHit);
00344   if (isHit) 
00345     *hit = this;
00346   
00347   return NS_OK;
00348 }
00349 
00350 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00351 nsSVGGlyphFrame::GetCoveredRegion()
00352 {
00353   nsISVGRendererRegion *region = nsnull;
00354   mGeometry->GetCoveredRegion(&region);
00355   return region;
00356 }
00357 
00358 NS_IMETHODIMP
00359 nsSVGGlyphFrame::InitialUpdate()
00360 {
00361   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00362   if (!outerSVGFrame) {
00363     NS_ERROR("No outerSVGFrame");
00364     return NS_ERROR_FAILURE;
00365   }
00366   
00367   outerSVGFrame->SuspendRedraw();
00368   UpdateFragmentTree();
00369   UpdateMetrics(nsISVGGeometrySource::UPDATEMASK_ALL);
00370   UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_ALL);
00371   outerSVGFrame->UnsuspendRedraw();
00372   
00373   return NS_OK;
00374 }  
00375 
00376 NS_IMETHODIMP
00377 nsSVGGlyphFrame::NotifyCTMChanged()
00378 {
00379   UpdateGeometry(nsISVGGeometrySource::UPDATEMASK_CTM);
00380   
00381   return NS_OK;
00382 }
00383 
00384 NS_IMETHODIMP
00385 nsSVGGlyphFrame::NotifyRedrawSuspended()
00386 {
00387   // XXX should we cache the fact that redraw is suspended?
00388   return NS_OK;
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsSVGGlyphFrame::NotifyRedrawUnsuspended()
00393 {
00394   NS_ASSERTION(!mMetricsUpdateFlags, "dirty metrics in nsSVGGlyphFrame::NotifyRedrawUnsuspended");
00395   NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::NotifyRedrawUnsuspended");
00396     
00397   if (mGeometryUpdateFlags != 0) {
00398     nsCOMPtr<nsISVGRendererRegion> dirty_region;
00399     mGeometry->Update(mGeometryUpdateFlags, getter_AddRefs(dirty_region));
00400     if (dirty_region) {
00401       nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00402       if (outerSVGFrame)
00403         outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00404     }
00405     mGeometryUpdateFlags = 0;
00406   }
00407   return NS_OK;
00408 }
00409 
00410 NS_IMETHODIMP
00411 nsSVGGlyphFrame::GetBBox(nsIDOMSVGRect **_retval)
00412 {
00413   *_retval = nsnull;
00414 
00415   nsresult rv = mMetrics->GetBoundingBox(_retval);
00416   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
00417   
00418   // offset the bounds by the position of this glyph fragment:
00419   float x,y;
00420   (*_retval)->GetX(&x);
00421   (*_retval)->GetY(&y);
00422   (*_retval)->SetX(x+mX);
00423   (*_retval)->SetY(y+mY);
00424   
00425   return NS_OK;
00426 }
00427 
00428 //----------------------------------------------------------------------
00429 // nsISVGGeometrySource methods:
00430 
00431 /* [noscript] readonly attribute nsIPresContext presContext; */
00432 NS_IMETHODIMP
00433 nsSVGGlyphFrame::GetPresContext(nsIPresContext * *aPresContext)
00434 {
00435   // XXX gcc 3.2.2 requires the explicit 'nsSVGGlyphFrameBase::' qualification
00436   *aPresContext = nsSVGGlyphFrameBase::GetPresContext();
00437   NS_ADDREF(*aPresContext);
00438   return NS_OK;
00439 }
00440 
00441 /* readonly attribute nsIDOMSVGMatrix CTM; */
00442 NS_IMETHODIMP
00443 nsSVGGlyphFrame::GetCTM(nsIDOMSVGMatrix * *aCTM)
00444 {
00445   *aCTM = nsnull;
00446   
00447   nsISVGTextFrame * textframe = GetTextFrame();
00448   NS_ASSERTION(textframe, "null textframe");
00449   
00450   return textframe->GetCTM(aCTM);  
00451 }
00452 
00453 /* readonly attribute float strokeOpacity; */
00454 NS_IMETHODIMP
00455 nsSVGGlyphFrame::GetStrokeOpacity(float *aStrokeOpacity)
00456 {
00457   *aStrokeOpacity = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeOpacity;
00458   return NS_OK;
00459 }
00460 
00461 /* readonly attribute float strokeWidth; */
00462 NS_IMETHODIMP
00463 nsSVGGlyphFrame::GetStrokeWidth(float *aStrokeWidth)
00464 {
00465   *aStrokeWidth = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeWidth;
00466   return NS_OK;
00467 }
00468 
00469 /* void getStrokeDashArray ([array, size_is (count)] out float arr, out unsigned long count); */
00470 NS_IMETHODIMP
00471 nsSVGGlyphFrame::GetStrokeDashArray(float **arr, PRUint32 *count)
00472 {
00473   *arr = nsnull;
00474   *count = 0;
00475   
00476   const nsString &dasharrayString = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeDasharray;
00477   if (dasharrayString.Length() == 0) return NS_OK;
00478 
00479   // XXX parsing of the dasharray string should be done elsewhere
00480 
00481   char *str = ToNewCString(dasharrayString);
00482 
00483   // array elements are separated by commas. count them to get our max
00484   // no of elems.
00485 
00486   int i=0;
00487   char* cp = str;
00488   while (*cp) {
00489     if (*cp == ',')
00490       ++i;
00491     ++cp;
00492   }
00493   ++i;
00494 
00495   // now get the elements
00496   
00497   *arr = (float*) nsMemory::Alloc(i * sizeof(float));
00498 
00499   cp = str;
00500   char *elem;
00501   while ((elem = nsCRT::strtok(cp, "',", &cp))) {
00502     char *end;
00503     (*arr)[(*count)++] = (float) PR_strtod(elem, &end);
00504 #ifdef DEBUG
00505     //printf("[%f]",(*arr)[(*count)-1]);
00506 #endif
00507   }
00508   
00509   nsMemory::Free(str);
00510 
00511   return NS_OK;
00512 }
00513 
00514 /* readonly attribute float strokeDashoffset; */
00515 NS_IMETHODIMP
00516 nsSVGGlyphFrame::GetStrokeDashoffset(float *aStrokeDashoffset)
00517 {
00518   *aStrokeDashoffset = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeDashoffset;
00519   return NS_OK;
00520 }
00521 
00522 /* readonly attribute unsigned short strokeLinecap; */
00523 NS_IMETHODIMP
00524 nsSVGGlyphFrame::GetStrokeLinecap(PRUint16 *aStrokeLinecap)
00525 {
00526   *aStrokeLinecap = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeLinecap;
00527   return NS_OK;
00528 }
00529 
00530 /* readonly attribute unsigned short strokeLinejoin; */
00531 NS_IMETHODIMP
00532 nsSVGGlyphFrame::GetStrokeLinejoin(PRUint16 *aStrokeLinejoin)
00533 {
00534   *aStrokeLinejoin = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeLinejoin;
00535   return NS_OK;
00536 }
00537 
00538 /* readonly attribute float strokeMiterlimit; */
00539 NS_IMETHODIMP
00540 nsSVGGlyphFrame::GetStrokeMiterlimit(float *aStrokeMiterlimit)
00541 {
00542   *aStrokeMiterlimit = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStrokeMiterlimit; 
00543   return NS_OK;
00544 }
00545 
00546 /* readonly attribute float fillOpacity; */
00547 NS_IMETHODIMP
00548 nsSVGGlyphFrame::GetFillOpacity(float *aFillOpacity)
00549 {
00550   *aFillOpacity = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mFillOpacity;
00551   return NS_OK;
00552 }
00553 
00554 /* readonly attribute unsigned short fillRule; */
00555 NS_IMETHODIMP
00556 nsSVGGlyphFrame::GetFillRule(PRUint16 *aFillRule)
00557 {
00558   *aFillRule = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mFillRule;
00559   return NS_OK;
00560 }
00561 
00562 /* readonly attribute unsigned short strokePaintType; */
00563 NS_IMETHODIMP
00564 nsSVGGlyphFrame::GetStrokePaintType(PRUint16 *aStrokePaintType)
00565 {
00566   *aStrokePaintType = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStroke.mType;
00567   return NS_OK;
00568 }
00569 
00570 /* [noscript] readonly attribute nscolor strokePaint; */
00571 NS_IMETHODIMP
00572 nsSVGGlyphFrame::GetStrokePaint(nscolor *aStrokePaint)
00573 {
00574   *aStrokePaint = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mStroke.mColor;
00575   return NS_OK;
00576 }
00577 
00578 /* readonly attribute unsigned short fillPaintType; */
00579 NS_IMETHODIMP
00580 nsSVGGlyphFrame::GetFillPaintType(PRUint16 *aFillPaintType)
00581 {
00582   *aFillPaintType = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mFill.mType;
00583   return NS_OK;
00584 }
00585 
00586 /* [noscript] readonly attribute nscolor fillPaint; */
00587 NS_IMETHODIMP
00588 nsSVGGlyphFrame::GetFillPaint(nscolor *aFillPaint)
00589 {
00590   *aFillPaint = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mFill.mColor;
00591   return NS_OK;
00592 }
00593 
00594 //----------------------------------------------------------------------
00595 // nsISVGGlyphMetricsSource methods:
00596 
00597 /* [noscript] readonly attribute nsFont font; */
00598 NS_IMETHODIMP
00599 nsSVGGlyphFrame::GetFont(nsFont *aFont)
00600 {
00601   *aFont = ((const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font))->mFont;
00602 
00603   // XXX eventually we will have to treat decorations separately from
00604   // fonts, because they can have a different color than the current
00605   // glyph.
00606   
00607   NS_ASSERTION(mParent, "no parent");
00608   nsStyleContext *parentContext = mParent->GetStyleContext();
00609   NS_ASSERTION(parentContext, "no style context on parent");
00610   
00611   PRUint8 styleDecorations =
00612     ((const nsStyleTextReset*)parentContext->GetStyleData(eStyleStruct_TextReset))->mTextDecoration;
00613   if (styleDecorations & NS_STYLE_TEXT_DECORATION_UNDERLINE)
00614     aFont->decorations |= NS_FONT_DECORATION_UNDERLINE;
00615   if (styleDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE)
00616     aFont->decorations |= NS_FONT_DECORATION_OVERLINE;
00617   if (styleDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH)
00618     aFont->decorations |= NS_FONT_DECORATION_LINE_THROUGH;    
00619   
00620   return NS_OK;
00621 }
00622 
00623 /* readonly attribute DOMString characterData; */
00624 NS_IMETHODIMP
00625 nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
00626 {
00627   aCharacterData = mCharacterData;
00628   return NS_OK;
00629 }
00630 
00631 /* readonly attribute unsigned short textRendering; */
00632 NS_IMETHODIMP
00633 nsSVGGlyphFrame::GetTextRendering(PRUint16 *aTextRendering)
00634 {
00635   *aTextRendering = ((const nsStyleSVG*) mStyleContext->GetStyleData(eStyleStruct_SVG))->mTextRendering;
00636   return NS_OK;
00637 }
00638 
00639 //----------------------------------------------------------------------
00640 // nsISVGGlyphGeometrySource methods:
00641 
00642 /* readonly attribute nsISVGRendererGlyphMetrics metrics; */
00643 NS_IMETHODIMP
00644 nsSVGGlyphFrame::GetMetrics(nsISVGRendererGlyphMetrics * *aMetrics)
00645 {
00646   *aMetrics = mMetrics;
00647   NS_ADDREF(*aMetrics);
00648   return NS_OK;
00649 }
00650 
00651 /* readonly attribute float x; */
00652 NS_IMETHODIMP
00653 nsSVGGlyphFrame::GetX(float *aX)
00654 {
00655   *aX = mX;
00656   return NS_OK;
00657 }
00658 
00659 /* readonly attribute float y; */
00660 NS_IMETHODIMP
00661 nsSVGGlyphFrame::GetY(float *aY)
00662 {
00663   *aY = mY;
00664   return NS_OK;
00665 }
00666 
00667 /* readonly attribute boolean hasHighlight; */
00668 NS_IMETHODIMP
00669 nsSVGGlyphFrame::GetHasHighlight(PRBool *aHasHighlight)
00670 {
00671   nsFrameState  frameState;
00672   GetFrameState(&frameState);
00673   *aHasHighlight = (frameState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
00674 
00675   return NS_OK;
00676 }
00677 
00678 
00679 // Utilities for converting from indices in the uncompressed content
00680 // element strings to compressed frame string and back:
00681 int CompressIndex(int index, const nsTextFragment*fragment)
00682 {
00683   int ci=0;
00684   if (fragment->Is2b()) {
00685     const PRUnichar *data=fragment->Get2b();
00686     while(*data && index) {
00687       if (XP_IS_SPACE_W(*data)){
00688         do {
00689           ++data;
00690           --index;
00691         }while(XP_IS_SPACE_W(*data) && index);
00692       }
00693       else {
00694         ++data;
00695         --index;
00696       }
00697       ++ci;
00698     }
00699   }
00700   else {
00701     const char *data=fragment->Get1b();
00702     while(*data && index) {
00703       if (XP_IS_SPACE_W(*data)){
00704         do {
00705           ++data;
00706           --index;
00707         }while(XP_IS_SPACE_W(*data) && index);
00708       }
00709       else {
00710         ++data;
00711         --index;
00712       }
00713       ++ci;
00714     }
00715   }
00716     
00717   return ci;
00718 }
00719 
00720 int UncompressIndex(int index, PRBool bRightAffinity, const nsTextFragment*fragment)
00721 {
00722   // XXX
00723   return index;
00724 }
00725 
00726 /* [noscript] void getHighlight (out unsigned long charnum, out unsigned long nchars, out nscolor foreground, out nscolor background); */
00727 NS_IMETHODIMP
00728 nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars, nscolor *foreground, nscolor *background)
00729 {
00730   *foreground = NS_RGB(255,255,255);
00731   *background = NS_RGB(0,0,0); 
00732   *charnum=0;
00733   *nchars=0;
00734 
00735     PRBool hasHighlight;
00736   GetHasHighlight(&hasHighlight);
00737 
00738   if (!hasHighlight) {
00739     NS_ERROR("nsSVGGlyphFrame::GetHighlight() called by renderer when there is no highlight");
00740     return NS_ERROR_FAILURE;
00741   }
00742 
00743   // XXX gcc 3.2.2 requires the explicit 'nsSVGGlyphFrameBase::' qualification
00744   nsIPresContext *presContext = nsSVGGlyphFrameBase::GetPresContext();
00745 
00746   nsCOMPtr<nsITextContent> tc = do_QueryInterface(mContent);
00747   NS_ASSERTION(tc, "no textcontent interface");
00748 
00749   // The selection ranges are relative to the uncompressed text in
00750   // the content element. We'll need the text fragment:
00751   const nsTextFragment*fragment=nsnull;
00752   tc->GetText(&fragment);
00753   NS_ASSERTION(fragment, "null text fragment");
00754 
00755   
00756   // get the selection details 
00757   SelectionDetails *details = nsnull;
00758   {
00759     nsCOMPtr<nsIFrameSelection> frameSelection;
00760     {
00761       nsCOMPtr<nsISelectionController> controller;
00762       GetSelectionController(presContext, getter_AddRefs(controller));
00763       
00764       if (!controller) {
00765         NS_ERROR("no selection controller");
00766         return NS_ERROR_FAILURE;
00767       }
00768       frameSelection = do_QueryInterface(controller);
00769     }
00770     if (!frameSelection) {
00771       nsCOMPtr<nsIPresShell> shell;
00772       presContext->GetShell(getter_AddRefs(shell));
00773       NS_ASSERTION(shell, "no presshell");
00774       shell->GetFrameSelection(getter_AddRefs(frameSelection));
00775     }
00776     if (!frameSelection) {
00777       NS_ERROR("no frameselection interface");
00778       return NS_ERROR_FAILURE;
00779     }
00780 
00781     PRInt32 length;
00782     tc->GetTextLength(&length);
00783     
00784     frameSelection->LookUpSelection(mContent, 0, length,
00785                                     &details, PR_FALSE);
00786   }
00787 
00788 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
00789   {
00790     SelectionDetails *dp = details;
00791     printf("nsSVGGlyphFrame(%p)::GetHighlight() [\n", this);
00792     while (dp) {
00793       printf("selection detail: %d(%d)->%d(%d) type %d\n",
00794              dp->mStart, CompressIndex(dp->mStart, fragment),
00795              dp->mEnd, CompressIndex(dp->mEnd, fragment),
00796              dp->mType);
00797       dp = dp->mNext;
00798     }
00799     printf("]\n");
00800       
00801   }
00802 #endif
00803   
00804   if (details) {
00805     NS_ASSERTION(details->mNext==nsnull, "can't do multiple selection ranges");
00806 
00807     *charnum=CompressIndex(details->mStart, fragment);
00808     *nchars=CompressIndex(details->mEnd, fragment)-*charnum;  
00809     
00810     nsCOMPtr<nsILookAndFeel> look;
00811     presContext->GetLookAndFeel(getter_AddRefs(look));
00812     NS_ASSERTION(look, "no LookAndFeel");
00813     if (look) {
00814       look->GetColor(nsILookAndFeel::eColor_TextSelectBackground, *background);
00815       look->GetColor(nsILookAndFeel::eColor_TextSelectForeground, *foreground);
00816     }
00817 
00818     SelectionDetails *dp = details;
00819     while ((dp=details->mNext) != nsnull) {
00820       delete details;
00821       details = dp;
00822     }
00823     delete details;
00824   }
00825   
00826   return NS_OK;
00827 }
00828 
00829 
00830 //----------------------------------------------------------------------
00831 // nsISVGGlyphFragmentLeaf interface:
00832 
00833 NS_IMETHODIMP_(void)
00834 nsSVGGlyphFrame::SetGlyphPosition(float x, float y)
00835 {
00836   mX = x;
00837   mY = y;
00838   UpdateGeometry(nsISVGGlyphGeometrySource::UPDATEMASK_X |
00839                  nsISVGGlyphGeometrySource::UPDATEMASK_Y);
00840 }
00841 
00842 NS_IMETHODIMP_(float)
00843 nsSVGGlyphFrame::GetGlyphPositionX()
00844 {
00845   return mX;
00846 }
00847 
00848 NS_IMETHODIMP_(float)
00849 nsSVGGlyphFrame::GetGlyphPositionY()
00850 {
00851   return mY;
00852 }
00853 
00854 
00855 NS_IMETHODIMP
00856 nsSVGGlyphFrame::GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics)
00857 {
00858   *metrics = mMetrics;
00859   NS_ADDREF(*metrics);
00860   return NS_OK;
00861 }
00862 
00863 NS_IMETHODIMP_(PRBool)
00864 nsSVGGlyphFrame::IsStartOfChunk()
00865 {
00866   // this fragment is a chunk if it has a corresponding absolute
00867   // position adjustment in an ancestors' x or y array. (At the moment
00868   // we don't map the full arrays, but only the first elements.)
00869 
00870   return PR_FALSE;
00871 }
00872 
00873 NS_IMETHODIMP_(void)
00874 nsSVGGlyphFrame::GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y)
00875 {
00876 }
00877 
00878 NS_IMETHODIMP_(PRUint32)
00879 nsSVGGlyphFrame::GetNumberOfChars()
00880 {
00881   return mCharacterData.Length();
00882 }
00883 
00884 NS_IMETHODIMP_(PRUint32)
00885 nsSVGGlyphFrame::GetCharNumberOffset()
00886 {
00887   return mCharOffset;
00888 }
00889 
00890 //----------------------------------------------------------------------
00891 // nsISVGGlyphFragmentNode interface:
00892 
00893 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
00894 nsSVGGlyphFrame::GetFirstGlyphFragment()
00895 {
00896   return this;
00897 }
00898 
00899 NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *)
00900 nsSVGGlyphFrame::GetNextGlyphFragment()
00901 {
00902   nsIFrame* sibling = mNextSibling;
00903   while (sibling) {
00904     nsISVGGlyphFragmentNode *node = nsnull;
00905     sibling->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00906     if (node)
00907       return node->GetFirstGlyphFragment();
00908     sibling->GetNextSibling(&sibling);
00909   }
00910 
00911   // no more siblings. go back up the tree.
00912   
00913   NS_ASSERTION(mParent, "null parent");
00914   nsISVGGlyphFragmentNode *node = nsnull;
00915   mParent->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode), (void**)&node);
00916   return node ? node->GetNextGlyphFragment() : nsnull;
00917 }
00918 
00919 NS_IMETHODIMP_(PRUint32)
00920 nsSVGGlyphFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch)
00921 {
00922   // XXX actually we should be building a new fragment for each chunk here...
00923 
00924 
00925   mCharOffset = charNum;
00926   nsCOMPtr<nsITextContent> tc = do_QueryInterface(mContent);
00927 
00928   PRInt32 length;
00929   tc->GetTextLength(&length);
00930   if (length==0) {
00931 #ifdef DEBUG
00932     printf("Glyph frame with zero length text\n");
00933 #endif
00934     mCharacterData = NS_LITERAL_STRING("");
00935     return charNum;
00936   }
00937   
00938   tc->CopyText(mCharacterData);
00939   mCharacterData.CompressWhitespace(charNum==0, lastBranch);
00940 
00941   return charNum+mCharacterData.Length();
00942 }
00943 
00944 NS_IMETHODIMP_(void)
00945 nsSVGGlyphFrame::NotifyMetricsSuspended()
00946 {
00947   // do nothing
00948 }
00949 
00950 NS_IMETHODIMP_(void)
00951 nsSVGGlyphFrame::NotifyMetricsUnsuspended()
00952 {
00953   NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::NotifyMetricsUnsuspended");
00954 
00955   if (mMetricsUpdateFlags != 0) {
00956     PRBool metricsDirty;
00957     mMetrics->Update(mMetricsUpdateFlags, &metricsDirty);
00958     if (metricsDirty) {
00959       mGeometryUpdateFlags |= nsISVGGlyphGeometrySource::UPDATEMASK_METRICS;
00960       nsISVGTextFrame* text_frame = GetTextFrame();
00961       NS_ASSERTION(text_frame, "null text frame");
00962       if (text_frame)
00963         text_frame->NotifyGlyphMetricsChange(this);
00964     }
00965     mMetricsUpdateFlags = 0;
00966   }   
00967 }
00968 
00969 NS_IMETHODIMP_(void)
00970 nsSVGGlyphFrame::NotifyGlyphFragmentTreeSuspended()
00971 {
00972   // do nothing
00973 }
00974 
00975 NS_IMETHODIMP_(void)
00976 nsSVGGlyphFrame::NotifyGlyphFragmentTreeUnsuspended()
00977 {
00978   if (mFragmentTreeDirty) {
00979     nsISVGTextFrame* text_frame = GetTextFrame();
00980     NS_ASSERTION(text_frame, "null text frame");
00981     if (text_frame)
00982       text_frame->NotifyGlyphFragmentTreeChange(this);
00983     mFragmentTreeDirty = PR_FALSE;
00984   }
00985 }
00986 
00987 
00988 
00989 //----------------------------------------------------------------------
00990 //
00991 
00992 void nsSVGGlyphFrame::UpdateGeometry(PRUint32 flags, PRBool bRedraw)
00993 {
00994   mGeometryUpdateFlags |= flags;
00995   
00996   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00997   if (!outerSVGFrame) {
00998     NS_ERROR("null outerSVGFrame");
00999     return;
01000   }
01001   
01002   PRBool suspended;
01003   outerSVGFrame->IsRedrawSuspended(&suspended);
01004   if (!suspended) {
01005     NS_ASSERTION(!mMetricsUpdateFlags, "dirty metrics in nsSVGGlyphFrame::UpdateGeometry");
01006     NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::UpdateGeometry");
01007     nsCOMPtr<nsISVGRendererRegion> dirty_region;
01008     mGeometry->Update(mGeometryUpdateFlags, getter_AddRefs(dirty_region));
01009     if (dirty_region)
01010       outerSVGFrame->InvalidateRegion(dirty_region, bRedraw);
01011     mGeometryUpdateFlags = 0;
01012   }  
01013 }
01014 
01015 void nsSVGGlyphFrame::UpdateMetrics(PRUint32 flags)
01016 {
01017   mMetricsUpdateFlags |= flags;
01018 
01019   nsISVGTextFrame* text_frame = GetTextFrame();
01020   if (!text_frame) {
01021     NS_ERROR("null text_frame");
01022     return;
01023   }
01024   
01025   PRBool suspended = text_frame->IsMetricsSuspended();
01026   if (!suspended) {
01027     NS_ASSERTION(!mFragmentTreeDirty, "dirty fragmenttree in nsSVGGlyphFrame::UpdateMetrics");
01028     PRBool metricsDirty;
01029     mMetrics->Update(mMetricsUpdateFlags, &metricsDirty);
01030     if (metricsDirty) {
01031       mGeometryUpdateFlags |= nsISVGGlyphGeometrySource::UPDATEMASK_METRICS;
01032       text_frame->NotifyGlyphMetricsChange(this);
01033     }
01034     mMetricsUpdateFlags = 0;
01035   }
01036 }
01037 
01038 void nsSVGGlyphFrame::UpdateFragmentTree()
01039 {
01040   mFragmentTreeDirty = PR_TRUE;
01041     
01042   nsISVGTextFrame* text_frame = GetTextFrame();
01043   if (!text_frame) {
01044     NS_ERROR("null text_frame");
01045     return;
01046   }
01047   
01048   PRBool suspended = text_frame->IsGlyphFragmentTreeSuspended();
01049   if (!suspended) {
01050     text_frame->NotifyGlyphFragmentTreeChange(this);
01051     mFragmentTreeDirty = PR_FALSE;
01052   }
01053 }
01054 
01055 nsISVGOuterSVGFrame *
01056 nsSVGGlyphFrame::GetOuterSVGFrame()
01057 {
01058   NS_ASSERTION(mParent, "null parent");
01059   
01060   nsISVGContainerFrame *containerFrame;
01061   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
01062   if (!containerFrame) {
01063     NS_ERROR("invalid container");
01064     return nsnull;
01065   }
01066 
01067   return containerFrame->GetOuterSVGFrame();  
01068 }
01069 
01070 nsISVGTextFrame *
01071 nsSVGGlyphFrame::GetTextFrame()
01072 {
01073   NS_ASSERTION(mParent, "null parent");
01074 
01075   nsISVGTextContainerFrame *containerFrame;
01076   mParent->QueryInterface(NS_GET_IID(nsISVGTextContainerFrame), (void**)&containerFrame);
01077   if (!containerFrame) {
01078     NS_ERROR("invalid container");
01079     return nsnull;
01080   }
01081 
01082   return containerFrame->GetTextFrame();
01083 }

Generated on Wed Sep 10 22:25:23 2003 for Mozilla SVG Project Rendering Backend by doxygen1.3