/layout/svg/base/src/nsSVGForeignObjectFrame.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) 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 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 "nsBlockFrame.h"
00040 #include "nsIDOMSVGGElement.h"
00041 #include "nsIPresContext.h"
00042 #include "nsISVGChildFrame.h"
00043 #include "nsISVGContainerFrame.h"
00044 #include "nsISVGRendererCanvas.h"
00045 #include "nsWeakReference.h"
00046 #include "nsISVGValue.h"
00047 #include "nsISVGValueObserver.h"
00048 #include "nsIDOMSVGTransformable.h"
00049 #include "nsIDOMSVGAnimTransformList.h"
00050 #include "nsIDOMSVGAnimatedLength.h"
00051 #include "nsIDOMSVGLength.h"
00052 #include "nsIDOMSVGForeignObjectElem.h"
00053 #include "nsIDOMSVGMatrix.h"
00054 #include "nsIDOMSVGSVGElement.h"
00055 #include "nsIDOMSVGPoint.h"
00056 #include "nsSpaceManager.h"
00057 #include "nsISVGRendererRegion.h"
00058 #include "nsISVGRenderer.h"
00059 #include "nsISVGOuterSVGFrame.h"
00060 #include "nsTransform2D.h"
00061 
00062 typedef nsBlockFrame nsSVGForeignObjectFrameBase;
00063 
00064 class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
00065                                 public nsISVGContainerFrame,
00066                                 public nsISVGChildFrame,
00067                                 public nsISVGValueObserver,
00068                                 public nsSupportsWeakReference
00069 {
00070   friend nsresult
00071   NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00072 protected:
00073   nsSVGForeignObjectFrame();
00074   virtual ~nsSVGForeignObjectFrame();
00075   nsresult Init();
00076   
00077   // nsISupports interface:
00078   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00079 private:
00080   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00081   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }  
00082 public:
00083   // nsIFrame:  
00084   NS_IMETHOD Init(nsIPresContext*  aPresContext,
00085                   nsIContent*      aContent,
00086                   nsIFrame*        aParent,
00087                   nsStyleContext*  aContext,
00088                   nsIFrame*        aPrevInFlow);
00089 
00090   NS_IMETHOD Reflow(nsIPresContext*          aPresContext,
00091                     nsHTMLReflowMetrics&     aDesiredSize,
00092                     const nsHTMLReflowState& aReflowState,
00093                     nsReflowStatus&          aStatus);
00094 
00095   NS_IMETHOD  AppendFrames(nsIPresContext* aPresContext,
00096                            nsIPresShell&   aPresShell,
00097                            nsIAtom*        aListName,
00098                            nsIFrame*       aFrameList);
00099   
00100   NS_IMETHOD  InsertFrames(nsIPresContext* aPresContext,
00101                            nsIPresShell&   aPresShell,
00102                            nsIAtom*        aListName,
00103                            nsIFrame*       aPrevFrame,
00104                            nsIFrame*       aFrameList);
00105   
00106   NS_IMETHOD  RemoveFrame(nsIPresContext* aPresContext,
00107                           nsIPresShell&   aPresShell,
00108                           nsIAtom*        aListName,
00109                           nsIFrame*       aOldFrame);
00110   
00111   NS_IMETHOD  ReplaceFrame(nsIPresContext* aPresContext,
00112                            nsIPresShell&   aPresShell,
00113                            nsIAtom*        aListName,
00114                            nsIFrame*       aOldFrame,
00115                            nsIFrame*       aNewFrame);
00116 
00117   // nsISVGValueObserver
00118   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable);
00119   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable);
00120 
00121   // nsISupportsWeakReference
00122   // implementation inherited from nsSupportsWeakReference
00123   
00124   // nsISVGChildFrame interface:
00125   NS_IMETHOD Paint(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00126   NS_IMETHOD GetFrameForPoint(float x, float y, nsIFrame** hit);  
00127   NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
00128   NS_IMETHOD InitialUpdate();
00129   NS_IMETHOD NotifyCTMChanged();
00130   NS_IMETHOD NotifyRedrawSuspended();
00131   NS_IMETHOD NotifyRedrawUnsuspended();
00132   NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
00133   
00134   // nsISVGContainerFrame interface:
00135   NS_IMETHOD_(nsISVGOuterSVGFrame *) GetOuterSVGFrame();
00136   
00137 protected:
00138   // implementation helpers:
00139   void Update();
00140   already_AddRefed<nsISVGRendererRegion> DoReflow();
00141   float GetPxPerTwips();
00142   float GetTwipsPerPx();
00143   void TransformPoint(float& x, float& y);
00144   void TransformVector(float& x, float& y);
00145   void GetCTM(nsIDOMSVGMatrix** ctm);
00146 
00147   PRBool mIsDirty;
00148   nsCOMPtr<nsIDOMSVGLength> mX;
00149   nsCOMPtr<nsIDOMSVGLength> mY;
00150   nsCOMPtr<nsIDOMSVGLength> mWidth;
00151   nsCOMPtr<nsIDOMSVGLength> mHeight;
00152 };
00153 
00154 //----------------------------------------------------------------------
00155 // Implementation
00156 
00157 nsresult
00158 NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00159 {
00160   *aNewFrame = nsnull;
00161   
00162   nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject = do_QueryInterface(aContent);
00163   if (!foreignObject) {
00164 #ifdef DEBUG
00165     printf("warning: trying to construct an SVGForeignObjectFrame for a content element that doesn't support the right interfaces\n");
00166 #endif
00167     return NS_ERROR_FAILURE;
00168   }
00169   
00170   nsSVGForeignObjectFrame* it = new (aPresShell) nsSVGForeignObjectFrame;
00171   if (nsnull == it)
00172     return NS_ERROR_OUT_OF_MEMORY;
00173 
00174   *aNewFrame = it;
00175 
00176   return NS_OK;
00177 }
00178 
00179 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame()
00180     : mIsDirty(PR_TRUE)
00181 {
00182 }
00183 
00184 nsSVGForeignObjectFrame::~nsSVGForeignObjectFrame()
00185 {
00186 //   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00187 //   NS_ASSERTION(transformable, "wrong content element");
00188 //   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00189 //   transformable->GetTransform(getter_AddRefs(transforms));
00190 //   nsCOMPtr<nsISVGValue> value = do_QueryInterface(transforms);
00191 //   NS_ASSERTION(value, "interface not found");
00192 //   if (value)
00193 //     value->RemoveObserver(this);
00194   nsCOMPtr<nsISVGValue> value;
00195   if (mX && (value = do_QueryInterface(mX)))
00196       value->RemoveObserver(this);
00197   if (mY && (value = do_QueryInterface(mY)))
00198       value->RemoveObserver(this);
00199   if (mWidth && (value = do_QueryInterface(mWidth)))
00200       value->RemoveObserver(this);
00201   if (mHeight && (value = do_QueryInterface(mHeight)))
00202       value->RemoveObserver(this);
00203 }
00204 
00205 nsresult nsSVGForeignObjectFrame::Init()
00206 {
00207   nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject = do_QueryInterface(mContent);
00208   NS_ASSERTION(foreignObject, "wrong content element");
00209   
00210   {
00211     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00212     foreignObject->GetX(getter_AddRefs(length));
00213     length->GetAnimVal(getter_AddRefs(mX));
00214     NS_ASSERTION(mX, "no x");
00215     if (!mX) return NS_ERROR_FAILURE;
00216     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mX);
00217     if (value)
00218       value->AddObserver(this);
00219   }
00220 
00221   {
00222     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00223     foreignObject->GetY(getter_AddRefs(length));
00224     length->GetAnimVal(getter_AddRefs(mY));
00225     NS_ASSERTION(mY, "no y");
00226     if (!mY) return NS_ERROR_FAILURE;
00227     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mY);
00228     if (value)
00229       value->AddObserver(this);
00230   }
00231 
00232   {
00233     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00234     foreignObject->GetWidth(getter_AddRefs(length));
00235     length->GetAnimVal(getter_AddRefs(mWidth));
00236     NS_ASSERTION(mWidth, "no width");
00237     if (!mWidth) return NS_ERROR_FAILURE;
00238     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mWidth);
00239     if (value)
00240       value->AddObserver(this);
00241   }
00242 
00243   {
00244     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00245     foreignObject->GetHeight(getter_AddRefs(length));
00246     length->GetAnimVal(getter_AddRefs(mHeight));
00247     NS_ASSERTION(mHeight, "no height");
00248     if (!mHeight) return NS_ERROR_FAILURE;
00249     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mHeight);
00250     if (value)
00251       value->AddObserver(this);
00252   }
00253   
00254 // XXX 
00255 //   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00256 //   NS_ASSERTION(transformable, "wrong content element");
00257 //   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00258 //   transformable->GetTransform(getter_AddRefs(transforms));
00259 //   nsCOMPtr<nsISVGValue> value = do_QueryInterface(transforms);
00260 //   NS_ASSERTION(value, "interface not found");
00261 //   if (value)
00262 //     value->AddObserver(this);
00263 
00264   // XXX for some reason updating fails when done here. Why is this too early?
00265   // anyway - we use a less desirable mechanism now of updating in paint().
00266 //  Update(); 
00267   
00268   return NS_OK;
00269 }
00270 
00271 //----------------------------------------------------------------------
00272 // nsISupports methods
00273 
00274 NS_INTERFACE_MAP_BEGIN(nsSVGForeignObjectFrame)
00275   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00276   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00277   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00278   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00279 NS_INTERFACE_MAP_END_INHERITING(nsSVGForeignObjectFrameBase)
00280 
00281 
00282 //----------------------------------------------------------------------
00283 // nsIFrame methods
00284 NS_IMETHODIMP
00285 nsSVGForeignObjectFrame::Init(nsIPresContext*  aPresContext,
00286                   nsIContent*      aContent,
00287                   nsIFrame*        aParent,
00288                   nsStyleContext*  aContext,
00289                   nsIFrame*        aPrevInFlow)
00290 {
00291   nsresult rv;
00292   rv = nsSVGForeignObjectFrameBase::Init(aPresContext, aContent, aParent,
00293                              aContext, aPrevInFlow);
00294 
00295   Init();
00296 
00297   return rv;
00298 }
00299 
00300 NS_IMETHODIMP
00301 nsSVGForeignObjectFrame::Reflow(nsIPresContext*          aPresContext,
00302                                 nsHTMLReflowMetrics&     aDesiredSize,
00303                                 const nsHTMLReflowState& aReflowState,
00304                                 nsReflowStatus&          aStatus)
00305 {
00306 #ifdef DEBUG
00307   printf("nsSVGForeignObjectFrame(%p)::Reflow\n", this);
00308 #endif
00309   
00310   float twipsPerPx = GetTwipsPerPx();
00311   
00312   NS_ENSURE_TRUE(mX && mY && mWidth && mHeight, NS_ERROR_FAILURE);
00313 
00314   float x, y, width, height;
00315   mX->GetValue(&x);
00316   mY->GetValue(&y);
00317   mWidth->GetValue(&width);
00318   mHeight->GetValue(&height);
00319 
00320   // transform x,y,width,height according to the current ctm:
00321   // XXX we're ignoring rotation at the moment
00322 
00323   // (x, y): (left, top) -> (center_x, center_y)
00324   x+=width/2.0f;
00325   y+=height/2.0f;
00326 
00327   // (x, y): (cx, cy) -> (cx', cy')
00328   TransformPoint(x, y);
00329   
00330   // find new ex & ey unit vectors
00331   float e1x = 1.0f, e1y = 0.0f, e2x = 0.0f, e2y = 1.0f;
00332   TransformVector(e1x, e1y);
00333   TransformVector(e2x, e2y);
00334   // adopt the scale of them for (w,h)
00335   width  *= (float)sqrt(e1x*e1x + e1y*e1y);
00336   height *= (float)sqrt(e2x*e2x + e2y*e2y);
00337   
00338   // (x, y): (cx', cy') -> (left', top')
00339   x -= width/2.0f;
00340   y -= height/2.0f;
00341 
00342   // move ourselves to (x,y):
00343   SetPosition(nsPoint((nscoord) (x*twipsPerPx), (nscoord) (y*twipsPerPx)));
00344   // Xxx: if zewe have a view, move that 
00345   
00346   // create a new reflow state, setting our max size to (width,height):
00347   nsSize availableSpace((nscoord)(width*twipsPerPx), (nscoord)(height*twipsPerPx));
00348   nsHTMLReflowState sizedReflowState(aPresContext,
00349                                      aReflowState,
00350                                      this,
00351                                      availableSpace);
00352 
00353   // XXX Not sure the dirty-state should be cleared here. We should
00354   // re-examine how the reflow is driven from nsSVGOuterSVGFrame. I
00355   // think we're missing a call to DidReflow somewhere ?
00356   mState &= ~NS_FRAME_IS_DIRTY;
00357   
00358   // leverage our base class' reflow function to do all the work:
00359   return nsSVGForeignObjectFrameBase::Reflow(aPresContext, aDesiredSize,
00360                                              sizedReflowState, aStatus);
00361 }
00362 
00363 NS_IMETHODIMP
00364 nsSVGForeignObjectFrame::AppendFrames(nsIPresContext* aPresContext,
00365                                       nsIPresShell&   aPresShell,
00366                                       nsIAtom*        aListName,
00367                                       nsIFrame*       aFrameList)
00368 {
00369 #ifdef DEBUG
00370   printf("**nsSVGForeignObjectFrame::AppendFrames()\n");
00371 #endif
00372     nsresult rv;
00373     rv = nsSVGForeignObjectFrameBase::AppendFrames(aPresContext, aPresShell,
00374                                                  aListName, aFrameList);
00375     Update();
00376     return rv;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsSVGForeignObjectFrame::InsertFrames(nsIPresContext* aPresContext,
00381                                      nsIPresShell&   aPresShell,
00382                                      nsIAtom*        aListName,
00383                                      nsIFrame*       aPrevFrame,
00384                                      nsIFrame*       aFrameList)
00385 {
00386 #ifdef DEBUG
00387   printf("**nsSVGForeignObjectFrame::InsertFrames()\n");
00388 #endif
00389     nsresult rv;
00390     rv = nsSVGForeignObjectFrameBase::InsertFrames(aPresContext, aPresShell,
00391                                                  aListName, aPrevFrame, aFrameList);
00392     Update();
00393     return rv;
00394 }
00395 
00396 NS_IMETHODIMP
00397 nsSVGForeignObjectFrame::RemoveFrame(nsIPresContext* aPresContext,
00398                                      nsIPresShell&   aPresShell,
00399                                      nsIAtom*        aListName,
00400                                      nsIFrame*       aOldFrame)
00401 {
00402     nsresult rv;
00403     rv = nsSVGForeignObjectFrameBase::RemoveFrame(aPresContext, aPresShell,
00404                                                 aListName, aOldFrame);
00405     Update();
00406     return rv;
00407 }
00408 
00409 NS_IMETHODIMP
00410 nsSVGForeignObjectFrame::ReplaceFrame(nsIPresContext* aPresContext,
00411                                       nsIPresShell&   aPresShell,
00412                                       nsIAtom*        aListName,
00413                                       nsIFrame*       aOldFrame,
00414                                       nsIFrame*       aNewFrame)
00415 {
00416 #ifdef DEBUG
00417   printf("**nsSVGForeignObjectFrame::ReplaceFrame()\n");
00418 #endif
00419     nsresult rv;
00420     rv = nsSVGForeignObjectFrameBase::ReplaceFrame(aPresContext, aPresShell,
00421                                                  aListName, aOldFrame, aNewFrame);
00422     Update();
00423     return rv;
00424 }
00425 
00426 //----------------------------------------------------------------------
00427 // nsISVGValueObserver methods:
00428 
00429 NS_IMETHODIMP
00430 nsSVGForeignObjectFrame::WillModifySVGObservable(nsISVGValue* observable)
00431 {
00432   return NS_OK;
00433 }
00434 
00435 
00436 NS_IMETHODIMP
00437 nsSVGForeignObjectFrame::DidModifySVGObservable (nsISVGValue* observable)
00438 {
00439   Update();
00440   
00441   return NS_OK;
00442 }
00443 
00444 
00445 //----------------------------------------------------------------------
00446 // nsISVGChildFrame methods
00447 
00448 NS_IMETHODIMP
00449 nsSVGForeignObjectFrame::Paint(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00450 {
00451   if (mIsDirty) {
00452     nsCOMPtr<nsISVGRendererRegion> region = DoReflow();
00453   }
00454 
00455   nsIPresContext *presContext = GetPresContext();
00456 
00457   nsRect r(mRect);
00458   if (!r.IntersectRect(dirtyRectTwips, r))
00459     return PR_TRUE;
00460   
00461   float pxPerTwips = GetPxPerTwips();
00462   r.x*=pxPerTwips;
00463   r.y*=pxPerTwips;
00464   r.width*=pxPerTwips;
00465   r.height*=pxPerTwips;
00466   
00467   nsCOMPtr<nsIRenderingContext> ctx;
00468   canvas->LockRenderingContext(r, getter_AddRefs(ctx));
00469 
00470   if (!ctx) {
00471     NS_WARNING("Can't render foreignObject element!");
00472     return NS_ERROR_FAILURE;
00473   }
00474   
00475   nsRect dirtyRect = dirtyRectTwips;
00476   dirtyRect.x -= mRect.x;
00477   dirtyRect.y -= mRect.y;
00478 
00479   // As described in nsContainerFrame, don't use PushState/PopState;
00480   // instead save/restore the modified transform components:
00481   float xMatrix;
00482   float yMatrix;
00483   nsTransform2D *theTransform;
00484   ctx->GetCurrentTransform(theTransform);
00485   theTransform->GetTranslation(&xMatrix, &yMatrix);
00486   ctx->Translate(mRect.x, mRect.y);
00487   
00488   nsSVGForeignObjectFrameBase::Paint(presContext,
00489                                      *ctx,
00490                                      dirtyRect,
00491                                      NS_FRAME_PAINT_LAYER_BACKGROUND,
00492                                      0);
00493   
00494   nsSVGForeignObjectFrameBase::Paint(presContext,
00495                                      *ctx,
00496                                      dirtyRect,
00497                                      NS_FRAME_PAINT_LAYER_FLOATERS,
00498                                      0);
00499   
00500   nsSVGForeignObjectFrameBase::Paint(presContext,
00501                                      *ctx,
00502                                      dirtyRect,
00503                                      NS_FRAME_PAINT_LAYER_FOREGROUND,
00504                                      0);
00505 
00506   theTransform->SetTranslation(xMatrix, yMatrix);
00507   ctx = nsnull;
00508   canvas->UnlockRenderingContext();
00509   
00510   return NS_OK;
00511 }
00512 
00513 
00514 NS_IMETHODIMP
00515 nsSVGForeignObjectFrame::GetFrameForPoint(float x, float y, nsIFrame** hit)
00516 {
00517   *hit = nsnull;
00518 
00519   nsIPresContext *presContext = GetPresContext();
00520 
00521   nsPoint p( (nscoord)(x*GetTwipsPerPx()),
00522              (nscoord)(y*GetTwipsPerPx()));
00523 
00524   nsresult rv;
00525 
00526   rv = nsSVGForeignObjectFrameBase::GetFrameForPoint(presContext, p,
00527                                                      NS_FRAME_PAINT_LAYER_FOREGROUND, hit);
00528   if (NS_SUCCEEDED(rv) && *hit) return rv;
00529 
00530   rv = nsSVGForeignObjectFrameBase::GetFrameForPoint(presContext, p,
00531                                                      NS_FRAME_PAINT_LAYER_FLOATERS, hit);
00532   if (NS_SUCCEEDED(rv) && *hit) return rv;
00533 
00534   return nsSVGForeignObjectFrameBase::GetFrameForPoint(presContext, p,
00535                                                        NS_FRAME_PAINT_LAYER_BACKGROUND, hit);
00536 }
00537 
00538 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00539 nsSVGForeignObjectFrame::GetCoveredRegion()
00540 {
00541   // get a region from our mRect
00542   
00543   //  if (mRect.width==0 || mRect.height==0) return nsnull;
00544   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00545   if (!outerSVGFrame) {
00546     NS_ERROR("null outerSVGFrame");
00547     return nsnull;
00548   }
00549   
00550   nsCOMPtr<nsISVGRenderer> renderer;
00551   outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
00552   
00553   float pxPerTwips = GetPxPerTwips();
00554 
00555   nsISVGRendererRegion *region = nsnull;
00556   renderer->CreateRectRegion((mRect.x-1) * pxPerTwips,
00557                              (mRect.y-1) * pxPerTwips,
00558                              (mRect.width+2) * pxPerTwips,
00559                              (mRect.height+2) * pxPerTwips,
00560                              &region);
00561   NS_ASSERTION(region, "could not create region");
00562   return region;
00563   
00564 }
00565 
00566 NS_IMETHODIMP
00567 nsSVGForeignObjectFrame::InitialUpdate()
00568 {
00569 //  Update();
00570   return NS_OK;
00571 }
00572 
00573 NS_IMETHODIMP
00574 nsSVGForeignObjectFrame::NotifyCTMChanged()
00575 {
00576   Update();
00577   return NS_OK;
00578 }
00579 
00580 NS_IMETHODIMP
00581 nsSVGForeignObjectFrame::NotifyRedrawSuspended()
00582 {
00583   return NS_OK;
00584 }
00585 
00586 NS_IMETHODIMP
00587 nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
00588 {
00589   if (mIsDirty) {
00590     nsCOMPtr<nsISVGRendererRegion> dirtyRegion = DoReflow();
00591     if (dirtyRegion) {
00592       nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00593       if (outerSVGFrame)
00594         outerSVGFrame->InvalidateRegion(dirtyRegion, PR_TRUE);
00595     }
00596   }
00597   return NS_OK;
00598 }
00599 
00600 NS_IMETHODIMP
00601 nsSVGForeignObjectFrame::GetBBox(nsIDOMSVGRect **_retval)
00602 {
00603   *_retval = nsnull;
00604   return NS_ERROR_FAILURE;
00605 }
00606 
00607 //----------------------------------------------------------------------
00608 // nsISVGContainerFrame methods:
00609 
00610 NS_IMETHODIMP_(nsISVGOuterSVGFrame *)
00611 nsSVGForeignObjectFrame::GetOuterSVGFrame()
00612 {
00613   NS_ASSERTION(mParent, "null parent");
00614 
00615   nsISVGContainerFrame *containerFrame;
00616   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00617   if (!containerFrame) {
00618     NS_ERROR("invalid parent");
00619     return nsnull;
00620   }
00621   
00622   return containerFrame->GetOuterSVGFrame();  
00623 }
00624 
00625 //----------------------------------------------------------------------
00626 // Implementation helpers
00627 
00628 void nsSVGForeignObjectFrame::Update()
00629 {
00630 #ifdef DEBUG
00631   printf("**nsSVGForeignObjectFrame::Update()\n");
00632 #endif
00633 
00634   mIsDirty = PR_TRUE;
00635 
00636   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00637   if (!outerSVGFrame) {
00638     NS_ERROR("null outerSVGFrame");
00639     return;
00640   }
00641   
00642   PRBool suspended;
00643   outerSVGFrame->IsRedrawSuspended(&suspended);
00644   if (!suspended) {
00645     nsCOMPtr<nsISVGRendererRegion> dirtyRegion = DoReflow();
00646     if (dirtyRegion) {
00647       outerSVGFrame->InvalidateRegion(dirtyRegion, PR_TRUE);
00648     }
00649   }  
00650 }
00651 
00652 already_AddRefed<nsISVGRendererRegion>
00653 nsSVGForeignObjectFrame::DoReflow()
00654 {
00655 #ifdef DEBUG
00656   printf("**nsSVGForeignObjectFrame::DoReflow()\n");
00657 #endif
00658 
00659   nsIPresContext *presContext = GetPresContext();
00660 
00661   // remember the area we have to invalidate after this reflow:
00662   nsCOMPtr<nsISVGRendererRegion> area_before = GetCoveredRegion();
00663   NS_ASSERTION(area_before, "could not get covered region");
00664   
00665   // initiate a synchronous reflow here and now:  
00666   nsSize availableSpace(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
00667   nsCOMPtr<nsIRenderingContext> renderingContext;
00668   nsCOMPtr<nsIPresShell> presShell;
00669   presContext->GetShell(getter_AddRefs(presShell));
00670   NS_ASSERTION(presShell, "null presShell");
00671   presShell->CreateRenderingContext(this,getter_AddRefs(renderingContext));
00672   
00673   // XXX we always pass this off as an initial reflow. is that a problem?
00674   nsHTMLReflowState reflowState(presContext, this, eReflowReason_Initial,
00675                                 renderingContext, availableSpace);
00676 
00677   nsSpaceManager* spaceManager = new nsSpaceManager(presShell, this);
00678   if (!spaceManager) {
00679     NS_ERROR("Could not create space manager");
00680     return nsnull;
00681   }
00682   reflowState.mSpaceManager = spaceManager;
00683    
00684   nsHTMLReflowMetrics desiredSize(nsnull);
00685   nsReflowStatus status;
00686   
00687   WillReflow(presContext);
00688   Reflow(presContext, desiredSize, reflowState, status);
00689   SetSize(nsSize(desiredSize.width, desiredSize.height));
00690   DidReflow(presContext, &reflowState, NS_FRAME_REFLOW_FINISHED);
00691 
00692   mIsDirty = PR_FALSE;
00693 
00694   nsCOMPtr<nsISVGRendererRegion> area_after = GetCoveredRegion();
00695   nsISVGRendererRegion *dirtyRegion;
00696   area_before->Combine(area_after, &dirtyRegion);
00697 
00698   return dirtyRegion;
00699 }
00700 
00701 float nsSVGForeignObjectFrame::GetPxPerTwips()
00702 {
00703   float val = GetTwipsPerPx();
00704   
00705   NS_ASSERTION(val!=0.0f, "invalid px/twips");  
00706   if (val == 0.0) val = 1e-20f;
00707   
00708   return 1.0f/val;
00709 }
00710 
00711 float nsSVGForeignObjectFrame::GetTwipsPerPx()
00712 {
00713   float twipsPerPx=16.0f;
00714 
00715   GetPresContext()->GetScaledPixelsToTwips(&twipsPerPx);
00716   return twipsPerPx;
00717 }
00718 
00719 void nsSVGForeignObjectFrame::TransformPoint(float& x, float& y)
00720 {
00721   nsCOMPtr<nsIDOMSVGMatrix> ctm;
00722   GetCTM(getter_AddRefs(ctm));
00723   if (!ctm) return;
00724 
00725   // XXX this is absurd! we need to add another method (interface
00726   // even?) to nsIDOMSVGMatrix to make this easier. (something like
00727   // nsIDOMSVGMatrix::TransformPoint(float*x,float*y))
00728   
00729   nsCOMPtr<nsIDOMSVGElement> el = do_QueryInterface(mContent);
00730   nsCOMPtr<nsIDOMSVGSVGElement> svg_el;
00731   el->GetOwnerSVGElement(getter_AddRefs(svg_el));
00732   if (!svg_el) return;
00733   nsCOMPtr<nsIDOMSVGPoint> point;
00734   svg_el->CreateSVGPoint(getter_AddRefs(point));
00735   NS_ASSERTION(point, "couldn't create point!");
00736   if (!point) return;
00737   
00738   point->SetX(x);
00739   point->SetY(y);
00740   nsCOMPtr<nsIDOMSVGPoint> xfpoint;
00741   point->MatrixTransform(ctm, getter_AddRefs(xfpoint));
00742   xfpoint->GetX(&x);
00743   xfpoint->GetY(&y);
00744 }
00745 
00746 void nsSVGForeignObjectFrame::TransformVector(float& x, float& y)
00747 {
00748   // XXX This is crazy. What we really want is
00749   // nsIDOMSVGMatrix::TransformVector(x,y);
00750   
00751   float x0=0.0f, y0=0.0f;
00752   TransformPoint(x0, y0);
00753   TransformPoint(x,y);
00754   x -= x0;
00755   y -= y0;
00756 }
00757 
00758 void nsSVGForeignObjectFrame::GetCTM(nsIDOMSVGMatrix** ctm)
00759 {
00760   *ctm = nsnull;
00761   
00762   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00763   NS_ASSERTION(transformable, "wrong content type");
00764   
00765   transformable->GetCTM(ctm);  
00766 }
00767 
00768 

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