Back to index

lightning-sunbird  0.9+nobinonly
nsSVGSVGElement.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  *   Jonathan Watt <jonathan.watt@strath.ac.uk>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsSVGStylableElement.h"
00041 #include "nsSVGAtoms.h"
00042 #include "nsIDOMSVGFitToViewBox.h"
00043 #include "nsIDOMSVGLocatable.h"
00044 #include "nsSVGAnimatedLength.h"
00045 #include "nsSVGLength.h"
00046 #include "nsSVGAngle.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsIPresShell.h"
00049 #include "nsIDocument.h"
00050 #include "nsPresContext.h"
00051 #include "nsSVGCoordCtxProvider.h"
00052 #include "nsSVGAnimatedRect.h"
00053 #include "nsSVGAnimatedPreserveAspectRatio.h"
00054 #include "nsSVGMatrix.h"
00055 #include "nsSVGPoint.h"
00056 #include "nsSVGTransform.h"
00057 #include "nsIDOMEventTarget.h"
00058 #include "nsIViewManager.h"
00059 #include "nsIBindingManager.h"
00060 #include "nsIWidget.h"
00061 #include "nsIFrame.h"
00062 #include "nsIScrollableView.h"
00063 #include "nsISVGSVGElement.h"
00064 #include "nsISVGSVGFrame.h" //XXX
00065 #include "nsSVGNumber.h"
00066 #include "nsSVGRect.h"
00067 #include "nsSVGPreserveAspectRatio.h"
00068 #include "nsISVGValueUtils.h"
00069 #include "nsDOMError.h"
00070 #include "nsIDOMSVGZoomAndPan.h"
00071 #include "nsSVGEnum.h"
00072 #include "nsISVGChildFrame.h"
00073 #include "nsGUIEvent.h"
00074 
00075 typedef nsSVGStylableElement nsSVGSVGElementBase;
00076 
00077 class nsSVGSVGElement : public nsSVGSVGElementBase,
00078                         public nsISVGSVGElement, // : nsIDOMSVGSVGElement
00079                         public nsIDOMSVGFitToViewBox,
00080                         public nsIDOMSVGLocatable,
00081                         public nsIDOMSVGZoomAndPan,
00082                         public nsSVGCoordCtxProvider
00083 {
00084 protected:
00085   friend nsresult NS_NewSVGSVGElement(nsIContent **aResult,
00086                                       nsINodeInfo *aNodeInfo);
00087   nsSVGSVGElement(nsINodeInfo* aNodeInfo);
00088   virtual ~nsSVGSVGElement();
00089   nsresult Init();
00090   
00091 public:
00092   // interfaces:
00093   
00094   NS_DECL_ISUPPORTS_INHERITED
00095   NS_DECL_NSIDOMSVGSVGELEMENT
00096   NS_DECL_NSIDOMSVGFITTOVIEWBOX
00097   NS_DECL_NSIDOMSVGLOCATABLE
00098   NS_DECL_NSIDOMSVGZOOMANDPAN
00099   
00100   // xxx I wish we could use virtual inheritance
00101   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGSVGElementBase::)
00102   NS_FORWARD_NSIDOMELEMENT(nsSVGSVGElementBase::)
00103   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGSVGElementBase::)
00104 
00105   // nsISVGSVGElement interface:
00106   NS_IMETHOD SetParentCoordCtxProvider(nsSVGCoordCtxProvider *parentCtx);
00107   NS_IMETHOD GetCurrentScaleNumber(nsIDOMSVGNumber **aResult);
00108   NS_IMETHOD GetZoomAndPanEnum(nsISVGEnum **aResult);
00109   NS_IMETHOD SetCurrentScaleTranslate(float s, float x, float y);
00110   NS_IMETHOD SetCurrentTranslate(float x, float y);
00111   NS_IMETHOD_(void) RecordCurrentScaleTranslate();
00112   NS_IMETHOD_(float) GetPreviousTranslate_x();
00113   NS_IMETHOD_(float) GetPreviousTranslate_y();
00114   NS_IMETHOD_(float) GetPreviousScale();
00115 
00116   // nsIStyledContent interface
00117   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
00118 
00119   // nsISVGValueObserver
00120   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00121                                      nsISVGValue::modificationType aModType);
00122   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00123                                      nsISVGValue::modificationType aModType);
00124 
00125 protected:
00126   // nsSVGElement overrides
00127   PRBool IsEventName(nsIAtom* aName);
00128 
00129   // implementation helpers:
00130   void GetOffsetToAncestor(nsIContent* ancestor, float &x, float &y);
00131 
00132   nsCOMPtr<nsIDOMSVGAnimatedLength> mWidth;
00133   nsCOMPtr<nsIDOMSVGAnimatedLength> mHeight;
00134   nsCOMPtr<nsIDOMSVGAnimatedRect>   mViewBox;
00135   nsCOMPtr<nsIDOMSVGMatrix>         mViewBoxToViewportTransform;
00136   nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
00137   nsCOMPtr<nsIDOMSVGAnimatedLength> mX;
00138   nsCOMPtr<nsIDOMSVGAnimatedLength> mY;
00139 
00140   // zoom and pan
00141   // IMPORTANT: only RecordCurrentScaleTranslate should change the "mPreviousX"
00142   // members below - see the comment in RecordCurrentScaleTranslate
00143   nsCOMPtr<nsISVGEnum>              mZoomAndPan;
00144   nsCOMPtr<nsIDOMSVGPoint>          mCurrentTranslate;
00145   nsCOMPtr<nsIDOMSVGNumber>         mCurrentScale;
00146   float                             mPreviousTranslate_x;
00147   float                             mPreviousTranslate_y;
00148   float                             mPreviousScale;
00149   PRBool                            mDispatchEvent;
00150 
00151   PRInt32 mRedrawSuspendCount;
00152 };
00153 
00154 
00155 NS_IMPL_NS_NEW_SVG_ELEMENT(SVG)
00156 
00157 
00158 //----------------------------------------------------------------------
00159 // nsISupports methods
00160 
00161 NS_IMPL_ADDREF_INHERITED(nsSVGSVGElement,nsSVGSVGElementBase)
00162 NS_IMPL_RELEASE_INHERITED(nsSVGSVGElement,nsSVGSVGElementBase)
00163 
00164 NS_INTERFACE_MAP_BEGIN(nsSVGSVGElement)
00165   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
00166   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
00167   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGElement)
00168   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGSVGElement)
00169   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGFitToViewBox)
00170   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLocatable)
00171   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGZoomAndPan)
00172   NS_INTERFACE_MAP_ENTRY(nsISVGSVGElement)
00173   NS_INTERFACE_MAP_ENTRY(nsSVGCoordCtxProvider)
00174   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGSVGElement)
00175 NS_INTERFACE_MAP_END_INHERITING(nsSVGSVGElementBase)
00176 
00177 //----------------------------------------------------------------------
00178 // Implementation
00179 
00180 nsSVGSVGElement::nsSVGSVGElement(nsINodeInfo* aNodeInfo)
00181   : nsSVGSVGElementBase(aNodeInfo), mRedrawSuspendCount(0)
00182 {
00183 }
00184 
00185 nsSVGSVGElement::~nsSVGSVGElement()
00186 {
00187   if (mPreserveAspectRatio) {
00188     NS_REMOVE_SVGVALUE_OBSERVER(mPreserveAspectRatio);
00189   }
00190   if (mViewBox) {
00191     NS_REMOVE_SVGVALUE_OBSERVER(mViewBox);
00192   }
00193 }
00194 
00195   
00196 nsresult
00197 nsSVGSVGElement::Init()
00198 {
00199   nsresult rv = nsSVGSVGElementBase::Init();
00200   NS_ENSURE_SUCCESS(rv,rv);
00201 
00202   
00203   // nsIDOMSVGSVGElement attributes ------:
00204   
00205   // DOM property: width ,  #IMPLIED attrib: width
00206   {
00207     nsCOMPtr<nsISVGLength> length;
00208     rv = NS_NewSVGLength(getter_AddRefs(length),
00209                          100.0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
00210     NS_ENSURE_SUCCESS(rv,rv);
00211 
00212     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mWidth), length);
00213     NS_ENSURE_SUCCESS(rv,rv);
00214     rv = AddMappedSVGValue(nsSVGAtoms::width, mWidth);
00215     NS_ENSURE_SUCCESS(rv,rv);
00216   }
00217   // DOM property: height , #IMPLIED attrib: height
00218   {
00219     nsCOMPtr<nsISVGLength> length;
00220     rv = NS_NewSVGLength(getter_AddRefs(length),
00221                          100.0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
00222     NS_ENSURE_SUCCESS(rv,rv);
00223 
00224     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mHeight), length);
00225     NS_ENSURE_SUCCESS(rv,rv);
00226     rv = AddMappedSVGValue(nsSVGAtoms::height, mHeight);
00227     NS_ENSURE_SUCCESS(rv,rv);
00228   }
00229 
00230   // DOM property: x ,  #IMPLIED attrib: x
00231   {
00232     nsCOMPtr<nsISVGLength> length;
00233     rv = NS_NewSVGLength(getter_AddRefs(length),
00234                          0.0f);
00235     NS_ENSURE_SUCCESS(rv,rv);
00236 
00237     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mX), length);
00238     NS_ENSURE_SUCCESS(rv,rv);
00239     rv = AddMappedSVGValue(nsSVGAtoms::x, mX);
00240     NS_ENSURE_SUCCESS(rv,rv);
00241   }
00242 
00243   // DOM property: y ,  #IMPLIED attrib: y
00244   {
00245     nsCOMPtr<nsISVGLength> length;
00246     rv = NS_NewSVGLength(getter_AddRefs(length),
00247                          0.0f);
00248     NS_ENSURE_SUCCESS(rv,rv);
00249 
00250     rv = NS_NewSVGAnimatedLength(getter_AddRefs(mY), length);
00251     NS_ENSURE_SUCCESS(rv,rv);
00252     rv = AddMappedSVGValue(nsSVGAtoms::y, mY);
00253     NS_ENSURE_SUCCESS(rv,rv);
00254   }
00255   
00256   // nsIDOMSVGFitToViewBox attributes ------:
00257   
00258   // DOM property: viewBox , #IMPLIED attrib: viewBox
00259   {
00260     nsCOMPtr<nsIDOMSVGRect> viewbox;
00261     nsCOMPtr<nsIDOMSVGLength> animWidth, animHeight;
00262     mWidth->GetAnimVal(getter_AddRefs(animWidth));
00263     mHeight->GetAnimVal(getter_AddRefs(animHeight));
00264     rv = NS_NewSVGViewBox(getter_AddRefs(viewbox), animWidth, animHeight);
00265     NS_ENSURE_SUCCESS(rv,rv);
00266     rv = NS_NewSVGAnimatedRect(getter_AddRefs(mViewBox), viewbox);
00267     NS_ENSURE_SUCCESS(rv,rv);
00268     rv = AddMappedSVGValue(nsSVGAtoms::viewBox, mViewBox);
00269     NS_ENSURE_SUCCESS(rv,rv);
00270     // initialize coordinate context with viewbox:
00271     SetCoordCtxRect(viewbox);
00272   }
00273 
00274   // DOM property: preserveAspectRatio , #IMPLIED attrib: preserveAspectRatio
00275   {
00276     nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
00277     rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
00278     NS_ENSURE_SUCCESS(rv,rv);
00279     rv = NS_NewSVGAnimatedPreserveAspectRatio(
00280                                           getter_AddRefs(mPreserveAspectRatio),
00281                                           preserveAspectRatio);
00282     NS_ENSURE_SUCCESS(rv,rv);
00283     rv = AddMappedSVGValue(nsSVGAtoms::preserveAspectRatio,
00284                            mPreserveAspectRatio);
00285     NS_ENSURE_SUCCESS(rv,rv);
00286   }
00287   
00288   // nsIDOMSVGZoomAndPan attribute ------:
00289 
00290   // Define enumeration mappings
00291   static struct nsSVGEnumMapping zoomMap[] = {
00292         {&nsSVGAtoms::disable, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_DISABLE},
00293         {&nsSVGAtoms::magnify, nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY},
00294         {nsnull, 0}
00295   };
00296 
00297   // DOM property: zoomAndPan ,  #IMPLIED attrib: zoomAndPan
00298   {
00299     rv = NS_NewSVGEnum(getter_AddRefs(mZoomAndPan),
00300                        nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY, zoomMap);
00301     NS_ENSURE_SUCCESS(rv,rv);
00302     rv = AddMappedSVGValue(nsSVGAtoms::zoomAndPan, mZoomAndPan);
00303     NS_ENSURE_SUCCESS(rv,rv);
00304   }
00305 
00306   // DOM property: currentScale
00307   {
00308     rv = NS_NewSVGNumber(getter_AddRefs(mCurrentScale), 1.0f);
00309     NS_ENSURE_SUCCESS(rv,rv);
00310     NS_ADD_SVGVALUE_OBSERVER(mCurrentScale);
00311   }
00312 
00313   // DOM property: currentTranslate
00314   {
00315     rv = NS_NewSVGPoint(getter_AddRefs(mCurrentTranslate));
00316     NS_ENSURE_SUCCESS(rv,rv);
00317     NS_ADD_SVGVALUE_OBSERVER(mCurrentTranslate);
00318   }
00319 
00320   // initialise "Previous" values
00321   RecordCurrentScaleTranslate();
00322   mDispatchEvent = PR_TRUE;
00323 
00324   return rv;
00325 }
00326 
00327 //----------------------------------------------------------------------
00328 // nsIDOMNode methods
00329 
00330 
00331 NS_IMPL_DOM_CLONENODE_WITH_INIT(nsSVGSVGElement)
00332 
00333 
00334 //----------------------------------------------------------------------
00335 // nsIDOMSVGSVGElement methods:
00336 
00337 /* readonly attribute nsIDOMSVGAnimatedLength x; */
00338 NS_IMETHODIMP
00339 nsSVGSVGElement::GetX(nsIDOMSVGAnimatedLength * *aX)
00340 {
00341   *aX = mX;
00342   NS_ADDREF(*aX);
00343   return NS_OK;
00344 }
00345 
00346 /* readonly attribute nsIDOMSVGAnimatedLength y; */
00347 NS_IMETHODIMP
00348 nsSVGSVGElement::GetY(nsIDOMSVGAnimatedLength * *aY)
00349 {
00350   *aY = mY;
00351   NS_ADDREF(*aY);
00352   return NS_OK;
00353 }
00354 
00355 /* readonly attribute nsIDOMSVGAnimatedLength width; */
00356 NS_IMETHODIMP
00357 nsSVGSVGElement::GetWidth(nsIDOMSVGAnimatedLength * *aWidth)
00358 {
00359   *aWidth = mWidth;
00360   NS_ADDREF(*aWidth);
00361   return NS_OK;
00362 }
00363 
00364 /* readonly attribute nsIDOMSVGAnimatedLength height; */
00365 NS_IMETHODIMP
00366 nsSVGSVGElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
00367 {
00368   *aHeight = mHeight;
00369   NS_ADDREF(*aHeight);
00370   return NS_OK;
00371 }
00372 
00373 /* attribute DOMString contentScriptType; */
00374 NS_IMETHODIMP
00375 nsSVGSVGElement::GetContentScriptType(nsAString & aContentScriptType)
00376 {
00377   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetContentScriptType");
00378   return NS_ERROR_NOT_IMPLEMENTED;
00379 }
00380 NS_IMETHODIMP
00381 nsSVGSVGElement::SetContentScriptType(const nsAString & aContentScriptType)
00382 {
00383   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetContentScriptType");
00384   return NS_ERROR_NOT_IMPLEMENTED;
00385 }
00386 
00387 /* attribute DOMString contentStyleType; */
00388 NS_IMETHODIMP
00389 nsSVGSVGElement::GetContentStyleType(nsAString & aContentStyleType)
00390 {
00391   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetContentStyleType");
00392   return NS_ERROR_NOT_IMPLEMENTED;
00393 }
00394 NS_IMETHODIMP
00395 nsSVGSVGElement::SetContentStyleType(const nsAString & aContentStyleType)
00396 {
00397   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetContentStyleType");
00398   return NS_ERROR_NOT_IMPLEMENTED;
00399 }
00400 
00401 /* readonly attribute nsIDOMSVGRect viewport; */
00402 NS_IMETHODIMP
00403 nsSVGSVGElement::GetViewport(nsIDOMSVGRect * *aViewport)
00404 {
00405   // XXX
00406   return NS_ERROR_NOT_IMPLEMENTED;
00407 }
00408 
00409 /* readonly attribute float pixelUnitToMillimeterX; */
00410 NS_IMETHODIMP
00411 nsSVGSVGElement::GetPixelUnitToMillimeterX(float *aPixelUnitToMillimeterX)
00412 {
00413   // to correctly determine this, the caller would need to pass in the
00414   // right PresContext...
00415 
00416   *aPixelUnitToMillimeterX = 0.28f; // 90dpi
00417 
00418   nsIDocument* doc = GetCurrentDoc();
00419   if (!doc) return NS_OK;
00420   // Get Presentation shell 0
00421   nsIPresShell *presShell = doc->GetShellAt(0);
00422   if (!presShell) return NS_OK;
00423   
00424   // Get the Presentation Context from the Shell
00425   nsPresContext *context = presShell->GetPresContext();
00426   if (!context) return NS_OK;
00427 
00428   *aPixelUnitToMillimeterX = context->ScaledPixelsToTwips() / TWIPS_PER_POINT_FLOAT / (72.0f * 0.03937f);
00429   return NS_OK;
00430 }
00431 
00432 /* readonly attribute float pixelUnitToMillimeterY; */
00433 NS_IMETHODIMP
00434 nsSVGSVGElement::GetPixelUnitToMillimeterY(float *aPixelUnitToMillimeterY)
00435 {
00436   return GetPixelUnitToMillimeterX(aPixelUnitToMillimeterY);
00437 }
00438 
00439 /* readonly attribute float screenPixelToMillimeterX; */
00440 NS_IMETHODIMP
00441 nsSVGSVGElement::GetScreenPixelToMillimeterX(float *aScreenPixelToMillimeterX)
00442 {
00443   // to correctly determine this, the caller would need to pass in the
00444   // right PresContext...
00445 
00446   *aScreenPixelToMillimeterX = 0.28f; // 90dpi
00447 
00448   nsIDocument* doc = GetCurrentDoc();
00449   if (!doc) return NS_OK;
00450     // Get Presentation shell 0
00451   nsIPresShell *presShell = doc->GetShellAt(0);
00452   if (!presShell) return NS_OK;
00453   
00454   // Get the Presentation Context from the Shell
00455   nsPresContext *context = presShell->GetPresContext();
00456   if (!context) return NS_OK;
00457 
00458   float TwipsPerPx;
00459   TwipsPerPx = context->PixelsToTwips();
00460   *aScreenPixelToMillimeterX = TwipsPerPx / TWIPS_PER_POINT_FLOAT / (72.0f * 0.03937f);
00461   return NS_OK;
00462 }
00463 
00464 /* readonly attribute float screenPixelToMillimeterY; */
00465 NS_IMETHODIMP
00466 nsSVGSVGElement::GetScreenPixelToMillimeterY(float *aScreenPixelToMillimeterY)
00467 {
00468   return GetScreenPixelToMillimeterX(aScreenPixelToMillimeterY);
00469 }
00470 
00471 /* attribute boolean useCurrentView; */
00472 NS_IMETHODIMP
00473 nsSVGSVGElement::GetUseCurrentView(PRBool *aUseCurrentView)
00474 {
00475   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetUseCurrentView");
00476   return NS_ERROR_NOT_IMPLEMENTED;
00477 }
00478 NS_IMETHODIMP
00479 nsSVGSVGElement::SetUseCurrentView(PRBool aUseCurrentView)
00480 {
00481   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetUseCurrentView");
00482   return NS_ERROR_NOT_IMPLEMENTED;
00483 }
00484 
00485 /* readonly attribute nsIDOMSVGViewSpec currentView; */
00486 NS_IMETHODIMP
00487 nsSVGSVGElement::GetCurrentView(nsIDOMSVGViewSpec * *aCurrentView)
00488 {
00489   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetCurrentView");
00490   return NS_ERROR_NOT_IMPLEMENTED;
00491 }
00492 
00493 /* attribute float currentScale; */
00494 NS_IMETHODIMP
00495 nsSVGSVGElement::GetCurrentScale(float *aCurrentScale)
00496 {
00497   return mCurrentScale->GetValue(aCurrentScale);
00498 }
00499 
00500 #define CURRENT_SCALE_MAX 16.0f
00501 #define CURRENT_SCALE_MIN 0.0625f
00502 
00503 NS_IMETHODIMP
00504 nsSVGSVGElement::SetCurrentScale(float aCurrentScale)
00505 {
00506   // Prevent bizarre behaviour and maxing out of CPU and memory by clamping
00507   if (aCurrentScale < CURRENT_SCALE_MIN)
00508     aCurrentScale = CURRENT_SCALE_MIN;
00509   else if (aCurrentScale > CURRENT_SCALE_MAX)
00510     aCurrentScale = CURRENT_SCALE_MAX;
00511 
00512   return mCurrentScale->SetValue(aCurrentScale);
00513 
00514   // We have to dispatch the required SVGZoom event from DidModifySVGObservable
00515   // since dispatching it here is too late (i.e. after repaint)
00516 }
00517 
00518 /* readonly attribute nsIDOMSVGPoint currentTranslate; */
00519 NS_IMETHODIMP
00520 nsSVGSVGElement::GetCurrentTranslate(nsIDOMSVGPoint * *aCurrentTranslate)
00521 {
00522   *aCurrentTranslate = mCurrentTranslate;
00523   NS_ADDREF(*aCurrentTranslate);
00524   return NS_OK;
00525 }
00526 
00527 /* unsigned long suspendRedraw (in unsigned long max_wait_milliseconds); */
00528 NS_IMETHODIMP
00529 nsSVGSVGElement::SuspendRedraw(PRUint32 max_wait_milliseconds, PRUint32 *_retval)
00530 {
00531   *_retval = 1;
00532 
00533   if (++mRedrawSuspendCount > 1) 
00534     return NS_OK;
00535 
00536   nsIDocument* doc = GetCurrentDoc();
00537   if (!doc) return NS_ERROR_FAILURE;
00538   nsIPresShell *presShell = doc->GetShellAt(0);
00539   NS_ASSERTION(presShell, "need presShell to suspend redraw");
00540   if (!presShell) return NS_ERROR_FAILURE;
00541 
00542   nsIFrame* frame;
00543   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
00544 #ifdef DEBUG
00545   // XXX We sometimes hit this assertion when the svg:svg element is
00546   // in a binding and svg children are inserted underneath it using
00547   // <children/>. If the svg children then call suspendRedraw, the
00548   // above function call fails although the svg:svg's frame has been
00549   // build. Strange...
00550   
00551   NS_ASSERTION(frame, "suspending redraw w/o frame");
00552 #endif
00553   if (frame) {
00554     nsISVGSVGFrame* svgframe;
00555     CallQueryInterface(frame, &svgframe);
00556     NS_ASSERTION(svgframe, "wrong frame type");
00557     if (svgframe) {
00558       svgframe->SuspendRedraw();
00559     }
00560   }
00561   
00562   return NS_OK;
00563 }
00564 
00565 /* void unsuspendRedraw (in unsigned long suspend_handle_id); */
00566 NS_IMETHODIMP
00567 nsSVGSVGElement::UnsuspendRedraw(PRUint32 suspend_handle_id)
00568 {
00569   if (mRedrawSuspendCount == 0) {
00570     NS_ASSERTION(1==0, "unbalanced suspend/unsuspend calls");
00571     return NS_ERROR_FAILURE;
00572   }
00573                  
00574   if (mRedrawSuspendCount > 1) {
00575     --mRedrawSuspendCount;
00576     return NS_OK;
00577   }
00578   
00579   return UnsuspendRedrawAll();
00580 }
00581 
00582 /* void unsuspendRedrawAll (); */
00583 NS_IMETHODIMP
00584 nsSVGSVGElement::UnsuspendRedrawAll()
00585 {
00586   mRedrawSuspendCount = 0;
00587 
00588   nsIDocument* doc = GetCurrentDoc();
00589   if (!doc) return NS_ERROR_FAILURE;
00590   nsIPresShell *presShell = doc->GetShellAt(0);
00591   NS_ASSERTION(presShell, "need presShell to unsuspend redraw");
00592   if (!presShell) return NS_ERROR_FAILURE;
00593 
00594   nsIFrame* frame;
00595   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
00596 #ifdef DEBUG
00597   NS_ASSERTION(frame, "unsuspending redraw w/o frame");
00598 #endif
00599   if (frame) {
00600     nsISVGSVGFrame* svgframe;
00601     CallQueryInterface(frame, &svgframe);
00602     NS_ASSERTION(svgframe, "wrong frame type");
00603     if (svgframe) {
00604       svgframe->UnsuspendRedraw();
00605     }
00606   }  
00607   return NS_OK;
00608 }
00609 
00610 /* void forceRedraw (); */
00611 NS_IMETHODIMP
00612 nsSVGSVGElement::ForceRedraw()
00613 {
00614   nsIDocument* doc = GetCurrentDoc();
00615   if (!doc) return NS_ERROR_FAILURE;
00616 
00617   doc->FlushPendingNotifications(Flush_Display);
00618 
00619   return NS_OK;
00620 }
00621 
00622 /* void pauseAnimations (); */
00623 NS_IMETHODIMP
00624 nsSVGSVGElement::PauseAnimations()
00625 {
00626   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::PauseAnimations");
00627   return NS_ERROR_NOT_IMPLEMENTED;
00628 }
00629 
00630 /* void unpauseAnimations (); */
00631 NS_IMETHODIMP
00632 nsSVGSVGElement::UnpauseAnimations()
00633 {
00634   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::UnpauseAnimations");
00635   return NS_ERROR_NOT_IMPLEMENTED;
00636 }
00637 
00638 /* boolean animationsPaused (); */
00639 NS_IMETHODIMP
00640 nsSVGSVGElement::AnimationsPaused(PRBool *_retval)
00641 {
00642   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::AnimationsPaused");
00643   return NS_ERROR_NOT_IMPLEMENTED;
00644 }
00645 
00646 /* float getCurrentTime (); */
00647 NS_IMETHODIMP
00648 nsSVGSVGElement::GetCurrentTime(float *_retval)
00649 {
00650   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetCurrentTime");
00651   return NS_ERROR_NOT_IMPLEMENTED;
00652 }
00653 
00654 /* void setCurrentTime (in float seconds); */
00655 NS_IMETHODIMP
00656 nsSVGSVGElement::SetCurrentTime(float seconds)
00657 {
00658   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetCurrentTime");
00659   return NS_ERROR_NOT_IMPLEMENTED;
00660 }
00661 
00662 /* nsIDOMNodeList getIntersectionList (in nsIDOMSVGRect rect, in nsIDOMSVGElement referenceElement); */
00663 NS_IMETHODIMP
00664 nsSVGSVGElement::GetIntersectionList(nsIDOMSVGRect *rect,
00665                                      nsIDOMSVGElement *referenceElement,
00666                                      nsIDOMNodeList **_retval)
00667 {
00668   // null check when implementing - this method can be used by scripts!
00669   // if (!rect || !referenceElement)
00670   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00671 
00672   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetIntersectionList");
00673   return NS_ERROR_NOT_IMPLEMENTED;
00674 }
00675 
00676 /* nsIDOMNodeList getEnclosureList (in nsIDOMSVGRect rect, in nsIDOMSVGElement referenceElement); */
00677 NS_IMETHODIMP
00678 nsSVGSVGElement::GetEnclosureList(nsIDOMSVGRect *rect,
00679                                   nsIDOMSVGElement *referenceElement,
00680                                   nsIDOMNodeList **_retval)
00681 {
00682   // null check when implementing - this method can be used by scripts!
00683   // if (!rect || !referenceElement)
00684   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00685 
00686   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetEnclosureList");
00687   return NS_ERROR_NOT_IMPLEMENTED;
00688 }
00689 
00690 /* boolean checkIntersection (in nsIDOMSVGElement element, in nsIDOMSVGRect rect); */
00691 NS_IMETHODIMP
00692 nsSVGSVGElement::CheckIntersection(nsIDOMSVGElement *element,
00693                                    nsIDOMSVGRect *rect,
00694                                    PRBool *_retval)
00695 {
00696   // null check when implementing - this method can be used by scripts!
00697   // if (!element || !rect)
00698   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00699 
00700   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::CheckIntersection");
00701   return NS_ERROR_NOT_IMPLEMENTED;
00702 }
00703 
00704 /* boolean checkEnclosure (in nsIDOMSVGElement element, in nsIDOMSVGRect rect); */
00705 NS_IMETHODIMP
00706 nsSVGSVGElement::CheckEnclosure(nsIDOMSVGElement *element,
00707                                 nsIDOMSVGRect *rect,
00708                                 PRBool *_retval)
00709 {
00710   // null check when implementing - this method can be used by scripts!
00711   // if (!element || !rect)
00712   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00713 
00714   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::CheckEnclosure");
00715   return NS_ERROR_NOT_IMPLEMENTED;
00716 }
00717 
00718 /* void deSelectAll (); */
00719 NS_IMETHODIMP
00720 nsSVGSVGElement::DeSelectAll()
00721 {
00722   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::DeSelectAll");
00723   return NS_ERROR_NOT_IMPLEMENTED;
00724 }
00725 
00726 /* nsIDOMSVGNumber createSVGNumber (); */
00727 NS_IMETHODIMP
00728 nsSVGSVGElement::CreateSVGNumber(nsIDOMSVGNumber **_retval)
00729 {
00730   return NS_NewSVGNumber(_retval);
00731 }
00732 
00733 /* nsIDOMSVGLength createSVGLength (); */
00734 NS_IMETHODIMP
00735 nsSVGSVGElement::CreateSVGLength(nsIDOMSVGLength **_retval)
00736 {
00737   return NS_NewSVGLength(NS_REINTERPRET_CAST(nsISVGLength**, _retval));
00738 }
00739 
00740 /* nsIDOMSVGAngle createSVGAngle (); */
00741 NS_IMETHODIMP
00742 nsSVGSVGElement::CreateSVGAngle(nsIDOMSVGAngle **_retval)
00743 {
00744   return NS_NewSVGAngle(_retval);
00745 }
00746 
00747 /* nsIDOMSVGPoint createSVGPoint (); */
00748 NS_IMETHODIMP
00749 nsSVGSVGElement::CreateSVGPoint(nsIDOMSVGPoint **_retval)
00750 {
00751   return NS_NewSVGPoint(_retval);
00752 }
00753 
00754 /* nsIDOMSVGMatrix createSVGMatrix (); */
00755 NS_IMETHODIMP
00756 nsSVGSVGElement::CreateSVGMatrix(nsIDOMSVGMatrix **_retval)
00757 {
00758   return NS_NewSVGMatrix(_retval);
00759 }
00760 
00761 /* nsIDOMSVGRect createSVGRect (); */
00762 NS_IMETHODIMP
00763 nsSVGSVGElement::CreateSVGRect(nsIDOMSVGRect **_retval)
00764 {
00765   return NS_NewSVGRect(_retval);
00766 }
00767 
00768 /* nsIDOMSVGTransform createSVGTransform (); */
00769 NS_IMETHODIMP
00770 nsSVGSVGElement::CreateSVGTransform(nsIDOMSVGTransform **_retval)
00771 {
00772   return NS_NewSVGTransform(_retval);
00773 }
00774 
00775 /* nsIDOMSVGTransform createSVGTransformFromMatrix (in nsIDOMSVGMatrix matrix); */
00776 NS_IMETHODIMP
00777 nsSVGSVGElement::CreateSVGTransformFromMatrix(nsIDOMSVGMatrix *matrix, 
00778                                               nsIDOMSVGTransform **_retval)
00779 {
00780   if (!matrix)
00781     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00782 
00783   nsresult rv = NS_NewSVGTransform(_retval);
00784   if (NS_FAILED(rv))
00785     return rv;
00786 
00787   (*_retval)->SetMatrix(matrix);
00788   return NS_OK;
00789 }
00790 
00791 /* DOMString createSVGString (); */
00792 NS_IMETHODIMP
00793 nsSVGSVGElement::CreateSVGString(nsAString & _retval)
00794 {
00795   return NS_ERROR_NOT_IMPLEMENTED;
00796 }
00797 
00798 /* nsIDOMElement getElementById (in DOMString elementId); */
00799 NS_IMETHODIMP
00800 nsSVGSVGElement::GetElementById(const nsAString & elementId, nsIDOMElement **_retval)
00801 {
00802   return NS_ERROR_NOT_IMPLEMENTED;
00803 }
00804 
00805 /* nsIDOMSVGMatrix getViewboxToViewportTransform (); */
00806 NS_IMETHODIMP
00807 nsSVGSVGElement::GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval)
00808 {
00809   nsresult rv = NS_OK;
00810 
00811   if (!mViewBoxToViewportTransform) {
00812     float viewportWidth;
00813     {
00814       nsCOMPtr<nsIDOMSVGLength> l;
00815       mWidth->GetAnimVal(getter_AddRefs(l));
00816       l->GetValue(&viewportWidth);
00817     }
00818     float viewportHeight;
00819     {
00820       nsCOMPtr<nsIDOMSVGLength> l;
00821       mHeight->GetAnimVal(getter_AddRefs(l));
00822       l->GetValue(&viewportHeight);
00823     }
00824     
00825     float viewboxX, viewboxY, viewboxWidth, viewboxHeight;
00826     {
00827       nsCOMPtr<nsIDOMSVGRect> vb;
00828       mViewBox->GetAnimVal(getter_AddRefs(vb));
00829       NS_ASSERTION(vb, "could not get viewbox");
00830       vb->GetX(&viewboxX);
00831       vb->GetY(&viewboxY);
00832       vb->GetWidth(&viewboxWidth);
00833       vb->GetHeight(&viewboxHeight);
00834     }
00835     if (viewboxWidth==0.0f || viewboxHeight==0.0f) {
00836       NS_ERROR("XXX. We shouldn't get here. Viewbox width/height is set to 0. Need to disable display of element as per specs.");
00837       viewboxWidth = 1.0f;
00838       viewboxHeight = 1.0f;
00839     }
00840     
00841     PRUint16 align, meetOrSlice;
00842     {
00843       nsCOMPtr<nsIDOMSVGPreserveAspectRatio> par;
00844       mPreserveAspectRatio->GetAnimVal(getter_AddRefs(par));
00845       NS_ASSERTION(par, "could not get preserveAspectRatio");
00846       par->GetAlign(&align);
00847       par->GetMeetOrSlice(&meetOrSlice);
00848     }
00849 
00850     // default to the defaults
00851     if (align == nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN)
00852       align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
00853     if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN)
00854       meetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
00855     
00856     float a, d, e, f;
00857     a = viewportWidth/viewboxWidth;
00858     d = viewportHeight/viewboxHeight;
00859     e = 0.0f;
00860     f = 0.0f;
00861 
00862     if (align != nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
00863         a != d) {
00864       if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
00865           a < d ||
00866           meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
00867           d < a) {
00868         d = a;
00869         switch (align) {
00870           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
00871           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
00872           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
00873             break;
00874           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
00875           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
00876           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
00877             f = (viewportHeight - a * viewboxHeight) / 2.0f;
00878             break;
00879           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
00880           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
00881           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
00882             f = viewportHeight - a * viewboxHeight;
00883             break;
00884           default:
00885             NS_NOTREACHED("Unknown value for align");
00886         }
00887       }
00888       else if (
00889           meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
00890           d < a ||
00891           meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
00892           a < d) {
00893         a = d;
00894         switch (align) {
00895           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
00896           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
00897           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
00898             break;
00899           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
00900           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
00901           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
00902             e = (viewportWidth - a * viewboxWidth) / 2.0f;
00903             break;
00904           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
00905           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
00906           case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
00907             e = viewportWidth - a * viewboxWidth;
00908             break;
00909           default:
00910             NS_NOTREACHED("Unknown value for align");
00911         }
00912       }
00913       else NS_NOTREACHED("Unknown value for meetOrSlice");
00914     }
00915 
00916     if (viewboxX) e += -a * viewboxX;
00917     if (viewboxY) f += -d * viewboxY;
00918     
00919 #ifdef DEBUG
00920     printf("SVG Viewport=(0?,0?,%f,%f)\n", viewportWidth, viewportHeight);
00921     printf("SVG Viewbox=(%f,%f,%f,%f)\n", viewboxX, viewboxY, viewboxWidth, viewboxHeight);
00922     printf("SVG Viewbox->Viewport xform [a c e] = [%f,   0, %f]\n", a, e);
00923     printf("                            [b d f] = [   0,  %f, %f]\n", d, f);
00924 #endif
00925     
00926     rv = NS_NewSVGMatrix(getter_AddRefs(mViewBoxToViewportTransform),
00927                          a, 0.0f, 0.0f, d, e, f);
00928   }
00929 
00930   *_retval = mViewBoxToViewportTransform;
00931   NS_IF_ADDREF(*_retval);
00932   return rv;
00933 }
00934 
00935 //----------------------------------------------------------------------
00936 // nsIDOMSVGFitToViewBox methods
00937 
00938 /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
00939 NS_IMETHODIMP
00940 nsSVGSVGElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
00941 {
00942   *aViewBox = mViewBox;
00943   NS_ADDREF(*aViewBox);
00944   return NS_OK;
00945 }
00946 
00947 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
00948 NS_IMETHODIMP
00949 nsSVGSVGElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio * *aPreserveAspectRatio)
00950 {
00951   *aPreserveAspectRatio = mPreserveAspectRatio;
00952   NS_ADDREF(*aPreserveAspectRatio);
00953   return NS_OK;
00954 }
00955 
00956 //----------------------------------------------------------------------
00957 // nsIDOMSVGLocatable methods
00958 
00959 /* readonly attribute nsIDOMSVGElement nearestViewportElement; */
00960 NS_IMETHODIMP
00961 nsSVGSVGElement::GetNearestViewportElement(nsIDOMSVGElement * *aNearestViewportElement)
00962 {
00963   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetNearestViewportElement");
00964   return NS_ERROR_NOT_IMPLEMENTED;
00965 }
00966 
00967 /* readonly attribute nsIDOMSVGElement farthestViewportElement; */
00968 NS_IMETHODIMP
00969 nsSVGSVGElement::GetFarthestViewportElement(nsIDOMSVGElement * *aFarthestViewportElement)
00970 {
00971   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetFarthestViewportElement");
00972   return NS_ERROR_NOT_IMPLEMENTED;
00973 }
00974 
00975 /* nsIDOMSVGRect getBBox (); */
00976 NS_IMETHODIMP
00977 nsSVGSVGElement::GetBBox(nsIDOMSVGRect **_retval)
00978 {
00979   *_retval = nsnull;
00980 
00981   nsIDocument* doc = GetCurrentDoc();
00982   if (!doc) return NS_ERROR_FAILURE;
00983   nsIPresShell *presShell = doc->GetShellAt(0);
00984   NS_ASSERTION(presShell, "no presShell");
00985   if (!presShell) return NS_ERROR_FAILURE;
00986 
00987   nsIFrame* frame;
00988   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
00989 
00990   NS_ASSERTION(frame, "can't get bounding box for element without frame");
00991 
00992   if (frame) {
00993     nsISVGChildFrame* svgframe;
00994     frame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&svgframe);
00995     if (svgframe) {
00996       svgframe->SetMatrixPropagation(PR_FALSE);
00997       svgframe->NotifyCanvasTMChanged();
00998       nsresult rv = svgframe->GetBBox(_retval);
00999       svgframe->SetMatrixPropagation(PR_TRUE);
01000       svgframe->NotifyCanvasTMChanged();
01001       return rv;
01002     } else {
01003       // XXX: outer svg
01004       return NS_ERROR_NOT_IMPLEMENTED;
01005     }
01006   }
01007   return NS_ERROR_FAILURE;
01008 }
01009 
01010 /* nsIDOMSVGMatrix getCTM (); */
01011 NS_IMETHODIMP
01012 nsSVGSVGElement::GetCTM(nsIDOMSVGMatrix **_retval)
01013 {
01014   nsresult rv;
01015   *_retval = nsnull;
01016 
01017   // first try to get the "screen" CTM of our nearest SVG ancestor
01018 
01019   nsIBindingManager *bindingManager = nsnull;
01020   // XXXbz I _think_ this is right.  We want to be using the binding manager
01021   // that would have attached the bindings that gives us our anonymous
01022   // ancestors. That's the binding manager for the document we actually belong
01023   // to, which is our owner doc.
01024   nsIDocument* ownerDoc = GetOwnerDoc();
01025   if (ownerDoc) {
01026     bindingManager = ownerDoc->BindingManager();
01027   }
01028 
01029   nsCOMPtr<nsIContent> element = this;
01030   nsCOMPtr<nsIContent> ancestor;
01031   unsigned short ancestorCount = 0;
01032   nsCOMPtr<nsIDOMSVGMatrix> ancestorCTM;
01033 
01034   while (1) {
01035     if (bindingManager) {
01036       // check for an anonymous ancestor first
01037       bindingManager->GetInsertionParent(element, getter_AddRefs(ancestor));
01038     }
01039     if (!ancestor) {
01040       // if we didn't find an anonymous ancestor, use the explicit one
01041       ancestor = element->GetParent();
01042     }
01043     if (!ancestor) {
01044       // reached the top of our parent chain without finding an SVG ancestor
01045       break;
01046     }
01047 
01048     nsCOMPtr<nsIDOMSVGSVGElement> viewportElement = do_QueryInterface(ancestor);
01049     if (viewportElement) {
01050       rv = viewportElement->GetViewboxToViewportTransform(getter_AddRefs(ancestorCTM));
01051       if (NS_FAILED(rv)) return rv;
01052       break;
01053     }
01054 
01055     nsCOMPtr<nsIDOMSVGLocatable> locatableElement = do_QueryInterface(ancestor);
01056     if (locatableElement) {
01057       rv = locatableElement->GetCTM(getter_AddRefs(ancestorCTM));
01058       if (NS_FAILED(rv)) return rv;
01059       break;
01060     }
01061 
01062     // ancestor was not SVG content. loop until we find an SVG ancestor
01063     element = ancestor;
01064     ancestorCount++;
01065   }
01066 
01067   // now account for our offset
01068 
01069   if (!ancestorCTM) {
01070     // we didn't find an SVG ancestor
01071     float s=1, x=0, y=0;
01072     if (ownerDoc &&
01073         ownerDoc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01074       // we're the root element. get our currentScale and currentTranslate vals
01075       mCurrentScale->GetValue(&s);
01076       mCurrentTranslate->GetX(&x);
01077       mCurrentTranslate->GetY(&y);
01078     }
01079     else {
01080       // we're inline in some non-SVG content. get our offset from the root
01081       GetOffsetToAncestor(nsnull, x, y);
01082     }
01083     rv = NS_NewSVGMatrix(getter_AddRefs(ancestorCTM), s, 0, 0, s, x, y);
01084     if (NS_FAILED(rv)) return rv;
01085   }
01086   else {
01087     // we found an SVG ancestor
01088     float x=0, y=0;
01089     nsCOMPtr<nsIDOMSVGMatrix> tmp;
01090     if (ancestorCount == 0) {
01091       // our immediate parent is an SVG element. get our 'x' and 'y' attribs
01092       nsCOMPtr<nsIDOMSVGLength> length;
01093       mX->GetAnimVal(getter_AddRefs(length));
01094       length->GetValue(&x);
01095       mY->GetAnimVal(getter_AddRefs(length));
01096       length->GetValue(&y);
01097     }
01098     else {
01099       // We have an SVG ancestor, but with non-SVG content between us
01100 #if 0
01101       nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject
01102                                               = do_QueryInterface(ancestor);
01103       if (!foreignObject) {
01104         NS_ERROR("the none-SVG content in the parent chain between us and our "
01105                  "SVG ancestor isn't rooted in a foreignObject element");
01106         return NS_ERROR_FAILURE;
01107       }
01108 #endif
01109       // XXXjwatt: this isn't quite right since foreignObject can transform its
01110       // content, but it's close enough until we turn foreignObject back on
01111       GetOffsetToAncestor(ancestor, x, y);
01112     }
01113     rv = ancestorCTM->Translate(x, y, getter_AddRefs(tmp));
01114     if (NS_FAILED(rv)) return rv;
01115     ancestorCTM.swap(tmp);
01116   }
01117 
01118   // finally append our viewbox transform
01119 
01120   nsCOMPtr<nsIDOMSVGMatrix> tmp;
01121   rv = GetViewboxToViewportTransform(getter_AddRefs(tmp));
01122   if (NS_FAILED(rv)) return rv;
01123   return ancestorCTM->Multiply(tmp, _retval);  // addrefs, so we don't
01124 }
01125 
01126 /* nsIDOMSVGMatrix getScreenCTM (); */
01127 NS_IMETHODIMP
01128 nsSVGSVGElement::GetScreenCTM(nsIDOMSVGMatrix **_retval)
01129 {
01130   nsresult rv;
01131   *_retval = nsnull;
01132 
01133   // first try to get the "screen" CTM of our nearest SVG ancestor
01134 
01135   nsIBindingManager *bindingManager = nsnull;
01136   // XXXbz I _think_ this is right.  We want to be using the binding manager
01137   // that would have attached the bindings that gives us our anonymous
01138   // ancestors. That's the binding manager for the document we actually belong
01139   // to, which is our owner doc.
01140   nsIDocument* ownerDoc = GetOwnerDoc();
01141   if (ownerDoc) {
01142     bindingManager = ownerDoc->BindingManager();
01143   }
01144 
01145   nsCOMPtr<nsIContent> element = this;
01146   nsCOMPtr<nsIContent> ancestor;
01147   unsigned short ancestorCount = 0;
01148   nsCOMPtr<nsIDOMSVGMatrix> ancestorScreenCTM;
01149 
01150   while (1) {
01151     if (bindingManager) {
01152       // check for an anonymous ancestor first
01153       bindingManager->GetInsertionParent(element, getter_AddRefs(ancestor));
01154     }
01155     if (!ancestor) {
01156       // if we didn't find an anonymous ancestor, use the explicit one
01157       ancestor = element->GetParent();
01158     }
01159     if (!ancestor) {
01160       // reached the top of our parent chain without finding an SVG ancestor
01161       break;
01162     }
01163 
01164     nsCOMPtr<nsIDOMSVGLocatable> locatableElement = do_QueryInterface(ancestor);
01165     if (locatableElement) {
01166       rv = locatableElement->GetScreenCTM(getter_AddRefs(ancestorScreenCTM));
01167       if (NS_FAILED(rv)) return rv;
01168       break;
01169     }
01170 
01171     // ancestor was not SVG content. loop until we find an SVG ancestor
01172     element = ancestor;
01173     ancestorCount++;
01174   }
01175 
01176   // now account for our offset
01177 
01178   if (!ancestorScreenCTM) {
01179     // we didn't find an SVG ancestor
01180     float s=1, x=0, y=0;
01181     if (ownerDoc &&
01182         ownerDoc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01183       // we're the root element. get our currentScale and currentTranslate vals
01184       mCurrentScale->GetValue(&s);
01185       mCurrentTranslate->GetX(&x);
01186       mCurrentTranslate->GetY(&y);
01187     }
01188     else {
01189       // we're inline in some non-SVG content. get our offset from the root
01190       GetOffsetToAncestor(nsnull, x, y);
01191     }
01192     rv = NS_NewSVGMatrix(getter_AddRefs(ancestorScreenCTM), s, 0, 0, s, x, y);
01193     if (NS_FAILED(rv)) return rv;
01194   }
01195   else {
01196     // we found an SVG ancestor
01197     float x=0, y=0;
01198     nsCOMPtr<nsIDOMSVGMatrix> tmp;
01199     if (ancestorCount == 0) {
01200       // our immediate parent is an SVG element. get our 'x' and 'y' attribs
01201       nsCOMPtr<nsIDOMSVGLength> length;
01202       mX->GetAnimVal(getter_AddRefs(length));
01203       length->GetValue(&x);
01204       mY->GetAnimVal(getter_AddRefs(length));
01205       length->GetValue(&y);
01206     }
01207     else {
01208       // We have an SVG ancestor, but with non-SVG content between us
01209 #if 0
01210       nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject
01211                                               = do_QueryInterface(ancestor);
01212       if (!foreignObject) {
01213         NS_ERROR("the none-SVG content in the parent chain between us and our "
01214                  "SVG ancestor isn't rooted in a foreignObject element");
01215         return NS_ERROR_FAILURE;
01216       }
01217 #endif
01218       // XXXjwatt: this isn't quite right since foreignObject can transform its
01219       // content, but it's close enough until we turn foreignObject back on
01220       GetOffsetToAncestor(ancestor, x, y);
01221     }
01222     rv = ancestorScreenCTM->Translate(x, y, getter_AddRefs(tmp));
01223     if (NS_FAILED(rv)) return rv;
01224     ancestorScreenCTM.swap(tmp);
01225   }
01226 
01227   // finally append our viewbox transform
01228 
01229   nsCOMPtr<nsIDOMSVGMatrix> tmp;
01230   rv = GetViewboxToViewportTransform(getter_AddRefs(tmp));
01231   if (NS_FAILED(rv)) return rv;
01232   return ancestorScreenCTM->Multiply(tmp, _retval);  // addrefs, so we don't
01233 }
01234 
01235 /* nsIDOMSVGMatrix getTransformToElement (in nsIDOMSVGElement element); */
01236 NS_IMETHODIMP
01237 nsSVGSVGElement::GetTransformToElement(nsIDOMSVGElement *element,
01238                                        nsIDOMSVGMatrix **_retval)
01239 {
01240   if (!element)
01241     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
01242 
01243   nsresult rv;
01244   *_retval = nsnull;
01245   nsCOMPtr<nsIDOMSVGMatrix> ourScreenCTM;
01246   nsCOMPtr<nsIDOMSVGMatrix> targetScreenCTM;
01247   nsCOMPtr<nsIDOMSVGMatrix> tmp;
01248   nsCOMPtr<nsIDOMSVGLocatable> target = do_QueryInterface(element, &rv);
01249   if (NS_FAILED(rv)) return rv;
01250 
01251   // the easiest way to do this (if likely to increase rounding error):
01252   rv = GetScreenCTM(getter_AddRefs(ourScreenCTM));
01253   if (NS_FAILED(rv)) return rv;
01254   rv = target->GetScreenCTM(getter_AddRefs(targetScreenCTM));
01255   if (NS_FAILED(rv)) return rv;
01256   rv = targetScreenCTM->Inverse(getter_AddRefs(tmp));
01257   if (NS_FAILED(rv)) return rv;
01258   return ourScreenCTM->Multiply(tmp, _retval);  // addrefs, so we don't
01259 }
01260 
01261 //----------------------------------------------------------------------
01262 // nsIDOMSVGZoomAndPan methods
01263 
01264 /* attribute unsigned short zoomAndPan; */
01265 NS_IMETHODIMP
01266 nsSVGSVGElement::GetZoomAndPan(PRUint16 *aZoomAndPan)
01267 {
01268   return mZoomAndPan->GetIntegerValue(*aZoomAndPan);
01269 }
01270 
01271 NS_IMETHODIMP
01272 nsSVGSVGElement::SetZoomAndPan(PRUint16 aZoomAndPan)
01273 {
01274   if (aZoomAndPan == nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_DISABLE ||
01275       aZoomAndPan == nsIDOMSVGZoomAndPan::SVG_ZOOMANDPAN_MAGNIFY)
01276     return mZoomAndPan->SetIntegerValue(aZoomAndPan);
01277 
01278   return NS_ERROR_DOM_SVG_INVALID_VALUE_ERR;
01279 }
01280 
01281 //----------------------------------------------------------------------
01282 // nsISVGSVGElement methods:
01283 
01284 NS_IMETHODIMP
01285 nsSVGSVGElement::SetParentCoordCtxProvider(nsSVGCoordCtxProvider *parentCtx)
01286 {
01287   if (!parentCtx) {
01288     NS_ERROR("null parent context");
01289     return NS_ERROR_FAILURE;
01290   }
01291   
01292   // set parent's mmPerPx on our coord contexts:
01293   float mmPerPxX = nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextX())->GetMillimeterPerPixel();
01294   float mmPerPxY = nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextY())->GetMillimeterPerPixel();
01295   SetCoordCtxMMPerPx(mmPerPxX, mmPerPxY);
01296   
01297   // set the parentCtx as context on our width/height/x/y:
01298   {
01299     nsCOMPtr<nsIDOMSVGLength> dom_length;
01300     mX->GetAnimVal(getter_AddRefs(dom_length));
01301     nsCOMPtr<nsISVGLength> l = do_QueryInterface(dom_length);
01302     l->SetContext(nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextX()));
01303   }
01304 
01305   {
01306     nsCOMPtr<nsIDOMSVGLength> dom_length;
01307     mY->GetAnimVal(getter_AddRefs(dom_length));
01308     nsCOMPtr<nsISVGLength> l = do_QueryInterface(dom_length);
01309     l->SetContext(nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextY()));
01310   }
01311 
01312   {
01313     nsCOMPtr<nsIDOMSVGLength> dom_length;
01314     mWidth->GetAnimVal(getter_AddRefs(dom_length));
01315     nsCOMPtr<nsISVGLength> l = do_QueryInterface(dom_length);
01316     l->SetContext(nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextX()));
01317   }
01318 
01319   {
01320     nsCOMPtr<nsIDOMSVGLength> dom_length;
01321     mHeight->GetAnimVal(getter_AddRefs(dom_length));
01322     nsCOMPtr<nsISVGLength> l = do_QueryInterface(dom_length);
01323     l->SetContext(nsRefPtr<nsSVGCoordCtx>(parentCtx->GetContextY()));
01324   }
01325   
01326   return NS_OK;
01327 }
01328 
01329 NS_IMETHODIMP
01330 nsSVGSVGElement::GetCurrentScaleNumber(nsIDOMSVGNumber **aResult)
01331 {
01332   *aResult = mCurrentScale;
01333   NS_ADDREF(*aResult);
01334   return NS_OK;
01335 }
01336 
01337 NS_IMETHODIMP
01338 nsSVGSVGElement::GetZoomAndPanEnum(nsISVGEnum **aResult)
01339 {
01340   *aResult = mZoomAndPan;
01341   NS_ADDREF(*aResult);
01342   return NS_OK;
01343 }
01344 
01345 NS_IMETHODIMP
01346 nsSVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
01347 {
01348   RecordCurrentScaleTranslate();
01349   mDispatchEvent = PR_FALSE;
01350   SetCurrentScale(s);  // clamps! don't call mCurrentScale->SetValue() directly
01351   mCurrentTranslate->SetX(x);
01352   mCurrentTranslate->SetY(y);
01353   mDispatchEvent = PR_TRUE;
01354 
01355   // now dispatch an SVGZoom event if we are the root element
01356   nsIDocument* doc = GetCurrentDoc();
01357   if (doc) {
01358     nsCOMPtr<nsIPresShell> presShell = doc->GetShellAt(0);
01359     NS_ASSERTION(presShell, "no presShell");
01360     if (presShell &&
01361         doc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01362       nsEventStatus status = nsEventStatus_eIgnore;
01363       nsGUIEvent event(PR_TRUE, NS_SVG_ZOOM, 0);
01364       event.eventStructType = NS_SVGZOOM_EVENT;
01365       presShell->HandleDOMEventWithTarget(this, &event, &status);
01366     }
01367   }
01368   return NS_OK;
01369 }
01370 
01371 NS_IMETHODIMP
01372 nsSVGSVGElement::SetCurrentTranslate(float x, float y)
01373 {
01374   RecordCurrentScaleTranslate();
01375   mDispatchEvent = PR_FALSE;
01376   mCurrentTranslate->SetX(x);
01377   mCurrentTranslate->SetY(y);
01378   mDispatchEvent = PR_TRUE;
01379 
01380   // now dispatch an SVGScroll event if we are the root element
01381   nsIDocument* doc = GetCurrentDoc();
01382   if (doc) {
01383     nsCOMPtr<nsIPresShell> presShell = doc->GetShellAt(0);
01384     NS_ASSERTION(presShell, "no presShell");
01385     if (presShell &&
01386         doc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01387       nsEventStatus status = nsEventStatus_eIgnore;
01388       nsEvent event(PR_TRUE, NS_SVG_SCROLL);
01389       event.eventStructType = NS_SVG_EVENT;
01390       presShell->HandleDOMEventWithTarget(this, &event, &status);
01391     }
01392   }
01393   return NS_OK;
01394 }
01395 
01396 NS_IMETHODIMP_(void)
01397 nsSVGSVGElement::RecordCurrentScaleTranslate()
01398 {
01399   // IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then
01400   // mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all
01401   // be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an
01402   // SVGZoomEvent's properties previousScale and previousTranslate must contain
01403   // the state of currentScale and currentTranslate immediately before the
01404   // change that caused the event's dispatch, which is *not* necessarily the
01405   // same thing as the values of currentScale and currentTranslate prior to
01406   // their own last change.
01407   mCurrentScale->GetValue(&mPreviousScale);
01408   mCurrentTranslate->GetX(&mPreviousTranslate_x);
01409   mCurrentTranslate->GetY(&mPreviousTranslate_y);
01410 }
01411 
01412 NS_IMETHODIMP_(float)
01413 nsSVGSVGElement::GetPreviousTranslate_x()
01414 {
01415   return mPreviousTranslate_x;
01416 }
01417 
01418 NS_IMETHODIMP_(float)
01419 nsSVGSVGElement::GetPreviousTranslate_y()
01420 {
01421   return mPreviousTranslate_y;
01422 }
01423 
01424 NS_IMETHODIMP_(float)
01425 nsSVGSVGElement::GetPreviousScale()
01426 {
01427   return mPreviousScale;
01428 }
01429 
01430 //----------------------------------------------------------------------
01431 // nsIStyledContent methods
01432 
01433 NS_IMETHODIMP_(PRBool)
01434 nsSVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
01435 {
01436   static const MappedAttributeEntry* const map[] = {
01437     sFillStrokeMap,
01438     sGraphicsMap,
01439     sTextContentElementsMap,
01440     sFontSpecificationMap,
01441     sViewportsMap
01442   };
01443 
01444   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
01445     nsSVGSVGElementBase::IsAttributeMapped(name);
01446 }
01447 
01448 //----------------------------------------------------------------------
01449 // nsISVGValueObserver methods:
01450 
01451 NS_IMETHODIMP
01452 nsSVGSVGElement::WillModifySVGObservable(nsISVGValue* observable,
01453                                          nsISVGValue::modificationType aModType)
01454 {
01455   if (mDispatchEvent) {
01456     // Modification isn't due to calling SetCurrent[Scale]Translate, so if
01457     // currentScale or currentTranslate is about to change we must record their
01458     // current values.
01459     nsCOMPtr<nsIDOMSVGNumber> n = do_QueryInterface(observable);
01460     if (n && n==mCurrentScale) {
01461       RecordCurrentScaleTranslate();
01462     }
01463     else {
01464       nsCOMPtr<nsIDOMSVGPoint> p = do_QueryInterface(observable);
01465       if (p && p==mCurrentTranslate) {
01466         RecordCurrentScaleTranslate();
01467       }
01468     }
01469   }
01470   return NS_OK;
01471 }
01472 
01473 NS_IMETHODIMP
01474 nsSVGSVGElement::DidModifySVGObservable (nsISVGValue* observable,
01475                                          nsISVGValue::modificationType aModType)
01476 {
01477   nsIDocument* doc = GetCurrentDoc();
01478   if (!doc) return NS_ERROR_FAILURE;
01479   nsCOMPtr<nsIPresShell> presShell = doc->GetShellAt(0);
01480   NS_ASSERTION(presShell, "no presShell");
01481   if (!presShell) return NS_ERROR_FAILURE;
01482 
01483   // If currentScale or currentTranslate has changed, we are the root element,
01484   // and the changes wasn't caused by SetCurrent[Scale]Translate then we must
01485   // dispatch an SVGZoom or SVGScroll DOM event before repainting
01486   nsCOMPtr<nsIDOMSVGNumber> n = do_QueryInterface(observable);
01487   if (n && n==mCurrentScale) {
01488     if (mDispatchEvent &&
01489         doc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01490       nsEventStatus status = nsEventStatus_eIgnore;
01491       nsGUIEvent event(PR_TRUE, NS_SVG_ZOOM, 0);
01492       event.eventStructType = NS_SVGZOOM_EVENT;
01493       presShell->HandleDOMEventWithTarget(this, &event, &status);
01494     }
01495     else {
01496       return NS_OK;  // we don't care about currentScale changes on non-root
01497     }
01498   }
01499   else {
01500     nsCOMPtr<nsIDOMSVGPoint> p = do_QueryInterface(observable);
01501     if (p && p==mCurrentTranslate) {
01502       if (mDispatchEvent &&
01503           doc->GetRootContent() == NS_STATIC_CAST(nsIContent*, this)) {
01504         nsEventStatus status = nsEventStatus_eIgnore;
01505         nsEvent event(PR_TRUE, NS_SVG_SCROLL);
01506         event.eventStructType = NS_SVG_EVENT;
01507         presShell->HandleDOMEventWithTarget(this, &event, &status);
01508       }
01509       else {
01510         return NS_OK;  // we don't care about currentScale changes on non-root
01511       }
01512     }
01513   }
01514 
01515   // invalidate viewbox -> viewport xform & inform frames
01516   mViewBoxToViewportTransform = nsnull;
01517 
01518   nsIFrame* frame;
01519   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
01520   if (frame) {
01521     nsISVGSVGFrame* svgframe;
01522     CallQueryInterface(frame, &svgframe);
01523     if (svgframe) {
01524       svgframe->NotifyViewportChange();
01525     }
01526 #ifdef DEBUG
01527     else {
01528       // XXX we get here during nsSVGOuterSVGFrame::Init() since that
01529       // function is called before the presshell association between us
01530       // and our frame is established.
01531       NS_WARNING("wrong frame type");
01532     }
01533 #endif
01534   }
01535   
01536   return NS_OK;
01537 }
01538 
01539 //----------------------------------------------------------------------
01540 // nsSVGElement overrides
01541 
01542 PRBool
01543 nsSVGSVGElement::IsEventName(nsIAtom* aName)
01544 {
01545   return IsGraphicElementEventName(aName) ||
01546 
01547   /* The following are for events that are only applicable to outermost 'svg'
01548      elements. We don't check if we're an outer 'svg' element in case we're not
01549      inserted into the document yet, but since the target of the events in
01550      question will always be the outermost 'svg' element, this shouldn't cause
01551      any real problems.
01552   */
01553          aName == nsSVGAtoms::onunload    ||
01554          aName == nsSVGAtoms::onscroll    ||
01555          aName == nsSVGAtoms::onzoom;
01556 }
01557 
01558 //----------------------------------------------------------------------
01559 // implementation helpers
01560 
01561 // if an ancestor isn't specified, obtains offset from root frame
01562 void nsSVGSVGElement::GetOffsetToAncestor(nsIContent* ancestor,
01563                                           float &x, float &y)
01564 {
01565   x = 0.0f;
01566   y = 0.0f;
01567 
01568   nsIDocument *document = GetCurrentDoc();
01569   if (!document) return;
01570 
01571   // Flush all pending notifications so that our frames are uptodate
01572   // Make sure to do this before we start grabbing layout objects like
01573   // presshells.
01574   document->FlushPendingNotifications(Flush_Layout);
01575   
01576   nsIPresShell *presShell = document->GetShellAt(0);
01577   if (!presShell) {
01578     return;
01579   }
01580 
01581   nsPresContext *context = presShell->GetPresContext();
01582   if (!context) {
01583     return;
01584   }
01585 
01586   nsIFrame* frame;
01587   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
01588   nsIFrame* ancestorFrame;
01589   if (ancestor)
01590     presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, ancestor), &ancestorFrame);
01591   else
01592     ancestorFrame = presShell->GetRootFrame();
01593 
01594   if (frame && ancestorFrame) {
01595     nsPoint point = frame->GetOffsetTo(ancestorFrame);
01596     x = point.x * context->TwipsToPixels();
01597     y = point.y * context->TwipsToPixels();
01598   }
01599 }