Back to index

lightning-sunbird  0.9+nobinonly
nsSVGInnerSVGFrame.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 "nsContainerFrame.h"
00040 #include "nsIDOMSVGGElement.h"
00041 #include "nsPresContext.h"
00042 #include "nsISVGChildFrame.h"
00043 #include "nsISVGContainerFrame.h"
00044 #include "nsISVGRendererCanvas.h"
00045 #include "nsISVGOuterSVGFrame.h"
00046 #include "nsIDOMSVGSVGElement.h"
00047 #include "nsISVGSVGElement.h"
00048 #include "nsIDOMSVGAnimatedLength.h"
00049 #include "nsIDOMSVGAnimatedRect.h"
00050 #include "nsIDOMSVGFitToViewBox.h"
00051 #include "nsSVGLength.h"
00052 #include "nsISVGValue.h"
00053 #include "nsISVGValueObserver.h"
00054 #include "nsWeakReference.h"
00055 #include "nsSVGMatrix.h"
00056 #include "nsLayoutAtoms.h"
00057 #include "nsSVGUtils.h"
00058 
00059 typedef nsContainerFrame nsSVGInnerSVGFrameBase;
00060 
00061 class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
00062                            public nsISVGChildFrame,
00063                            public nsISVGContainerFrame,
00064                            public nsISVGValueObserver,
00065                            public nsSupportsWeakReference,
00066                            public nsISVGSVGFrame
00067 {
00068   friend nsresult
00069   NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00070 protected:
00071   nsSVGInnerSVGFrame();
00072   virtual ~nsSVGInnerSVGFrame();
00073   nsresult Init();
00074   
00075    // nsISupports interface:
00076   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00077 private:
00078   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00079   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }  
00080 public:
00081   // nsIFrame:
00082   
00083   NS_IMETHOD  AppendFrames(nsIAtom*       aListName,
00084                            nsIFrame*      aFrameList);
00085   NS_IMETHOD  InsertFrames(nsIAtom*       aListName,
00086                            nsIFrame*      aPrevFrame,
00087                            nsIFrame*      aFrameList);
00088   NS_IMETHOD  RemoveFrame(nsIAtom*       aListName,
00089                           nsIFrame*      aOldFrame);
00090   NS_IMETHOD  ReplaceFrame(nsIAtom*       aListName,
00091                            nsIFrame*      aOldFrame,
00092                            nsIFrame*      aNewFrame);
00093   NS_IMETHOD Init(nsPresContext*  aPresContext,
00094                   nsIContent*     aContent,
00095                   nsIFrame*       aParent,
00096                   nsStyleContext* aContext,
00097                   nsIFrame*       aPrevInFlow);
00098 
00099   NS_IMETHOD  AttributeChanged(nsIContent*    aChild,
00100                                PRInt32        aNameSpaceID,
00101                                nsIAtom*       aAttribute,
00102                                PRInt32        aModType);
00108   virtual nsIAtom* GetType() const;
00109   virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
00110 
00111 #ifdef DEBUG
00112   NS_IMETHOD GetFrameName(nsAString& aResult) const
00113   {
00114     return MakeFrameName(NS_LITERAL_STRING("SVGInnerSVG"), aResult);
00115   }
00116 #endif
00117 
00118   // nsISVGChildFrame interface:
00119   NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00120   NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);  
00121   NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
00122   NS_IMETHOD InitialUpdate();
00123   NS_IMETHOD NotifyCanvasTMChanged();
00124   NS_IMETHOD NotifyRedrawSuspended();
00125   NS_IMETHOD NotifyRedrawUnsuspended();
00126   NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
00127   NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
00128   
00129   // nsISVGContainerFrame interface:
00130   nsISVGOuterSVGFrame*GetOuterSVGFrame();
00131   already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
00132   already_AddRefed<nsSVGCoordCtxProvider> GetCoordContextProvider();
00133 
00134   // nsISVGValueObserver
00135   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00136                                      nsISVGValue::modificationType aModType);
00137   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00138                                      nsISVGValue::modificationType aModType);
00139 
00140   // nsISupportsWeakReference
00141   // implementation inherited from nsSupportsWeakReference
00142 
00143   // nsISVGSVGFrame interface:
00144   NS_IMETHOD SuspendRedraw();
00145   NS_IMETHOD UnsuspendRedraw();
00146   NS_IMETHOD NotifyViewportChange();
00147 
00148 protected:
00149   nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
00150 
00151   nsCOMPtr<nsIDOMSVGLength> mX;
00152   nsCOMPtr<nsIDOMSVGLength> mY;
00153   nsCOMPtr<nsIDOMSVGLength> mWidth;
00154   nsCOMPtr<nsIDOMSVGLength> mHeight;
00155 
00156   PRBool mPropagateTransform;
00157 };
00158 
00159 //----------------------------------------------------------------------
00160 // Implementation
00161 
00162 nsresult
00163 NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00164 {
00165   nsSVGInnerSVGFrame* it = new (aPresShell) nsSVGInnerSVGFrame;
00166   if (nsnull == it)
00167     return NS_ERROR_OUT_OF_MEMORY;
00168 
00169   *aNewFrame = it;
00170 
00171   return NS_OK;
00172 }
00173 
00174 nsSVGInnerSVGFrame::nsSVGInnerSVGFrame() : mPropagateTransform(PR_TRUE)
00175 {
00176 #ifdef DEBUG
00177 //  printf("nsSVGInnerSVGFrame CTOR\n");
00178 #endif
00179 }
00180 
00181 nsSVGInnerSVGFrame::~nsSVGInnerSVGFrame()
00182 {
00183 #ifdef DEBUG
00184 //  printf("~nsSVGInnerSVGFrame\n");
00185 #endif
00186   nsCOMPtr<nsISVGValue> value;
00187   if (mX && (value = do_QueryInterface(mX)))
00188       value->RemoveObserver(this);
00189   if (mY && (value = do_QueryInterface(mY)))
00190       value->RemoveObserver(this);
00191   if (mWidth && (value = do_QueryInterface(mWidth)))
00192       value->RemoveObserver(this);
00193   if (mHeight && (value = do_QueryInterface(mHeight)))
00194       value->RemoveObserver(this);
00195 }
00196 
00197 nsresult nsSVGInnerSVGFrame::Init()
00198 {
00199   NS_ASSERTION(mParent, "no parent");
00200   
00201   // hook up CoordContextProvider chain:
00202   
00203   nsISVGContainerFrame *containerFrame;
00204   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00205   if (!containerFrame) {
00206     NS_ERROR("invalid container");
00207     return NS_ERROR_FAILURE;
00208   }
00209 
00210   nsCOMPtr<nsISVGSVGElement> SVGElement = do_QueryInterface(mContent);
00211   NS_ASSERTION(SVGElement, "wrong content element");
00212   SVGElement->SetParentCoordCtxProvider(nsRefPtr<nsSVGCoordCtxProvider>(containerFrame->GetCoordContextProvider()));
00213 
00214   {
00215     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00216     SVGElement->GetX(getter_AddRefs(length));
00217     length->GetAnimVal(getter_AddRefs(mX));
00218     NS_ASSERTION(mX, "no x");
00219     if (!mX) return NS_ERROR_FAILURE;
00220     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mX);
00221     if (value)
00222       value->AddObserver(this);  // nsISVGValueObserver
00223   }
00224 
00225   {
00226     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00227     SVGElement->GetY(getter_AddRefs(length));
00228     length->GetAnimVal(getter_AddRefs(mY));
00229     NS_ASSERTION(mY, "no y");
00230     if (!mY) return NS_ERROR_FAILURE;
00231     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mY);
00232     if (value)
00233       value->AddObserver(this);
00234   }
00235 
00236   {
00237     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00238     SVGElement->GetWidth(getter_AddRefs(length));
00239     length->GetAnimVal(getter_AddRefs(mWidth));
00240     NS_ASSERTION(mWidth, "no width");
00241     if (!mWidth) return NS_ERROR_FAILURE;
00242     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mWidth);
00243     if (value)
00244       value->AddObserver(this);
00245   }
00246 
00247   {
00248     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00249     SVGElement->GetHeight(getter_AddRefs(length));
00250     length->GetAnimVal(getter_AddRefs(mHeight));
00251     NS_ASSERTION(mHeight, "no height");
00252     if (!mHeight) return NS_ERROR_FAILURE;
00253     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mHeight);
00254     if (value)
00255       value->AddObserver(this);
00256   }
00257 
00258   return NS_OK;
00259 }
00260 
00261 //----------------------------------------------------------------------
00262 // nsISupports methods
00263 
00264 NS_INTERFACE_MAP_BEGIN(nsSVGInnerSVGFrame)
00265   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00266   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00267   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00268   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00269   NS_INTERFACE_MAP_ENTRY(nsISVGSVGFrame)
00270 NS_INTERFACE_MAP_END_INHERITING(nsSVGInnerSVGFrameBase)
00271 
00272 
00273 //----------------------------------------------------------------------
00274 // nsIFrame methods
00275 
00276 NS_IMETHODIMP
00277 nsSVGInnerSVGFrame::Init(nsPresContext*  aPresContext,
00278                          nsIContent*     aContent,
00279                          nsIFrame*       aParent,
00280                          nsStyleContext* aContext,
00281                          nsIFrame*       aPrevInFlow)
00282 {
00283   nsresult rv;
00284   rv = nsSVGInnerSVGFrameBase::Init(aPresContext, aContent, aParent,
00285                              aContext, aPrevInFlow);
00286 
00287   Init();
00288   
00289   return rv;
00290 }
00291 
00292 
00293 NS_IMETHODIMP
00294 nsSVGInnerSVGFrame::AppendFrames(nsIAtom*       aListName,
00295                                  nsIFrame*      aFrameList)
00296 {
00297   // append == insert at end:
00298   return InsertFrames(aListName, mFrames.LastChild(), aFrameList);  
00299 }
00300 
00301 NS_IMETHODIMP
00302 nsSVGInnerSVGFrame::InsertFrames(nsIAtom*       aListName,
00303                                  nsIFrame*      aPrevFrame,
00304                                  nsIFrame*      aFrameList)
00305 {
00306   nsIFrame* lastNewFrame = nsnull;
00307   {
00308     nsFrameList tmpList(aFrameList);
00309     lastNewFrame = tmpList.LastChild();
00310   }
00311   
00312   // Insert the new frames
00313   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
00314 
00315   // call InitialUpdate() on all new frames:
00316   nsIFrame* end = nsnull;
00317   if (lastNewFrame)
00318     end = lastNewFrame->GetNextSibling();
00319 
00320   for (nsIFrame*kid=aFrameList; kid != end; kid = kid->GetNextSibling()) {
00321     nsISVGChildFrame* SVGFrame=nsnull;
00322     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00323     if (SVGFrame) {
00324       SVGFrame->InitialUpdate(); 
00325     }
00326   }
00327   
00328   return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsSVGInnerSVGFrame::RemoveFrame(nsIAtom*       aListName,
00333                                 nsIFrame*      aOldFrame)
00334 {
00335   nsCOMPtr<nsISVGRendererRegion> dirty_region;
00336   
00337   nsISVGChildFrame* SVGFrame=nsnull;
00338   aOldFrame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00339 
00340   if (SVGFrame)
00341     dirty_region = SVGFrame->GetCoveredRegion();
00342 
00343   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00344 
00345   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00346   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
00347   if (dirty_region && outerSVGFrame)
00348     outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00349 
00350   NS_ASSERTION(result, "didn't find frame to delete");
00351   return result ? NS_OK : NS_ERROR_FAILURE;
00352 }
00353 
00354 NS_IMETHODIMP
00355 nsSVGInnerSVGFrame::ReplaceFrame(nsIAtom*       aListName,
00356                                  nsIFrame*      aOldFrame,
00357                                  nsIFrame*      aNewFrame)
00358 {
00359   NS_NOTYETIMPLEMENTED("nsSVGInnerSVGFrame::ReplaceFrame");
00360   return NS_ERROR_NOT_IMPLEMENTED;
00361 }
00362 
00363 NS_IMETHODIMP
00364 nsSVGInnerSVGFrame::AttributeChanged(nsIContent*    aChild,
00365                                      PRInt32        aNameSpaceID,
00366                                      nsIAtom*       aAttribute,
00367                                      PRInt32        aModType)
00368 {
00369 #ifdef DEBUG
00370     nsAutoString str;
00371     aAttribute->ToString(str);
00372     printf("** nsSVGInnerSVGFrame::AttributeChanged(%s)\n",
00373            NS_LossyConvertUCS2toASCII(str).get());
00374 #endif
00375 
00376   return NS_OK;
00377 }
00378 
00379 nsIAtom *
00380 nsSVGInnerSVGFrame::GetType() const
00381 {
00382   return nsLayoutAtoms::svgInnerSVGFrame;
00383 }
00384 
00385 PRBool
00386 nsSVGInnerSVGFrame::IsFrameOfType(PRUint32 aFlags) const
00387 {
00388   return !(aFlags & ~nsIFrame::eSVG);
00389 }
00390 
00391 //----------------------------------------------------------------------
00392 // nsISVGChildFrame methods
00393 
00394 NS_IMETHODIMP
00395 nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00396 {
00397 #ifdef DEBUG
00398 //  printf("nsSVGInnerSVG(%p)::Paint\n", this);
00399 #endif
00400 
00401   canvas->PushClip();
00402 
00403   if (GetStyleDisplay()->IsScrollableOverflow()) {
00404     float x, y, width, height;
00405     mX->GetValue(&x);
00406     mY->GetValue(&y);
00407     mWidth->GetValue(&width);
00408     mHeight->GetValue(&height);
00409 
00410     nsCOMPtr<nsIDOMSVGMatrix> clipTransform;
00411     if (!mPropagateTransform) {
00412       NS_NewSVGMatrix(getter_AddRefs(clipTransform));
00413     } else {
00414       nsISVGContainerFrame *parent;
00415       CallQueryInterface(mParent, &parent);
00416       if (parent)
00417         clipTransform = parent->GetCanvasTM();
00418     }
00419 
00420     if (clipTransform)
00421       canvas->SetClipRect(clipTransform, x, y, width, height);
00422   }
00423 
00424   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00425        kid = kid->GetNextSibling()) {
00426     nsISVGChildFrame* SVGFrame=nsnull;
00427     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00428     if (SVGFrame)
00429       SVGFrame->PaintSVG(canvas, dirtyRectTwips);
00430   }
00431 
00432   canvas->PopClip();
00433 
00434   return NS_OK;
00435 }
00436 
00437 NS_IMETHODIMP
00438 nsSVGInnerSVGFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00439 {
00440 #ifdef DEBUG
00441 //  printf("nsSVGInnerSVGFrame(%p)::GetFrameForPoint\n", this);
00442 #endif
00443   *hit = nsnull;
00444 
00445   if (GetStyleDisplay()->IsScrollableOverflow()) {
00446     float clipX, clipY, clipWidth, clipHeight;
00447     nsCOMPtr<nsIDOMSVGMatrix> clipTransform;
00448 
00449     mX->GetValue(&clipX);
00450     mY->GetValue(&clipY);
00451     mWidth->GetValue(&clipWidth);
00452     mHeight->GetValue(&clipHeight);
00453 
00454     nsISVGContainerFrame *parent = nsnull;
00455     CallQueryInterface(mParent, &parent);
00456 
00457     if (parent) {
00458       clipTransform = parent->GetCanvasTM();
00459 
00460       if (!nsSVGUtils::HitTestRect(clipTransform,
00461                                    clipX, clipY, clipWidth, clipHeight,
00462                                    x, y))
00463         return NS_OK;
00464     }
00465   }
00466 
00467   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00468        kid = kid->GetNextSibling()) {
00469     nsISVGChildFrame* SVGFrame=nsnull;
00470     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00471     if (SVGFrame) {
00472       nsIFrame* temp=nsnull;
00473       nsresult rv = SVGFrame->GetFrameForPointSVG(x, y, &temp);
00474       if (NS_SUCCEEDED(rv) && temp) {
00475         *hit = temp;
00476         // return NS_OK; can't return. we need reverse order but only
00477         // have a singly linked list...
00478       }
00479     }
00480   }
00481   
00482   return *hit ? NS_OK : NS_ERROR_FAILURE;
00483 }
00484 
00485 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00486 nsSVGInnerSVGFrame::GetCoveredRegion()
00487 {
00488   nsISVGRendererRegion *accu_region=nsnull;
00489   
00490   nsIFrame* kid = mFrames.FirstChild();
00491   while (kid) {
00492     nsISVGChildFrame* SVGFrame=0;
00493     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00494     if (SVGFrame) {
00495       nsCOMPtr<nsISVGRendererRegion> dirty_region = SVGFrame->GetCoveredRegion();
00496       if (dirty_region) {
00497         if (accu_region) {
00498           nsCOMPtr<nsISVGRendererRegion> temp = dont_AddRef(accu_region);
00499           dirty_region->Combine(temp, &accu_region);
00500         }
00501         else {
00502           accu_region = dirty_region;
00503           NS_IF_ADDREF(accu_region);
00504         }
00505       }
00506     }
00507     kid = kid->GetNextSibling();
00508   }
00509   
00510   return accu_region;
00511 }
00512 
00513 NS_IMETHODIMP
00514 nsSVGInnerSVGFrame::InitialUpdate()
00515 {
00516   nsIFrame* kid = mFrames.FirstChild();
00517   while (kid) {
00518     nsISVGChildFrame* SVGFrame=0;
00519     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00520     if (SVGFrame) {
00521       SVGFrame->InitialUpdate();
00522     }
00523     kid = kid->GetNextSibling();
00524   }
00525   return NS_OK;
00526 }  
00527 
00528 NS_IMETHODIMP
00529 nsSVGInnerSVGFrame::NotifyCanvasTMChanged()
00530 {
00531   // make sure our cached transform matrix gets (lazily) updated
00532   mCanvasTM = nsnull;
00533   
00534   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00535        kid = kid->GetNextSibling()) {
00536     nsISVGChildFrame* SVGFrame=nsnull;
00537     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00538     if (SVGFrame) {
00539       SVGFrame->NotifyCanvasTMChanged();
00540     }
00541   }
00542   return NS_OK;
00543 }
00544 
00545 NS_IMETHODIMP
00546 nsSVGInnerSVGFrame::NotifyRedrawSuspended()
00547 {
00548   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00549        kid = kid->GetNextSibling()) {
00550     nsISVGChildFrame* SVGFrame=0;
00551     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00552     if (SVGFrame) {
00553       SVGFrame->NotifyRedrawSuspended();
00554     }
00555   }
00556   return NS_OK;
00557 }
00558 
00559 NS_IMETHODIMP
00560 nsSVGInnerSVGFrame::NotifyRedrawUnsuspended()
00561 {
00562   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00563        kid = kid->GetNextSibling()) {
00564     nsISVGChildFrame* SVGFrame=nsnull;
00565     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00566     if (SVGFrame) {
00567       SVGFrame->NotifyRedrawUnsuspended();
00568     }
00569   }
00570  return NS_OK;
00571 }
00572 
00573 NS_IMETHODIMP
00574 nsSVGInnerSVGFrame::SetMatrixPropagation(PRBool aPropagate)
00575 {
00576   mPropagateTransform = aPropagate;
00577   return NS_OK;
00578 }
00579 
00580 NS_IMETHODIMP
00581 nsSVGInnerSVGFrame::GetBBox(nsIDOMSVGRect **_retval)
00582 {
00583   float minx, miny, maxx, maxy;
00584   minx = miny = FLT_MAX;
00585   maxx = maxy = -1.0 * FLT_MAX;
00586 
00587   nsCOMPtr<nsIDOMSVGRect> unionRect;
00588 
00589   nsIFrame* kid = mFrames.FirstChild();
00590   while (kid) {
00591     nsISVGChildFrame* SVGFrame=0;
00592     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00593     if (SVGFrame) {
00594       nsCOMPtr<nsIDOMSVGRect> box;
00595       SVGFrame->GetBBox(getter_AddRefs(box));
00596 
00597       if (box) {
00598         float bminx, bminy, bmaxx, bmaxy, width, height;
00599         box->GetX(&bminx);
00600         box->GetY(&bminy);
00601         box->GetWidth(&width);
00602         box->GetHeight(&height);
00603         bmaxx = bminx+width;
00604         bmaxy = bminy+height;
00605 
00606         if (!unionRect)
00607           unionRect = box;
00608         minx = PR_MIN(minx, bminx);
00609         miny = PR_MIN(miny, bminy);
00610         maxx = PR_MAX(maxx, bmaxx);
00611         maxy = PR_MAX(maxy, bmaxy);
00612       }
00613     }
00614     kid = kid->GetNextSibling();
00615   }
00616 
00617   if (unionRect) {
00618     unionRect->SetX(minx);
00619     unionRect->SetY(miny);
00620     unionRect->SetWidth(maxx-minx);
00621     unionRect->SetHeight(maxy-miny);
00622     *_retval = unionRect;
00623     NS_ADDREF(*_retval);
00624     return NS_OK;
00625   }
00626 
00627   return NS_ERROR_FAILURE;
00628 }
00629 
00630 //----------------------------------------------------------------------
00631 // nsISVGSVGFrame methods:
00632 
00633 NS_IMETHODIMP
00634 nsSVGInnerSVGFrame::SuspendRedraw()
00635 {
00636   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00637   if (!outerSVGFrame) {
00638     NS_ERROR("no outer svg frame");
00639     return NS_ERROR_FAILURE;
00640   }
00641   return outerSVGFrame->SuspendRedraw();
00642 }
00643 
00644 NS_IMETHODIMP
00645 nsSVGInnerSVGFrame::UnsuspendRedraw()
00646 {
00647   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00648   if (!outerSVGFrame) {
00649     NS_ERROR("no outer svg frame");
00650     return NS_ERROR_FAILURE;
00651   }
00652   return outerSVGFrame->UnsuspendRedraw();
00653 }
00654 
00655 NS_IMETHODIMP
00656 nsSVGInnerSVGFrame::NotifyViewportChange()
00657 {
00658   // make sure canvas transform matrix gets (lazily) recalculated:
00659   mCanvasTM = nsnull;
00660   
00661   // inform children
00662   SuspendRedraw();
00663   nsIFrame* kid = mFrames.FirstChild();
00664   while (kid) {
00665     nsISVGChildFrame* SVGFrame=nsnull;
00666     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00667     if (SVGFrame)
00668       SVGFrame->NotifyCanvasTMChanged(); 
00669     kid = kid->GetNextSibling();
00670   }
00671   UnsuspendRedraw();
00672   return NS_OK;
00673 }
00674 
00675 //----------------------------------------------------------------------
00676 // nsISVGContainerFrame methods:
00677 
00678 nsISVGOuterSVGFrame *
00679 nsSVGInnerSVGFrame::GetOuterSVGFrame()
00680 {
00681   NS_ASSERTION(mParent, "null parent");
00682   
00683   nsISVGContainerFrame *containerFrame;
00684   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00685   if (!containerFrame) {
00686     NS_ERROR("invalid container");
00687     return nsnull;
00688   }
00689 
00690   return containerFrame->GetOuterSVGFrame();  
00691 }
00692 
00693 already_AddRefed<nsIDOMSVGMatrix>
00694 nsSVGInnerSVGFrame::GetCanvasTM()
00695 {
00696   // parentTM * Translate(x,y) * viewboxToViewportTM
00697 
00698   if (!mCanvasTM) {
00699     if (!mPropagateTransform) {
00700       nsIDOMSVGMatrix *retval;
00701       NS_NewSVGMatrix(&retval);
00702       return retval;
00703     }
00704 
00705     // get the transform from our parent's coordinate system to ours:
00706     NS_ASSERTION(mParent, "null parent");
00707     nsISVGContainerFrame *containerFrame;
00708     mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00709     if (!containerFrame) {
00710       NS_ERROR("invalid parent");
00711       return nsnull;
00712     }
00713     nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
00714     NS_ASSERTION(parentTM, "null TM");
00715 
00716     // append the transform due to the 'x' and 'y' attributes:
00717     float x, y;
00718     mX->GetValue(&x);
00719     mY->GetValue(&y);
00720     nsCOMPtr<nsIDOMSVGMatrix> xyTM;
00721     parentTM->Translate(x, y, getter_AddRefs(xyTM));
00722 
00723     // append the viewbox to viewport transform:
00724     nsCOMPtr<nsIDOMSVGMatrix> viewBoxToViewportTM;
00725     nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(mContent);
00726     NS_ASSERTION(svgElement, "wrong content element");
00727     svgElement->GetViewboxToViewportTransform(getter_AddRefs(viewBoxToViewportTM));
00728     xyTM->Multiply(viewBoxToViewportTM, getter_AddRefs(mCanvasTM));
00729   }    
00730 
00731   nsIDOMSVGMatrix* retval = mCanvasTM.get();
00732   NS_IF_ADDREF(retval);
00733   return retval;
00734 }
00735 
00736 already_AddRefed<nsSVGCoordCtxProvider>
00737 nsSVGInnerSVGFrame::GetCoordContextProvider()
00738 {
00739   NS_ASSERTION(mContent, "null parent");
00740 
00741   // Our <svg> content element is the CoordContextProvider for our children:
00742   nsSVGCoordCtxProvider *provider;
00743   mContent->QueryInterface(NS_GET_IID(nsSVGCoordCtxProvider), (void**)&provider);
00744 
00745   return provider;
00746 }
00747 
00748 //----------------------------------------------------------------------
00749 // nsISVGValueObserver methods:
00750 
00751 NS_IMETHODIMP
00752 nsSVGInnerSVGFrame::WillModifySVGObservable(nsISVGValue* observable,
00753                                             nsISVGValue::modificationType aModType)
00754 {
00755   return NS_OK;
00756 }
00757        
00758 NS_IMETHODIMP
00759 nsSVGInnerSVGFrame::DidModifySVGObservable (nsISVGValue* observable,
00760                                             nsISVGValue::modificationType aModType)
00761 {
00762   NotifyViewportChange();
00763   
00764   return NS_OK;
00765 }