Bug 186103. r=ere, sr=tor. Fix PNG background images being too dark. Windows Only.

This commit is contained in:
paper%animecity.nu 2003-01-15 20:24:47 +00:00
Родитель cd9b93cc54
Коммит 8023c1301e
2 изменённых файлов: 201 добавлений и 146 удалений

Просмотреть файл

@ -740,7 +740,6 @@ NS_IMETHODIMP nsImageWin :: Draw(nsIRenderingContext &aContext, nsDrawingSurface
/** --------------------------------------------------- /** ---------------------------------------------------
* See documentation in nsIRenderingContext.h * See documentation in nsIRenderingContext.h
* @update 8/26/02 dwc
*/ */
NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext, NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext,
nsDrawingSurface aSurface, nsDrawingSurface aSurface,
@ -749,7 +748,6 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext,
{ {
float scale; float scale;
unsigned char *targetRow,*imageRow,*alphaRow; unsigned char *targetRow,*imageRow,*alphaRow;
PRBool result;
PRInt32 numTiles,x0,y0,x1,y1,destScaledWidth,destScaledHeight; PRInt32 numTiles,x0,y0,x1,y1,destScaledWidth,destScaledHeight;
PRInt32 validWidth,validHeight,validX,validY,targetRowBytes; PRInt32 validWidth,validHeight,validX,validY,targetRowBytes;
PRInt32 x,y,width,height,canRaster; PRInt32 x,y,width,height,canRaster;
@ -806,7 +804,7 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext,
((nsDrawingSurfaceWin *)aSurface)->GetTECHNOLOGY(&canRaster); ((nsDrawingSurfaceWin *)aSurface)->GetTECHNOLOGY(&canRaster);
// do alpha depth equal to 8 here.. this needs some special attention // do alpha depth equal to 8 here.. this needs some special attention
if ( mAlphaDepth == 8) { if (mAlphaDepth == 8 && !mIsOptimized) {
unsigned char *screenBits=nsnull,*adjAlpha,*adjImage,*adjScreen; unsigned char *screenBits=nsnull,*adjAlpha,*adjImage,*adjScreen;
HDC memDC=nsnull; HDC memDC=nsnull;
HBITMAP tmpBitmap=nsnull,oldBitmap; HBITMAP tmpBitmap=nsnull,oldBitmap;
@ -900,19 +898,19 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext,
} }
} }
numTiles = (aDestRect.width*aDestRect.height)/(ScaledTileWidth*ScaledTileHeight); numTiles = (aDestRect.width * aDestRect.height) /
(ScaledTileWidth * ScaledTileHeight);
// if alpha is less than 8,not printing, and not 8 bit palette image then we can do // If not printing, and not 8 bit palette image then we can do a progressive
// a progressive tile and the tile is at least 8 times smaller than the area to update // tile. If the number of tiles are less than 32 the progressive doubling
// if the number of tiles are less than 32 the progressive doubling can slow down // can slow down because of the creation of the offscreens, DC's etc.
// because of the creation of the offscreens, DC's etc. // XXX How was 32 determined optimal?
if ( (mAlphaDepth < 8) && (canRaster!=DT_RASPRINTER) && (256!=mNumPaletteColors) && if ((canRaster != DT_RASPRINTER) && (256 != mNumPaletteColors) &&
(numTiles > 32) ) { (numTiles > 32)) {
result = ProgressiveDoubleBlit(aSurface,x1-x0, y1-y0, if (ProgressiveDoubleBlit(aSurface, x1 - x0, y1 - y0,
ScaledTileWidth,ScaledTileHeight, x0,y0,x1,y1); ScaledTileWidth, ScaledTileHeight,
if (result ) { x0, y0, x1, y1))
return(NS_OK); return NS_OK;
}
} }
// if we got to this point.. everything else failed.. and the slow blit backstop // if we got to this point.. everything else failed.. and the slow blit backstop
@ -930,124 +928,212 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext,
/** --------------------------------------------------- /** ---------------------------------------------------
* See documentation in nsImageWin.h * See documentation in nsImageWin.h
* @update 8/26/02 dwc
*/ */
PRBool PRBool
nsImageWin::ProgressiveDoubleBlit(nsDrawingSurface aSurface, nsImageWin::ProgressiveDoubleBlit(nsDrawingSurface aSurface,
PRInt32 aDestBufferWidth, PRInt32 aDestBufferHeight, PRInt32 aDestBufferWidth,
PRInt32 aScaledTileWidth,PRInt32 aScaledTileHeight, PRInt32 aDestBufferHeight,
PRInt32 aX0,PRInt32 aY0, PRInt32 aScaledTileWidth,
PRInt32 aX1,PRInt32 aY1) PRInt32 aScaledTileHeight,
PRInt32 aX0, PRInt32 aY0,
PRInt32 aX1, PRInt32 aY1)
{ {
PRInt32 x,y,width,height;
nsRect srcRect; nsRect srcRect;
HDC theHDC,offDC,maskDC; HDC theHDC, offDC, maskDC;
HBITMAP maskBits,tileBits,oldBits,oldMaskBits; HBITMAP maskBits, tileBits, oldBits, oldMaskBits;
int offDCBytesPerPix;
PRInt32 offDCWidth, offDCHeight;
// create a larger tile from the smaller one // create a larger tile from the smaller one
((nsDrawingSurfaceWin *)aSurface)->GetDC(&theHDC); ((nsDrawingSurfaceWin *)aSurface)->GetDC(&theHDC);
if (NULL == theHDC) { if (!theHDC)
return (PR_FALSE); return PR_FALSE;
}
// so we will create a screen compatible bitmap and then install this into the
// so we will create a screen compatible bitmap and then install this into the offscreen DC // offscreen DC
offDC = ::CreateCompatibleDC(theHDC); offDC = ::CreateCompatibleDC(theHDC);
if (!offDC)
return PR_FALSE;
if (NULL ==offDC) { // Calculate bytesPerPix for memory DC
return (PR_FALSE); if (mAlphaDepth == 8 && mIsOptimized)
offDCBytesPerPix = 4;
else
offDCBytesPerPix = ::GetDeviceCaps(offDC, BITSPIXEL) / 8;
// Win 95/98/ME can't do > 0xFF0000 DDBs. Adjust our memory DC
// Note: This should be extremely rare. We'd need a tile of
// 1920x2176 @ 4 bytesPerPix before we hit this.
if (gPlatform == VER_PLATFORM_WIN32_WINDOWS &&
aDestBufferWidth * aDestBufferHeight * offDCBytesPerPix > 0xFF0000) {
PRUint32 sizeSoFar = mBHead->biWidth * mBHead->biHeight * offDCBytesPerPix;
if (aDestBufferWidth * offDCBytesPerPix * mBHead->biHeight < 0xFF0000)
offDCWidth = aDestBufferWidth;
else
offDCWidth = PRUint32(0xFF0000 / sizeSoFar) * mBHead->biWidth;
sizeSoFar = offDCWidth * mBHead->biHeight * offDCBytesPerPix;
offDCHeight = PR_MIN(mBHead->biHeight,
PRUint32(0xFF0000 / sizeSoFar) *
mBHead->biHeight);
} else {
offDCWidth = aDestBufferWidth;
offDCHeight = aDestBufferHeight;
} }
tileBits = ::CreateCompatibleBitmap(theHDC, aDestBufferWidth,aDestBufferHeight); // Create DDB
if (mAlphaDepth == 8 && mIsOptimized) {
// Create a bitmap of 1 plane, 32 bit color depth
if (NULL == tileBits) { // Can't use ::CreateBitmap, since the resulting HBITMAP will only be able
// to be selected into a compatible HDC (ie. User is @ 24 bit, you can't
// select the 32 HBITMAP into the HDC.)
ALPHA32BITMAPINFO bmi(offDCWidth, offDCHeight);
tileBits = ::CreateDIBSection(theHDC, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS,
NULL, NULL, 0);
} else {
tileBits = ::CreateCompatibleBitmap(theHDC, offDCWidth, offDCHeight);
}
if (!tileBits) {
::DeleteDC(offDC); ::DeleteDC(offDC);
return (PR_FALSE); return PR_FALSE;
} }
oldBits =(HBITMAP) ::SelectObject(offDC,tileBits);
oldBits = (HBITMAP)::SelectObject(offDC, tileBits);
if (1==mAlphaDepth) { if (1 == mAlphaDepth) {
// larger tile for mask // larger tile for mask
maskDC = ::CreateCompatibleDC(theHDC); maskDC = ::CreateCompatibleDC(theHDC);
if (NULL ==maskDC){ if (!maskDC){
::SelectObject(offDC,oldBits); ::SelectObject(offDC, oldBits);
::DeleteObject(tileBits); ::DeleteObject(tileBits);
::DeleteDC(offDC); ::DeleteDC(offDC);
return (PR_FALSE); return PR_FALSE;
} }
maskBits = ::CreateCompatibleBitmap(theHDC, aDestBufferWidth, aDestBufferHeight); maskBits = ::CreateCompatibleBitmap(theHDC, offDCWidth, offDCHeight);
if (NULL ==maskBits) { if (!maskBits) {
::SelectObject(offDC,oldBits); ::SelectObject(offDC, oldBits);
::DeleteObject(tileBits); ::DeleteObject(tileBits);
::DeleteDC(offDC); ::DeleteDC(offDC);
::DeleteDC(maskDC); ::DeleteDC(maskDC);
return (PR_FALSE); return PR_FALSE;
} }
oldMaskBits = (HBITMAP)::SelectObject(maskDC,maskBits); oldMaskBits = (HBITMAP)::SelectObject(maskDC, maskBits);
// get the mask into our new tiled mask // get the mask into our new tiled mask
MONOBITMAPINFO bmi(mAlphaWidth,mAlphaHeight); MONOBITMAPINFO bmi(mAlphaWidth, mAlphaHeight);
::StretchDIBits(maskDC, 0, 0, aScaledTileWidth, aScaledTileHeight,0, 0, ::SetDIBitsToDevice(maskDC, 0, 0, aScaledTileWidth, aScaledTileHeight,
mAlphaWidth, mAlphaHeight, mAlphaBits,(LPBITMAPINFO)&bmi, DIB_RGB_COLORS, SRCCOPY); 0, 0, 0, aScaledTileHeight, mAlphaBits,
(LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
srcRect.SetRect(0, 0, aScaledTileWidth, aScaledTileHeight);
::BitBlt(maskDC,0,0,aScaledTileWidth,aScaledTileHeight,maskDC,0,0,SRCCOPY); BuildTile(maskDC, srcRect, offDCWidth, offDCHeight, SRCCOPY);
srcRect.SetRect(0,0,aScaledTileWidth,aScaledTileHeight);
BuildTile(maskDC,srcRect,aDestBufferWidth/2,aDestBufferHeight/2,SRCCOPY);
} }
// put the initial tile of background image into the offscreen // put the initial tile of background image into the offscreen
if (!IsOptimized() || nsnull==mHBitmap) { if (!mIsOptimized || !mHBitmap) {
::StretchDIBits(offDC, 0, 0, aScaledTileWidth, aScaledTileHeight,0, 0, aScaledTileWidth, aScaledTileHeight, mImageBits, ::StretchDIBits(offDC, 0, 0, aScaledTileWidth, aScaledTileHeight,
(LPBITMAPINFO)mBHead, 256 == mNumPaletteColors ? DIB_PAL_COLORS:DIB_RGB_COLORS, 0, 0, aScaledTileWidth, aScaledTileHeight,
mImageBits, (LPBITMAPINFO)mBHead,
256 == mNumPaletteColors ? DIB_PAL_COLORS : DIB_RGB_COLORS,
SRCCOPY); SRCCOPY);
} else { } else {
// need to select install this bitmap into this DC first // need to select install this bitmap into this DC first
HBITMAP oldBits; HBITMAP oldBits;
oldBits = (HBITMAP)::SelectObject(theHDC, mHBitmap); oldBits = (HBITMAP)::SelectObject(theHDC, mHBitmap);
::BitBlt(offDC,0,0,aScaledTileWidth,aScaledTileHeight,theHDC,0,0,SRCCOPY); ::BitBlt(offDC, 0, 0, aScaledTileWidth, aScaledTileHeight,
theHDC, 0, 0, SRCCOPY);
::SelectObject(theHDC, oldBits); ::SelectObject(theHDC, oldBits);
} }
srcRect.SetRect(0,0,aScaledTileWidth,aScaledTileHeight); srcRect.SetRect(0, 0, aScaledTileWidth, aScaledTileHeight);
BuildTile(offDC,srcRect,aDestBufferWidth/2,aDestBufferHeight/2,SRCCOPY); // srcRect returns width/height containing tiled image
BuildTile(offDC, srcRect, offDCWidth, offDCHeight, SRCCOPY);
// now duplicate our tile into the background // now duplicate our tile into the background
width = srcRect.width;
height = srcRect.height;
if (1!=mAlphaDepth) { if (mAlphaDepth == 1) {
for (y=aY0;y<aY1;y+=srcRect.height) { for (PRInt32 y = aY0; y < aY1; y += srcRect.height) {
for (x=aX0;x<aX1;x+=srcRect.width) { for (PRInt32 x = aX0; x < aX1; x += srcRect.width) {
::BitBlt(theHDC,x,y,width,height,offDC,0,0,SRCCOPY); ::BitBlt(theHDC, x, y, srcRect.width, srcRect.height,
} maskDC, 0, 0, SRCAND);
} ::BitBlt(theHDC, x, y, srcRect.width, srcRect.height,
} else { offDC, 0, 0, SRCPAINT);
for (y=aY0;y<aY1;y+=srcRect.height) {
for (x=aX0;x<aX1;x+=srcRect.width) {
::BitBlt(theHDC,x,y,width,height,maskDC,0,0,SRCAND);
::BitBlt(theHDC,x,y,width,height,offDC,0,0,SRCPAINT);
} }
} }
// Destroy Alpha/Mask GDI Object
::SelectObject(maskDC,oldMaskBits); ::SelectObject(maskDC,oldMaskBits);
::DeleteObject(maskBits); ::DeleteObject(maskBits);
::DeleteDC(maskDC); ::DeleteDC(maskDC);
} else if (mAlphaDepth == 8) {
BLENDFUNCTION blendFunction;
blendFunction.BlendOp = AC_SRC_OVER;
blendFunction.BlendFlags = 0;
blendFunction.SourceConstantAlpha = 255;
blendFunction.AlphaFormat = 1;
for (PRInt32 y = aY0; y < aY1; y += srcRect.height) {
for (PRInt32 x = aX0; x < aX1; x += srcRect.width) {
gAlphaBlend(theHDC, x, y, srcRect.width, srcRect.height,
offDC, 0, 0, srcRect.width, srcRect.height, blendFunction);
}
}
} else {
for (PRInt32 y = aY0; y < aY1; y += srcRect.height) {
for (PRInt32 x = aX0; x < aX1; x += srcRect.width) {
::BitBlt(theHDC, x, y, srcRect.width, srcRect.height,
offDC, 0, 0, SRCCOPY);
}
}
} }
::SelectObject(offDC,oldBits); ::SelectObject(offDC,oldBits);
::DeleteObject(tileBits); ::DeleteObject(tileBits);
::DeleteDC(offDC); ::DeleteDC(offDC);
return(PR_TRUE); return PR_TRUE;
} }
/** ---------------------------------------------------
* build a tile area by doubling the image until it reaches its limits
* @param aTheHDC -- HDC to render to
* @param aSrcRect -- the size of the tile we are building
* @param aWidth -- max width allowed for the HDC
* @param aHeight -- max height allowed for the HDC
*/
void
nsImageWin::BuildTile(HDC aTheHDC, nsRect &aSrcRect,
PRInt32 aWidth, PRInt32 aHeight, PRInt32 aCopyMode)
{
nsRect destRect;
// keep doubling the width until doubling results in more than the max width
while (aSrcRect.width < aWidth) {
destRect.x = aSrcRect.XMost();
destRect.width = aSrcRect.width;
if (destRect.XMost() > aWidth)
destRect.width = aWidth - destRect.x;
::BitBlt(aTheHDC, destRect.x, aSrcRect.y, destRect.width, aSrcRect.height,
aTheHDC, aSrcRect.x, aSrcRect.y, aCopyMode);
aSrcRect.width += destRect.width;
}
// keep doubling the height until doubling results in more than the max height
while (aSrcRect.height < aHeight) {
destRect.y = aSrcRect.YMost();
destRect.height = aSrcRect.height;
if (destRect.YMost() > aHeight)
destRect.height = aHeight - destRect.y;
::BitBlt(aTheHDC, aSrcRect.x, destRect.y, aSrcRect.width, destRect.height,
aTheHDC, aSrcRect.x, aSrcRect.y, aCopyMode);
aSrcRect.height += destRect.height;
}
}
ALPHABLENDPROC nsImageWin::gAlphaBlend = NULL; ALPHABLENDPROC nsImageWin::gAlphaBlend = NULL;
@ -1450,36 +1536,6 @@ nsImageWin::SetDecodedRect(PRInt32 x1, PRInt32 y1, PRInt32 x2, PRInt32 y2)
} }
/** ---------------------------------------------------
* A bit blitter to tile images to the background recursively
* @update 9/9/2000 dwc
* @param aTheHDC -- HDC to render to
* @param aSrcRect -- the size of the tile we are building
* @param aWidth -- max width allowed for the HDC
* @param aHeight -- max height allowed for the HDC
*/
void
nsImageWin::BuildTile(HDC TheHDC,nsRect &aSrcRect,PRInt16 aWidth,PRInt16 aHeight,PRInt32 aCopyMode)
{
nsRect destRect;
if (aSrcRect.width < aWidth) {
// width is less than double so double our source bitmap width
destRect = aSrcRect;
destRect.x += aSrcRect.width;
::BitBlt(TheHDC,destRect.x,destRect.y,destRect.width,destRect.height,TheHDC,aSrcRect.x,aSrcRect.y,aCopyMode);
aSrcRect.width*=2;
this->BuildTile(TheHDC,aSrcRect,aWidth,aHeight,aCopyMode);
}else if (aSrcRect.height < aHeight) {
// height is less than double so double our source bitmap height
destRect = aSrcRect;
destRect.y += aSrcRect.height;
::BitBlt(TheHDC,destRect.x,destRect.y,destRect.width,destRect.height,TheHDC,aSrcRect.x,aSrcRect.y,aCopyMode);
aSrcRect.height*=2;
this->BuildTile(TheHDC,aSrcRect,aWidth,aHeight,aCopyMode);
}
}
/** /**
* Get a pointer to the bits for the pixelmap. Will convert to DIB if * Get a pointer to the bits for the pixelmap. Will convert to DIB if

Просмотреть файл

@ -125,7 +125,6 @@ public:
/** /**
* Progressivly double the bitmap size as we blit.. very fast way to tile * Progressivly double the bitmap size as we blit.. very fast way to tile
* @update - dwc 4/160/02
* @param aSurface the surface to blit to * @param aSurface the surface to blit to
* @param aDestBufferWidth Width of buffer * @param aDestBufferWidth Width of buffer
* @param aDestBufferHeight Height of buffer * @param aDestBufferHeight Height of buffer
@ -242,14 +241,14 @@ private:
/** --------------------------------------------------- /** ---------------------------------------------------
* A bit blitter to tile images to the background recursively * build a tile area by doubling the image until it reaches its limits
* @update 3/29/00 dwc * @param aTheHDC -- HDC to render to
* @param aDS -- Target drawing surface for the rendering context
* @param aSrcRect -- Rectangle we are build with the image * @param aSrcRect -- Rectangle we are build with the image
* @param aHeight -- height of the tile * @param aHeight -- height of the tile
* @param aWidth -- width of the tile * @param aWidth -- width of the tile
*/ */
void BuildTile(HDC SrcDestDC,nsRect &aSrcRect,PRInt16 aWidth,PRInt16 aHeight,PRInt32 aCopyMode); void BuildTile(HDC aTheHDC, nsRect &aSrcRect,
PRInt32 aWidth, PRInt32 aHeight, PRInt32 aCopyMode);