Back to index

lightning-sunbird  0.9+nobinonly
gfxImageFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
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 "gfxImageFrame.h"
00041 #include "nsIServiceManager.h"
00042 
00043 NS_IMPL_ISUPPORTS2(gfxImageFrame, gfxIImageFrame, nsIInterfaceRequestor)
00044 
00045 gfxImageFrame::gfxImageFrame() :
00046   mInitalized(PR_FALSE),
00047   mMutable(PR_TRUE),
00048   mHasBackgroundColor(PR_FALSE),
00049   mTimeout(100),
00050   mBackgroundColor(0),
00051   mDisposalMethod(0)
00052 {
00053   /* member initializers and constructor code */
00054 }
00055 
00056 gfxImageFrame::~gfxImageFrame()
00057 {
00058   /* destructor code */
00059 }
00060 
00061 /* void init (in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfx_format aFormat); */
00062 NS_IMETHODIMP gfxImageFrame::Init(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, gfx_format aFormat,gfx_depth aDepth)
00063 {
00064   if (mInitalized)
00065     return NS_ERROR_FAILURE;
00066 
00067   if (aWidth <= 0 || aHeight <= 0) {
00068     NS_ASSERTION(0, "error - negative image size\n");
00069     return NS_ERROR_FAILURE;
00070   }
00071 
00072   /* check to make sure we don't overflow a 32-bit */
00073   PRInt32 tmp = aWidth * aHeight;
00074   if (tmp / aHeight != aWidth) {
00075     NS_ASSERTION(0, "width or height too large\n");
00076     return NS_ERROR_FAILURE;
00077   }
00078   tmp = tmp * 4;
00079   if (tmp / 4 != aWidth * aHeight) {
00080     NS_ASSERTION(0, "width or height too large\n");
00081     return NS_ERROR_FAILURE;
00082   }
00083 
00084   if ( (aDepth != 8) && (aDepth != 24) ){
00085     NS_ERROR("This Depth is not supported\n");
00086     return NS_ERROR_FAILURE;
00087   }
00088 
00089   /* reject over-wide or over-tall images */
00090   const PRInt32 k64KLimit = 0x0000FFFF;
00091   if ( aWidth > k64KLimit || aHeight > k64KLimit ){
00092     NS_ERROR("image too big");
00093     return NS_ERROR_FAILURE;
00094   }
00095 
00096   nsresult rv;
00097 
00098   mOffset.MoveTo(aX, aY);
00099   mSize.SizeTo(aWidth, aHeight);
00100 
00101   mFormat = aFormat;
00102 
00103   mImage = do_CreateInstance("@mozilla.org/gfx/image;1", &rv);
00104   NS_ASSERTION(mImage, "creation of image failed");
00105   if (NS_FAILED(rv)) return rv;
00106 
00107   gfx_depth depth = aDepth;
00108   nsMaskRequirements maskReq;
00109 
00110   switch (aFormat) {
00111   case gfxIFormats::BGR:
00112   case gfxIFormats::RGB:
00113     maskReq = nsMaskRequirements_kNoMask;
00114     break;
00115 
00116   case gfxIFormats::BGRA:
00117   case gfxIFormats::RGBA:
00118 #ifdef DEBUG
00119     printf("we can't do this with the old image code\n");
00120 #endif
00121     maskReq = nsMaskRequirements_kNeeds8Bit;
00122     break;
00123 
00124   case gfxIFormats::BGR_A1:
00125   case gfxIFormats::RGB_A1:
00126     maskReq = nsMaskRequirements_kNeeds1Bit;
00127     break;
00128 
00129   case gfxIFormats::BGR_A8:
00130   case gfxIFormats::RGB_A8:
00131     maskReq = nsMaskRequirements_kNeeds8Bit;
00132     break;
00133 
00134   default:
00135 #ifdef DEBUG
00136     printf("unsupposed gfx_format\n");
00137 #endif
00138     break;
00139   }
00140 
00141   rv = mImage->Init(aWidth, aHeight, depth, maskReq);
00142   if (NS_FAILED(rv)) return rv;
00143 
00144   mInitalized = PR_TRUE;
00145   return NS_OK;
00146 }
00147 
00148 
00149 /* attribute boolean mutable */
00150 NS_IMETHODIMP gfxImageFrame::GetMutable(PRBool *aMutable)
00151 {
00152   if (!mInitalized)
00153     return NS_ERROR_NOT_INITIALIZED;
00154 
00155   NS_ASSERTION(mInitalized, "gfxImageFrame::GetMutable called on non-inited gfxImageFrame");
00156   *aMutable = mMutable;
00157   return NS_OK;
00158 }
00159 
00160 NS_IMETHODIMP gfxImageFrame::SetMutable(PRBool aMutable)
00161 {
00162   if (!mInitalized)
00163     return NS_ERROR_NOT_INITIALIZED;
00164 
00165   mMutable = aMutable;
00166 
00167   if (!aMutable)
00168     mImage->Optimize(nsnull);
00169 
00170   return NS_OK;
00171 }
00172 
00173 /* readonly attribute PRInt32 x; */
00174 NS_IMETHODIMP gfxImageFrame::GetX(PRInt32 *aX)
00175 {
00176   if (!mInitalized)
00177     return NS_ERROR_NOT_INITIALIZED;
00178 
00179   *aX = mOffset.x;
00180   return NS_OK;
00181 }
00182 
00183 /* readonly attribute PRInt32 y; */
00184 NS_IMETHODIMP gfxImageFrame::GetY(PRInt32 *aY)
00185 {
00186   if (!mInitalized)
00187     return NS_ERROR_NOT_INITIALIZED;
00188 
00189   *aY = mOffset.y;
00190   return NS_OK;
00191 }
00192 
00193 
00194 /* readonly attribute PRInt32 width; */
00195 NS_IMETHODIMP gfxImageFrame::GetWidth(PRInt32 *aWidth)
00196 {
00197   if (!mInitalized)
00198     return NS_ERROR_NOT_INITIALIZED;
00199 
00200   *aWidth = mSize.width;
00201   return NS_OK;
00202 }
00203 
00204 /* readonly attribute PRInt32 height; */
00205 NS_IMETHODIMP gfxImageFrame::GetHeight(PRInt32 *aHeight)
00206 {
00207   if (!mInitalized)
00208     return NS_ERROR_NOT_INITIALIZED;
00209 
00210   *aHeight = mSize.height;
00211   return NS_OK;
00212 }
00213 
00214 /* void getRect(in nsRectRef rect); */
00215 NS_IMETHODIMP gfxImageFrame::GetRect(nsIntRect &aRect)
00216 {
00217   if (!mInitalized)
00218     return NS_ERROR_NOT_INITIALIZED;
00219 
00220   aRect.SetRect(mOffset.x, mOffset.y, mSize.width, mSize.height);
00221 
00222   return NS_OK;
00223 }
00224 
00225 /* readonly attribute gfx_format format; */
00226 NS_IMETHODIMP gfxImageFrame::GetFormat(gfx_format *aFormat)
00227 {
00228   if (!mInitalized)
00229     return NS_ERROR_NOT_INITIALIZED;
00230 
00231   *aFormat = mFormat;
00232   return NS_OK;
00233 }
00234 
00235 /* readonly attribute boolean needsBackground; */
00236 NS_IMETHODIMP gfxImageFrame::GetNeedsBackground(PRBool *aNeedsBackground)
00237 {
00238   if (!mInitalized)
00239     return NS_ERROR_NOT_INITIALIZED;
00240 
00241   *aNeedsBackground = (mFormat != gfxIFormats::RGB && 
00242                        mFormat != gfxIFormats::BGR) ||
00243                       !mImage->GetIsImageComplete();
00244   return NS_OK;
00245 }
00246 
00247 
00248 /* readonly attribute unsigned long imageBytesPerRow; */
00249 NS_IMETHODIMP gfxImageFrame::GetImageBytesPerRow(PRUint32 *aBytesPerRow)
00250 {
00251   if (!mInitalized)
00252     return NS_ERROR_NOT_INITIALIZED;
00253 
00254   *aBytesPerRow = mImage->GetLineStride();
00255   return NS_OK;
00256 }
00257 
00258 /* readonly attribute unsigned long imageDataLength; */
00259 NS_IMETHODIMP gfxImageFrame::GetImageDataLength(PRUint32 *aBitsLength)
00260 {
00261   if (!mInitalized)
00262     return NS_ERROR_NOT_INITIALIZED;
00263 
00264   *aBitsLength = mImage->GetLineStride() * mSize.height;
00265   return NS_OK;
00266 }
00267 
00268 /* void getImageData([array, size_is(length)] out PRUint8 bits, out unsigned long length); */
00269 NS_IMETHODIMP gfxImageFrame::GetImageData(PRUint8 **aData, PRUint32 *length)
00270 {
00271   if (!mInitalized)
00272     return NS_ERROR_NOT_INITIALIZED;
00273 
00274   NS_ASSERTION(mMutable, "trying to get data on an immutable frame");
00275 
00276   *aData = mImage->GetBits();
00277   *length = mImage->GetLineStride() * mSize.height;
00278 
00279   return NS_OK;
00280 }
00281 
00282 /* void setImageData ([array, size_is (length), const] in PRUint8 data, in unsigned long length, in long offset); */
00283 NS_IMETHODIMP gfxImageFrame::SetImageData(const PRUint8 *aData, PRUint32 aLength, PRInt32 aOffset)
00284 {
00285   if (!mInitalized)
00286     return NS_ERROR_NOT_INITIALIZED;
00287 
00288   NS_ASSERTION(mMutable, "trying to set data on an immutable frame");
00289   if (!mMutable)
00290     return NS_ERROR_FAILURE;
00291 
00292   if (aLength == 0)
00293     return NS_OK;
00294 
00295   PRInt32 row_stride = mImage->GetLineStride();
00296 
00297   mImage->LockImagePixels(PR_FALSE);
00298   PRUint8 *imgData = mImage->GetBits();
00299   PRInt32 imgLen = row_stride * mSize.height;
00300 
00301   PRInt32 newOffset;
00302 #ifdef MOZ_PLATFORM_IMAGES_BOTTOM_TO_TOP
00303   // Adjust: We need offset to be top-down rows & LTR within each row
00304   PRUint32 yOffset = ((PRUint32)(aOffset / row_stride)) * row_stride;
00305   newOffset = ((mSize.height - 1) * row_stride) - yOffset + (aOffset % row_stride);
00306 #else
00307   newOffset = aOffset;
00308 #endif
00309 
00310   if (((newOffset + (PRInt32)aLength) > imgLen) || !imgData) {
00311     mImage->UnlockImagePixels(PR_FALSE);
00312     return NS_ERROR_FAILURE;
00313   }
00314 
00315   if (aData)
00316     memcpy(imgData + newOffset, aData, aLength);
00317   else
00318     memset(imgData + newOffset, 0, aLength);
00319   mImage->UnlockImagePixels(PR_FALSE);
00320 
00321   PRInt32 row = (aOffset / row_stride);
00322 
00323   // adjust for aLength < row_stride
00324   PRInt32 numnewrows = ((aLength - 1) / row_stride) + 1;
00325   nsIntRect r(0, row, mSize.width, numnewrows);
00326   mImage->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
00327 
00328   return NS_OK;
00329 }
00330 
00331 /* void lockImageData (); */
00332 NS_IMETHODIMP gfxImageFrame::LockImageData()
00333 {
00334   if (!mInitalized)
00335     return NS_ERROR_NOT_INITIALIZED;
00336 
00337   return mImage->LockImagePixels(PR_FALSE);
00338 }
00339 
00340 /* void unlockImageData (); */
00341 NS_IMETHODIMP gfxImageFrame::UnlockImageData()
00342 {
00343   if (!mInitalized)
00344     return NS_ERROR_NOT_INITIALIZED;
00345 
00346   return mImage->UnlockImagePixels(PR_FALSE);
00347 }
00348 
00349 /* readonly attribute unsigned long alphaBytesPerRow; */
00350 NS_IMETHODIMP gfxImageFrame::GetAlphaBytesPerRow(PRUint32 *aBytesPerRow)
00351 {
00352   if (!mInitalized || !mImage->GetHasAlphaMask())
00353     return NS_ERROR_NOT_INITIALIZED;
00354 
00355   *aBytesPerRow = mImage->GetAlphaLineStride();
00356   return NS_OK;
00357 }
00358 
00359 /* readonly attribute unsigned long alphaDataLength; */
00360 NS_IMETHODIMP gfxImageFrame::GetAlphaDataLength(PRUint32 *aBitsLength)
00361 {
00362   if (!mInitalized || !mImage->GetHasAlphaMask())
00363     return NS_ERROR_NOT_INITIALIZED;
00364 
00365   *aBitsLength = mImage->GetAlphaLineStride() * mSize.height;
00366   return NS_OK;
00367 }
00368 
00369 /* void getAlphaData([array, size_is(length)] out PRUint8 bits, out unsigned long length); */
00370 NS_IMETHODIMP gfxImageFrame::GetAlphaData(PRUint8 **aData, PRUint32 *length)
00371 {
00372   if (!mInitalized || !mImage->GetHasAlphaMask())
00373     return NS_ERROR_NOT_INITIALIZED;
00374 
00375   NS_ASSERTION(mMutable, "trying to get data on an immutable frame");
00376 
00377   *aData = mImage->GetAlphaBits();
00378   *length = mImage->GetAlphaLineStride() * mSize.height;
00379 
00380   return NS_OK;
00381 }
00382 
00383 /* void setAlphaData ([array, size_is (length), const] in PRUint8 data, in unsigned long length, in long offset); */
00384 NS_IMETHODIMP gfxImageFrame::SetAlphaData(const PRUint8 *aData, PRUint32 aLength, PRInt32 aOffset)
00385 {
00386   if (!mInitalized || !mImage->GetHasAlphaMask())
00387     return NS_ERROR_NOT_INITIALIZED;
00388 
00389   NS_ASSERTION(mMutable, "trying to set data on an immutable frame");
00390   if (!mMutable)
00391     return NS_ERROR_FAILURE;
00392 
00393   PRInt32 row_stride = mImage->GetAlphaLineStride();
00394 
00395   mImage->LockImagePixels(PR_TRUE);
00396   PRUint8 *alphaData = mImage->GetAlphaBits();
00397   PRInt32 alphaLen = row_stride * mSize.height;
00398 
00399   PRInt32 offset;
00400 #ifdef MOZ_PLATFORM_IMAGES_BOTTOM_TO_TOP
00401   // Adjust: We need offset to be top-down rows & LTR within each row
00402   PRUint32 yOffset = ((PRUint32)(aOffset / row_stride)) * row_stride;
00403   offset = ((mSize.height - 1) * row_stride) - yOffset + (aOffset % row_stride);
00404 #else
00405   offset = aOffset;
00406 #endif
00407 
00408   if (((offset + (PRInt32)aLength) > alphaLen) || !alphaData) {
00409     mImage->UnlockImagePixels(PR_TRUE);
00410     return NS_ERROR_FAILURE;
00411   }
00412 
00413   if (aData)
00414     memcpy(alphaData + offset, aData, aLength);
00415   else
00416     memset(alphaData + offset, 0, aLength);
00417   mImage->UnlockImagePixels(PR_TRUE);
00418   return NS_OK;
00419 }
00420 
00421 /* void lockAlphaData (); */
00422 NS_IMETHODIMP gfxImageFrame::LockAlphaData()
00423 {
00424   if (!mInitalized || !mImage->GetHasAlphaMask())
00425     return NS_ERROR_NOT_INITIALIZED;
00426 
00427   return mImage->LockImagePixels(PR_TRUE);
00428 }
00429 
00430 /* void unlockAlphaData (); */
00431 NS_IMETHODIMP gfxImageFrame::UnlockAlphaData()
00432 {
00433   if (!mInitalized || !mImage->GetHasAlphaMask())
00434     return NS_ERROR_NOT_INITIALIZED;
00435 
00436   return mImage->UnlockImagePixels(PR_TRUE);
00437 }
00438 
00439 
00440 
00441 
00442 
00443 /* void drawTo */
00444 NS_IMETHODIMP gfxImageFrame::DrawTo(gfxIImageFrame* aDst, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
00445 {
00446   if (!mInitalized)
00447     return NS_ERROR_NOT_INITIALIZED;
00448 
00449   nsCOMPtr<nsIImage> img(do_GetInterface(aDst));
00450   return mImage->DrawToImage(img, aDX, aDY, aDWidth, aDHeight);
00451 }
00452 
00453 
00454 /* attribute long timeout; */
00455 NS_IMETHODIMP gfxImageFrame::GetTimeout(PRInt32 *aTimeout)
00456 {
00457   if (!mInitalized)
00458     return NS_ERROR_NOT_INITIALIZED;
00459 
00460   // Ensure a minimal time between updates so we don't throttle the UI thread.
00461   // consider 0 == unspecified and make it fast but not too fast.  See bug
00462   // 125137, bug 139677, and bug 207059.  The behavior of recent IE and Opera
00463   // versions seems to be:
00464   // IE 6/Win:
00465   //   10 - 50ms go 100ms
00466   //   >50ms go correct speed
00467   // Opera 7 final/Win:
00468   //   10ms goes 100ms
00469   //   >10ms go correct speed
00470   // It seems that there are broken tools out there that set a 0ms or 10ms
00471   // timeout when they really want a "default" one.  So munge values in that
00472   // range.
00473   if (mTimeout >= 0 && mTimeout <= 10)
00474     *aTimeout = 100;
00475   else
00476     *aTimeout = mTimeout;
00477 
00478   return NS_OK;
00479 }
00480 
00481 NS_IMETHODIMP gfxImageFrame::SetTimeout(PRInt32 aTimeout)
00482 {
00483   if (!mInitalized)
00484     return NS_ERROR_NOT_INITIALIZED;
00485 
00486   mTimeout = aTimeout;
00487   return NS_OK;
00488 }
00489 
00490 /* attribute long frameDisposalMethod; */
00491 NS_IMETHODIMP gfxImageFrame::GetFrameDisposalMethod(PRInt32 *aFrameDisposalMethod)
00492 {
00493   if (!mInitalized)
00494     return NS_ERROR_NOT_INITIALIZED;
00495 
00496   *aFrameDisposalMethod = mDisposalMethod;
00497   return NS_OK;
00498 }
00499 NS_IMETHODIMP gfxImageFrame::SetFrameDisposalMethod(PRInt32 aFrameDisposalMethod)
00500 {
00501   if (!mInitalized)
00502     return NS_ERROR_NOT_INITIALIZED;
00503 
00504   mDisposalMethod = aFrameDisposalMethod;
00505   return NS_OK;
00506 }
00507 
00508 /* attribute gfx_color backgroundColor; */
00509 NS_IMETHODIMP gfxImageFrame::GetBackgroundColor(gfx_color *aBackgroundColor)
00510 {
00511   if (!mInitalized || !mHasBackgroundColor)
00512     return NS_ERROR_NOT_INITIALIZED;
00513 
00514   *aBackgroundColor = mBackgroundColor;
00515   return NS_OK;
00516 }
00517 NS_IMETHODIMP gfxImageFrame::SetBackgroundColor(gfx_color aBackgroundColor)
00518 {
00519   if (!mInitalized)
00520     return NS_ERROR_NOT_INITIALIZED;
00521 
00522   mBackgroundColor = aBackgroundColor;
00523   mHasBackgroundColor = PR_TRUE;
00524   return NS_OK;
00525 }
00526 
00527 NS_IMETHODIMP gfxImageFrame::GetInterface(const nsIID & aIID, void * *result)
00528 {
00529   if (!mInitalized)
00530     return NS_ERROR_NOT_INITIALIZED;
00531 
00532   NS_ENSURE_ARG_POINTER(result);
00533 
00534   if (NS_SUCCEEDED(QueryInterface(aIID, result)))
00535     return NS_OK;
00536   if (mImage && aIID.Equals(NS_GET_IID(nsIImage)))
00537     return mImage->QueryInterface(aIID, result);
00538 
00539   return NS_NOINTERFACE;
00540 }
00541