Back to index

lightning-sunbird  0.9+nobinonly
nsSVGRectFrame.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  *   William Cook <william.cook@crocodile-clips.com> (original author)
00024  *   Håkan Waara <hwaara@chello.se>
00025  *   Alex Fritze <alex.fritze@crocodile-clips.com>
00026  *   Jonathan Watt <jonathan.watt@strath.ac.uk>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsSVGPathGeometryFrame.h"
00043 #include "nsISVGRendererPathBuilder.h"
00044 #include "nsIDOMSVGAnimatedLength.h"
00045 #include "nsIDOMSVGLength.h"
00046 #include "nsIDOMSVGRectElement.h"
00047 #include "nsINameSpaceManager.h"
00048 #include "nsSVGAtoms.h"
00049 #include "nsLayoutAtoms.h"
00050 
00051 class nsSVGRectFrame : public nsSVGPathGeometryFrame
00052 {
00053 protected:
00054   friend nsresult
00055   NS_NewSVGRectFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00056                      nsIFrame** aNewFrame);
00057 
00058   virtual ~nsSVGRectFrame();
00059   NS_IMETHOD InitSVG();
00060 
00061 public:
00062   // nsISVGValueObserver interface:
00063   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
00064                                     nsISVGValue::modificationType aModType);
00065 
00066   // nsISVGPathGeometrySource interface:
00067   NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder);
00068 
00074   virtual nsIAtom* GetType() const;
00075 
00076 #ifdef DEBUG
00077   NS_IMETHOD GetFrameName(nsAString& aResult) const
00078   {
00079     return MakeFrameName(NS_LITERAL_STRING("SVGRect"), aResult);
00080   }
00081 #endif
00082 
00083 private:
00084   nsCOMPtr<nsIDOMSVGLength> mX;
00085   nsCOMPtr<nsIDOMSVGLength> mY;
00086   nsCOMPtr<nsIDOMSVGLength> mWidth;
00087   nsCOMPtr<nsIDOMSVGLength> mHeight;
00088   nsCOMPtr<nsIDOMSVGLength> mRx;
00089   nsCOMPtr<nsIDOMSVGLength> mRy;
00090 };
00091 
00092 //----------------------------------------------------------------------
00093 // Implementation
00094 
00095 nsresult
00096 NS_NewSVGRectFrame(nsIPresShell* aPresShell, nsIContent* aContent,
00097                    nsIFrame** aNewFrame)
00098 {
00099   *aNewFrame = nsnull;
00100 
00101   nsCOMPtr<nsIDOMSVGRectElement> Rect = do_QueryInterface(aContent);
00102   if (!Rect) {
00103     NS_ASSERTION(Rect != nsnull, "wrong content element");
00104     return NS_ERROR_NO_INTERFACE;
00105   }
00106 
00107   nsSVGRectFrame* it = new (aPresShell) nsSVGRectFrame;
00108   if (!it)
00109     return NS_ERROR_OUT_OF_MEMORY;
00110 
00111   *aNewFrame = it;
00112   return NS_OK;
00113 }
00114 
00115 nsSVGRectFrame::~nsSVGRectFrame()
00116 {
00117   nsCOMPtr<nsISVGValue> value;
00118   if (mX && (value = do_QueryInterface(mX)))
00119       value->RemoveObserver(this);
00120   if (mY && (value = do_QueryInterface(mY)))
00121       value->RemoveObserver(this);
00122   if (mWidth && (value = do_QueryInterface(mWidth)))
00123       value->RemoveObserver(this);
00124   if (mHeight && (value = do_QueryInterface(mHeight)))
00125       value->RemoveObserver(this);
00126   if (mRx && (value = do_QueryInterface(mRx)))
00127       value->RemoveObserver(this);
00128   if (mRy && (value = do_QueryInterface(mRy)))
00129       value->RemoveObserver(this);
00130 }
00131 
00132 NS_IMETHODIMP
00133 nsSVGRectFrame::InitSVG()
00134 {
00135   nsresult rv = nsSVGPathGeometryFrame::InitSVG();
00136   if (NS_FAILED(rv))
00137     return rv;
00138 
00139   nsCOMPtr<nsIDOMSVGRectElement> Rect = do_QueryInterface(mContent);
00140 
00141   {
00142     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00143     Rect->GetX(getter_AddRefs(length));
00144     length->GetAnimVal(getter_AddRefs(mX));
00145     NS_ASSERTION(mX, "no x");
00146     if (!mX)
00147       return NS_ERROR_FAILURE;
00148     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mX);
00149     if (value)
00150       value->AddObserver(this);
00151   }
00152 
00153   {
00154     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00155     Rect->GetY(getter_AddRefs(length));
00156     length->GetAnimVal(getter_AddRefs(mY));
00157     NS_ASSERTION(mY, "no y");
00158     if (!mY)
00159       return NS_ERROR_FAILURE;
00160     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mY);
00161     if (value)
00162       value->AddObserver(this);
00163   }
00164 
00165   {
00166     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00167     Rect->GetWidth(getter_AddRefs(length));
00168     length->GetAnimVal(getter_AddRefs(mWidth));
00169     NS_ASSERTION(mWidth, "no width");
00170     if (!mWidth)
00171       return NS_ERROR_FAILURE;
00172     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mWidth);
00173     if (value)
00174       value->AddObserver(this);
00175   }
00176   {
00177     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00178     Rect->GetHeight(getter_AddRefs(length));
00179     length->GetAnimVal(getter_AddRefs(mHeight));
00180     NS_ASSERTION(mHeight, "no height");
00181     if (!mHeight)
00182       return NS_ERROR_FAILURE;
00183     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mHeight);
00184     if (value)
00185       value->AddObserver(this);
00186   }
00187 
00188   {
00189     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00190     Rect->GetRx(getter_AddRefs(length));
00191     length->GetAnimVal(getter_AddRefs(mRx));
00192     NS_ASSERTION(mRx, "no rx");
00193     if (!mRx)
00194       return NS_ERROR_FAILURE;
00195     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mRx);
00196     if (value)
00197       value->AddObserver(this);
00198   }
00199 
00200   {
00201     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00202     Rect->GetRy(getter_AddRefs(length));
00203     length->GetAnimVal(getter_AddRefs(mRy));
00204     NS_ASSERTION(mRy, "no ry");
00205     if (!mRy)
00206       return NS_ERROR_FAILURE;
00207     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mRy);
00208     if (value)
00209       value->AddObserver(this);
00210   }
00211 
00212   return NS_OK; 
00213 }
00214 
00215 //----------------------------------------------------------------------
00216 // nsISVGValueObserver methods:
00217 
00218 NS_IMETHODIMP
00219 nsSVGRectFrame::DidModifySVGObservable(nsISVGValue* observable,
00220                                        nsISVGValue::modificationType aModType)
00221 {
00222   nsCOMPtr<nsIDOMSVGLength> l = do_QueryInterface(observable);
00223   if (l && (mX==l || mY==l || mWidth==l || mHeight==l || mRx==l || mRy==l)) {
00224     UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_PATH);
00225     return NS_OK;
00226   }
00227 
00228   return nsSVGPathGeometryFrame::DidModifySVGObservable(observable, aModType);
00229 }
00230 
00231 //----------------------------------------------------------------------
00232 // nsISVGPathGeometrySource methods:
00233 
00234 /* void constructPath (in nsISVGRendererPathBuilder pathBuilder); */
00235 NS_IMETHODIMP
00236 nsSVGRectFrame::ConstructPath(nsISVGRendererPathBuilder* pathBuilder)
00237 {
00238   float x, y, width, height, rx, ry;
00239 
00240   mX->GetValue(&x);
00241   mY->GetValue(&y);
00242   mWidth->GetValue(&width);
00243   mHeight->GetValue(&height);
00244   mRx->GetValue(&rx);
00245   mRy->GetValue(&ry);
00246 
00247   /* In a perfect world, this would be handled by the DOM, and 
00248      return a DOM exception. */
00249   if (width <= 0 || height <= 0 || ry < 0 || rx < 0)
00250     return NS_OK;
00251 
00252   /* Clamp rx and ry to half the rect's width and height respectively. */
00253   float halfWidth  = width/2;
00254   float halfHeight = height/2;
00255   if (rx > halfWidth)
00256     rx = halfWidth;
00257   if (ry > halfHeight)
00258     ry = halfHeight;
00259 
00260   /* If either the 'rx' or the 'ry' attribute isn't set in the markup, then we
00261      have to set it to the value of the other. We do this after clamping rx and
00262      ry since omiting one of the attributes implicitly means they should both
00263      be the same. */
00264   PRBool hasRx = mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::rx);
00265   PRBool hasRy = mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::ry);
00266   if (hasRx && !hasRy)
00267     ry = rx;
00268   else if (hasRy && !hasRx)
00269     rx = ry;
00270 
00271   /* However, we may now have made rx > width/2 or else ry > height/2. (If this
00272      is the case, we know we must be giving rx and ry the same value.) */
00273   if (rx > halfWidth)
00274     rx = ry = halfWidth;
00275   else if (ry > halfHeight)
00276     rx = ry = halfHeight;
00277 
00278   pathBuilder->Moveto(x+rx, y);
00279   pathBuilder->Lineto(x+width-rx, y);
00280   pathBuilder->Arcto(x+width, y+ry , rx, ry, 0.0f, PR_FALSE, PR_TRUE);
00281   pathBuilder->Lineto(x+width, y+height-ry);
00282   pathBuilder->Arcto(x+width-rx, y+height , rx, ry, 0.0f, PR_FALSE, PR_TRUE);
00283   pathBuilder->Lineto(x+rx,y+height);
00284   pathBuilder->Arcto(x, y+height-ry , rx, ry, 0.0f, PR_FALSE, PR_TRUE);
00285   pathBuilder->Lineto(x,y+ry);
00286   pathBuilder->Arcto(x+rx, y, rx, ry, 0.0f, PR_FALSE, PR_TRUE);
00287   pathBuilder->ClosePath(&x,&y);
00288 
00289   return NS_OK;
00290 }
00291 
00292 nsIAtom *
00293 nsSVGRectFrame::GetType() const
00294 {
00295   return nsLayoutAtoms::svgRectFrame;
00296 }