Mozilla/mozilla/gfx/src/shared/gfxImageFrame.cpp
pedemont%us.ibm.com 5739faf6df Bug 245407 - Use Quartz for nsImageMac. r=sfraser, sr=tor.
git-svn-id: svn://10.0.0.236/trunk@169511 18797224-902f-48f8-a5cc-f745e15eee43
2005-02-20 03:21:04 +00:00

529 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "gfxImageFrame.h"
#include "nsIServiceManager.h"
NS_IMPL_ISUPPORTS2(gfxImageFrame, gfxIImageFrame, nsIInterfaceRequestor)
gfxImageFrame::gfxImageFrame() :
mInitalized(PR_FALSE),
mMutable(PR_TRUE),
mHasBackgroundColor(PR_FALSE),
mTimeout(100),
mBackgroundColor(0),
mDisposalMethod(0)
{
/* member initializers and constructor code */
}
gfxImageFrame::~gfxImageFrame()
{
/* destructor code */
}
/* void init (in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfx_format aFormat); */
NS_IMETHODIMP gfxImageFrame::Init(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, gfx_format aFormat,gfx_depth aDepth)
{
if (mInitalized)
return NS_ERROR_FAILURE;
if (aWidth <= 0 || aHeight <= 0) {
NS_ASSERTION(0, "error - negative image size\n");
return NS_ERROR_FAILURE;
}
/* check to make sure we don't overflow a 32-bit */
PRInt32 tmp = aWidth * aHeight;
if (tmp / aHeight != aWidth) {
NS_ASSERTION(0, "width or height too large\n");
return NS_ERROR_FAILURE;
}
tmp = tmp * 4;
if (tmp / 4 != aWidth * aHeight) {
NS_ASSERTION(0, "width or height too large\n");
return NS_ERROR_FAILURE;
}
if ( (aDepth != 8) && (aDepth != 24) ){
NS_ERROR("This Depth is not supported\n");
return NS_ERROR_FAILURE;
}
/* reject over-wide or over-tall images */
const PRInt32 k64KLimit = 0x0000FFFF;
if ( aWidth > k64KLimit || aHeight > k64KLimit ){
NS_ERROR("image too big");
return NS_ERROR_FAILURE;
}
nsresult rv;
mOffset.MoveTo(aX, aY);
mSize.SizeTo(aWidth, aHeight);
mFormat = aFormat;
mImage = do_CreateInstance("@mozilla.org/gfx/image;1", &rv);
NS_ASSERTION(mImage, "creation of image failed");
if (NS_FAILED(rv)) return rv;
gfx_depth depth = aDepth;
nsMaskRequirements maskReq;
switch (aFormat) {
case gfxIFormats::BGR:
case gfxIFormats::RGB:
maskReq = nsMaskRequirements_kNoMask;
break;
case gfxIFormats::BGRA:
case gfxIFormats::RGBA:
#ifdef DEBUG
printf("we can't do this with the old image code\n");
#endif
maskReq = nsMaskRequirements_kNeeds8Bit;
break;
case gfxIFormats::BGR_A1:
case gfxIFormats::RGB_A1:
maskReq = nsMaskRequirements_kNeeds1Bit;
break;
case gfxIFormats::BGR_A8:
case gfxIFormats::RGB_A8:
maskReq = nsMaskRequirements_kNeeds8Bit;
break;
default:
#ifdef DEBUG
printf("unsupposed gfx_format\n");
#endif
break;
}
rv = mImage->Init(aWidth, aHeight, depth, maskReq);
if (NS_FAILED(rv)) return rv;
mInitalized = PR_TRUE;
return NS_OK;
}
/* attribute boolean mutable */
NS_IMETHODIMP gfxImageFrame::GetMutable(PRBool *aMutable)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mInitalized, "gfxImageFrame::GetMutable called on non-inited gfxImageFrame");
*aMutable = mMutable;
return NS_OK;
}
NS_IMETHODIMP gfxImageFrame::SetMutable(PRBool aMutable)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
mMutable = aMutable;
if (!aMutable)
mImage->Optimize(nsnull);
return NS_OK;
}
/* readonly attribute PRInt32 x; */
NS_IMETHODIMP gfxImageFrame::GetX(PRInt32 *aX)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aX = mOffset.x;
return NS_OK;
}
/* readonly attribute PRInt32 y; */
NS_IMETHODIMP gfxImageFrame::GetY(PRInt32 *aY)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aY = mOffset.y;
return NS_OK;
}
/* readonly attribute PRInt32 width; */
NS_IMETHODIMP gfxImageFrame::GetWidth(PRInt32 *aWidth)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aWidth = mSize.width;
return NS_OK;
}
/* readonly attribute PRInt32 height; */
NS_IMETHODIMP gfxImageFrame::GetHeight(PRInt32 *aHeight)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aHeight = mSize.height;
return NS_OK;
}
/* void getRect(in nsRectRef rect); */
NS_IMETHODIMP gfxImageFrame::GetRect(nsIntRect &aRect)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
aRect.SetRect(mOffset.x, mOffset.y, mSize.width, mSize.height);
return NS_OK;
}
/* readonly attribute gfx_format format; */
NS_IMETHODIMP gfxImageFrame::GetFormat(gfx_format *aFormat)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aFormat = mFormat;
return NS_OK;
}
/* readonly attribute unsigned long imageBytesPerRow; */
NS_IMETHODIMP gfxImageFrame::GetImageBytesPerRow(PRUint32 *aBytesPerRow)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aBytesPerRow = mImage->GetLineStride();
return NS_OK;
}
/* readonly attribute unsigned long imageDataLength; */
NS_IMETHODIMP gfxImageFrame::GetImageDataLength(PRUint32 *aBitsLength)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aBitsLength = mImage->GetLineStride() * mSize.height;
return NS_OK;
}
/* void getImageData([array, size_is(length)] out PRUint8 bits, out unsigned long length); */
NS_IMETHODIMP gfxImageFrame::GetImageData(PRUint8 **aData, PRUint32 *length)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mMutable, "trying to get data on an immutable frame");
*aData = mImage->GetBits();
*length = mImage->GetLineStride() * mSize.height;
return NS_OK;
}
/* void setImageData ([array, size_is (length), const] in PRUint8 data, in unsigned long length, in long offset); */
NS_IMETHODIMP gfxImageFrame::SetImageData(const PRUint8 *aData, PRUint32 aLength, PRInt32 aOffset)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mMutable, "trying to set data on an immutable frame");
if (!mMutable)
return NS_ERROR_FAILURE;
if (aLength == 0)
return NS_OK;
PRInt32 row_stride = mImage->GetLineStride();
mImage->LockImagePixels(PR_FALSE);
PRUint8 *imgData = mImage->GetBits();
PRInt32 imgLen = row_stride * mSize.height;
PRInt32 newOffset;
#ifdef MOZ_PLATFORM_IMAGES_BOTTOM_TO_TOP
// Adjust: We need offset to be top-down rows & LTR within each row
PRUint32 yOffset = ((PRUint32)(aOffset / row_stride)) * row_stride;
newOffset = ((mSize.height - 1) * row_stride) - yOffset + (aOffset % row_stride);
#else
newOffset = aOffset;
#endif
if (((newOffset + (PRInt32)aLength) > imgLen) || !imgData) {
mImage->UnlockImagePixels(PR_FALSE);
return NS_ERROR_FAILURE;
}
if (aData)
memcpy(imgData + newOffset, aData, aLength);
else
memset(imgData + newOffset, 0, aLength);
mImage->UnlockImagePixels(PR_FALSE);
PRInt32 row = (aOffset / row_stride);
// adjust for aLength < row_stride
PRInt32 numnewrows = ((aLength - 1) / row_stride) + 1;
nsIntRect r(0, row, mSize.width, numnewrows);
mImage->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
return NS_OK;
}
/* void lockImageData (); */
NS_IMETHODIMP gfxImageFrame::LockImageData()
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
return mImage->LockImagePixels(PR_FALSE);
}
/* void unlockImageData (); */
NS_IMETHODIMP gfxImageFrame::UnlockImageData()
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
return mImage->UnlockImagePixels(PR_FALSE);
}
/* readonly attribute unsigned long alphaBytesPerRow; */
NS_IMETHODIMP gfxImageFrame::GetAlphaBytesPerRow(PRUint32 *aBytesPerRow)
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
*aBytesPerRow = mImage->GetAlphaLineStride();
return NS_OK;
}
/* readonly attribute unsigned long alphaDataLength; */
NS_IMETHODIMP gfxImageFrame::GetAlphaDataLength(PRUint32 *aBitsLength)
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
*aBitsLength = mImage->GetAlphaLineStride() * mSize.height;
return NS_OK;
}
/* void getAlphaData([array, size_is(length)] out PRUint8 bits, out unsigned long length); */
NS_IMETHODIMP gfxImageFrame::GetAlphaData(PRUint8 **aData, PRUint32 *length)
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mMutable, "trying to get data on an immutable frame");
*aData = mImage->GetAlphaBits();
*length = mImage->GetAlphaLineStride() * mSize.height;
return NS_OK;
}
/* void setAlphaData ([array, size_is (length), const] in PRUint8 data, in unsigned long length, in long offset); */
NS_IMETHODIMP gfxImageFrame::SetAlphaData(const PRUint8 *aData, PRUint32 aLength, PRInt32 aOffset)
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mMutable, "trying to set data on an immutable frame");
if (!mMutable)
return NS_ERROR_FAILURE;
PRInt32 row_stride = mImage->GetAlphaLineStride();
mImage->LockImagePixels(PR_TRUE);
PRUint8 *alphaData = mImage->GetAlphaBits();
PRInt32 alphaLen = row_stride * mSize.height;
PRInt32 offset;
#ifdef MOZ_PLATFORM_IMAGES_BOTTOM_TO_TOP
// Adjust: We need offset to be top-down rows & LTR within each row
PRUint32 yOffset = ((PRUint32)(aOffset / row_stride)) * row_stride;
offset = ((mSize.height - 1) * row_stride) - yOffset + (aOffset % row_stride);
#else
offset = aOffset;
#endif
if (((offset + (PRInt32)aLength) > alphaLen) || !alphaData) {
mImage->UnlockImagePixels(PR_TRUE);
return NS_ERROR_FAILURE;
}
if (aData)
memcpy(alphaData + offset, aData, aLength);
else
memset(alphaData + offset, 0, aLength);
mImage->UnlockImagePixels(PR_TRUE);
return NS_OK;
}
/* void lockAlphaData (); */
NS_IMETHODIMP gfxImageFrame::LockAlphaData()
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
return mImage->LockImagePixels(PR_TRUE);
}
/* void unlockAlphaData (); */
NS_IMETHODIMP gfxImageFrame::UnlockAlphaData()
{
if (!mInitalized || !mImage->GetHasAlphaMask())
return NS_ERROR_NOT_INITIALIZED;
return mImage->UnlockImagePixels(PR_TRUE);
}
/* void drawTo */
NS_IMETHODIMP gfxImageFrame::DrawTo(gfxIImageFrame* aDst, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIImage> img(do_GetInterface(aDst));
return mImage->DrawToImage(img, aDX, aDY, aDWidth, aDHeight);
}
/* attribute long timeout; */
NS_IMETHODIMP gfxImageFrame::GetTimeout(PRInt32 *aTimeout)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
// Ensure a minimal time between updates so we don't throttle the UI thread.
// consider 0 == unspecified and make it fast but not too fast. See bug
// 125137, bug 139677, and bug 207059. The behavior of recent IE and Opera
// versions seems to be:
// IE 6/Win:
// 10 - 50ms go 100ms
// >50ms go correct speed
// Opera 7 final/Win:
// 10ms goes 100ms
// >10ms go correct speed
// It seems that there are broken tools out there that set a 0ms or 10ms
// timeout when they really want a "default" one. So munge values in that
// range.
if (mTimeout >= 0 && mTimeout <= 10)
*aTimeout = 100;
else
*aTimeout = mTimeout;
return NS_OK;
}
NS_IMETHODIMP gfxImageFrame::SetTimeout(PRInt32 aTimeout)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
mTimeout = aTimeout;
return NS_OK;
}
/* attribute long frameDisposalMethod; */
NS_IMETHODIMP gfxImageFrame::GetFrameDisposalMethod(PRInt32 *aFrameDisposalMethod)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
*aFrameDisposalMethod = mDisposalMethod;
return NS_OK;
}
NS_IMETHODIMP gfxImageFrame::SetFrameDisposalMethod(PRInt32 aFrameDisposalMethod)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
mDisposalMethod = aFrameDisposalMethod;
return NS_OK;
}
/* attribute gfx_color backgroundColor; */
NS_IMETHODIMP gfxImageFrame::GetBackgroundColor(gfx_color *aBackgroundColor)
{
if (!mInitalized || !mHasBackgroundColor)
return NS_ERROR_NOT_INITIALIZED;
*aBackgroundColor = mBackgroundColor;
return NS_OK;
}
NS_IMETHODIMP gfxImageFrame::SetBackgroundColor(gfx_color aBackgroundColor)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
mBackgroundColor = aBackgroundColor;
mHasBackgroundColor = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP gfxImageFrame::GetInterface(const nsIID & aIID, void * *result)
{
if (!mInitalized)
return NS_ERROR_NOT_INITIALIZED;
NS_ENSURE_ARG_POINTER(result);
if (NS_SUCCEEDED(QueryInterface(aIID, result)))
return NS_OK;
if (mImage && aIID.Equals(NS_GET_IID(nsIImage)))
return mImage->QueryInterface(aIID, result);
return NS_NOINTERFACE;
}