Back to index

lightning-sunbird  0.9+nobinonly
nsSVGDefsFrame.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 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 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 "nsIDOMSVGRect.h"
00040 #include "nsIDOMSVGGElement.h"
00041 #include "nsPresContext.h"
00042 #include "nsISVGOuterSVGFrame.h"
00043 #include "nsISVGRendererCanvas.h"
00044 #include "nsISVGValue.h"
00045 #include "nsIDOMSVGTransformable.h"
00046 #include "nsIDOMSVGAnimTransformList.h"
00047 #include "nsIDOMSVGTransformList.h"
00048 #include "nsSVGDefsFrame.h"
00049 #include "nsSVGMatrix.h"
00050 
00051 //----------------------------------------------------------------------
00052 // Implementation
00053 
00054 nsresult
00055 NS_NewSVGDefsFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00056 {
00057   *aNewFrame = nsnull;
00058   
00059   nsSVGDefsFrame* it = new (aPresShell) nsSVGDefsFrame;
00060   if (nsnull == it)
00061     return NS_ERROR_OUT_OF_MEMORY;
00062 
00063   *aNewFrame = it;
00064 
00065   return NS_OK;
00066 }
00067 
00068 nsSVGDefsFrame::nsSVGDefsFrame() : mPropagateTransform(PR_TRUE)
00069 {
00070 }
00071 
00072 nsSVGDefsFrame::~nsSVGDefsFrame()
00073 {
00074   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00075   if (!transformable)
00076     return;
00077 
00078   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00079   transformable->GetTransform(getter_AddRefs(transforms));
00080   nsCOMPtr<nsISVGValue> value = do_QueryInterface(transforms);
00081   NS_ASSERTION(value, "interface not found");
00082   if (value)
00083     value->RemoveObserver(this);
00084 }
00085 
00086 NS_IMETHODIMP
00087 nsSVGDefsFrame::InitSVG()
00088 {
00089   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00090   if (!transformable)
00091     return NS_OK;
00092 
00093   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00094   transformable->GetTransform(getter_AddRefs(transforms));
00095   nsCOMPtr<nsISVGValue> value = do_QueryInterface(transforms);
00096   NS_ASSERTION(value, "interface not found");
00097   if (value)
00098     value->AddObserver(this);
00099   return NS_OK;
00100 }
00101 
00102 //----------------------------------------------------------------------
00103 // nsISupports methods
00104 
00105 NS_INTERFACE_MAP_BEGIN(nsSVGDefsFrame)
00106   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00107   NS_INTERFACE_MAP_ENTRY(nsISVGContainerFrame)
00108   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00109   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00110 NS_INTERFACE_MAP_END_INHERITING(nsSVGDefsFrameBase)
00111 
00112 
00113 //----------------------------------------------------------------------
00114 // nsIFrame methods
00115 NS_IMETHODIMP
00116 nsSVGDefsFrame::Init(nsPresContext*  aPresContext,
00117                   nsIContent*      aContent,
00118                   nsIFrame*        aParent,
00119                   nsStyleContext*  aContext,
00120                   nsIFrame*        aPrevInFlow)
00121 {
00122   nsresult rv;
00123   rv = nsSVGDefsFrameBase::Init(aPresContext, aContent, aParent,
00124                                 aContext, aPrevInFlow);
00125 
00126   InitSVG();
00127   
00128   return rv;
00129 }
00130 
00131 NS_IMETHODIMP
00132 nsSVGDefsFrame::AppendFrames(nsIAtom*  aListName,
00133                              nsIFrame* aFrameList)
00134 {
00135   // append == insert at end:
00136   return InsertFrames(aListName, mFrames.LastChild(), aFrameList);  
00137 }
00138 
00139 NS_IMETHODIMP
00140 nsSVGDefsFrame::InsertFrames(nsIAtom*  aListName,
00141                              nsIFrame* aPrevFrame,
00142                              nsIFrame* aFrameList)
00143 {
00144   // memorize last new frame
00145   nsIFrame* lastNewFrame = nsnull;
00146   {
00147     nsFrameList tmpList(aFrameList);
00148     lastNewFrame = tmpList.LastChild();
00149   }
00150   
00151   // Insert the new frames
00152   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
00153 
00154   // call InitialUpdate() on all new frames:
00155   nsIFrame* end = nsnull;
00156   if (lastNewFrame)
00157     end = lastNewFrame->GetNextSibling();
00158   
00159   for (nsIFrame* kid = aFrameList; kid != end;
00160        kid = kid->GetNextSibling()) {
00161     nsISVGChildFrame* SVGFrame=nsnull;
00162     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00163     if (SVGFrame) {
00164       SVGFrame->InitialUpdate(); 
00165     }
00166   }
00167   
00168   return NS_OK;
00169 }
00170 
00171 NS_IMETHODIMP
00172 nsSVGDefsFrame::RemoveFrame(nsIAtom*  aListName,
00173                             nsIFrame* aOldFrame)
00174 {
00175   nsCOMPtr<nsISVGRendererRegion> dirty_region;
00176   
00177   nsISVGChildFrame* SVGFrame=nsnull;
00178   aOldFrame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00179 
00180   if (SVGFrame)
00181     dirty_region = SVGFrame->GetCoveredRegion();
00182 
00183   PRBool result = mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00184 
00185   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00186   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
00187   if (dirty_region && outerSVGFrame)
00188     outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00189 
00190   NS_ASSERTION(result, "didn't find frame to delete");
00191   return result ? NS_OK : NS_ERROR_FAILURE;
00192 }
00193 
00194 NS_IMETHODIMP
00195 nsSVGDefsFrame::ReplaceFrame(nsIAtom*  aListName,
00196                              nsIFrame* aOldFrame,
00197                              nsIFrame* aNewFrame)
00198 {
00199   NS_NOTYETIMPLEMENTED("nsSVGDefsFrame::ReplaceFrame");
00200   return NS_ERROR_NOT_IMPLEMENTED;
00201 }
00202 
00203 nsIAtom *
00204 nsSVGDefsFrame::GetType() const
00205 {
00206   return nsLayoutAtoms::svgDefsFrame;
00207 }
00208 
00209 PRBool
00210 nsSVGDefsFrame::IsFrameOfType(PRUint32 aFlags) const
00211 {
00212   return !(aFlags & ~nsIFrame::eSVG);
00213 }
00214 
00215 //----------------------------------------------------------------------
00216 // nsISVGValueObserver methods:
00217 
00218 NS_IMETHODIMP
00219 nsSVGDefsFrame::WillModifySVGObservable(nsISVGValue* observable,
00220                                         nsISVGValue::modificationType aModType)
00221 {
00222   return NS_OK;
00223 }
00224 
00225 
00226 NS_IMETHODIMP
00227 nsSVGDefsFrame::DidModifySVGObservable (nsISVGValue* observable,
00228                                         nsISVGValue::modificationType aModType)
00229 {
00230   // make sure our cached transform matrix gets (lazily) updated
00231   mCanvasTM = nsnull;
00232   
00233   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00234        kid = kid->GetNextSibling()) {
00235     nsISVGChildFrame* SVGFrame=nsnull;
00236     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00237     if (SVGFrame)
00238       SVGFrame->NotifyCanvasTMChanged();
00239   }  
00240   return NS_OK;
00241 }
00242 
00243 
00244 //----------------------------------------------------------------------
00245 // nsISVGChildFrame methods
00246 
00247 NS_IMETHODIMP
00248 nsSVGDefsFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00249 {
00250   // defs don't paint
00251 
00252   return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsSVGDefsFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00257 {
00258   *hit = nsnull;
00259   
00260   return NS_OK;
00261 }
00262 
00263 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00264 nsSVGDefsFrame::GetCoveredRegion()
00265 {
00266   nsISVGRendererRegion *accu_region=nsnull;
00267   
00268   return accu_region;
00269 }
00270 
00271 NS_IMETHODIMP
00272 nsSVGDefsFrame::InitialUpdate()
00273 {
00274   nsIFrame* kid = mFrames.FirstChild();
00275   while (kid) {
00276     nsISVGChildFrame* SVGFrame=0;
00277     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00278     if (SVGFrame) {
00279       SVGFrame->InitialUpdate();
00280     }
00281     kid = kid->GetNextSibling();
00282   }
00283   return NS_OK;
00284 }  
00285 
00286 NS_IMETHODIMP
00287 nsSVGDefsFrame::NotifyCanvasTMChanged()
00288 {
00289   // make sure our cached transform matrix gets (lazily) updated
00290   mCanvasTM = nsnull;
00291   
00292   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00293        kid = kid->GetNextSibling()) {
00294     nsISVGChildFrame* SVGFrame=nsnull;
00295     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00296     if (SVGFrame) {
00297       SVGFrame->NotifyCanvasTMChanged();
00298     }
00299   }
00300   return NS_OK;
00301 }
00302 
00303 NS_IMETHODIMP
00304 nsSVGDefsFrame::NotifyRedrawSuspended()
00305 {
00306   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00307        kid = kid->GetNextSibling()) {
00308     nsISVGChildFrame* SVGFrame=nsnull;
00309     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00310     if (SVGFrame) {
00311       SVGFrame->NotifyRedrawSuspended();
00312     }
00313   }
00314   return NS_OK;
00315 }
00316 
00317 NS_IMETHODIMP
00318 nsSVGDefsFrame::NotifyRedrawUnsuspended()
00319 {
00320   for (nsIFrame* kid = mFrames.FirstChild(); kid;
00321        kid = kid->GetNextSibling()) {
00322     nsISVGChildFrame* SVGFrame=nsnull;
00323     kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
00324     if (SVGFrame) {
00325       SVGFrame->NotifyRedrawUnsuspended();
00326     }
00327   }
00328   return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP
00332 nsSVGDefsFrame::SetMatrixPropagation(PRBool aPropagate)
00333 {
00334   mPropagateTransform = aPropagate;
00335   return NS_OK;
00336 }
00337 
00338 NS_IMETHODIMP
00339 nsSVGDefsFrame::GetBBox(nsIDOMSVGRect **_retval)
00340 {
00341   *_retval = nsnull;
00342   return NS_ERROR_FAILURE;
00343 }
00344 
00345 //----------------------------------------------------------------------
00346 // nsISVGContainerFrame methods:
00347 
00348 nsISVGOuterSVGFrame *
00349 nsSVGDefsFrame::GetOuterSVGFrame()
00350 {
00351   NS_ASSERTION(mParent, "null parent");
00352   
00353   nsISVGContainerFrame *containerFrame;
00354   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00355   if (!containerFrame) {
00356     NS_ERROR("invalid container");
00357     return nsnull;
00358   }
00359 
00360   return containerFrame->GetOuterSVGFrame();  
00361 }
00362 
00363 already_AddRefed<nsIDOMSVGMatrix>
00364 nsSVGDefsFrame::GetCanvasTM()
00365 {
00366   if (!mPropagateTransform) {
00367     nsIDOMSVGMatrix *retval;
00368     NS_NewSVGMatrix(&retval);
00369     return retval;
00370   }
00371 
00372   if (!mCanvasTM) {
00373     // get our parent's tm and append local transforms (if any):
00374     NS_ASSERTION(mParent, "null parent");
00375     nsISVGContainerFrame *containerFrame;
00376     mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00377     if (!containerFrame) {
00378       NS_ERROR("invalid parent");
00379       return nsnull;
00380     }
00381     nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
00382     NS_ASSERTION(parentTM, "null TM");
00383 
00384     // got the parent tm, now check for local tm:
00385     nsCOMPtr<nsIDOMSVGMatrix> localTM;
00386     {
00387       nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00388       NS_ASSERTION(transformable, "wrong content element");
00389       nsCOMPtr<nsIDOMSVGAnimatedTransformList> atl;
00390       transformable->GetTransform(getter_AddRefs(atl));
00391       NS_ASSERTION(atl, "null animated transform list");
00392       nsCOMPtr<nsIDOMSVGTransformList> transforms;
00393       atl->GetAnimVal(getter_AddRefs(transforms));
00394       NS_ASSERTION(transforms, "null transform list");
00395       PRUint32 numberOfItems;
00396       transforms->GetNumberOfItems(&numberOfItems);
00397       if (numberOfItems>0)
00398         transforms->GetConsolidationMatrix(getter_AddRefs(localTM));
00399     }
00400     
00401     if (localTM)
00402       parentTM->Multiply(localTM, getter_AddRefs(mCanvasTM));
00403     else
00404       mCanvasTM = parentTM;
00405   }
00406 
00407   nsIDOMSVGMatrix* retval = mCanvasTM.get();
00408   NS_IF_ADDREF(retval);
00409   return retval;
00410 }
00411 
00412 already_AddRefed<nsSVGCoordCtxProvider>
00413 nsSVGDefsFrame::GetCoordContextProvider()
00414 {
00415   NS_ASSERTION(mParent, "null parent");
00416   
00417   nsISVGContainerFrame *containerFrame;
00418   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00419   if (!containerFrame) {
00420     NS_ERROR("invalid container");
00421     return nsnull;
00422   }
00423 
00424   return containerFrame->GetCoordContextProvider();  
00425 }