gecko-dev/widget/src/windows/nsImageClipboard.cpp

373 lines
11 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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):
* Mike Pinkerton <pinkerton@netscape.com>
* Gus Verdun <gustavoverdun@aol.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either 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 "nsImageClipboard.h"
#include "nsGfxCIID.h"
/* Things To Do 11/8/00
Check image metrics, can we support them? Do we need to?
Any other render format? HTML?
*/
//
// nsImageToClipboard ctor
//
// Given an nsIImage, convert it to a DIB that is ready to go on the win32 clipboard
//
nsImageToClipboard :: nsImageToClipboard ( nsIImage* inImage )
: mImage(inImage)
{
// nothing to do here
}
//
// nsImageToClipboard dtor
//
// Clean up after ourselves. We know that we have created the bitmap
// successfully if we still have a pointer to the header.
//
nsImageToClipboard::~nsImageToClipboard()
{
}
//
// GetPicture
//
// Call to get the actual bits that go on the clipboard. If an error
// ocurred during conversion, |outBits| will be null.
//
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
//
nsresult
nsImageToClipboard :: GetPicture ( HANDLE* outBits )
{
NS_ASSERTION ( outBits, "Bad parameter" );
return CreateFromImage ( mImage, outBits );
} // GetPicture
//
// CalcSize
//
// Computes # of bytes needed by a bitmap with the specified attributes.
//
PRInt32
nsImageToClipboard :: CalcSize ( PRInt32 aHeight, PRInt32 aColors, WORD aBitsPerPixel, PRInt32 aSpanBytes )
{
PRInt32 HeaderMem = sizeof(BITMAPINFOHEADER);
// add size of pallette to header size
if (aBitsPerPixel < 16)
HeaderMem += aColors * sizeof(RGBQUAD);
if (aHeight < 0)
aHeight = -aHeight;
return (HeaderMem + (aHeight * aSpanBytes));
}
//
// CalcSpanLength
//
// Computes the span bytes for determining the overall size of the image
//
PRInt32
nsImageToClipboard::CalcSpanLength(PRUint32 aWidth, PRUint32 aBitCount)
{
PRInt32 spanBytes = (aWidth * aBitCount) >> 5;
if ((aWidth * aBitCount) & 0x1F)
spanBytes++;
spanBytes <<= 2;
return spanBytes;
}
//
// CreateFromImage
//
// Do the work to setup the bitmap header and copy the bits out of the
// image.
//
nsresult
nsImageToClipboard::CreateFromImage ( nsIImage* inImage, HANDLE* outBitmap )
{
nsresult result = NS_OK;
*outBitmap = nsnull;
/*
//pHead = (BITMAPINFOHEADER*)pImage->GetBitInfo();
//pImage->GetNativeData((void**)&hBitMap);
if (hBitMap)
{
BITMAPINFO * pBMI;
pBMI = (BITMAPINFO *)new BYTE[(sizeof(BITMAPINFOHEADER)+256*4)];
BITMAPINFOHEADER * pBIH = (BITMAPINFOHEADER *)pBMI;
pBIH->biSize = sizeof(BITMAPINFOHEADER);
pBIH->biBitCount = 0;
pBIH->biPlanes = 1;
pBIH->biSizeImage = 0;
pBIH->biXPelsPerMeter = 0;
pBIH->biYPelsPerMeter = 0;
pBIH->biClrUsed = 0; // Always use the whole palette.
pBIH->biClrImportant = 0;
// Get bitmap format.
HDC hdc = ::GetDC(NULL);
int rc = ::GetDIBits(hdc, hBitMap, 0, 0, NULL, pBMI, DIB_RGB_COLORS);
NS_ASSERTION(rc, "rc returned false");
nLength = CalcSize(pBIH->biHeight, pBIH->biClrUsed, pBIH->biBitCount, CalcSpanLength(pBIH->biWidth, pBIH->biBitCount));
// alloc and lock
mBitmap = (HANDLE)::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, nLength);
if (mBitmap && (mHeader = (BITMAPINFOHEADER*)::GlobalLock((HGLOBAL) mBitmap)) )
{
result = TRUE;
pBits = (PBYTE)&mHeader[1];
memcpy(mHeader, pBIH, sizeof (BITMAPINFOHEADER));
rc = ::GetDIBits(hdc, hBitMap, 0, mHeader->biHeight, pBits, (BITMAPINFO *)mHeader, DIB_RGB_COLORS);
NS_ASSERTION(rc, "rc returned false");
delete[] (BYTE*)pBMI;
::GlobalUnlock((HGLOBAL)mBitmap); // we use mHeader to tell if we have to free it later.
}
::ReleaseDC(NULL, hdc);
}
else
{
*/
inImage->LockImagePixels ( PR_FALSE );
if ( inImage->GetBits() ) {
BITMAPINFOHEADER* imageHeader = NS_REINTERPRET_CAST(BITMAPINFOHEADER*, inImage->GetBitInfo());
NS_ASSERTION ( imageHeader, "Can't get header for image" );
if ( !imageHeader )
return NS_ERROR_FAILURE;
PRInt32 imageSize = CalcSize(imageHeader->biHeight, imageHeader->biClrUsed, imageHeader->biBitCount, inImage->GetLineStride());
// Create the buffer where we'll copy the image bits (and header) into and lock it
BITMAPINFOHEADER* header = nsnull;
2001-03-27 06:04:33 +00:00
*outBitmap = (HANDLE)::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, imageSize);
if (*outBitmap && (header = (BITMAPINFOHEADER*)::GlobalLock((HGLOBAL) *outBitmap)) )
{
RGBQUAD *pRGBQUAD = (RGBQUAD *)&header[1];
PBYTE bits = (PBYTE)&pRGBQUAD[imageHeader->biClrUsed];
// Fill in the header info.
header->biSize = sizeof(BITMAPINFOHEADER);
header->biWidth = imageHeader->biWidth;
header->biHeight = imageHeader->biHeight;
header->biPlanes = 1;
header->biBitCount = imageHeader->biBitCount;
header->biCompression = BI_RGB; // No compression
header->biSizeImage = 0;
header->biXPelsPerMeter = 0;
header->biYPelsPerMeter = 0;
header->biClrUsed = imageHeader->biClrUsed;
header->biClrImportant = 0;
// Set up the color map.
nsColorMap *colorMap = inImage->GetColorMap();
if ( colorMap ) {
PBYTE pClr = colorMap->Index;
NS_ASSERTION(( ((DWORD)colorMap->NumColors) == header->biClrUsed), "Color counts must match");
for ( UINT i=0; i < header->biClrUsed; ++i ) {
NS_WARNING ( "Cool! You found a test case for this! Let Gus or Pink know" );
// now verify that the order is correct
pRGBQUAD[i].rgbBlue = *pClr++;
pRGBQUAD[i].rgbGreen = *pClr++;
pRGBQUAD[i].rgbRed = *pClr++;
}
}
else
NS_ASSERTION(header->biClrUsed == 0, "Ok, now why are there colors and no table?");
// Copy!!
::CopyMemory(bits, inImage->GetBits(), inImage->GetLineStride() * header->biHeight);
::GlobalUnlock((HGLOBAL)outBitmap);
}
else
result = NS_ERROR_FAILURE;
} // if we can get the bits from the image
inImage->UnlockImagePixels ( PR_FALSE );
return result;
}
#if XP_MAC
#pragma mark -
#endif
nsImageFromClipboard :: nsImageFromClipboard ( BITMAPV4HEADER* inHeader )
: mHeader(inHeader)
{
// nothing to do here
}
nsImageFromClipboard :: ~nsImageFromClipboard ( )
{
// since the output is a COM object, it is refcounted and such we've got
// nothing to do.
}
//
// GetImage
//
// Take the image data in the given buffer and create an nsIImage based
// off it
//
nsresult
nsImageFromClipboard :: GetImage ( nsIImage** outImage )
{
NS_ASSERTION ( outImage, "Bad parameter" );
*outImage = nsnull;
static NS_DEFINE_IID(kCImageCID, NS_IMAGE_CID);
nsresult rv = CallCreateInstance(kCImageCID, outImage);
if ( NS_SUCCEEDED(rv) ) {
// pull the size informat out of the BITMAPINFO header and
// initialize the image
PRInt32 width = mHeader->bV4Width;
PRInt32 height = mHeader->bV4Height;
PRInt32 depth = mHeader->bV4BitCount;
PRUint8 * bits = GetDIBBits();
if ( !bits )
return NS_ERROR_FAILURE;
// BUG 44369 notes problems with the GFX image code handling
// depths other than 8 or 24 bits. Ensure that's what we have
// before we try to work with the image. (pinkerton)
if ( depth == 24 || depth == 8 ) {
(*outImage)->Init(width, height, depth, nsMaskRequirements_kNoMask);
// Now, copy the image bits from the Dib into the nsIImage's buffer
PRUint8* imageBits = (*outImage)->GetBits();
depth = (depth >> 3);
PRUint32 size = width * height * depth;
::CopyMemory(imageBits, bits, size);
}
}
return rv;
} // GetImage
//
// GetDIBBits
//
// Compute the sizes of the various headers then return a ptr into the buffer
// that is at the start of the bits.
//
PRUint8*
nsImageFromClipboard :: GetDIBBits ( )
{
BITMAPINFO * aBitmapInfo = (BITMAPINFO*) mHeader;
DWORD maskSize;
DWORD colorSize;
// Get the size of the information header
DWORD headerSize = aBitmapInfo->bmiHeader.biSize ;
if (headerSize != sizeof (BITMAPCOREHEADER) &&
headerSize != sizeof (BITMAPINFOHEADER) &&
//headerSize != sizeof (BITMAPV5HEADER) &&
headerSize != sizeof (BITMAPV4HEADER))
return NULL ;
// Get the size of the color masks
if (headerSize == sizeof (BITMAPINFOHEADER) &&
aBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
maskSize = 3 * sizeof (DWORD);
else
maskSize = 0;
// Get the size of the color table
if (headerSize == sizeof (BITMAPCOREHEADER)) {
int iBitCount = ((BITMAPCOREHEADER *) aBitmapInfo)->bcBitCount;
if (iBitCount <= 8)
colorSize = (1 << iBitCount) * sizeof (RGBTRIPLE);
else
colorSize = 0 ;
}
else { // All non-OS/2 compatible DIBs
if (aBitmapInfo->bmiHeader.biClrUsed > 0)
colorSize = aBitmapInfo->bmiHeader.biClrUsed * sizeof (RGBQUAD);
else if (aBitmapInfo->bmiHeader.biBitCount <= 8)
colorSize = (1 << aBitmapInfo->bmiHeader.biBitCount) * sizeof (RGBQUAD);
else
colorSize = 0;
}
// the bits are at an offset into the buffer that is the header size plus the
// mask size plus the color table size.
return (BYTE *) aBitmapInfo + (headerSize + maskSize + colorSize);
} // GetDIBBits