Back to index

lightning-sunbird  0.9+nobinonly
nsSVGImageFrame.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) 2004
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 "nsSVGPathGeometryFrame.h"
00038 #include "nsIDOMSVGAnimatedLength.h"
00039 #include "nsIDOMSVGLength.h"
00040 #include "nsIDOMSVGImageElement.h"
00041 #include "nsIDOMSVGElement.h"
00042 #include "nsISVGRendererPathBuilder.h"
00043 #include "nsISVGRendererSurface.h"
00044 #include "nsISVGRendererCanvas.h"
00045 #include "nsISVGRenderer.h"
00046 #include "nsIDOMSVGMatrix.h"
00047 #include "nsIDOMSVGAnimPresAspRatio.h"
00048 #include "nsIDOMSVGPresAspectRatio.h"
00049 #include "imgIDecoderObserver.h"
00050 #include "imgIContainerObserver.h"
00051 #include "nsIImageLoadingContent.h"
00052 #include "imgIContainer.h"
00053 #include "gfxIImageFrame.h"
00054 #include "nsIImage.h"
00055 #include "imgIRequest.h"
00056 #include "nsSVGClipPathFrame.h"
00057 #include "nsLayoutAtoms.h"
00058 #include "nsSVGUtils.h"
00059 
00060 #define NS_GET_BIT(rowptr, x) (rowptr[(x)>>3] &  (1<<(7-(x)&0x7)))
00061 
00062 class nsSVGImageFrame;
00063 
00064 class nsSVGImageListener : public imgIDecoderObserver
00065 {
00066 public:
00067   nsSVGImageListener(nsSVGImageFrame *aFrame);
00068   virtual ~nsSVGImageListener();
00069 
00070   NS_DECL_ISUPPORTS
00071   NS_DECL_IMGIDECODEROBSERVER
00072   NS_DECL_IMGICONTAINEROBSERVER
00073 
00074   void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
00075 
00076 private:
00077   nsSVGImageFrame *mFrame;
00078 };
00079 
00080 
00081 class nsSVGImageFrame : public nsSVGPathGeometryFrame
00082 {
00083 protected:
00084   friend nsresult
00085   NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00086 
00087   virtual ~nsSVGImageFrame();
00088   NS_IMETHOD InitSVG();
00089 
00090 public:
00091   // nsISVGValueObserver interface:
00092   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
00093                                     nsISVGValue::modificationType aModType);
00094 
00095   // nsISVGPathGeometrySource interface:
00096   NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder);
00097 
00098   // nsISVGChildFrame interface:
00099   NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips);
00100   NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
00101 
00102   // nsISVGGeometrySource interface:
00103   NS_IMETHOD GetStrokePaintType(PRUint16 *aStrokePaintType);
00104   NS_IMETHOD GetFillPaintType(PRUint16 *aFillPaintType);
00105   NS_IMETHOD GetHittestMask(PRUint16 *aHittestMask);
00106   
00112   virtual nsIAtom* GetType() const;
00113 
00114 #ifdef DEBUG
00115   NS_IMETHOD GetFrameName(nsAString& aResult) const
00116   {
00117     return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
00118   }
00119 #endif
00120 
00121 private:
00122   nsCOMPtr<nsIDOMSVGLength> mX;
00123   nsCOMPtr<nsIDOMSVGLength> mY;
00124   nsCOMPtr<nsIDOMSVGLength> mWidth;
00125   nsCOMPtr<nsIDOMSVGLength> mHeight;
00126   nsCOMPtr<nsIDOMSVGPreserveAspectRatio> mPreserveAspectRatio;
00127 
00128   nsCOMPtr<imgIDecoderObserver> mListener;
00129   nsCOMPtr<nsISVGRendererSurface> mSurface;
00130 
00131   nsresult ConvertFrame(gfxIImageFrame *aNewFrame);
00132   already_AddRefed<nsIDOMSVGMatrix> GetImageTransform();
00133 
00134   friend class nsSVGImageListener;
00135   PRBool mSurfaceInvalid;
00136 };
00137 
00138 //----------------------------------------------------------------------
00139 // Implementation
00140 
00141 nsresult
00142 NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00143 {
00144   *aNewFrame = nsnull;
00145 
00146   nsCOMPtr<nsIDOMSVGImageElement> Rect = do_QueryInterface(aContent);
00147   if (!Rect) {
00148 #ifdef DEBUG
00149     printf("warning: trying to construct an SVGImageFrame for a content element that doesn't support the right interfaces\n");
00150 #endif
00151     return NS_ERROR_FAILURE;
00152   }
00153 
00154   nsSVGImageFrame* it = new (aPresShell) nsSVGImageFrame;
00155   if (nsnull == it)
00156     return NS_ERROR_OUT_OF_MEMORY;
00157 
00158   *aNewFrame = it;
00159   return NS_OK;
00160 }
00161 
00162 nsSVGImageFrame::~nsSVGImageFrame()
00163 {
00164   nsCOMPtr<nsISVGValue> value;
00165   if (mX && (value = do_QueryInterface(mX)))
00166       value->RemoveObserver(this);
00167   if (mY && (value = do_QueryInterface(mY)))
00168       value->RemoveObserver(this);
00169   if (mWidth && (value = do_QueryInterface(mWidth)))
00170       value->RemoveObserver(this);
00171   if (mHeight && (value = do_QueryInterface(mHeight)))
00172       value->RemoveObserver(this);
00173   if (mPreserveAspectRatio && (value = do_QueryInterface(mPreserveAspectRatio)))
00174       value->RemoveObserver(this);
00175 
00176   // set the frame to null so we don't send messages to a dead object.
00177   if (mListener) {
00178     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
00179     if (imageLoader) {
00180       imageLoader->RemoveObserver(mListener);
00181     }
00182     NS_REINTERPRET_CAST(nsSVGImageListener*, mListener.get())->SetFrame(nsnull);
00183   }
00184   mListener = nsnull;
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsSVGImageFrame::InitSVG()
00189 {
00190   nsresult rv = nsSVGPathGeometryFrame::InitSVG();
00191   if (NS_FAILED(rv)) return rv;
00192   
00193   nsCOMPtr<nsIDOMSVGImageElement> Rect = do_QueryInterface(mContent);
00194   NS_ASSERTION(Rect,"wrong content element");
00195 
00196   {
00197     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00198     Rect->GetX(getter_AddRefs(length));
00199     length->GetAnimVal(getter_AddRefs(mX));
00200     NS_ASSERTION(mX, "no x");
00201     if (!mX) return NS_ERROR_FAILURE;
00202     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mX);
00203     if (value)
00204       value->AddObserver(this);
00205   }
00206 
00207   {
00208     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00209     Rect->GetY(getter_AddRefs(length));
00210     length->GetAnimVal(getter_AddRefs(mY));
00211     NS_ASSERTION(mY, "no y");
00212     if (!mY) return NS_ERROR_FAILURE;
00213     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mY);
00214     if (value)
00215       value->AddObserver(this);
00216   }
00217 
00218   {
00219     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00220     Rect->GetWidth(getter_AddRefs(length));
00221     length->GetAnimVal(getter_AddRefs(mWidth));
00222     NS_ASSERTION(mWidth, "no width");
00223     if (!mWidth) return NS_ERROR_FAILURE;
00224     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mWidth);
00225     if (value)
00226       value->AddObserver(this);
00227   }
00228 
00229   {
00230     nsCOMPtr<nsIDOMSVGAnimatedLength> length;
00231     Rect->GetHeight(getter_AddRefs(length));
00232     length->GetAnimVal(getter_AddRefs(mHeight));
00233     NS_ASSERTION(mHeight, "no height");
00234     if (!mHeight) return NS_ERROR_FAILURE;
00235     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mHeight);
00236     if (value)
00237       value->AddObserver(this);
00238   }
00239 
00240   {
00241     nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> ratio;
00242     Rect->GetPreserveAspectRatio(getter_AddRefs(ratio));
00243     ratio->GetAnimVal(getter_AddRefs(mPreserveAspectRatio));
00244     NS_ASSERTION(mHeight, "no preserveAspectRatio");
00245     if (!mPreserveAspectRatio) return NS_ERROR_FAILURE;
00246     nsCOMPtr<nsISVGValue> value = do_QueryInterface(mPreserveAspectRatio);
00247     if (value)
00248       value->AddObserver(this);
00249   }
00250 
00251   mSurface = nsnull;
00252   mSurfaceInvalid = PR_TRUE;
00253 
00254   mListener = new nsSVGImageListener(this);
00255   if (!mListener) return NS_ERROR_OUT_OF_MEMORY;
00256   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
00257   NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
00258   imageLoader->AddObserver(mListener);
00259 
00260   return NS_OK; 
00261 }
00262 
00263 //----------------------------------------------------------------------
00264 // nsISVGValueObserver methods:
00265 
00266 NS_IMETHODIMP
00267 nsSVGImageFrame::DidModifySVGObservable(nsISVGValue* observable,
00268                                         nsISVGValue::modificationType aModType)
00269 {
00270   nsCOMPtr<nsIDOMSVGLength> l = do_QueryInterface(observable);
00271   if (l && (mX==l || mY==l || mWidth==l || mHeight==l)) {
00272     UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_PATH);
00273     return NS_OK;
00274   }
00275   // else
00276   return nsSVGPathGeometryFrame::DidModifySVGObservable(observable, aModType);
00277 }
00278 
00279 //----------------------------------------------------------------------
00280 // nsISVGPathGeometrySource methods:
00281 
00282 /* void constructPath (in nsISVGRendererPathBuilder pathBuilder); */
00283 /* For the purposes of the update/invalidation logic pretend to
00284    be a rectangle. */
00285 NS_IMETHODIMP nsSVGImageFrame::ConstructPath(nsISVGRendererPathBuilder* pathBuilder)
00286 {
00287   float x, y, width, height;
00288 
00289   mX->GetValue(&x);
00290   mY->GetValue(&y);
00291   mWidth->GetValue(&width);
00292   mHeight->GetValue(&height);
00293 
00294   /* In a perfect world, this would be handled by the DOM, and 
00295      return a DOM exception. */
00296   if (width <= 0 || height <= 0)
00297     return NS_OK;
00298 
00299   pathBuilder->Moveto(x, y);
00300   pathBuilder->Lineto(x+width, y);
00301   pathBuilder->Lineto(x+width, y+height);
00302   pathBuilder->Lineto(x, y+height);
00303   pathBuilder->ClosePath(&x, &y);
00304 
00305   return NS_OK;
00306 }
00307 
00308 already_AddRefed<nsIDOMSVGMatrix>
00309 nsSVGImageFrame::GetImageTransform()
00310 {
00311   nsCOMPtr<nsIDOMSVGMatrix> ctm;
00312   GetCanvasTM(getter_AddRefs(ctm));
00313 
00314   float x, y, width, height;
00315   mX->GetValue(&x);
00316   mY->GetValue(&y);
00317   mWidth->GetValue(&width);
00318   mHeight->GetValue(&height);
00319 
00320   PRUint32 nativeWidth, nativeHeight;
00321   mSurface->GetWidth(&nativeWidth);
00322   mSurface->GetHeight(&nativeHeight);
00323 
00324   PRUint16 align, meetOrSlice;
00325   mPreserveAspectRatio->GetAlign(&align);
00326   mPreserveAspectRatio->GetMeetOrSlice(&meetOrSlice);
00327 
00328   // default to the defaults
00329   if (align == nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN)
00330     align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
00331   if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN)
00332     meetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
00333 
00334   float a, d, e, f;
00335   a = width/nativeWidth;
00336   d = height/nativeHeight;
00337   e = 0.0f;
00338   f = 0.0f;
00339 
00340   if (align != nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
00341       a != d) {
00342     if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
00343         a < d ||
00344         meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
00345         d < a) {
00346       d = a;
00347       switch (align) {
00348         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
00349         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
00350         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
00351           break;
00352         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
00353         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
00354         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
00355           f = (height - a * nativeHeight) / 2.0f;
00356           break;
00357         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
00358         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
00359         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
00360           f = height - a * nativeHeight;
00361           break;
00362         default:
00363           NS_NOTREACHED("Unknown value for align");
00364       }
00365     }
00366     else if (
00367       meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
00368       d < a ||
00369       meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
00370       a < d) {
00371       a = d;
00372       switch (align) {
00373         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
00374         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
00375         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
00376           break;
00377         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
00378         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
00379         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
00380           e = (width - a * nativeWidth) / 2.0f;
00381           break;
00382         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
00383         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
00384         case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
00385           e = width - a * nativeWidth;
00386           break;
00387         default:
00388           NS_NOTREACHED("Unknown value for align");
00389       }
00390     }
00391     else NS_NOTREACHED("Unknown value for meetOrSlice");
00392   }
00393 
00394   nsCOMPtr<nsIDOMSVGMatrix> trans;
00395   ctm->Translate(x + e, y + f, getter_AddRefs(trans));
00396 
00397   nsCOMPtr<nsIDOMSVGMatrix> fini;
00398   trans->ScaleNonUniform(a, d, getter_AddRefs(fini));
00399 
00400   nsIDOMSVGMatrix *retval = nsnull;
00401   fini.swap(retval);
00402   return retval;
00403 }
00404 
00405 //----------------------------------------------------------------------
00406 // nsISVGChildFrame methods:
00407 NS_IMETHODIMP
00408 nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00409 {
00410   if (!GetStyleVisibility()->IsVisible())
00411     return NS_OK;
00412 
00413   float width, height;
00414   mWidth->GetValue(&width);
00415   mHeight->GetValue(&height);
00416   if (width <= 0 || height <= 0)
00417     return NS_OK;
00418 
00419   if (mSurfaceInvalid) {
00420     nsCOMPtr<imgIRequest> currentRequest;
00421     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
00422     if (imageLoader)
00423       imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
00424                               getter_AddRefs(currentRequest));
00425 
00426     nsCOMPtr<imgIContainer> currentContainer;
00427     if (currentRequest)
00428       currentRequest->GetImage(getter_AddRefs(currentContainer));
00429 
00430     nsCOMPtr<gfxIImageFrame> currentFrame;
00431     if (currentContainer) 
00432       currentContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
00433 
00434     if (currentFrame) {
00435       ConvertFrame(currentFrame);
00436       mSurfaceInvalid = PR_FALSE;
00437     } else {
00438       return NS_OK;
00439     }
00440   }
00441 
00442   canvas->PushClip();
00443 
00444   /* check for a clip path */
00445   nsIURI *aURI;
00446   nsSVGClipPathFrame *clip = NULL;
00447   aURI = GetStyleSVGReset()->mClipPath;
00448   if (aURI) {
00449     NS_GetSVGClipPathFrame(&clip, aURI, mContent);
00450 
00451     if (clip) {
00452       nsCOMPtr<nsIDOMSVGMatrix> matrix;
00453       GetCanvasTM(getter_AddRefs(matrix));
00454       clip->ClipPaint(canvas, this, matrix);
00455     }
00456   }
00457 
00458   if (mSurface) {
00459     nsCOMPtr<nsIDOMSVGMatrix> ctm;
00460     GetCanvasTM(getter_AddRefs(ctm));
00461 
00462     float x, y;
00463     mX->GetValue(&x);
00464     mY->GetValue(&y);
00465 
00466     if (GetStyleDisplay()->IsScrollableOverflow())
00467       canvas->SetClipRect(ctm, x, y, width, height);
00468 
00469     nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
00470 
00471     canvas->CompositeSurfaceMatrix(mSurface,
00472                                    fini,
00473                                    mStyleContext->GetStyleDisplay()->mOpacity);
00474   }
00475 
00476   canvas->PopClip();
00477 
00478   return NS_OK;
00479 }
00480 
00481 NS_IMETHODIMP
00482 nsSVGImageFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00483 {
00484   if (GetStyleDisplay()->IsScrollableOverflow() && mSurface) {
00485     PRUint32 nativeWidth, nativeHeight;
00486     mSurface->GetWidth(&nativeWidth);
00487     mSurface->GetHeight(&nativeHeight);
00488 
00489     nsCOMPtr<nsIDOMSVGMatrix> fini = GetImageTransform();
00490 
00491     if (!nsSVGUtils::HitTestRect(fini,
00492                                  0, 0, nativeWidth, nativeHeight,
00493                                  x, y)) {
00494       *hit = nsnull;
00495       return NS_OK;
00496     }
00497   }
00498 
00499   return nsSVGPathGeometryFrame::GetFrameForPointSVG(x, y, hit);
00500 }
00501 
00502 nsIAtom *
00503 nsSVGImageFrame::GetType() const
00504 {
00505   return nsLayoutAtoms::svgImageFrame;
00506 }
00507 
00508 nsresult
00509 nsSVGImageFrame::ConvertFrame(gfxIImageFrame *aNewFrame)
00510 {
00511   PRInt32 width, height;
00512   aNewFrame->GetWidth(&width);
00513   aNewFrame->GetHeight(&height);
00514   
00515   nsresult rv;
00516   nsCOMPtr<nsISVGRenderer> renderer;
00517 
00518   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00519   if (!outerSVGFrame)
00520     return NS_ERROR_FAILURE;
00521   rv = outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
00522   if (NS_FAILED(rv))
00523     return rv;
00524   rv = renderer->CreateSurface(width, height, getter_AddRefs(mSurface));
00525   if (NS_FAILED(rv))
00526     return rv;
00527   
00528   PRUint8 *data, *target;
00529   PRUint32 length;
00530   PRInt32 stride;
00531   mSurface->Lock();
00532   mSurface->GetData(&data, &length, &stride);
00533   if (!data) {
00534     mSurface->Unlock();
00535     return NS_ERROR_FAILURE;
00536   }
00537 #ifdef MOZ_PLATFORM_IMAGES_BOTTOM_TO_TOP
00538   stride = -stride;
00539 #endif
00540 
00541   aNewFrame->LockImageData();
00542   aNewFrame->LockAlphaData();
00543   
00544   PRUint8 *rgb, *alpha = nsnull;
00545   PRUint32 bpr, abpr;
00546   aNewFrame->GetImageData(&rgb, &length);
00547   aNewFrame->GetImageBytesPerRow(&bpr);
00548   if (!rgb) {
00549     mSurface->Unlock();
00550     aNewFrame->UnlockImageData();
00551     aNewFrame->UnlockAlphaData();
00552     return NS_ERROR_FAILURE;
00553   }
00554 
00555   aNewFrame->GetAlphaData(&alpha, &length);
00556   aNewFrame->GetAlphaBytesPerRow(&abpr);
00557 
00558   // some platforms return 4bpp (OSX and Win32 under some circumstances)
00559   const PRUint32 bpp = bpr/width;
00560 
00561 #ifdef XP_MACOSX
00562   // pixels on os-x have a lead byte we don't care about (alpha or
00563   // garbage, depending on the image format) - shift our pointer down
00564   // one so we can use the rest of the code as-is
00565   rgb++;
00566 #endif
00567 
00568 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00569 #define REVERSE_CHANNELS
00570 #endif
00571 
00572 #if defined(XP_MACOSX) && defined(__i386__)
00573 #define REVERSE_CHANNELS
00574 #endif
00575 
00576   // cairo/os-x wants ABGR format, GDI+ wants RGBA, cairo/unix wants BGRA
00577   if (!alpha) {
00578     for (PRInt32 y=0; y<height; y++) {
00579       if (stride > 0)
00580         target = data + stride * y;
00581       else
00582         target = data + stride * (1 - height) + stride * y;
00583       for (PRInt32 x=0; x<width; x++) {
00584 #if defined(XP_MACOSX) && !defined(__i386__)
00585         *target++ = 255;
00586 #endif
00587 #ifndef REVERSE_CHANNELS
00588         *target++ = rgb[y*bpr + bpp*x];
00589         *target++ = rgb[y*bpr + bpp*x + 1];
00590         *target++ = rgb[y*bpr + bpp*x + 2];
00591 #else
00592         *target++ = rgb[y*bpr + bpp*x + 2];
00593         *target++ = rgb[y*bpr + bpp*x + 1];
00594         *target++ = rgb[y*bpr + bpp*x];
00595 #endif
00596 #if !defined(XP_MACOSX) || (defined(XP_MACOSX) && defined(__i386__))
00597         *target++ = 255;
00598 #endif
00599       }
00600     }
00601   } else {
00602     if (abpr >= width) {
00603       /* 8-bit alpha */
00604       for (PRInt32 y=0; y<height; y++) {
00605         if (stride > 0)
00606           target = data + stride * y;
00607         else
00608           target = data + stride * (1 - height) + stride * y;
00609         for (PRInt32 x=0; x<width; x++) {
00610           PRUint32 a = alpha[y*abpr + x];
00611 #if defined(XP_MACOSX) && !defined(__i386__)
00612           *target++ = a;
00613 #endif
00614 #ifndef REVERSE_CHANNELS
00615           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x] * a);
00616           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x + 1] * a);
00617           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x + 2] * a);
00618 #else
00619           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x + 2] * a);
00620           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x + 1] * a);
00621           FAST_DIVIDE_BY_255(*target++, rgb[y*bpr + bpp*x] * a);
00622 #endif
00623 #if !defined(XP_MACOSX) || (defined(XP_MACOSX) && defined(__i386__))
00624           *target++ = a;
00625 #endif
00626         }
00627       }
00628     } else {
00629       /* 1-bit alpha */
00630       for (PRInt32 y=0; y<height; y++) {
00631         if (stride > 0)
00632           target = data + stride * y;
00633         else
00634           target = data + stride * (1 - height) + stride * y;
00635         PRUint8 *alphaRow = alpha + y*abpr;
00636         
00637         for (PRUint32 x=0; x<width; x++) {
00638           if (NS_GET_BIT(alphaRow, x)) {
00639 #ifdef XP_MACOSX
00640             *target++ = 255;
00641 #endif
00642 #ifndef REVERSE_CHANNELS
00643             *target++ = rgb[y*bpr + bpp*x];
00644             *target++ = rgb[y*bpr + bpp*x + 1];
00645             *target++ = rgb[y*bpr + bpp*x + 2];
00646 #else
00647             *target++ = rgb[y*bpr + bpp*x + 2];
00648             *target++ = rgb[y*bpr + bpp*x + 1];
00649             *target++ = rgb[y*bpr + bpp*x];
00650 #endif
00651 #ifndef XP_MACOSX
00652             *target++ = 255;
00653 #endif
00654           } else {
00655             *target++ = 0;
00656             *target++ = 0;
00657             *target++ = 0;
00658             *target++ = 0;
00659           }
00660         }
00661       }
00662     }
00663   }
00664 
00665 #undef REVERSE_CHANNELS
00666   
00667   mSurface->Unlock();
00668   aNewFrame->UnlockImageData();
00669   aNewFrame->UnlockAlphaData();
00670   
00671   return NS_OK;
00672 }
00673 
00674 // Lie about our fill/stroke so that hit detection works properly
00675 
00676 /* readonly attribute unsigned short strokePaintType; */
00677 NS_IMETHODIMP
00678 nsSVGImageFrame::GetStrokePaintType(PRUint16 *aStrokePaintType)
00679 {
00680   *aStrokePaintType = nsISVGGeometrySource::PAINT_TYPE_NONE;
00681   return NS_OK;
00682 }
00683 
00684 /* readonly attribute unsigned short fillPaintType; */
00685 NS_IMETHODIMP
00686 nsSVGImageFrame::GetFillPaintType(PRUint16 *aFillPaintType)
00687 {
00688   *aFillPaintType = nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR;
00689   return NS_OK;
00690 }
00691 
00692 NS_IMETHODIMP
00693 nsSVGImageFrame::GetHittestMask(PRUint16 *aHittestMask)
00694 {
00695   *aHittestMask=0;
00696 
00697   switch(GetStyleSVG()->mPointerEvents) {
00698     case NS_STYLE_POINTER_EVENTS_NONE:
00699       break;
00700     case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
00701       if (GetStyleVisibility()->IsVisible()) {
00702         /* XXX: should check pixel transparency */
00703         *aHittestMask |= HITTEST_MASK_FILL;
00704       }
00705       break;
00706     case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
00707     case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
00708     case NS_STYLE_POINTER_EVENTS_VISIBLE:
00709       if (GetStyleVisibility()->IsVisible()) {
00710         *aHittestMask |= HITTEST_MASK_FILL;
00711       }
00712       break;
00713     case NS_STYLE_POINTER_EVENTS_PAINTED:
00714       /* XXX: should check pixel transparency */
00715       *aHittestMask |= HITTEST_MASK_FILL;
00716       break;
00717     case NS_STYLE_POINTER_EVENTS_FILL:
00718     case NS_STYLE_POINTER_EVENTS_STROKE:
00719     case NS_STYLE_POINTER_EVENTS_ALL:
00720       *aHittestMask |= HITTEST_MASK_FILL;
00721       break;
00722     default:
00723       NS_ERROR("not reached");
00724       break;
00725   }
00726   
00727   return NS_OK;
00728 }
00729 
00730 //----------------------------------------------------------------------
00731 // nsSVGImageListener implementation
00732 
00733 NS_IMPL_ISUPPORTS2(nsSVGImageListener,
00734                    imgIDecoderObserver,
00735                    imgIContainerObserver)
00736 
00737 nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) :  mFrame(aFrame)
00738 {
00739 }
00740 
00741 nsSVGImageListener::~nsSVGImageListener()
00742 {
00743 }
00744 
00745 NS_IMETHODIMP nsSVGImageListener::OnStartDecode(imgIRequest *aRequest)
00746 {
00747   return NS_OK;
00748 }
00749 
00750 NS_IMETHODIMP nsSVGImageListener::OnStartContainer(imgIRequest *aRequest,
00751                                                    imgIContainer *aImage)
00752 {
00753   return NS_OK;
00754 }
00755 
00756 NS_IMETHODIMP nsSVGImageListener::OnStartFrame(imgIRequest *aRequest,
00757                                             gfxIImageFrame *aFrame)
00758 {
00759   return NS_OK;
00760 }
00761 
00762 NS_IMETHODIMP nsSVGImageListener::OnDataAvailable(imgIRequest *aRequest,
00763                                                   gfxIImageFrame *aFrame,
00764                                                   const nsRect *aRect)
00765 {
00766   return NS_OK;
00767 }
00768 
00769 NS_IMETHODIMP nsSVGImageListener::OnStopFrame(imgIRequest *aRequest,
00770                                               gfxIImageFrame *aFrame)
00771 {
00772   return NS_OK;
00773 }
00774 
00775 NS_IMETHODIMP nsSVGImageListener::OnStopContainer(imgIRequest *aRequest,
00776                                                   imgIContainer *aImage)
00777 {
00778   return NS_OK;
00779 }
00780 
00781 NS_IMETHODIMP nsSVGImageListener::OnStopDecode(imgIRequest *aRequest,
00782                                                nsresult status,
00783                                                const PRUnichar *statusArg)
00784 {
00785   if (!mFrame)
00786     return NS_ERROR_FAILURE;
00787 
00788   mFrame->mSurfaceInvalid = PR_TRUE;
00789   mFrame->UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_ALL);
00790   return NS_OK;
00791 }
00792 
00793 NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIContainer *aContainer,
00794                                                gfxIImageFrame *newframe,
00795                                                nsRect * dirtyRect)
00796 {
00797   if (!mFrame)
00798     return NS_ERROR_FAILURE;
00799 
00800   mFrame->mSurfaceInvalid = PR_TRUE;
00801   mFrame->UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_ALL);
00802   return NS_OK;
00803 }
00804