Back to index

lightning-sunbird  0.9+nobinonly
nsSVGLibartBitmapAlpha.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  * Alex Fritze.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alex Fritze <alex@croczilla.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsISVGLibartBitmap.h"
00042 #include "nsIRenderingContext.h"
00043 #include "nsIDeviceContext.h"
00044 #include "nsPresContext.h"
00045 #include "nsRect.h"
00046 #include "nsIImage.h"
00047 #include "nsIComponentManager.h"
00048 #include "imgIContainer.h"
00049 #include "gfxIImageFrame.h"
00050 #include "nsIInterfaceRequestor.h"
00051 #include "nsIInterfaceRequestorUtils.h"
00052 
00057 
00058 
00067 class nsSVGLibartBitmapAlpha : public nsISVGLibartBitmap
00068 {
00069 public:
00070   nsSVGLibartBitmapAlpha();
00071   ~nsSVGLibartBitmapAlpha();
00072   nsresult Init(nsIRenderingContext *ctx,
00073                 nsPresContext* presContext,
00074                 const nsRect & rect);
00075 
00076   // nsISupports interface:
00077   NS_DECL_ISUPPORTS
00078 
00079   // nsISVGLibartBitmap interface:
00080   NS_IMETHOD_(PRUint8 *) GetBits();
00081 
00082   NS_IMETHOD_(nsISVGLibartBitmap::PixelFormat) GetPixelFormat();
00083   NS_IMETHOD_(int) GetLineStride();
00084 
00085   NS_IMETHOD_(int) GetWidth();
00086   NS_IMETHOD_(int) GetHeight();
00087   NS_IMETHOD_(void) LockRenderingContext(const nsRect& rect,
00088                                          nsIRenderingContext**ctx);
00089   NS_IMETHOD_(void) UnlockRenderingContext();
00090   NS_IMETHOD_(void) Flush();
00091   
00092 private:
00093   void LockBuffer();
00094   void UnlockBuffer();
00095 
00096   PRBool mLocked;
00097   nsCOMPtr<nsIRenderingContext> mRenderingContext;
00098   nsCOMPtr<imgIContainer> mContainer;
00099   nsCOMPtr<gfxIImageFrame> mBuffer;
00100   nsRect mRectTwips;
00101   nsRect mRect;
00102   PRUint8 *mTempBits;
00103   PRInt32 mTempLineStride;
00104 };
00105 
00108 //----------------------------------------------------------------------
00109 // implementation:
00110 
00111 nsSVGLibartBitmapAlpha::nsSVGLibartBitmapAlpha()
00112     : mLocked(PR_FALSE), mTempBits(nsnull)
00113 {
00114 }
00115 
00116 nsSVGLibartBitmapAlpha::~nsSVGLibartBitmapAlpha()
00117 {
00118     if (mTempBits) {
00119       delete [] mTempBits;
00120       mTempBits = nsnull;
00121     }
00122 }
00123 
00124 nsresult
00125 nsSVGLibartBitmapAlpha::Init(nsIRenderingContext* ctx,
00126                                nsPresContext* presContext,
00127                                const nsRect & rect)
00128 {
00129   mRenderingContext = ctx;
00130 
00131   PRUint32 tempSize;
00132   float twipsPerPx;
00133 
00134   twipsPerPx = presContext->PixelsToTwips();
00135   mRectTwips.x = (nscoord)(rect.x*twipsPerPx);
00136   mRectTwips.y = (nscoord)(rect.y*twipsPerPx);
00137   mRectTwips.width = (nscoord)(rect.width*twipsPerPx);
00138   mRectTwips.height = (nscoord)(rect.height*twipsPerPx);
00139   mRect = rect;
00140   
00141   mContainer = do_CreateInstance("@mozilla.org/image/container;1");
00142   mContainer->Init(rect.width, rect.height, nsnull);
00143     
00144   mBuffer = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
00145   mBuffer->Init(0, 0, rect.width, rect.height, gfxIFormats::RGB_A8, 24);
00146   mContainer->AppendFrame(mBuffer);
00147 
00148   mTempLineStride = rect.width * 4; // i.e. 4-bytes per pixel (RGBA)
00149   mTempLineStride = (mTempLineStride + 3) & ~0x3; // 32-bit align
00150   tempSize = mTempLineStride * rect.height;
00151   mTempBits = new PRUint8[tempSize];
00152   if (!mTempBits) return NS_ERROR_OUT_OF_MEMORY;
00153 
00154   memset(mTempBits, 0, tempSize); // initialise to black and transparent
00155   
00156   return NS_OK;
00157 }
00158 
00159 nsresult
00160 NS_NewSVGLibartBitmap(nsISVGLibartBitmap **result,
00161                       nsIRenderingContext *ctx,
00162                       nsPresContext* presContext,
00163                       const nsRect & rect)
00164 {
00165   nsSVGLibartBitmapAlpha* bm = new nsSVGLibartBitmapAlpha();
00166   if (!bm) return NS_ERROR_OUT_OF_MEMORY;
00167 
00168   NS_ADDREF(bm);
00169 
00170   nsresult rv = bm->Init(ctx, presContext, rect);
00171 
00172   if (NS_FAILED(rv)) {
00173     NS_RELEASE(bm);
00174     return rv;
00175   }
00176   
00177   *result = bm;
00178   return rv;
00179 }
00180 
00181 //----------------------------------------------------------------------
00182 // nsISupports methods:
00183 
00184 NS_IMPL_ADDREF(nsSVGLibartBitmapAlpha)
00185 NS_IMPL_RELEASE(nsSVGLibartBitmapAlpha)
00186 
00187 NS_INTERFACE_MAP_BEGIN(nsSVGLibartBitmapAlpha)
00188   NS_INTERFACE_MAP_ENTRY(nsISVGLibartBitmap)
00189   NS_INTERFACE_MAP_ENTRY(nsISupports)
00190 NS_INTERFACE_MAP_END
00191 
00192 //----------------------------------------------------------------------
00193 // Implementation helpers:
00194 void
00195 nsSVGLibartBitmapAlpha::LockBuffer()
00196 {
00197   // XXX not really sure if this makes sense now that we're using a temporary
00198   // buffer. Really we should lock the temporary buffer instead.
00199   if (mLocked) return;
00200 
00201   mBuffer->LockImageData();
00202   mBuffer->LockAlphaData();
00203   mLocked = PR_TRUE;
00204 }
00205 
00206 void
00207 nsSVGLibartBitmapAlpha::UnlockBuffer()
00208 {
00209   if (!mLocked) return;
00210 
00211   mBuffer->UnlockAlphaData();
00212   mBuffer->UnlockImageData();
00213   mLocked = PR_FALSE;
00214 }
00215 
00216 
00217 //----------------------------------------------------------------------
00218 // nsISVGLibartBitmap methods:
00219 
00220 NS_IMETHODIMP_(PRUint8 *)
00221 nsSVGLibartBitmapAlpha::GetBits()
00222 {
00223   LockBuffer();
00224   return mTempBits;
00225 }
00226 
00227 
00228 NS_IMETHODIMP_(nsISVGLibartBitmap::PixelFormat)
00229 nsSVGLibartBitmapAlpha::GetPixelFormat()
00230 {
00231 #if defined(XP_WIN) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON) || defined(XP_OS2)
00232   return PIXEL_FORMAT_32_BGRA;
00233 #else
00234   return PIXEL_FORMAT_32_RGBA;
00235 #endif
00236 }
00237 
00238 NS_IMETHODIMP_(int)
00239 nsSVGLibartBitmapAlpha::GetLineStride()
00240 {
00241   return (int) mTempLineStride;
00242 }
00243 
00244 
00245 NS_IMETHODIMP_(int)
00246 nsSVGLibartBitmapAlpha::GetWidth()
00247 {
00248   return mRect.width; 
00249 }
00250 
00251 NS_IMETHODIMP_(int)
00252 nsSVGLibartBitmapAlpha::GetHeight()
00253 {
00254   return mRect.height;
00255 }
00256 
00257 NS_IMETHODIMP_(void)
00258 nsSVGLibartBitmapAlpha::LockRenderingContext(const nsRect& rect,
00259                                              nsIRenderingContext** ctx)
00260 {
00261   // doesn't work on alpha bitmap!
00262   *ctx = nsnull;
00263 }
00264 
00265 NS_IMETHODIMP_(void)
00266 nsSVGLibartBitmapAlpha::UnlockRenderingContext()
00267 {
00268   // doesn't work on alpha bitmap!
00269 }
00270 
00271 NS_IMETHODIMP_(void)
00272 nsSVGLibartBitmapAlpha::Flush()
00273 {
00274   UnlockBuffer();
00275 
00276   nsCOMPtr<nsIDeviceContext> ctx;
00277   mRenderingContext->GetDeviceContext(*getter_AddRefs(ctx));
00278 
00279   nsCOMPtr<nsIInterfaceRequestor> ireq(do_QueryInterface(mBuffer));
00280   if (ireq) {
00281     nsCOMPtr<nsIImage> img(do_GetInterface(ireq));
00282 
00283     // Flip image first so we don't have to flip the alpha buffer separately
00284     if (!img->GetIsRowOrderTopToBottom()) {
00285       // XXX we need to flip the image. This is silly. Blt should take
00286       // care of it
00287       int stride = mTempLineStride;
00288       int height = GetHeight();
00289       PRUint8* bits = mTempBits;
00290       PRUint8* rowbuf = new PRUint8[stride];
00291       for (int row=0; row<height/2; ++row) {
00292         memcpy(rowbuf, bits+row*stride, stride);
00293         memcpy(bits+row*stride, bits+(height-1-row)*stride, stride);
00294         memcpy(bits+(height-1-row)*stride, rowbuf, stride);
00295       }
00296       delete[] rowbuf;
00297     }
00298 
00299     int width = GetWidth();
00300     int height = GetHeight();
00301 
00302     const PRUint8* const src = mTempBits;
00303     PRUint8* const dst = img->GetBits();
00304     PRUint8* const dstAlpha = img->GetAlphaBits();
00305 
00306     int dstStride = img->GetLineStride();
00307     int dstAlphaStride = img->GetAlphaLineStride();
00308 
00309     // Copy the bits from the temporary buffer to the nsImage image buffer and
00310     // alpha buffer
00311     for (int row = 0; row < height; ++row) {
00312       // XXX Definitely not the most efficient way of doing this but it is
00313       // consistent with nsImageWin::CreateImageWithAlphaBits
00314       const PRUint8 *srcRow = src + row * mTempLineStride;
00315       PRUint8 *dstRow = dst + row * dstStride;
00316       PRUint8 *dstAlphaRow = dstAlpha + row * dstAlphaStride;
00317       for (int x = 0; x < width; x++) {
00318 #ifdef XP_MACOSX
00319         *dstRow++      = 0;
00320 #endif
00321         *dstRow++      = *srcRow++;
00322         *dstRow++      = *srcRow++;
00323         *dstRow++      = *srcRow++;
00324         *dstAlphaRow++ = *srcRow++;
00325       }
00326     }
00327     
00328     nsRect r(0, 0, GetWidth(), GetHeight());
00329     img->ImageUpdated(ctx, nsImageUpdateFlags_kBitsChanged, &r);
00330   }
00331   
00332   mContainer->DecodingComplete();
00333   mRenderingContext->DrawTile(mContainer, mRectTwips.x, mRectTwips.y,
00334     &mRectTwips);
00335 }
00336