Back to index

lightning-sunbird  0.9+nobinonly
nsSVGTextPathFrame.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 IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nsSVGTSpanFrame.h"
00038 #include "nsIDOMSVGTextPathElement.h"
00039 #include "nsIDOMSVGAnimatedLength.h"
00040 #include "nsIDOMSVGAnimatedString.h"
00041 #include "nsSVGLengthList.h"
00042 #include "nsISVGPathFlatten.h"
00043 #include "nsSVGLength.h"
00044 
00045 #include "nsIDOMSVGAnimatedPathData.h"
00046 #include "nsIDOMSVGPathSegList.h"
00047 #include "nsIDOMSVGURIReference.h"
00048 #include "nsIDOMDocument.h"
00049 #include "nsIDocument.h"
00050 
00051 typedef nsSVGTSpanFrame nsSVGTextPathFrameBase;
00052 
00053 class nsSVGTextPathFrame : public nsSVGTextPathFrameBase,
00054                            public nsISVGPathFlatten
00055 {
00056 public:
00057 
00063   virtual nsIAtom* GetType() const;
00064   virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
00065 
00066 #ifdef DEBUG
00067   NS_IMETHOD GetFrameName(nsAString& aResult) const
00068   {
00069     return MakeFrameName(NS_LITERAL_STRING("SVGTextPath"), aResult);
00070   }
00071 #endif
00072 
00073   // nsISVGValueObserver interface:
00074   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
00075                                     nsISVGValue::modificationType aModType);
00076 
00077   // nsISVGPathFlatten interface
00078   NS_IMETHOD GetFlattenedPath(nsSVGPathData **data, PRBool useLocalTransform);
00079 
00080    // nsISupports interface:
00081   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00082 
00083 private:
00084   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00085   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00086 
00087 protected:
00088   virtual ~nsSVGTextPathFrame();
00089   virtual nsresult InitSVG();
00090 
00091   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetX();
00092   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetY();
00093   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDx();
00094   NS_IMETHOD_(already_AddRefed<nsIDOMSVGLengthList>) GetDy();
00095 
00096 private:
00097 
00098   nsCOMPtr<nsIDOMSVGLength> mStartOffset;
00099   nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
00100   nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
00101 
00102   nsCOMPtr<nsISVGLengthList> mX;
00103 };
00104 
00105 NS_INTERFACE_MAP_BEGIN(nsSVGTextPathFrame)
00106   NS_INTERFACE_MAP_ENTRY(nsISVGPathFlatten)
00107 NS_INTERFACE_MAP_END_INHERITING(nsSVGTSpanFrame)
00108 
00109 
00110 //----------------------------------------------------------------------
00111 // Implementation
00112 
00113 nsresult
00114 NS_NewSVGTextPathFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00115                        nsIFrame* parentFrame, nsIFrame** aNewFrame)
00116 {
00117   *aNewFrame = nsnull;
00118 
00119   NS_ASSERTION(parentFrame, "null parent");
00120   nsISVGTextFrame *text_container;
00121   parentFrame->QueryInterface(NS_GET_IID(nsISVGTextFrame), (void**)&text_container);
00122   if (!text_container) {
00123     NS_ERROR("trying to construct an SVGTextPathFrame for an invalid container");
00124     return NS_ERROR_FAILURE;
00125   }
00126 
00127   nsCOMPtr<nsIDOMSVGTextPathElement> tspan_elem = do_QueryInterface(aContent);
00128   if (!tspan_elem) {
00129     NS_ERROR("Trying to construct an SVGTextPathFrame for a "
00130              "content element that doesn't support the right interfaces");
00131     return NS_ERROR_FAILURE;
00132   }
00133 
00134   nsSVGTextPathFrame* it = new (aPresShell) nsSVGTextPathFrame;
00135   if (nsnull == it)
00136     return NS_ERROR_OUT_OF_MEMORY;
00137 
00138   *aNewFrame = it;
00139 
00140   return NS_OK;
00141 }
00142 
00143 nsSVGTextPathFrame::~nsSVGTextPathFrame()
00144 {
00145   NS_REMOVE_SVGVALUE_OBSERVER(mStartOffset);
00146   NS_REMOVE_SVGVALUE_OBSERVER(mHref);
00147   NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
00148 }
00149 
00150 nsresult
00151 nsSVGTextPathFrame::InitSVG()
00152 {
00153   nsCOMPtr<nsIDOMSVGTextPathElement> tpath = do_QueryInterface(mContent);
00154 
00155   {
00156     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00157     tpath->GetStartOffset(getter_AddRefs(length));
00158     length->GetAnimVal(getter_AddRefs(mStartOffset));
00159     NS_ASSERTION(mStartOffset, "no startOffset");
00160     if (!mStartOffset)
00161       return NS_ERROR_FAILURE;
00162 
00163     NS_NewSVGLengthList(getter_AddRefs(mX));
00164     if (mX) {
00165       nsCOMPtr<nsIDOMSVGLength> length;
00166       mX->AppendItem(mStartOffset, getter_AddRefs(length));
00167     }
00168 
00169     NS_ADD_SVGVALUE_OBSERVER(mStartOffset);
00170   }
00171 
00172   {
00173     nsCOMPtr<nsIDOMSVGURIReference> aRef = do_QueryInterface(mContent);
00174     if (aRef)
00175       aRef->GetHref(getter_AddRefs(mHref));
00176     if (!mHref)
00177       return NS_ERROR_FAILURE;
00178     NS_ADD_SVGVALUE_OBSERVER(mHref);
00179   }
00180 
00181   return NS_OK;
00182 }
00183 
00184 nsIAtom *
00185 nsSVGTextPathFrame::GetType() const
00186 {
00187   return nsLayoutAtoms::svgTextPathFrame;
00188 }
00189 
00190 PRBool
00191 nsSVGTextPathFrame::IsFrameOfType(PRUint32 aFlags) const
00192 {
00193   return !(aFlags & ~nsIFrame::eSVG);
00194 }
00195 
00196 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00197 nsSVGTextPathFrame::GetX()
00198 {
00199   nsISVGLengthList *retval = mX;
00200   NS_IF_ADDREF(retval);
00201   return retval;
00202 }
00203 
00204 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00205 nsSVGTextPathFrame::GetY()
00206 {
00207   return nsnull;
00208 }
00209 
00210 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00211 nsSVGTextPathFrame::GetDx()
00212 {
00213   return nsnull;
00214 }
00215 
00216 NS_IMETHODIMP_(already_AddRefed<nsIDOMSVGLengthList>)
00217 nsSVGTextPathFrame::GetDy()
00218 {
00219   return nsnull;
00220 }
00221 
00222 //----------------------------------------------------------------------
00223 // nsISVGPathFlatten methods:
00224 
00225 nsresult GetReferencedFrame(nsIFrame **aServer, nsCAutoString& uriSpec, nsIContent *aContent,
00226                                         nsIPresShell *aPresShell)
00227 {
00228   nsresult rv = NS_OK;
00229   *aServer = nsnull;
00230 
00231   // Get the ID from the spec (no ID = an error)
00232   PRInt32 pos = uriSpec.FindChar('#');
00233   if (pos == -1) {
00234     NS_ASSERTION(pos != -1, "URI Spec not a reference");
00235     return NS_ERROR_FAILURE;
00236   }
00237 
00238   // Strip off the hash and get the name
00239   nsCAutoString aURICName;
00240   uriSpec.Right(aURICName, uriSpec.Length()-(pos + 1));
00241 
00242   // Get a unicode string
00243   nsAutoString  aURIName;
00244   CopyUTF8toUTF16(aURICName, aURIName);
00245 
00246   // Get the domDocument
00247   nsCOMPtr<nsIDOMDocument>domDoc = do_QueryInterface(aContent->GetDocument());
00248   NS_ASSERTION(domDoc, "Content doesn't reference a dom Document");
00249   if (domDoc == nsnull) {
00250     return NS_ERROR_FAILURE;
00251   }
00252 
00253   // Get the element
00254   nsCOMPtr<nsIDOMElement> element;
00255   rv = domDoc->GetElementById(aURIName, getter_AddRefs(element));
00256   if (!NS_SUCCEEDED(rv) || element == nsnull) {
00257     return rv;
00258   }
00259 
00260   // Get the Primary Frame
00261   nsCOMPtr<nsIContent> aGContent = do_QueryInterface(element);
00262   NS_ASSERTION(aPresShell, "Get referenced SVG frame -- no pres shell provided");
00263   if (!aPresShell)
00264     return NS_ERROR_FAILURE;
00265 
00266   rv = aPresShell->GetPrimaryFrameFor(aGContent, aServer);
00267   if (!(*aServer)) return NS_ERROR_FAILURE;
00268   return rv;
00269 }
00270 
00271 NS_IMETHODIMP
00272 nsSVGTextPathFrame::GetFlattenedPath(nsSVGPathData **data,
00273                                      PRBool useLocalTransform) {
00274   *data = nsnull;
00275   nsIFrame *path = nsnull;
00276 
00277   nsAutoString aStr;
00278   mHref->GetAnimVal(aStr);
00279 
00280   nsCAutoString aCStr;
00281   CopyUTF16toUTF8(aStr, aCStr);
00282 
00283   GetReferencedFrame(&path, aCStr, mContent, GetPresContext()->PresShell());
00284 
00285   if (!path)
00286     return NS_ERROR_FAILURE;
00287 
00288   if (!mSegments) {
00289     nsCOMPtr<nsIDOMSVGAnimatedPathData> data =
00290       do_QueryInterface(path->GetContent());
00291     if (data) {
00292       data->GetAnimatedPathSegList(getter_AddRefs(mSegments));
00293       NS_ADD_SVGVALUE_OBSERVER(mSegments);
00294     }
00295   }
00296 
00297   nsISVGPathFlatten *flatten;
00298   CallQueryInterface(path, &flatten);
00299 
00300   if (!flatten)
00301     return NS_ERROR_FAILURE;
00302 
00303   return flatten->GetFlattenedPath(data, PR_TRUE);
00304 }
00305 
00306 //----------------------------------------------------------------------
00307 // nsISVGValueObserver methods:
00308 
00309 NS_IMETHODIMP
00310 nsSVGTextPathFrame::DidModifySVGObservable(nsISVGValue* observable,
00311                                            nsISVGValue::modificationType aModType)
00312 {
00313   nsCOMPtr<nsIDOMSVGAnimatedString> s = do_QueryInterface(observable);
00314   if (s && mHref==s) {
00315     NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
00316     mSegments = nsnull;
00317   }
00318 
00319   return nsSVGTextPathFrameBase::DidModifySVGObservable(observable, aModType);
00320 }