Back to index

lightning-sunbird  0.9+nobinonly
nsSVGGraphicElement.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 "nsSVGGraphicElement.h"
00041 #include "nsSVGTransformList.h"
00042 #include "nsSVGAnimatedTransformList.h"
00043 #include "nsSVGAtoms.h"
00044 #include "nsSVGMatrix.h"
00045 #include "nsISVGSVGElement.h"
00046 #include "nsIDOMEventTarget.h"
00047 #include "nsIBindingManager.h"
00048 #include "nsIDocument.h"
00049 #include "nsIPresShell.h"
00050 #include "nsIFrame.h"
00051 #include "nsISVGChildFrame.h"
00052 #include "nsIDOMSVGPoint.h"
00053 #include "nsDOMError.h"
00054 
00055 //----------------------------------------------------------------------
00056 // nsISupports methods
00057 
00058 NS_IMPL_ADDREF_INHERITED(nsSVGGraphicElement, nsSVGGraphicElementBase)
00059 NS_IMPL_RELEASE_INHERITED(nsSVGGraphicElement, nsSVGGraphicElementBase)
00060 
00061 NS_INTERFACE_MAP_BEGIN(nsSVGGraphicElement)
00062   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLocatable)
00063   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGTransformable)
00064 NS_INTERFACE_MAP_END_INHERITING(nsSVGGraphicElementBase)
00065 
00066 //----------------------------------------------------------------------
00067 // Implementation
00068 
00069 nsSVGGraphicElement::nsSVGGraphicElement(nsINodeInfo *aNodeInfo)
00070   : nsSVGGraphicElementBase(aNodeInfo)
00071 {
00072 
00073 }
00074 
00075 nsresult
00076 nsSVGGraphicElement::Init()
00077 {
00078   nsresult rv = nsSVGGraphicElementBase::Init();
00079   NS_ENSURE_SUCCESS(rv,rv);
00080 
00081   // Create mapped properties:
00082 
00083   // DOM property: transform, #IMPLIED attrib: transform
00084   {
00085     nsCOMPtr<nsIDOMSVGTransformList> transformList;
00086     rv = nsSVGTransformList::Create(getter_AddRefs(transformList));
00087     NS_ENSURE_SUCCESS(rv,rv);
00088     rv = NS_NewSVGAnimatedTransformList(getter_AddRefs(mTransforms),
00089                                         transformList);
00090     NS_ENSURE_SUCCESS(rv,rv);
00091     rv = AddMappedSVGValue(nsSVGAtoms::transform, mTransforms);
00092     NS_ENSURE_SUCCESS(rv,rv);
00093   }
00094 
00095   return rv;
00096 }
00097 
00098 //----------------------------------------------------------------------
00099 // nsIDOMSVGLocatable methods
00100 
00101 /* readonly attribute nsIDOMSVGElement nearestViewportElement; */
00102 NS_IMETHODIMP nsSVGGraphicElement::GetNearestViewportElement(nsIDOMSVGElement * *aNearestViewportElement)
00103 {
00104   NS_NOTYETIMPLEMENTED("nsSVGGraphicElement::GetNearestViewportElement");
00105   return NS_ERROR_NOT_IMPLEMENTED;
00106 }
00107 
00108 /* readonly attribute nsIDOMSVGElement farthestViewportElement; */
00109 NS_IMETHODIMP nsSVGGraphicElement::GetFarthestViewportElement(nsIDOMSVGElement * *aFarthestViewportElement)
00110 {
00111   NS_NOTYETIMPLEMENTED("nsSVGGraphicElement::GetFarthestViewportElement");
00112   return NS_ERROR_NOT_IMPLEMENTED;
00113 }
00114 
00115 /* nsIDOMSVGRect getBBox (); */
00116 NS_IMETHODIMP nsSVGGraphicElement::GetBBox(nsIDOMSVGRect **_retval)
00117 {
00118   *_retval = nsnull;
00119 
00120   nsIDocument* doc = GetCurrentDoc();
00121   if (!doc) return NS_ERROR_FAILURE;
00122   nsIPresShell *presShell = doc->GetShellAt(0);
00123   NS_ASSERTION(presShell, "no presShell");
00124   if (!presShell) return NS_ERROR_FAILURE;
00125 
00126   nsIFrame* frame;
00127   presShell->GetPrimaryFrameFor(NS_STATIC_CAST(nsIStyledContent*, this), &frame);
00128 
00129   NS_ASSERTION(frame, "can't get bounding box for element without frame");
00130 
00131   if (frame) {
00132     nsISVGChildFrame* svgframe;
00133     frame->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&svgframe);
00134     NS_ASSERTION(svgframe, "wrong frame type");
00135     if (svgframe) {
00136       svgframe->SetMatrixPropagation(PR_FALSE);
00137       svgframe->NotifyCanvasTMChanged();
00138       nsresult rv = svgframe->GetBBox(_retval);
00139       svgframe->SetMatrixPropagation(PR_TRUE);
00140       svgframe->NotifyCanvasTMChanged();
00141       return rv;
00142     }
00143   }
00144   return NS_ERROR_FAILURE;
00145 }
00146 
00147 /* nsIDOMSVGMatrix getCTM (); */
00148 NS_IMETHODIMP nsSVGGraphicElement::GetCTM(nsIDOMSVGMatrix **_retval)
00149 {
00150   nsresult rv;
00151   *_retval = nsnull;
00152 
00153   nsIBindingManager *bindingManager = nsnull;
00154   // XXXbz I _think_ this is right.  We want to be using the binding manager
00155   // that would have attached the binding that gives us our anonymous parent.
00156   // That's the binding manager for the document we actually belong to, which
00157   // is our owner doc.
00158   nsIDocument* ownerDoc = GetOwnerDoc();
00159   if (ownerDoc) {
00160     bindingManager = ownerDoc->BindingManager();
00161   }
00162 
00163   nsCOMPtr<nsIContent> parent;
00164   nsCOMPtr<nsIDOMSVGMatrix> parentCTM;
00165 
00166   if (bindingManager) {
00167     // check for an anonymous parent first
00168     bindingManager->GetInsertionParent(this, getter_AddRefs(parent));
00169   }
00170   if (!parent) {
00171     // if we didn't find an anonymous parent, use the explicit one
00172     parent = GetParent();
00173   }
00174 
00175   nsCOMPtr<nsIDOMSVGLocatable> locatableElement = do_QueryInterface(parent);
00176   if (!locatableElement) {
00177     // we don't have an SVGLocatable parent so we aren't even rendered
00178     NS_WARNING("SVGGraphicElement without an SVGLocatable parent");
00179     return NS_ERROR_FAILURE;
00180   }
00181 
00182   // get our parent's CTM
00183   rv = locatableElement->GetCTM(getter_AddRefs(parentCTM));
00184   if (NS_FAILED(rv)) return rv;
00185 
00186   // append our local transformations
00187   nsCOMPtr<nsIDOMSVGTransformList> transforms;
00188   mTransforms->GetAnimVal(getter_AddRefs(transforms));
00189   NS_ENSURE_TRUE(transforms, NS_ERROR_FAILURE);
00190   nsCOMPtr<nsIDOMSVGMatrix> matrix;
00191   transforms->GetConsolidationMatrix(getter_AddRefs(matrix));
00192   return parentCTM->Multiply(matrix, _retval);  // addrefs, so we don't
00193 }
00194 
00195 /* nsIDOMSVGMatrix getScreenCTM (); */
00196 NS_IMETHODIMP nsSVGGraphicElement::GetScreenCTM(nsIDOMSVGMatrix **_retval)
00197 {
00198   nsresult rv;
00199   *_retval = nsnull;
00200 
00201   nsIBindingManager *bindingManager = nsnull;
00202   // XXXbz I _think_ this is right.  We want to be using the binding manager
00203   // that would have attached the binding that gives us our anonymous parent.
00204   // That's the binding manager for the document we actually belong to, which
00205   // is our owner doc.
00206   nsIDocument* ownerDoc = GetOwnerDoc();
00207   if (ownerDoc) {
00208     bindingManager = ownerDoc->BindingManager();
00209   }
00210 
00211   nsCOMPtr<nsIContent> parent;
00212   nsCOMPtr<nsIDOMSVGMatrix> parentScreenCTM;
00213 
00214   if (bindingManager) {
00215     // check for an anonymous parent first
00216     bindingManager->GetInsertionParent(this, getter_AddRefs(parent));
00217   }
00218   if (!parent) {
00219     // if we didn't find an anonymous parent, use the explicit one
00220     parent = GetParent();
00221   }
00222 
00223   nsCOMPtr<nsIDOMSVGLocatable> locatableElement = do_QueryInterface(parent);
00224   if (!locatableElement) {
00225     // we don't have an SVGLocatable parent so we aren't even rendered
00226     NS_WARNING("SVGGraphicElement without an SVGLocatable parent");
00227     return NS_ERROR_FAILURE;
00228   }
00229 
00230   // get our parent's "screen" CTM
00231   rv = locatableElement->GetScreenCTM(getter_AddRefs(parentScreenCTM));
00232   if (NS_FAILED(rv)) return rv;
00233 
00234   // append our local transformations
00235   nsCOMPtr<nsIDOMSVGTransformList> transforms;
00236   mTransforms->GetAnimVal(getter_AddRefs(transforms));
00237   NS_ENSURE_TRUE(transforms, NS_ERROR_FAILURE);
00238   nsCOMPtr<nsIDOMSVGMatrix> matrix;
00239   transforms->GetConsolidationMatrix(getter_AddRefs(matrix));
00240   return parentScreenCTM->Multiply(matrix, _retval);  // addrefs, so we don't
00241 }
00242 
00243 /* nsIDOMSVGMatrix getTransformToElement (in nsIDOMSVGElement element); */
00244 NS_IMETHODIMP nsSVGGraphicElement::GetTransformToElement(nsIDOMSVGElement *element, nsIDOMSVGMatrix **_retval)
00245 {
00246   if (!element)
00247     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00248 
00249   nsresult rv;
00250   *_retval = nsnull;
00251   nsCOMPtr<nsIDOMSVGMatrix> ourScreenCTM;
00252   nsCOMPtr<nsIDOMSVGMatrix> targetScreenCTM;
00253   nsCOMPtr<nsIDOMSVGMatrix> tmp;
00254   nsCOMPtr<nsIDOMSVGLocatable> target = do_QueryInterface(element, &rv);
00255   if (NS_FAILED(rv)) return rv;
00256 
00257   // the easiest way to do this (if likely to increase rounding error):
00258   rv = GetScreenCTM(getter_AddRefs(ourScreenCTM));
00259   if (NS_FAILED(rv)) return rv;
00260   rv = target->GetScreenCTM(getter_AddRefs(targetScreenCTM));
00261   if (NS_FAILED(rv)) return rv;
00262   rv = targetScreenCTM->Inverse(getter_AddRefs(tmp));
00263   if (NS_FAILED(rv)) return rv;
00264   return ourScreenCTM->Multiply(tmp, _retval);  // addrefs, so we don't
00265 }
00266 
00267 //----------------------------------------------------------------------
00268 // nsIDOMSVGTransformable methods
00269 /* readonly attribute nsIDOMSVGAnimatedTransformList transform; */
00270 
00271 NS_IMETHODIMP nsSVGGraphicElement::GetTransform(nsIDOMSVGAnimatedTransformList * *aTransform)
00272 {
00273   *aTransform = mTransforms;
00274   NS_IF_ADDREF(*aTransform);
00275   return NS_OK;
00276 }
00277 
00278 
00279 //----------------------------------------------------------------------
00280 // nsIStyledContent methods
00281 
00282 NS_IMETHODIMP_(PRBool)
00283 nsSVGGraphicElement::IsAttributeMapped(const nsIAtom* name) const
00284 {
00285   static const MappedAttributeEntry* const map[] = {
00286     sFillStrokeMap,
00287     sGraphicsMap,
00288     sColorMap
00289   };
00290   
00291   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
00292     nsSVGGraphicElementBase::IsAttributeMapped(name);
00293 }
00294 
00295 //----------------------------------------------------------------------
00296 // nsSVGElement overrides
00297 
00298 PRBool
00299 nsSVGGraphicElement::IsEventName(nsIAtom* aName)
00300 {
00301   return IsGraphicElementEventName(aName);
00302 }