diff --git a/gfx/src/windows/nsImageWin.cpp b/gfx/src/windows/nsImageWin.cpp index b1cda7068281..559ce98f541c 100644 --- a/gfx/src/windows/nsImageWin.cpp +++ b/gfx/src/windows/nsImageWin.cpp @@ -40,9 +40,6 @@ #include "nsImageWin.h" #include "nsRenderingContextWin.h" -#define MAX_BUFFER_WIDTH 128 -#define MAX_BUFFER_HEIGHT 128 - static nsresult BuildDIB(LPBITMAPINFOHEADER *aBHead,PRInt32 aWidth,PRInt32 aHeight,PRInt32 aDepth,PRInt8 *aNumBitPix); @@ -661,118 +658,118 @@ NS_IMETHODIMP nsImageWin :: Draw(nsIRenderingContext &aContext, nsDrawingSurface NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext, nsDrawingSurface aSurface, PRInt32 aSXOffset, PRInt32 aSYOffset, - const nsRect &aTileRect) + const nsRect &aDestRect) { - float scale; + float scale; + unsigned char *targetRow,*imageRow,*alphaRow; + PRBool result; + PRInt32 numTiles,x0,y0,x1,y1,destScaledWidth,destScaledHeight; + PRInt32 validWidth,validHeight,validX,validY,targetRowBytes; + PRInt32 temp1,temp2,ScaledTileHeight_Offset,ScaledTileWidth_Offset; + PRInt32 x,y,width,height,canRaster; + nsCOMPtr theDeviceContext; + HDC theHDC; + nsRect destRect,srcRect; + nscoord ScaledTileWidth,ScaledTileHeight; - { - nsCOMPtr theDeviceContext; - aContext.GetDeviceContext(*getter_AddRefs(theDeviceContext)); - theDeviceContext->GetCanonicalPixelScale(scale); - } + aContext.GetDeviceContext(*getter_AddRefs(theDeviceContext)); + theDeviceContext->GetCanonicalPixelScale(scale); + + destScaledWidth = PR_MAX(PRInt32(mBHead->biWidth*scale), 1); + destScaledHeight = PR_MAX(PRInt32(mBHead->biHeight*scale), 1); - - PRInt32 - destScaledWidth = PR_MAX(int(mBHead->biWidth*scale), 1), - destScaledHeight = PR_MAX(int(mBHead->biHeight*scale), 1); - - PRInt32 - validX = 0, - validY = 0, - validWidth = mBHead->biWidth, - validHeight = mBHead->biHeight; + validX = 0; + validY = 0; + validWidth = mBHead->biWidth; + validHeight = mBHead->biHeight; // limit the image rectangle to the size of the image data which // has been validated. if (mDecodedY2 < mBHead->biHeight) { validHeight = mDecodedY2 - mDecodedY1; - destScaledHeight = PR_MAX(int(validHeight*scale), 1); + destScaledHeight = PR_MAX(PRInt32(validHeight*scale), 1); } if (mDecodedX2 < mBHead->biWidth) { validWidth = mDecodedX2 - mDecodedX1; - destScaledWidth = PR_MAX(int(validWidth*scale), 1); + destScaledWidth = PR_MAX(PRInt32(validWidth*scale), 1); } if (mDecodedY1 > 0) { validHeight -= mDecodedY1; - destScaledHeight = PR_MAX(int(validHeight*scale), 1); + destScaledHeight = PR_MAX(PRInt32(validHeight*scale), 1); validY = mDecodedY1; } if (mDecodedX1 > 0) { validWidth -= mDecodedX1; - destScaledWidth = PR_MAX(int(validWidth*scale), 1); + destScaledWidth = PR_MAX(PRInt32(validWidth*scale), 1); validX = mDecodedX1; } // put the width and hieght into the devices coordinates - PRInt32 aY0 = aTileRect.y - aSYOffset, - aX0 = aTileRect.x - aSXOffset, - aY1 = aTileRect.y + aTileRect.height, - aX1 = aTileRect.x + aTileRect.width; + // put the DestRect into absolute coordintes of the device + + y0 = aDestRect.y - aSYOffset; + x0 = aDestRect.x - aSXOffset; + y1 = aDestRect.y + aDestRect.height; + x1 = aDestRect.x + aDestRect.width; // this is the width and height of the image in pixels // we need to map this to the pixel height of the device - nscoord imageScaledWidth = PR_MAX(int(mBHead->biWidth*scale), 1); - nscoord imageScaledHeight = PR_MAX(int(mBHead->biHeight*scale), 1); - - nscoord tileWidth = aTileRect.width; - nscoord tileHeight = aTileRect.height; - - PRBool tryAgain = PR_FALSE; - nsRect destRect,srcRect,tvrect; - HDC TheHDC,offDC,maskDC; - PRInt32 x,y,width,height,canRaster,TileBufferWidth,TileBufferHeight; - HBITMAP maskBits,tileBits,oldBits,oldMaskBits; + ScaledTileWidth = PR_MAX(PRInt32(mBHead->biWidth*scale), 1); + ScaledTileHeight = PR_MAX(PRInt32(mBHead->biHeight*scale), 1); + - // The slower tiling will need to be used for the following cases: - // 1.) Printers 2.) When in 256 color mode 3.) when the tile is larger than the buffer - tvrect.SetRect(0,0,aX1-aX0,aY1-aY0); ((nsDrawingSurfaceWin *)aSurface)->GetTECHNOLOGY(&canRaster); - if( mAlphaDepth == 8){ - if(!mImageBits){ + // do alpha depth equal to 8 here.. this needs some special attention + + if ( mAlphaDepth == 8) { + unsigned char *screenBits=nsnull; + HDC memDC=nsnull; + HBITMAP tmpBitmap=nsnull,oldBitmap; + unsigned char alpha; + + if (!mImageBits) { ConvertDDBtoDIB(); } - /** - * do alpha depth equal to 8 here.. this needs some special attention - * draw the alpha and the bitmap to an offscreen buffer.. for the blend.. first - */ - // get the current HDC to draw to.. - ((nsDrawingSurfaceWin *)aSurface)->GetDC(&TheHDC); - if (NULL == TheHDC){ - return (PR_FALSE); - } + + + // draw the alpha and the bitmap to an offscreen buffer.. for the blend.. first + ((nsDrawingSurfaceWin *)aSurface)->GetDC(&theHDC); + if (theHDC) { // create a buffer for the blend - HDC memDC = CreateCompatibleDC(TheHDC); - unsigned char *screenBits; - width = aX1-aX0; - height = aY1-aY0; - ALPHA24BITMAPINFO bmi(width, height); - HBITMAP tmpBitmap = ::CreateDIBSection(memDC, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, (LPVOID *)&screenBits, NULL, 0); - HBITMAP oldBitmap = (HBITMAP)::SelectObject(memDC, tmpBitmap); - if(0 == tmpBitmap){ - ::DeleteObject(memDC); - tryAgain = PR_TRUE; + memDC = CreateCompatibleDC(theHDC); + width = x1-x0; + height = y1-y0; + + ALPHA24BITMAPINFO bmi(width, height); + tmpBitmap = ::CreateDIBSection(memDC, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, (LPVOID *)&screenBits, NULL, 0); + oldBitmap = (HBITMAP)::SelectObject(memDC, tmpBitmap); + } + + if (!tmpBitmap) { + if (memDC) { + ::DeleteObject(memDC); + } + // this failed..and will fall into the slow blitting code + NS_WARNING("The Creation of the tmpBitmap failed \n"); } else { // Copy from the HDC to the memory DC - ::StretchBlt(memDC, 0, 0, width, height,TheHDC, 0, 0, width, height, SRCCOPY); + ::StretchBlt(memDC, 0, 0, width, height,theHDC, 0, 0, width, height, SRCCOPY); - PRInt32 targetRowBytes = ((width * 3) + 3) & ~3; - unsigned char *targetRow,*imageRow,*alphaRow; - PRInt32 temp1,temp2,imageScaledHeightPlus,imageScaledWidthPlus; + targetRowBytes = ((width * 3) + 3) & ~3; + ScaledTileHeight_Offset = ScaledTileHeight + aSYOffset; + ScaledTileWidth_Offset = ScaledTileWidth + aSXOffset; - - imageScaledHeightPlus = imageScaledHeight + aSYOffset; - imageScaledWidthPlus = imageScaledWidth + aSXOffset; temp1 = mRowBytes + 3 * aSXOffset; temp2 = mARowBytes + aSXOffset; for (int y = 0,byw=aSYOffset; y < height; y++,byw++) { - if(byw >= imageScaledHeightPlus){ + if (byw >= ScaledTileHeight_Offset) { byw = aSYOffset; } targetRow = screenBits + y * targetRowBytes; @@ -780,12 +777,12 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext, alphaRow = mAlphaBits + byw * temp2; for (int x=0,bxw=aSXOffset;x=imageScaledWidthPlus){ + if (bxw>=ScaledTileWidth_Offset) { bxw = aSXOffset; imageRow = mImageBits + byw * mRowBytes + ((3*bxw)%mRowBytes); alphaRow = mAlphaBits + byw * mARowBytes + (bxw%mRowBytes); } - unsigned alpha = *alphaRow; + alpha = *alphaRow; MOZ_BLEND(targetRow[0], targetRow[0], imageRow[0], alpha); MOZ_BLEND(targetRow[1], targetRow[1], imageRow[1], alpha); @@ -794,255 +791,158 @@ NS_IMETHODIMP nsImageWin::DrawTile(nsIRenderingContext &aContext, } // Copy back to the HDC - ::StretchBlt(TheHDC, 0, 0, width, height,memDC, 0, 0, width, height, SRCCOPY); + ::StretchBlt(theHDC, 0, 0, width, height,memDC, 0, 0, width, height, SRCCOPY); ::SelectObject(memDC, oldBitmap); ::DeleteObject(tmpBitmap); ::DeleteObject(memDC); - return(PR_TRUE); + return(NS_OK); } } + numTiles = (aDestRect.width*aDestRect.height)/(ScaledTileWidth*ScaledTileHeight); - // figure out which case to use for tiling - PRBool useSlow = PR_FALSE; + // if alpha is less than 8,not printing, and not 8 bit palette image then we can do + // a progressive tile and the tile is at least 4 times smaller than the area to update + if ( (mAlphaDepth < 8) && (canRaster!=DT_RASPRINTER) && (256!=mNumPaletteColors) && + (numTiles > 3) ) { + result = ProgressiveDoubleBlit(aSurface,aDestRect.width, aDestRect.height, + ScaledTileWidth,ScaledTileHeight, x0,y0,x1,y1); + if (result ) { + return(NS_OK); + } + } - if ((mAlphaDepth>8) || ((mAlphaDepth==8)&&tryAgain) || (canRaster==DT_RASPRINTER) - || (256==mNumPaletteColors)){ - // CASE 1 -- ALPHA DEPTH IS TO HIGH OR WE ARE PRINTING OR ALPHA ALGORITHM FROM ABOVE FAILED - useSlow = PR_TRUE; - } else if ( (imageScaledWidth>MAX_BUFFER_WIDTH) || (imageScaledHeight>MAX_BUFFER_HEIGHT)) { - if(PR_TRUE != gIsWinNT){ - // CASE 2 -- THE PLATFORM IS NOT ON NT AND CAN NOT USE A PATBLT - useSlow = PR_TRUE; + // if we got to this point.. everything else failed.. and the slow blit backstop + // will finish this tiling + for (y=y0;yGetDC(&theHDC); + if (NULL == theHDC) { + return (PR_FALSE); + } + + // so we will create a screen compatible bitmap and then install this into the offscreen DC + offDC = ::CreateCompatibleDC(theHDC); + + if (NULL ==offDC) { + return (PR_FALSE); + } + + tileBits = ::CreateCompatibleBitmap(theHDC, aDestBufferWidth,aDestBufferHeight); + + if (NULL == tileBits) { + ::DeleteObject(offDC); + return (PR_FALSE); + } + oldBits =(HBITMAP) ::SelectObject(offDC,tileBits); + + if (1==mAlphaDepth) { + // larger tile for mask + maskDC = ::CreateCompatibleDC(theHDC); + if (NULL ==maskDC){ + ::SelectObject(offDC,oldBits); + ::DeleteObject(tileBits); + ::DeleteObject(offDC); + return (PR_FALSE); + } + maskBits = ::CreateCompatibleBitmap(theHDC, aDestBufferWidth, aDestBufferHeight); + if (NULL ==maskBits) { + ::SelectObject(offDC,oldBits); + ::DeleteObject(tileBits); + ::DeleteObject(offDC); + ::DeleteObject(maskDC); + return (PR_FALSE); + } + + oldMaskBits = (HBITMAP)::SelectObject(maskDC,maskBits); + + // get the mask into our new tiled mask + MONOBITMAPINFO bmi(mAlphaWidth,mAlphaHeight); + ::StretchDIBits(maskDC, 0, 0, aScaledTileWidth, aScaledTileHeight,0, 0, + mAlphaWidth, mAlphaHeight, mAlphaBits,(LPBITMAPINFO)&bmi, DIB_RGB_COLORS, SRCCOPY); + + ::BitBlt(maskDC,0,0,aScaledTileWidth,aScaledTileHeight,maskDC,0,0,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 + if (!IsOptimized() || nsnull==mHBitmap) { + ::StretchDIBits(offDC, 0, 0, aScaledTileWidth, aScaledTileHeight,0, 0, aScaledTileWidth, aScaledTileHeight, mImageBits, + (LPBITMAPINFO)mBHead, 256 == mNumPaletteColors ? DIB_PAL_COLORS:DIB_RGB_COLORS, + SRCCOPY); } else { - if( (imageScaledWidth < MAX_BUFFER_WIDTH) || (imageScaledHeight < MAX_BUFFER_HEIGHT) ) { - // CASE 3 -- THE PLATFORM IS ON NT AND WE HAVE ONE LARGE AND ONE SMALL WIDTH AND HEIGHT - if (PatBltTile(aContext,aSurface,aX0,aY0,aX1,aY1)) { - return(PR_TRUE); + // need to select install this bitmap into this DC first + HBITMAP oldBits; + oldBits = (HBITMAP)::SelectObject(theHDC, mHBitmap); + ::BitBlt(offDC,0,0,aScaledTileWidth,aScaledTileHeight,theHDC,0,0,SRCCOPY); + ::SelectObject(theHDC, oldBits); + } + + srcRect.SetRect(0,0,aScaledTileWidth,aScaledTileHeight); + BuildTile(offDC,srcRect,aDestBufferWidth/2,aDestBufferHeight/2,SRCCOPY); + + // now duplicate our tile into the background + destRect = srcRect; + width = destRect.width; + height = destRect.height; + + if (1!=mAlphaDepth) { + for (y=aY0;yGetDC(&TheHDC); - if (NULL == TheHDC){ - return (PR_FALSE); - } - - // IF WE MADE IT THIS FAR.. A PROGRESSIVE DOUBLING ALGORITHM WILL BE USED TO TILE - - // so we will create a screen compatible bitmap and then install this into the offscreen DC - tvrect.SetRect(0,0,aX1-aX0,aY1-aY0); - offDC = ::CreateCompatibleDC(TheHDC); - if (NULL ==offDC){ - return (PR_FALSE); - } - - if (tileWidth < tvrect.width){ - TileBufferWidth = MAX_BUFFER_WIDTH; - } else { - TileBufferWidth = tileWidth; - } - - if (tileHeight < tvrect.height){ - TileBufferHeight = MAX_BUFFER_HEIGHT; - } else { - TileBufferHeight = tileHeight; - } - - tileBits = ::CreateCompatibleBitmap(TheHDC, TileBufferWidth,TileBufferHeight); - - if (NULL == tileBits){ - ::DeleteObject(offDC); - return (PR_FALSE); - } - oldBits =(HBITMAP) ::SelectObject(offDC,tileBits); - - - if (1==mAlphaDepth) { - // larger tile for mask - maskDC = ::CreateCompatibleDC(TheHDC); - if (NULL ==maskDC){ - ::SelectObject(offDC,oldBits); - ::DeleteObject(tileBits); - ::DeleteObject(offDC); - return (PR_FALSE); - } - maskBits = ::CreateCompatibleBitmap(TheHDC, TileBufferWidth, TileBufferHeight); - if (NULL ==maskBits){ - ::SelectObject(offDC,oldBits); - ::DeleteObject(tileBits); - ::DeleteObject(offDC); + } + } else { + for (y=aY0;yGetDC(&TheHDC); - if (NULL == TheHDC){ - return (PR_FALSE); - } - - // default copy mode - rop = PATCOPY; - - - // we have to reset the origin here.. - ::SetBrushOrgEx(TheHDC,aX0,aY0,&originalPoint); - - // if there is an alpha layer, lay down the mask first - if (1==mAlphaDepth){ - ((nsDrawingSurfaceWin *)aSurface)->GetDC(&TheHDC); - theBits = ::CreateBitmap(mAlphaWidth,mAlphaHeight,1,1,NULL); - MONOBITMAPINFO bmi(mAlphaWidth, mAlphaHeight); - SetDIBits(TheHDC,theBits,0,mAlphaHeight,mAlphaBits,(LPBITMAPINFO)&bmi,DIB_RGB_COLORS); - hBrush = CreatePatternBrush(theBits); - oldBrush = (HBRUSH)SelectObject(TheHDC,hBrush); - success = PatBlt( TheHDC, aX0,aY0,aX1-aX0,aY1-aY0,0xA000C9); - SelectObject(TheHDC,oldBrush); - DeleteObject(hBrush); - DeleteObject(theBits); - rop = 0xFA0089; - } - - // do a pattern blit - if (mHBitmap == NULL) { - problem = TRUE; - } - - hBrush = CreatePatternBrush(mHBitmap); - oldBrush = (HBRUSH)SelectObject(TheHDC,hBrush); - success = PatBlt( TheHDC, aX0,aY0,aX1-aX0,aY1-aY0,rop); - SelectObject(TheHDC,oldBrush); - DeleteObject(hBrush); - - ::SetBrushOrgEx(TheHDC,originalPoint.x,originalPoint.y,NULL); - - return (PR_TRUE); -} ALPHABLENDPROC nsImageWin::gAlphaBlend = NULL; diff --git a/gfx/src/windows/nsImageWin.h b/gfx/src/windows/nsImageWin.h index 100266a023ce..bd5489ad4182 100644 --- a/gfx/src/windows/nsImageWin.h +++ b/gfx/src/windows/nsImageWin.h @@ -126,17 +126,24 @@ public: const nsRect &aTileRect); /** - * Draw a tiled version of the bitmap, but use the windows specific highly optimized PatBlt - * @update - dwc 3/30/00 + * 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 aX The destination horizontal location - * @param aY The destination vertical location + * @param aDestBufferWidth Width of buffer + * @param aDestBufferHeight Height of buffer + * @param aScaledTileWidth Width of tile + * @param aScaledTileHeight Height of tile + * @param aX0,aY0,aX1,aY1 Coordinates of screen to blit to * @return if TRUE, no errors - */ - PRBool PatBltTile(nsIRenderingContext &aContext, nsDrawingSurface aSurface,nscoord aX0,nscoord aY0,nscoord aX1,nscoord aY1); + */ + PRBool ProgressiveDoubleBlit(nsDrawingSurface aSurface, + PRInt32 aDestBufferWidth, PRInt32 aDestBufferHeight, + PRInt32 aScaledTileWidth,PRInt32 aScaledTileHeight, + PRInt32 aX0,PRInt32 aY0, + PRInt32 aX1,PRInt32 aY1); - /** + /** * Return the header size of the Device Independent Bitmap(DIB). * @return size of header in bytes */