Back to index

lightning-sunbird  0.9+nobinonly
nsSVGOuterSVGFrame.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) 2001
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 "nsHTMLContainerFrame.h"
00040 #include "nsContainerFrame.h"
00041 #include "nsCSSRendering.h"
00042 #include "nsISVGSVGElement.h"
00043 #include "nsPresContext.h"
00044 #include "nsIDOMSVGAnimatedLength.h"
00045 #include "nsIDOMSVGLength.h"
00046 #include "nsISVGContainerFrame.h"
00047 #include "nsISVGChildFrame.h"
00048 #include "nsISVGOuterSVGFrame.h"
00049 #include "nsISVGRendererCanvas.h"
00050 #include "nsIView.h"
00051 #include "nsIViewManager.h"
00052 #include "nsWeakReference.h"
00053 #include "nsISVGValue.h"
00054 #include "nsISVGValueObserver.h"
00055 #include "nsHTMLParts.h"
00056 #include "nsReflowPath.h"
00057 #include "nsISVGRenderer.h"
00058 #include "nsISVGRendererRegion.h"
00059 #include "nsIServiceManager.h"
00060 #include "nsISVGRectangleSink.h"
00061 #include "nsISVGValueUtils.h"
00062 #include "nsIDOMSVGRect.h"
00063 #include "nsIDOMSVGNumber.h"
00064 #include "nsSVGCoordCtxProvider.h"
00065 #if defined(DEBUG) && defined(SVG_DEBUG_PRINTING)
00066 #include "nsIDeviceContext.h"
00067 #include "nsTransform2D.h"
00068 #endif
00069 #include "nsISVGEnum.h"
00070 #include "nsIDOMSVGPoint.h"
00071 #include "nsIDOMSVGZoomAndPan.h"
00072 #include "nsIDOMSVGAnimatedRect.h"
00073 #include "nsIDOMSVGFitToViewBox.h"
00074 #include "nsSVGRect.h"
00075 #include "nsLayoutAtoms.h"
00076 #include "nsIDocument.h"
00077 #ifdef XP_OS2
00078 #define INCL_WINWINDOWMGR
00079 #define INCL_GPIBITMAPS
00080 #include <os2.h>
00081 #include "cairo-os2.h"
00082 #endif
00083 
00085 // VMRectInvalidator: helper class for invalidating rects on the viewmanager.
00086 // used in nsSVGOuterSVGFrame::InvalidateRegion
00087 
00088 class VMRectInvalidator : public nsISVGRectangleSink
00089 {  
00090 protected:
00091   friend already_AddRefed<nsISVGRectangleSink> CreateVMRectInvalidator(nsIViewManager* vm,
00092                                                                        nsIView* view,
00093                                                                        int twipsPerPx);
00094   VMRectInvalidator(nsIViewManager* vm, nsIView* view, int twipsPerPx); 
00095 
00096 public:
00097   // nsISupports interface:
00098   NS_DECL_ISUPPORTS
00099 
00100   // nsISVGRectangleSink interface:
00101   NS_DECL_NSISVGRECTANGLESINK
00102 private:
00103   nsCOMPtr<nsIViewManager> mViewManager;
00104   nsIView* mView;
00105   int mTwipsPerPx;
00106 };
00107 
00108 //----------------------------------------------------------------------
00109 // Implementation:
00110 
00111 VMRectInvalidator::VMRectInvalidator(nsIViewManager* vm, nsIView* view,
00112                                      int twipsPerPx)
00113     : mViewManager(vm), mView(view), mTwipsPerPx(twipsPerPx)
00114 {
00115 }
00116 
00117 already_AddRefed<nsISVGRectangleSink>
00118 CreateVMRectInvalidator(nsIViewManager* vm, nsIView* view, int twipsPerPx)
00119 {
00120   nsISVGRectangleSink* retval = new VMRectInvalidator(vm, view, twipsPerPx);
00121   NS_IF_ADDREF(retval);
00122   return retval;
00123 }
00124 
00125 
00126 //----------------------------------------------------------------------
00127 // nsISupports methods:
00128 
00129 NS_IMPL_ADDREF(VMRectInvalidator)
00130 NS_IMPL_RELEASE(VMRectInvalidator)
00131 
00132 NS_INTERFACE_MAP_BEGIN(VMRectInvalidator)
00133   NS_INTERFACE_MAP_ENTRY(nsISVGRectangleSink)
00134   NS_INTERFACE_MAP_ENTRY(nsISupports)
00135 NS_INTERFACE_MAP_END
00136 
00137 //----------------------------------------------------------------------
00138 // nsISVGRectangleSink methods:
00139 
00140 /* void sinkRectangle (in float x, in float y, in float width, in float height); */
00141 NS_IMETHODIMP
00142 VMRectInvalidator::SinkRectangle(float x, float y, float width, float height)
00143 {
00144 #ifdef DEBUG
00145   // printf("invalidating %f %f %f %f\n", x,y,width,height);
00146 #endif
00147   nsRect rect((nscoord)(x*mTwipsPerPx), (nscoord)(y*mTwipsPerPx),
00148               (nscoord)(width*mTwipsPerPx), (nscoord)(height*mTwipsPerPx));
00149   mViewManager->UpdateView(mView, rect, NS_VMREFRESH_NO_SYNC);
00150   return NS_OK;
00151 }
00152 
00153 
00155 // nsSVGOuterSVGFrame class
00156 
00157 //typedef nsHTMLContainerFrame nsSVGOuterSVGFrameBase;
00158 typedef nsContainerFrame nsSVGOuterSVGFrameBase;
00159 
00160 class nsSVGOuterSVGFrame : public nsSVGOuterSVGFrameBase,
00161                            public nsISVGOuterSVGFrame,
00162                            public nsISVGContainerFrame,
00163                            public nsISVGValueObserver,
00164                            public nsSupportsWeakReference,
00165                            public nsSVGCoordCtxProvider
00166 {
00167   friend nsresult
00168   NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00169 protected:
00170   nsSVGOuterSVGFrame();
00171   virtual ~nsSVGOuterSVGFrame();
00172   nsresult Init();
00173   
00174    // nsISupports interface:
00175   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00176 private:
00177   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00178   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }  
00179 public:
00180   // nsIFrame:
00181   NS_IMETHOD Init(nsPresContext*  aPresContext,
00182                   nsIContent*      aContent,
00183                   nsIFrame*        aParent,
00184                   nsStyleContext*  aContext,
00185                   nsIFrame*        aPrevInFlow);
00186   
00187   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
00188                     nsHTMLReflowMetrics&     aDesiredSize,
00189                     const nsHTMLReflowState& aReflowState,
00190                     nsReflowStatus&          aStatus);
00191 
00192   NS_IMETHOD  DidReflow(nsPresContext*   aPresContext,
00193                         const nsHTMLReflowState*  aReflowState,
00194                         nsDidReflowStatus aStatus);
00195 
00196 
00197   NS_IMETHOD  AppendFrames(nsIAtom*        aListName,
00198                            nsIFrame*       aFrameList);
00199   NS_IMETHOD  InsertFrames(nsIAtom*        aListName,
00200                            nsIFrame*       aPrevFrame,
00201                            nsIFrame*       aFrameList);
00202   NS_IMETHOD  RemoveFrame(nsIAtom*        aListName,
00203                           nsIFrame*       aOldFrame);
00204   NS_IMETHOD  ReplaceFrame(nsIAtom*        aListName,
00205                            nsIFrame*       aOldFrame,
00206                            nsIFrame*       aNewFrame);
00207 
00208   NS_IMETHOD  AttributeChanged(nsIContent*     aChild,
00209                                PRInt32         aNameSpaceID,
00210                                nsIAtom*        aAttribute,
00211                                PRInt32         aModType);
00212 
00213   NS_IMETHOD  GetFrameForPoint(const nsPoint& aPoint, 
00214                                nsFramePaintLayer aWhichLayer,
00215                                nsIFrame**     aFrame);
00216 
00217   
00218   NS_IMETHOD  Paint(nsPresContext* aPresContext,
00219                     nsIRenderingContext& aRenderingContext,
00220                     const nsRect& aDirtyRect,
00221                     nsFramePaintLayer aWhichLayer,
00222                     PRUint32 aFlags = 0);
00223 
00224   PRBool CanPaintBackground() { return PR_FALSE; }
00225 
00231   virtual nsIAtom* GetType() const;
00232   virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
00233 
00234 #ifdef DEBUG
00235   NS_IMETHOD GetFrameName(nsAString& aResult) const
00236   {
00237     return MakeFrameName(NS_LITERAL_STRING("SVGOuterSVG"), aResult);
00238   }
00239 #endif
00240 
00241   // nsISVGValueObserver
00242   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00243                                      nsISVGValue::modificationType aModType);
00244   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00245                                      nsISVGValue::modificationType aModType);
00246 
00247   // nsISupportsWeakReference
00248   // implementation inherited from nsSupportsWeakReference
00249   
00250   // nsISVGOuterSVGFrame interface:
00251   NS_IMETHOD InvalidateRegion(nsISVGRendererRegion* region, PRBool bRedraw);
00252   NS_IMETHOD IsRedrawSuspended(PRBool* isSuspended);
00253   NS_IMETHOD GetRenderer(nsISVGRenderer**renderer);
00254 
00255   // nsISVGSVGFrame interface:
00256   NS_IMETHOD SuspendRedraw();
00257   NS_IMETHOD UnsuspendRedraw();
00258   NS_IMETHOD NotifyViewportChange();
00259   
00260   // nsISVGContainerFrame interface:
00261   nsISVGOuterSVGFrame*GetOuterSVGFrame();
00262   already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
00263   already_AddRefed<nsSVGCoordCtxProvider> GetCoordContextProvider();
00264   
00265 protected:
00266   // implementation helpers:
00267   void InitiateReflow();
00268   
00269   float GetPxPerTwips();
00270   float GetTwipsPerPx();
00271 
00272   void AddAsWidthHeightObserver();
00273   void RemoveAsWidthHeightObserver();
00274 
00275   void CalculateAvailableSpace(nsRect *maxRect, nsRect *preferredRect,
00276                                nsPresContext* aPresContext,
00277                                const nsHTMLReflowState& aReflowState);
00278   
00279 //  nsIView* mView;
00280   PRUint32 mRedrawSuspendCount;
00281   PRBool mNeedsReflow;
00282   PRBool mViewportInitialized;
00283   nsCOMPtr<nsISVGRenderer> mRenderer;
00284   nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
00285 
00286   // zoom and pan
00287   nsCOMPtr<nsISVGEnum>      mZoomAndPan;
00288   nsCOMPtr<nsIDOMSVGPoint>  mCurrentTranslate;
00289   nsCOMPtr<nsIDOMSVGNumber> mCurrentScale;
00290 };
00291 
00292 //----------------------------------------------------------------------
00293 // Implementation
00294 
00295 nsresult
00296 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00297 {
00298   *aNewFrame = nsnull;
00299   
00300   nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(aContent);
00301   if (!svgElement) {
00302 #ifdef DEBUG
00303     printf("warning: trying to construct an SVGOuterSVGFrame for a content element that doesn't support the right interfaces\n");
00304 #endif
00305     return NS_ERROR_FAILURE;
00306   }
00307 
00308   nsSVGOuterSVGFrame* it = new (aPresShell) nsSVGOuterSVGFrame;
00309   if (nsnull == it)
00310     return NS_ERROR_OUT_OF_MEMORY;
00311 
00312   *aNewFrame = it;
00313 
00314   return NS_OK;
00315 }
00316 
00317 nsSVGOuterSVGFrame::nsSVGOuterSVGFrame()
00318     : mRedrawSuspendCount(0),
00319       mNeedsReflow(PR_FALSE),
00320       mViewportInitialized(PR_FALSE)
00321 {
00322 #ifdef XP_OS2
00323   cairo_os2_initialize();
00324 #endif
00325 }
00326 
00327 nsSVGOuterSVGFrame::~nsSVGOuterSVGFrame()
00328 {
00329 #ifdef DEBUG
00330 //  printf("~nsSVGOuterSVGFrame %p\n", this);
00331 #endif
00332 
00333   if (mZoomAndPan)
00334     NS_REMOVE_SVGVALUE_OBSERVER(mZoomAndPan);
00335 
00336   RemoveAsWidthHeightObserver();
00337 
00338 #ifdef XP_OS2
00339   cairo_os2_uninitialize();
00340 #endif
00341 }
00342 
00343 nsresult nsSVGOuterSVGFrame::Init()
00344 {
00345 #if (defined(MOZ_SVG_RENDERER_GDIPLUS) + \
00346      defined(MOZ_SVG_RENDERER_LIBART) + \
00347      defined(MOZ_SVG_RENDERER_CAIRO) > 1)
00348 #error "Multiple SVG renderers. Please choose one manually."
00349 #elif defined(MOZ_SVG_RENDERER_GDIPLUS)  
00350   mRenderer = do_CreateInstance(NS_SVG_RENDERER_GDIPLUS_CONTRACTID);
00351 #elif defined(MOZ_SVG_RENDERER_LIBART)
00352   mRenderer = do_CreateInstance(NS_SVG_RENDERER_LIBART_CONTRACTID);
00353 #elif defined(MOZ_SVG_RENDERER_CAIRO)
00354   mRenderer = do_CreateInstance(NS_SVG_RENDERER_CAIRO_CONTRACTID);
00355 #else
00356 #error "No SVG renderer."
00357 #endif
00358   NS_ASSERTION(mRenderer, "could not get renderer");
00359 
00360   // we are an *outer* svg element, so this frame will become the
00361   // coordinate context for our content element:
00362   float mmPerPx = GetTwipsPerPx() / TWIPS_PER_POINT_FLOAT / (72.0f * 0.03937f);
00363   SetCoordCtxMMPerPx(mmPerPx, mmPerPx);
00364   
00365   nsCOMPtr<nsISVGSVGElement> SVGElement = do_QueryInterface(mContent);
00366   NS_ASSERTION(SVGElement, "wrong content element");
00367   SVGElement->SetParentCoordCtxProvider(this);
00368 
00369   // we only care about our content's zoom and pan values if it's the root element
00370   nsIDocument* doc = mContent->GetCurrentDoc();
00371   if (doc && doc->GetRootContent() == mContent) {
00372     SVGElement->GetZoomAndPanEnum(getter_AddRefs(mZoomAndPan));
00373     NS_ADD_SVGVALUE_OBSERVER(mZoomAndPan);
00374     SVGElement->GetCurrentTranslate(getter_AddRefs(mCurrentTranslate));
00375     SVGElement->GetCurrentScaleNumber(getter_AddRefs(mCurrentScale));
00376   }
00377 
00378   AddAsWidthHeightObserver();
00379   SuspendRedraw();
00380   return NS_OK;
00381 }
00382 
00383 //----------------------------------------------------------------------
00384 // nsISupports methods
00385 
00386 NS_INTERFACE_MAP_BEGIN(nsSVGOuterSVGFrame)
00387   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00388   NS_INTERFACE_MAP_ENTRY(nsISVGOuterSVGFrame)
00389   NS_INTERFACE_MAP_ENTRY(nsISVGSVGFrame)
00390   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00391   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00392   NS_INTERFACE_MAP_ENTRY(nsSVGCoordCtxProvider)
00393 NS_INTERFACE_MAP_END_INHERITING(nsSVGOuterSVGFrameBase)
00394 
00395 //----------------------------------------------------------------------
00396 // nsIFrame methods
00397 
00398 NS_IMETHODIMP
00399 nsSVGOuterSVGFrame::Init(nsPresContext*  aPresContext,
00400                          nsIContent*     aContent,
00401                          nsIFrame*       aParent,
00402                          nsStyleContext* aContext,
00403                          nsIFrame*       aPrevInFlow)
00404 {
00405   nsresult rv;
00406   rv = nsSVGOuterSVGFrameBase::Init(aPresContext, aContent, aParent,
00407                                     aContext, aPrevInFlow);
00408 
00409   Init();
00410 
00411   return rv;
00412 }
00413 
00414 
00415   
00416 //----------------------------------------------------------------------
00417 // reflowing
00418 
00419 NS_IMETHODIMP
00420 nsSVGOuterSVGFrame::Reflow(nsPresContext*          aPresContext,
00421                            nsHTMLReflowMetrics&     aDesiredSize,
00422                            const nsHTMLReflowState& aReflowState,
00423                            nsReflowStatus&          aStatus)
00424 {
00425 #if defined(DEBUG) && defined(SVG_DEBUG_PRINTING)
00426   {
00427     printf("nsSVGOuterSVGFrame(%p)::Reflow()[\n",this);
00428     float twipsPerScPx = aPresContext->ScaledPixelsToTwips();
00429     float twipsPerPx = aPresContext->PixelsToTwips();
00430     printf("tw/sc(px)=%f tw/px=%f\n", twipsPerScPx, twipsPerPx);
00431     printf("]\n");
00432   }
00433 #endif
00434   
00435   // check whether this reflow request is targeted at us or a child
00436   // frame (e.g. a foreignObject):
00437   if (aReflowState.reason == eReflowReason_Incremental) {
00438     nsReflowPath::iterator iter = aReflowState.path->FirstChild();
00439     nsReflowPath::iterator end = aReflowState.path->EndChildren();
00440 
00441     for ( ; iter != end; ++iter) {
00442       // The actual target of this reflow is one of our child
00443       // frames. Since SVG as such doesn't use reflow, this will
00444       // probably be the child of a <foreignObject>. Some HTML|XUL
00445       // content frames target reflow events at themselves when they
00446       // need to be redrawn in response to e.g. a style change. For
00447       // correct visual updating, we must make sure the reflow
00448       // reaches its intended target.
00449         
00450       // Since it is an svg frame (probably an nsSVGForeignObjectFrame),
00451       // we might as well pass in our aDesiredSize and aReflowState
00452       // objects - they are ignored by svg frames:
00453       nsSize availSpace(0, 0); // XXXwaterson probably wrong!
00454       nsHTMLReflowState state(aPresContext, aReflowState, *iter, availSpace);
00455       (*iter)->Reflow (aPresContext,
00456                        aDesiredSize,
00457                        state,
00458                        aStatus);
00459 
00460       // XXX do we really have to return our metrics although we're
00461       // not affected by the reflow? Is there a way of telling our
00462       // parent that we don't want anything changed?
00463       aDesiredSize.width  = mRect.width;
00464       aDesiredSize.height = mRect.height;
00465       aDesiredSize.ascent = aDesiredSize.height;
00466       aDesiredSize.descent = 0;
00467     }
00468 
00469     if (! aReflowState.path->mReflowCommand) {
00470       // We're not the target of the incremental reflow, so just bail.
00471       aStatus = NS_FRAME_COMPLETE;
00472       return NS_OK;
00473     }
00474   }
00475   
00476   //  SVG CR 20001102: When the SVG content is embedded inline within
00477   //  a containing document, and that document is styled using CSS,
00478   //  then if there are CSS positioning properties specified on the
00479   //  outermost 'svg' element that are sufficient to establish the
00480   //  width of the viewport, then these positioning properties
00481   //  establish the viewport's width; otherwise, the width attribute
00482   //  on the outermost 'svg' element establishes the viewport's width.
00483   //  Similarly, if there are CSS positioning properties specified on
00484   //  the outermost 'svg' element that are sufficient to establish the
00485   //  height of the viewport, then these positioning properties
00486   //  establish the viewport's height; otherwise, the height attribute
00487   //  on the outermost 'svg' element establishes the viewport's
00488   //  height.
00489 #ifdef DEBUG
00490   // printf("--- nsSVGOuterSVGFrame(%p)::Reflow(frame:%p,reason:%d) ---\n",this,aReflowState.frame,aReflowState.reason);
00491 #endif
00492   
00493   nsCOMPtr<nsISVGSVGElement> SVGElement = do_QueryInterface(mContent);
00494   NS_ENSURE_TRUE(SVGElement, NS_ERROR_FAILURE);
00495 
00496   float pxPerTwips = GetPxPerTwips();
00497   float twipsPerPx = GetTwipsPerPx();
00498 
00499   // The width/height attribs given on the <svg>-element might be
00500   // percentage values of the parent viewport. We will set the parent
00501   // coordinate context dimensions to the available space.
00502 
00503   nsRect maxRect, preferredRect;
00504   CalculateAvailableSpace(&maxRect, &preferredRect, aPresContext, aReflowState);
00505   float preferredWidth = preferredRect.width * pxPerTwips;
00506   float preferredHeight = preferredRect.height * pxPerTwips;
00507 
00508   SuspendRedraw(); 
00509   
00510   // As soon as we set the coordinate context, the width/height
00511   // attributes might emit change-notifications. We don't want those
00512   // right now:
00513   RemoveAsWidthHeightObserver();
00514 
00515   nsCOMPtr<nsIDOMSVGRect> r;
00516   NS_NewSVGRect(getter_AddRefs(r), 0, 0, preferredWidth, preferredHeight);
00517   SetCoordCtxRect(r);
00518   
00519 #ifdef DEBUG
00520   // some debug stuff:
00521 //   {
00522 //     nsRect r=aPresContext->GetVisibleArea();
00523 //     printf("******* aw: %d, ah: %d visiw: %d, visih: %d\n",
00524 //            aReflowState.availableWidth,
00525 //            aReflowState.availableHeight,
00526 //            r.width, r.height);
00527 //     printf("******* cw: %d, ch: %d \n    cmaxw: %d, cmaxh: %d\n",
00528 //            aReflowState.mComputedWidth,
00529 //            aReflowState.mComputedHeight,
00530 //            aReflowState.mComputedMaxWidth,
00531 //            aReflowState.mComputedMaxHeight);
00532 
00533 //     if (aReflowState.parentReflowState) {
00534 //       printf("******* parent aw: %d, parent ah: %d \n",
00535 //              aReflowState.parentReflowState->availableWidth,
00536 //              aReflowState.parentReflowState->availableHeight);
00537 //       printf("******* parent cw: %d, parent ch: %d \n  parent cmaxw: %d, parent cmaxh: %d\n",
00538 //              aReflowState.parentReflowState->mComputedWidth,
00539 //              aReflowState.parentReflowState->mComputedHeight,
00540 //              aReflowState.parentReflowState->mComputedMaxWidth,
00541 //              aReflowState.parentReflowState->mComputedMaxHeight);
00542 //     }
00543 //   }
00544 #endif
00545 
00546   // now that the parent coord ctx dimensions have been set, the
00547   // width/height attributes will be valid.
00548   // Let's work out our desired dimensions.
00549 
00550   float width;
00551   {
00552     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
00553     SVGElement->GetWidth(getter_AddRefs(animLength));
00554     NS_ENSURE_TRUE(animLength, NS_ERROR_FAILURE);
00555     nsCOMPtr<nsIDOMSVGLength> length;
00556     animLength->GetAnimVal(getter_AddRefs(length));
00557     NS_ENSURE_TRUE(length, NS_ERROR_FAILURE);
00558     
00559     length->GetValue(&width);
00560     
00561     aDesiredSize.width = (int)(width*twipsPerPx);
00562   }
00563 
00564   float height;
00565   {
00566     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
00567     SVGElement->GetHeight(getter_AddRefs(animLength));
00568     NS_ENSURE_TRUE(animLength, NS_ERROR_FAILURE);
00569     nsCOMPtr<nsIDOMSVGLength> length;
00570     animLength->GetAnimVal(getter_AddRefs(length));
00571     NS_ENSURE_TRUE(length, NS_ERROR_FAILURE);
00572     
00573     length->GetValue(&height);
00574     
00575     aDesiredSize.height = (int)(height*twipsPerPx);
00576   }
00577   
00578 
00579   aDesiredSize.ascent = aDesiredSize.height;
00580   aDesiredSize.descent = 0;
00581   
00582   // XXX add in CSS borders ??
00583 
00584   aStatus = NS_FRAME_COMPLETE;
00585   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00586 
00587   AddAsWidthHeightObserver();
00588   
00589   UnsuspendRedraw();
00590   
00591   return NS_OK;
00592 }
00593 
00594 NS_IMETHODIMP
00595 nsSVGOuterSVGFrame::DidReflow(nsPresContext*   aPresContext,
00596                               const nsHTMLReflowState*  aReflowState,
00597                               nsDidReflowStatus aStatus)
00598 {
00599   nsresult rv = nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus);
00600 
00601   if (!mViewportInitialized) {
00602     // it is now
00603     mViewportInitialized = PR_TRUE;
00604 
00605     // call InitialUpdate() on all frames:
00606     nsIFrame* kid = mFrames.FirstChild();
00607     while (kid) {
00608       nsISVGChildFrame* SVGFrame=nsnull;
00609       kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00610       if (SVGFrame) {
00611         SVGFrame->InitialUpdate(); 
00612       }
00613       kid = kid->GetNextSibling();
00614     }
00615     
00616     UnsuspendRedraw();
00617   }
00618   
00619   return rv;
00620 }
00621 
00622 //----------------------------------------------------------------------
00623 // container methods
00624 
00625 NS_IMETHODIMP
00626 nsSVGOuterSVGFrame::AppendFrames(nsIAtom*        aListName,
00627                                  nsIFrame*       aFrameList)
00628 {
00629   // append == insert at end:
00630   return InsertFrames(aListName, mFrames.LastChild(), aFrameList);  
00631 }
00632 
00633 NS_IMETHODIMP
00634 nsSVGOuterSVGFrame::InsertFrames(nsIAtom*        aListName,
00635                                  nsIFrame*       aPrevFrame,
00636                                  nsIFrame*       aFrameList)
00637 {
00638   // memorize last new frame
00639   nsIFrame* lastNewFrame = nsnull;
00640   {
00641     nsFrameList tmpList(aFrameList);
00642     lastNewFrame = tmpList.LastChild();
00643   }
00644   
00645   // Insert the new frames
00646   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
00647 
00648   SuspendRedraw();
00649 
00650   // call InitialUpdate() on all new frames:
00651   
00652   nsIFrame* end = nsnull;
00653   if (lastNewFrame)
00654     end = lastNewFrame->GetNextSibling();
00655 
00656   for (nsIFrame* kid = aFrameList; kid != end;
00657        kid = kid->GetNextSibling()) {
00658     nsISVGChildFrame* SVGFrame=nsnull;
00659     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00660     if (SVGFrame) {
00661       SVGFrame->InitialUpdate(); 
00662     }
00663   }
00664 
00665   UnsuspendRedraw();
00666   
00667   return NS_OK;
00668 }
00669 
00670 NS_IMETHODIMP
00671 nsSVGOuterSVGFrame::RemoveFrame(nsIAtom*        aListName,
00672                                 nsIFrame*       aOldFrame)
00673 {
00674   nsCOMPtr<nsISVGRendererRegion> dirty_region;
00675   
00676   nsISVGChildFrame* SVGFrame=nsnull;
00677   aOldFrame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00678 
00679   if (SVGFrame)
00680     dirty_region = SVGFrame->GetCoveredRegion();
00681 
00682   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00683 
00684   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00685   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
00686   if (dirty_region && outerSVGFrame)
00687     outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00688 
00689   NS_ASSERTION(result, "didn't find frame to delete");
00690   return result ? NS_OK : NS_ERROR_FAILURE;
00691 }
00692 
00693 NS_IMETHODIMP
00694 nsSVGOuterSVGFrame::ReplaceFrame(nsIAtom*        aListName,
00695                                  nsIFrame*       aOldFrame,
00696                                  nsIFrame*       aNewFrame)
00697 {
00698   NS_NOTYETIMPLEMENTED("nsSVGOuterSVGFrame::ReplaceFrame");
00699   return NS_ERROR_NOT_IMPLEMENTED;
00700 }
00701 
00702 NS_IMETHODIMP
00703 nsSVGOuterSVGFrame::AttributeChanged(nsIContent*     aChild,
00704                                      PRInt32         aNameSpaceID,
00705                                      nsIAtom*        aAttribute,
00706                                      PRInt32         aModType)
00707 {
00708 #ifdef DEBUG
00709 //  {
00710 //    nsAutoString str;
00711 //    aAttribute->ToString(str);
00712 //    printf("** nsSVGOuterSVGFrame::AttributeChanged(%s)\n",
00713 //           NS_LossyConvertUCS2toASCII(str).get());
00714 //  }
00715 #endif
00716   return NS_OK;
00717 }
00718 
00719 
00720 nsresult
00721 nsSVGOuterSVGFrame::GetFrameForPoint(const nsPoint& aPoint,
00722                                      nsFramePaintLayer aWhichLayer,
00723                                      nsIFrame**     aFrame)
00724 {
00725   // XXX This algorithm is really bad. Because we only have a
00726   // singly-linked list we have to test each and every SVG element for
00727   // a hit. What we really want is a double-linked list.
00728   
00729 
00730   *aFrame = nsnull;
00731   if (aWhichLayer != NS_FRAME_PAINT_LAYER_FOREGROUND) return NS_ERROR_FAILURE;
00732   
00733   float x = GetPxPerTwips() * ( aPoint.x - mRect.x);
00734   float y = GetPxPerTwips() * ( aPoint.y - mRect.y);
00735   
00736   PRBool inThisFrame = mRect.Contains(aPoint);
00737   
00738   if (!inThisFrame || !mRenderer) {
00739     return NS_ERROR_FAILURE;
00740   }
00741 
00742   *aFrame = this;
00743   nsIFrame* hit = nsnull;
00744   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00745        kid = kid->GetNextSibling()) {
00746     nsISVGChildFrame* SVGFrame=nsnull;
00747     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00748     if (SVGFrame) {
00749       nsresult rv = SVGFrame->GetFrameForPointSVG(x, y, &hit);
00750       if (NS_SUCCEEDED(rv) && hit) {
00751         *aFrame = hit;
00752         // return NS_OK; can't return. we need reverse order but only
00753         // have a singly linked list...
00754       }
00755     }
00756   }
00757     
00758   return NS_OK;
00759 }
00760 
00761 
00762 
00763 //----------------------------------------------------------------------
00764 // painting
00765 
00766 NS_IMETHODIMP
00767 nsSVGOuterSVGFrame::Paint(nsPresContext* aPresContext,
00768                           nsIRenderingContext& aRenderingContext,
00769                           const nsRect& aDirtyRect,
00770                           nsFramePaintLayer aWhichLayer,
00771                           PRUint32 aFlags)
00772 {
00773   
00774 //    if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00775 //      if (GetStyleDisplay()->IsVisible() && mRect.width && mRect.height) {
00776 //        // Paint our background and border
00777 //        const nsStyleBorder* border = GetStyleBorder();
00778 //        const nsStylePadding* padding = GetStylePadding();
00779 //        const nsStyleOutline* outline = GetStyleOutline();
00780 
00781 //        nsRect  rect(0, 0, mRect.width, mRect.height);
00782 // //       nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
00783 // //                                       aDirtyRect, rect, *border, *padding, PR_TRUE);
00784 //        nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
00785 //                                    aDirtyRect, rect, *border, mStyleContext, 0);
00786 //        nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
00787 //                                    aDirtyRect, rect, *border, *outline, mStyleContext, 0);
00788       
00789 //      }
00790 //    }
00791 
00792   if (aWhichLayer != NS_FRAME_PAINT_LAYER_FOREGROUND) return NS_OK;
00793   if (aDirtyRect.width<=0 || aDirtyRect.height<=0) return NS_OK;
00794 
00795 #if defined(DEBUG) && defined(SVG_DEBUG_PRINTING)
00796   {
00797     nsCOMPtr<nsIDeviceContext>  dx;
00798     aRenderingContext.GetDeviceContext(*getter_AddRefs(dx));
00799     float zoom,tzoom,scale;
00800     dx->GetZoom(zoom);
00801     dx->GetTextZoom(tzoom);
00802     dx->GetCanonicalPixelScale(scale);
00803     printf("nsSVGOuterSVGFrame(%p)::Paint()[ z=%f tz=%f ps=%f\n",this,zoom,tzoom,scale);
00804     printf("dirtyrect= %d, %d, %d, %d\n", aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
00805     nsTransform2D* xform;
00806     aRenderingContext.GetCurrentTransform(xform);
00807     printf("translation=(%f,%f)\n", xform->GetXTranslation(), xform->GetYTranslation());
00808     float sx=1.0f,sy=1.0f;
00809     xform->TransformNoXLate(&sx,&sy);
00810     printf("scale=(%f,%f)\n", sx, sy);
00811     float twipsPerScPx = aPresContext->ScaledPixelsToTwips();
00812     float twipsPerPx = aPresContext->PixelsToTwips();
00813     printf("tw/sc(px)=%f tw/px=%f\n", twipsPerScPx, twipsPerPx);
00814     int fontsc;
00815     aPresContext->GetFontScaler(&fontsc);
00816     printf("font scale=%d\n",fontsc);
00817     printf("]\n");
00818   }
00819 #endif
00820   
00821   // initialize Mozilla rendering context
00822   aRenderingContext.PushState();
00823   
00824   aRenderingContext.SetClipRect(aDirtyRect, nsClipCombine_kIntersect);
00825 
00826 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
00827   PRTime start = PR_Now();
00828 #endif
00829 
00830   float pxPerTwips = GetPxPerTwips();
00831   int x0 = (int)(aDirtyRect.x*pxPerTwips);
00832   int y0 = (int)(aDirtyRect.y*pxPerTwips);
00833   int x1 = (int)ceil((aDirtyRect.x+aDirtyRect.width)*pxPerTwips);
00834   int y1 = (int)ceil((aDirtyRect.y+aDirtyRect.height)*pxPerTwips);
00835   NS_ASSERTION(x0>=0 && y0>=0, "unexpected negative coordinates");
00836   NS_ASSERTION(x1-x0>0 && y1-y0>0, "zero sized dirtyRect");
00837   nsRect dirtyRectPx(x0, y0, x1-x0, y1-y0);
00838 
00839   // If we don't have a renderer due to the component failing
00840   // to load (gdi+ or cairo not available), indicate to the user
00841   // what's going on by drawing a red "X" at the appropriate spot.
00842   if (!mRenderer) {
00843     aRenderingContext.SetColor(NS_RGB(255,0,0));
00844     aRenderingContext.DrawLine(mRect.x, mRect.y,
00845                                mRect.x + mRect.width, mRect.y + mRect.height);
00846     aRenderingContext.DrawLine(mRect.x + mRect.width, mRect.y,
00847                                mRect.x, mRect.y + mRect.height);
00848     aRenderingContext.PopState();
00849     return NS_OK;
00850   }
00851 
00852   nsCOMPtr<nsISVGRendererCanvas> canvas;
00853   mRenderer->CreateCanvas(&aRenderingContext, aPresContext, dirtyRectPx,
00854                           getter_AddRefs(canvas));
00855 
00856   // paint children:
00857   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00858        kid = kid->GetNextSibling()) {
00859     nsISVGChildFrame* SVGFrame=nsnull;
00860     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00861     if (SVGFrame)
00862       SVGFrame->PaintSVG(canvas, aDirtyRect);
00863   }
00864   
00865   canvas->Flush();
00866 
00867   canvas = nsnull;
00868 
00869 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
00870   PRTime end = PR_Now();
00871   printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
00872 #endif
00873   
00874   aRenderingContext.PopState();
00875   
00876   return NS_OK;
00877   // see if we have to draw a selection frame around this container
00878   //return nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
00879 }
00880 
00881 nsIAtom *
00882 nsSVGOuterSVGFrame::GetType() const
00883 {
00884   return nsLayoutAtoms::svgOuterSVGFrame;
00885 }
00886 
00887 PRBool
00888 nsSVGOuterSVGFrame::IsFrameOfType(PRUint32 aFlags) const
00889 {
00890   return !(aFlags & ~nsIFrame::eSVG);
00891 }
00892 
00893 //----------------------------------------------------------------------
00894 // nsISVGValueObserver methods:
00895 
00896 NS_IMETHODIMP
00897 nsSVGOuterSVGFrame::WillModifySVGObservable(nsISVGValue* observable,
00898                                             nsISVGValue::modificationType aModType)
00899 {
00900   return NS_OK;
00901 }
00902 
00903 
00904 NS_IMETHODIMP
00905 nsSVGOuterSVGFrame::DidModifySVGObservable(nsISVGValue* observable,
00906                                            nsISVGValue::modificationType aModType)
00907 {
00908   mNeedsReflow = PR_TRUE;
00909   if (mRedrawSuspendCount==0) {
00910     InitiateReflow();
00911   }
00912   
00913   return NS_OK;
00914 }
00915 
00916 
00917 //----------------------------------------------------------------------
00918 // nsISVGOuterSVGFrame methods:
00919 
00920 NS_IMETHODIMP
00921 nsSVGOuterSVGFrame::InvalidateRegion(nsISVGRendererRegion* region, PRBool bRedraw)
00922 {
00923 //  NS_ASSERTION(mView, "need a view!");
00924 //  if (!mView) return NS_ERROR_FAILURE;
00925   
00926   if (!region && !bRedraw) return NS_OK;
00927 
00928   // just ignore invalidates if painting is suppressed by the shell
00929   PRBool suppressed = PR_FALSE;
00930   GetPresContext()->PresShell()->IsPaintingSuppressed(&suppressed);
00931   if (suppressed) return NS_OK;
00932   
00933   nsIView* view = GetClosestView();
00934   NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
00935 
00936   nsIViewManager* vm = view->GetViewManager();
00937 
00938   vm->BeginUpdateViewBatch();
00939   if (region) {
00940     nsCOMPtr<nsISVGRectangleSink> sink = CreateVMRectInvalidator(vm, view,
00941                                                                  (int)(GetTwipsPerPx()+0.5f));
00942     NS_ASSERTION(sink, "could not create rectangle sink for viewmanager");
00943     if (sink)
00944       region->GetRectangleScans(sink);
00945   }
00946   vm->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
00947   
00948   return NS_OK;
00949 }
00950 
00951 NS_IMETHODIMP
00952 nsSVGOuterSVGFrame::IsRedrawSuspended(PRBool* isSuspended)
00953 {
00954   *isSuspended = (mRedrawSuspendCount>0) || !mViewportInitialized;
00955   return NS_OK;
00956 }
00957 
00958 NS_IMETHODIMP
00959 nsSVGOuterSVGFrame::GetRenderer(nsISVGRenderer**renderer)
00960 {
00961   *renderer = mRenderer;
00962   NS_IF_ADDREF(*renderer);
00963   return NS_OK;
00964 }
00965 
00966 //----------------------------------------------------------------------
00967 // nsISVGSVGFrame methods:
00968 
00969 
00970 NS_IMETHODIMP
00971 nsSVGOuterSVGFrame::SuspendRedraw()
00972 {
00973   if (!mRenderer)
00974     return NS_OK;
00975 
00976 #ifdef DEBUG
00977   //printf("suspend redraw (count=%d)\n", mRedrawSuspendCount);
00978 #endif
00979   if (++mRedrawSuspendCount != 1)
00980     return NS_OK;
00981 
00982   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00983        kid = kid->GetNextSibling()) {
00984     nsISVGChildFrame* SVGFrame=nsnull;
00985     CallQueryInterface(kid, &SVGFrame);
00986     if (SVGFrame) {
00987       SVGFrame->NotifyRedrawSuspended();
00988     }
00989   }
00990   return NS_OK;
00991 }
00992 
00993 NS_IMETHODIMP
00994 nsSVGOuterSVGFrame::UnsuspendRedraw()
00995 {
00996   if (!mRenderer)
00997     return NS_OK;
00998 
00999 #ifdef DEBUG
01000 //  printf("unsuspend redraw (count=%d)\n", mRedrawSuspendCount);
01001 #endif
01002   if (--mRedrawSuspendCount > 0)
01003     return NS_OK;
01004   
01005   NS_ASSERTION(mRedrawSuspendCount >=0, "unbalanced suspend count!");
01006   
01007   // If we need to reflow, do so before we update any of our
01008   // children. Reflows are likely to affect the display of children:
01009   if (mNeedsReflow)
01010     InitiateReflow();
01011   
01012   for (nsIFrame* kid = mFrames.FirstChild(); kid;
01013        kid = kid->GetNextSibling()) {
01014     nsISVGChildFrame* SVGFrame=nsnull;
01015     CallQueryInterface(kid, &SVGFrame);
01016     if (SVGFrame) {
01017       SVGFrame->NotifyRedrawUnsuspended();
01018     }
01019   }
01020 
01021   return NS_OK;
01022 }
01023 
01024 NS_IMETHODIMP
01025 nsSVGOuterSVGFrame::NotifyViewportChange()
01026 {
01027   if (!mRenderer)
01028     return NS_OK;
01029 
01030   // no point in doing anything when were not init'ed yet:
01031   if (!mViewportInitialized) return NS_OK;
01032 
01033   // make sure canvas transform matrix gets (lazily) recalculated:
01034   mCanvasTM = nsnull;
01035   
01036   // inform children
01037   SuspendRedraw();
01038   nsIFrame* kid = mFrames.FirstChild();
01039   while (kid) {
01040     nsISVGChildFrame* SVGFrame=nsnull;
01041     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
01042     if (SVGFrame)
01043       SVGFrame->NotifyCanvasTMChanged(); 
01044     kid = kid->GetNextSibling();
01045   }
01046   UnsuspendRedraw();
01047   return NS_OK;
01048 }
01049 
01050 //----------------------------------------------------------------------
01051 // nsISVGContainerFrame methods:
01052 
01053 nsISVGOuterSVGFrame *
01054 nsSVGOuterSVGFrame::GetOuterSVGFrame()
01055 {
01056   return this;
01057 }
01058 
01059 already_AddRefed<nsIDOMSVGMatrix>
01060 nsSVGOuterSVGFrame::GetCanvasTM()
01061 {
01062   if (!mCanvasTM) {
01063     nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(mContent);
01064     NS_ASSERTION(svgElement, "wrong content element");
01065     svgElement->GetViewboxToViewportTransform(getter_AddRefs(mCanvasTM));
01066 
01067     if (mZoomAndPan) {
01068       // our content is the document element so we must premultiply the values
01069       // of it's currentScale and currentTranslate properties
01070       PRUint16 val;
01071       mZoomAndPan->GetIntegerValue(val);
01072       if (val == nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY) {
01073         nsCOMPtr<nsIDOMSVGMatrix> zoomPanMatrix;
01074         nsCOMPtr<nsIDOMSVGMatrix> temp;
01075         float scale, x, y;
01076         mCurrentScale->GetValue(&scale);
01077         mCurrentTranslate->GetX(&x);
01078         mCurrentTranslate->GetY(&y);
01079         svgElement->CreateSVGMatrix(getter_AddRefs(zoomPanMatrix));
01080         zoomPanMatrix->Translate(x, y, getter_AddRefs(temp));
01081         temp->Scale(scale, getter_AddRefs(zoomPanMatrix));
01082         zoomPanMatrix->Multiply(mCanvasTM, getter_AddRefs(temp));
01083         temp.swap(mCanvasTM);
01084       }
01085     }
01086   }
01087   nsIDOMSVGMatrix* retval = mCanvasTM.get();
01088   NS_IF_ADDREF(retval);
01089   return retval;
01090 }
01091 
01092 already_AddRefed<nsSVGCoordCtxProvider>
01093 nsSVGOuterSVGFrame::GetCoordContextProvider()
01094 {
01095   NS_ASSERTION(mContent, "null parent");
01096 
01097   // Our <svg> content element is the CoordContextProvider for our children:
01098   nsSVGCoordCtxProvider *provider;
01099   CallQueryInterface(mContent, &provider);
01100 
01101   return provider;  
01102 }
01103 
01104 //----------------------------------------------------------------------
01105 // Implementation helpers
01106 
01107 float nsSVGOuterSVGFrame::GetPxPerTwips()
01108 {
01109   float val = GetTwipsPerPx();
01110   
01111   NS_ASSERTION(val!=0.0f, "invalid px/twips");  
01112   if (val == 0.0) val = 1e-20f;
01113   
01114   return 1.0f/val;
01115 }
01116 
01117 float nsSVGOuterSVGFrame::GetTwipsPerPx()
01118 {
01119   return GetPresContext()->ScaledPixelsToTwips();
01120 }
01121 
01122 void nsSVGOuterSVGFrame::InitiateReflow()
01123 {
01124   mNeedsReflow = PR_FALSE;
01125   
01126   // Generate a reflow command to reflow ourselves
01127   nsIPresShell* presShell = GetPresContext()->PresShell();
01128   presShell->AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull);
01129   // XXXbz why is this synchronously flushing reflows, exactly?  If it
01130   // needs to, why is it not using the presshell's reflow batching
01131   // instead of hacking its own?
01132   presShell->FlushPendingNotifications(Flush_OnlyReflow);  
01133 }
01134 
01135 
01136 void nsSVGOuterSVGFrame::AddAsWidthHeightObserver()
01137 {
01138   nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(mContent);
01139   NS_ASSERTION(svgElement, "wrong content element");  
01140  
01141   {
01142     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
01143     svgElement->GetWidth(getter_AddRefs(animLength));
01144     NS_ASSERTION(animLength, "could not get <svg>:width");
01145     nsCOMPtr<nsIDOMSVGLength> length;
01146     animLength->GetAnimVal(getter_AddRefs(length));
01147     NS_ASSERTION(length, "could not get <svg>:width:animval");
01148     NS_ADD_SVGVALUE_OBSERVER(length);
01149   }
01150 
01151   {
01152     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
01153     svgElement->GetHeight(getter_AddRefs(animLength));
01154     NS_ASSERTION(animLength, "could not get <svg>:height");
01155     nsCOMPtr<nsIDOMSVGLength> length;
01156     animLength->GetAnimVal(getter_AddRefs(length));
01157     NS_ASSERTION(length, "could not get <svg>:height:animval");
01158     NS_ADD_SVGVALUE_OBSERVER(length);
01159   }  
01160 }
01161 
01162 void nsSVGOuterSVGFrame::RemoveAsWidthHeightObserver()
01163 {
01164   nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(mContent);
01165   NS_ASSERTION(svgElement, "wrong content element");  
01166 
01167   {
01168     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
01169     svgElement->GetWidth(getter_AddRefs(animLength));
01170     NS_ASSERTION(animLength, "could not get <svg>:width");
01171     nsCOMPtr<nsIDOMSVGLength> length;
01172     animLength->GetAnimVal(getter_AddRefs(length));
01173     NS_ASSERTION(length, "could not get <svg>:width:animval");
01174     NS_REMOVE_SVGVALUE_OBSERVER(length);
01175   }
01176 
01177   {
01178     nsCOMPtr<nsIDOMSVGAnimatedLength> animLength;
01179     svgElement->GetHeight(getter_AddRefs(animLength));
01180     NS_ASSERTION(animLength, "could not get <svg>:height");
01181     nsCOMPtr<nsIDOMSVGLength> length;
01182     animLength->GetAnimVal(getter_AddRefs(length));
01183     NS_ASSERTION(length, "could not get <svg>:height:animval");
01184     NS_REMOVE_SVGVALUE_OBSERVER(length);
01185   }  
01186 }
01187 
01188 void
01189 nsSVGOuterSVGFrame::CalculateAvailableSpace(nsRect *maxRect,
01190                                             nsRect *preferredRect,
01191                                             nsPresContext* aPresContext,
01192                                             const nsHTMLReflowState& aReflowState)
01193 {
01194   *preferredRect = aPresContext->GetVisibleArea();
01195   
01196   if (aReflowState.availableWidth != NS_INTRINSICSIZE)
01197     maxRect->width = aReflowState.availableWidth;
01198   else if (aReflowState.parentReflowState &&
01199            aReflowState.parentReflowState->mComputedWidth != NS_INTRINSICSIZE)
01200     maxRect->width = aReflowState.parentReflowState->mComputedWidth;
01201   else
01202     maxRect->width = NS_MAXSIZE;
01203   
01204   if (aReflowState.availableHeight != NS_INTRINSICSIZE)
01205     maxRect->height = aReflowState.availableHeight;    
01206   else if (aReflowState.parentReflowState &&
01207            aReflowState.parentReflowState->mComputedHeight != NS_INTRINSICSIZE)
01208     maxRect->height = aReflowState.parentReflowState->mComputedHeight;
01209   else
01210     maxRect->height = NS_MAXSIZE;
01211 
01212   if (preferredRect->width > maxRect->width)
01213     preferredRect->width = maxRect->width;
01214   if (preferredRect->height > maxRect->height)
01215     preferredRect->height = maxRect->height;
01216 }