From 2ee2592948667d658bf00a00ea5454046270d1de Mon Sep 17 00:00:00 2001 From: "scott%scott-macgregor.org" Date: Thu, 25 Aug 2005 22:35:49 +0000 Subject: [PATCH] Bug #223909 --> Land the aviary 1.0 changes for supporting copy and paste of windows clipboard images into HTML mail compose onto the 1.8 branch. Changes were re-reviewed for 1.8 by various folks including module owners: stuart, biesi, glazman a=asa git-svn-id: svn://10.0.0.236/branches/MOZILLA_1_8_BRANCH@179004 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/libeditor/html/Makefile.in | 2 + .../libeditor/html/nsHTMLDataTransfer.cpp | 68 ++- .../modules/libpr0n/build/nsImageModule.cpp | 15 + .../modules/libpr0n/decoders/jpeg/Makefile.in | 10 +- .../libpr0n/decoders/jpeg/nsJPEGEncoder.cpp | 567 ++++++++++++++++++ .../libpr0n/decoders/jpeg/nsJPEGEncoder.h | 91 +++ mozilla/modules/libpr0n/public/Makefile.in | 1 + .../modules/libpr0n/public/imgIEncoder.idl | 58 ++ mozilla/widget/public/nsIClipboard.idl | 16 + mozilla/widget/public/nsWidgetsCID.h | 4 + mozilla/widget/src/build/Makefile.in | 4 + .../widget/src/build/nsWinWidgetFactory.cpp | 5 + mozilla/widget/src/windows/nsClipboard.cpp | 103 +++- mozilla/widget/src/windows/nsClipboard.h | 14 + 14 files changed, 935 insertions(+), 23 deletions(-) create mode 100755 mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp create mode 100755 mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h create mode 100755 mozilla/modules/libpr0n/public/imgIEncoder.idl diff --git a/mozilla/editor/libeditor/html/Makefile.in b/mozilla/editor/libeditor/html/Makefile.in index 9cdeabbddc2..1c85176cc5b 100644 --- a/mozilla/editor/libeditor/html/Makefile.in +++ b/mozilla/editor/libeditor/html/Makefile.in @@ -59,9 +59,11 @@ REQUIRES = xpcom \ necko \ pref \ gfx \ + imglib2 \ widget \ view \ webshell \ + exthandler \ $(NULL) # Building the full blown HTML Editor so add its source files and objects: diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp index 9ab4e373b03..b2d34a33e14 100644 --- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -130,6 +130,10 @@ #include "nsIPrefBranch.h" #include "nsIPrefService.h" #include "nsIContentFilter.h" +#include "imgIEncoder.h" + +#include "nsIExternalHelperAppService.h" +#include "nsCExternalHandlerService.h" const PRUnichar nbsp = 160; @@ -1143,7 +1147,11 @@ NS_IMETHODIMP nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransfera } (*aTransferable)->AddDataFlavor(kHTMLMime); (*aTransferable)->AddDataFlavor(kFileMime); - //(*aTransferable)->AddDataFlavor(kJPEGImageMime); +#ifdef XP_WIN32 + // we only support copy and paste of clipboard images on Windows + (*aTransferable)->AddDataFlavor(kJPEGImageMime); + (*aTransferable)->AddDataFlavor(kNativeImageMime); +#endif } (*aTransferable)->AddDataFlavor(kUnicodeMime); } @@ -1407,14 +1415,58 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable } } } + else if (flavor.Equals(NS_LITERAL_STRING(kNativeImageMime))) + { + nsXPIDLString htmlstr; + nsAutoEditBatch beginBatching(this); + rv = InsertHTMLWithContext(htmlstr, EmptyString(), EmptyString(), flavor, aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection); + } else if (0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime)) { - // need to provide a hook from here - // Insert Image code here - printf("Don't know how to insert an image yet!\n"); - //nsIImage* image = (nsIImage *)data; - //NS_RELEASE(image); - rv = NS_ERROR_NOT_IMPLEMENTED; // for now give error code + // Insert Image code + nsCOMPtr clipboardImage (do_QueryInterface(genericDataObj)); + if (clipboardImage) + { + // invoke image encoder + nsCOMPtr imgEncoder (do_CreateInstance("@mozilla.org/image/encoder;2?type=image/jpeg")); + if (imgEncoder) + { + nsCOMPtr clipboardImageFile; + rv = imgEncoder->EncodeClipboardImage(clipboardImage, getter_AddRefs(clipboardImageFile)); + + if (NS_FAILED(rv) || !clipboardImageFile) + return rv; + + nsCOMPtr uri; + rv = NS_NewFileURI(getter_AddRefs(uri), clipboardImageFile); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr fileURL(do_QueryInterface(uri)); + if (fileURL) + { + nsCAutoString urltext; + rv = fileURL->GetSpec(urltext); + if (NS_SUCCEEDED(rv) && !urltext.IsEmpty()) + { + stuffToPaste.AssignLiteral("\"\""); + nsAutoEditBatch beginBatching(this); + rv = InsertHTMLWithContext(stuffToPaste, + nsString(), nsString(), NS_LITERAL_STRING(kFileMime), + aSourceDoc, + aDestinationNode, aDestOffset, + aDoDeleteSelection); + } + } + + nsCOMPtr tempFileManager (do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID)); + if (tempFileManager) + tempFileManager->DeleteTemporaryFileOnExit(clipboardImageFile); + } + else + rv = NS_ERROR_NOT_IMPLEMENTED; // for now give error code, we don't know how to handle the image format from the clipboard + } } } nsCRT::free(bestFlavor); @@ -1927,7 +1979,7 @@ NS_IMETHODIMP nsHTMLEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste) // the flavors that we can deal with const char* const textEditorFlavors[] = { kUnicodeMime, nsnull }; - const char* const htmlEditorFlavors[] = { kHTMLMime, kJPEGImageMime, nsnull }; + const char* const htmlEditorFlavors[] = { kHTMLMime, kJPEGImageMime, kNativeImageMime, nsnull }; nsCOMPtr flavorsList = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv); diff --git a/mozilla/modules/libpr0n/build/nsImageModule.cpp b/mozilla/modules/libpr0n/build/nsImageModule.cpp index 122cf4c6c1d..14b7d42ed8f 100644 --- a/mozilla/modules/libpr0n/build/nsImageModule.cpp +++ b/mozilla/modules/libpr0n/build/nsImageModule.cpp @@ -74,6 +74,10 @@ #include "nsPNGDecoder.h" #endif +#if defined(XP_WIN32) && defined(IMG_BUILD_jpeg) +#include "nsJPEGEncoder.h" +#endif + #ifdef IMG_BUILD_jpeg // jpeg #include "nsJPEGDecoder.h" @@ -102,6 +106,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2) NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGDecoder) #endif +#if defined(XP_WIN32) && defined(IMG_BUILD_jpeg) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGEncoder) +#endif + #ifdef IMG_BUILD_bmp // bmp NS_GENERIC_FACTORY_CONSTRUCTOR(nsICODecoder) @@ -227,6 +235,13 @@ static const nsModuleComponentInfo components[] = nsJPEGDecoderConstructor, }, #endif +#if defined(XP_WIN32) && defined(IMG_BUILD_jpeg) + { "JPEG encoder", + NS_JPEGENCODER_CID, + "@mozilla.org/image/encoder;2?type=image/jpeg", + nsJPEGEncoderConstructor, }, +#endif + #ifdef IMG_BUILD_bmp // bmp { "ICO Decoder", diff --git a/mozilla/modules/libpr0n/decoders/jpeg/Makefile.in b/mozilla/modules/libpr0n/decoders/jpeg/Makefile.in index 8dc8d2ea1b9..d9ea01a17db 100644 --- a/mozilla/modules/libpr0n/decoders/jpeg/Makefile.in +++ b/mozilla/modules/libpr0n/decoders/jpeg/Makefile.in @@ -35,11 +35,17 @@ LIBXUL_LIBRARY = 1 REQUIRES = xpcom \ string \ gfx \ + widget \ imglib2 \ + necko \ $(JPEG_REQUIRES) \ $(NULL) -CPPSRCS = nsJPEGDecoder.cpp +CPPSRCS = nsJPEGDecoder.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += nsJPEGEncoder.cpp +endif include $(topsrcdir)/config/rules.mk - diff --git a/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp b/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp new file mode 100755 index 00000000000..cf649099d77 --- /dev/null +++ b/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp @@ -0,0 +1,567 @@ +/* -*- 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 the JPEG image encoder. + * + * The Initial Developer of the Original Code is + * Scott MacGregor . + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifdef MOZ_LOGGING +// sorry, this has to be before the pre-compiled header +#define FORCE_PR_LOG /* Allow logging in the release build */ +#endif + +#include +#include "nsJPEGEncoder.h" +#include "nsIClipboard.h" +#include "nsIComponentManager.h" +#include "nspr.h" +#include "nsCRT.h" +#include "ImageLogging.h" +#include "jerror.h" + +#include "nsILocalFile.h" +#include "nsIOutputStream.h" +#include "nsNetUtil.h" +#include "nsDirectoryServiceDefs.h" + +PRLogModuleInfo *gJPEGEncoderLog = PR_NewLogModule("JPEGEncoder"); + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +NS_IMPL_ISUPPORTS1(nsJPEGEncoder, imgIEncoder) + +METHODDEF(boolean) empty_output_buffer (j_compress_ptr jd); +METHODDEF(void) init_destination (j_compress_ptr jd); +METHODDEF(void) term_destination (j_compress_ptr cinfo); +METHODDEF(void) my_error_exit (j_common_ptr cinfo); + +// helper declarations for converting a bitmap to 4 byte RGB data + +nsresult ConvertColorBitMap(unsigned char * aBitmapBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutputBuffer);nsJPEGEncoder * getEncoderForCompressionInfoStruct(jpeg_compress_struct * cInfo); + +struct bitFields { + PRUint32 red; + PRUint32 green; + PRUint32 blue; + PRUint8 redLeftShift; + PRUint8 redRightShift; + PRUint8 greenLeftShift; + PRUint8 greenRightShift; + PRUint8 blueLeftShift; + PRUint8 blueRightShift; +}; + +void CalcBitShift(bitFields * aColorMask); + +/* + * Implementation of a JPEG destination manager object + */ +typedef struct { + /* public fields; must be first in this struct! */ + struct jpeg_destination_mgr pub; + + nsJPEGEncoder *encoder; // weak reference + +} encoder_destination_mgr; + +nsJPEGEncoder::nsJPEGEncoder() +{ + mBuffer = nsnull; + mBufferLen = mBufferSize = 0; + memset(&mInfo, 0, sizeof(jpeg_compress_struct)); +} + +nsJPEGEncoder::~nsJPEGEncoder() +{ +} + +nsresult nsJPEGEncoder::initCompressionInfo() +{ + /* We set up the normal JPEG error routines, then override error_exit. */ + mInfo.err = jpeg_std_error(&mErr.pub); + mErr.pub.error_exit = my_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(mErr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + return NS_ERROR_FAILURE; + } + + jpeg_create_compress(&mInfo); + + encoder_destination_mgr * destinationManager; + + // first, setup the destination manager + if (mInfo.dest == NULL) + { + destinationManager = PR_NEWZAP(encoder_destination_mgr); + if (!destinationManager) + return NS_ERROR_OUT_OF_MEMORY; + + mInfo.dest = NS_REINTERPRET_CAST(struct jpeg_destination_mgr *, destinationManager); + } + + /* Setup callback functions. */ + destinationManager->pub.init_destination = init_destination ; + destinationManager->pub.empty_output_buffer = empty_output_buffer; + destinationManager->pub.term_destination = term_destination; + + destinationManager->encoder = this; // note the lack of a reference here. We own the lifetime of the destinationManager object + + return NS_OK; +} + +nsJPEGEncoder * getEncoderForCompressionInfoStruct(jpeg_compress_struct * cInfo) +{ + if (cInfo && cInfo->dest) + { + encoder_destination_mgr *destinationManager = NS_REINTERPRET_CAST(encoder_destination_mgr *, cInfo->dest); + return destinationManager->encoder; + } + + return NULL; +} + + +/** imgIEncoder methods **/ + +NS_IMETHODIMP nsJPEGEncoder::EncodeClipboardImage(nsIClipboardImage * aClipboardImage, nsIFile ** aImageFile) +{ + // this is windows only.... + STGMEDIUM stm; + nsresult rv = aClipboardImage->GetNativeImage( (void *) &stm); + NS_ENSURE_SUCCESS(rv, rv); + + // test...try writing the bitmap to a file + nsCOMPtr fileToUse; + NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(fileToUse)); + + fileToUse->Append(NS_LITERAL_STRING("moz-screenshot.jpg")); + nsCOMPtr path = do_QueryInterface(fileToUse); + path->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); + + rv = NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), path); + NS_ENSURE_SUCCESS(rv, rv); + + // It is critical that we do not return early in this routine from here on out. + // We must release our lock and release stm before exiting + HGLOBAL hGlobal = stm.hGlobal; + BYTE * pGlobal = (BYTE *)::GlobalLock (hGlobal); + BITMAPINFO * bitMapInfo = (BITMAPINFO *) pGlobal; + + rv = initCompressionInfo(); + if (NS_SUCCEEDED(rv)) + { + mInfo.in_color_space = JCS_RGB; + mInfo.input_components = 3; + mInfo.data_precision = 8; + mInfo.image_width = (JDIMENSION) bitMapInfo->bmiHeader.biWidth; + mInfo.image_height = (JDIMENSION) bitMapInfo->bmiHeader.biHeight; + + unsigned char * rgbData = (unsigned char *) malloc (bitMapInfo->bmiHeader.biWidth * bitMapInfo->bmiHeader.biHeight * 3 /* RGB */); + + if (rgbData) + { + rv = ConvertColorBitMap((unsigned char *) (pGlobal + bitMapInfo->bmiHeader.biSize), bitMapInfo, rgbData); + if (NS_SUCCEEDED(rv)) + { + jpeg_set_defaults(&mInfo); + + if ( bitMapInfo->bmiHeader.biXPelsPerMeter > 0 && bitMapInfo->bmiHeader.biYPelsPerMeter > 0) + { + /* Set JFIF density parameters from the BMP data */ + mInfo.X_density = (UINT16) ( bitMapInfo->bmiHeader.biXPelsPerMeter/100); /* 100 cm per meter */ + mInfo.Y_density = (UINT16) ( bitMapInfo->bmiHeader.biYPelsPerMeter/100); + mInfo.density_unit = 2; /* dots/cm */ + } + + jpeg_start_compress(&mInfo, TRUE); + + PRInt32 row_stride = bitMapInfo->bmiHeader.biWidth * 3; + JSAMPROW row_pointer[1]; + + while (mInfo.next_scanline < mInfo.image_height) + { + row_pointer[0] = &rgbData[mInfo.next_scanline * row_stride]; + jpeg_write_scanlines(&mInfo, row_pointer, 1); + } + + jpeg_finish_compress(&mInfo); + } + + free(rgbData); + } // if rgbdata + + jpeg_destroy_compress(&mInfo); + } + + // close the output file stream. we are done with it + mOutputStream->Close(); + + // return the file URL to the JPG + NS_IF_ADDREF(*aImageFile = fileToUse); + + ::GlobalUnlock (hGlobal); // release our lock on the bitmap + + aClipboardImage->ReleaseNativeImage( (void *) &stm); + + return NS_OK; +} + +void InvertRows(unsigned char * aInitialBuffer, PRUint32 sizeOfBuffer, PRUint32 numBytesPerRow) +{ + if (!numBytesPerRow) + return; + + PRUint32 numRows = sizeOfBuffer / numBytesPerRow; + void * temporaryRowHolder = (void *) nsMemory::Alloc(numBytesPerRow); + + PRUint32 currentRow = 0; + PRUint32 lastRow = (numRows - 1) * numBytesPerRow; + while (currentRow < lastRow) + { + // store the current row into a temporary buffer + memcpy(temporaryRowHolder, (void *) &aInitialBuffer[currentRow], numBytesPerRow); + memcpy((void *) &aInitialBuffer[currentRow], (void *)&aInitialBuffer[lastRow], numBytesPerRow); + memcpy((void *) &aInitialBuffer[lastRow], temporaryRowHolder, numBytesPerRow); + lastRow -= numBytesPerRow; + currentRow += numBytesPerRow; + } + + nsMemory::Free(temporaryRowHolder); +} + +nsresult ConvertColorBitMap(unsigned char * buffer, PBITMAPINFO pBitMapInfo, unsigned char * outBuffer) +{ + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap")); + + PRUint8 bitCount = pBitMapInfo->bmiHeader.biBitCount; + PRUint32 imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand + PRUint32 bytesPerPixel = bitCount / 8; + + if (bitCount <= 4) + bytesPerPixel = 1; + + // rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't + // correspond to biWidth. + PRUint32 rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up + if (rowSize % 4) + rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary + + // if our buffer includes a color map, skip over it + if (bitCount <= 8) + { + PRInt32 bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD); + buffer += bytesToSkip; + } + + bitFields colorMasks; // only used if biCompression == BI_BITFIELDS + + if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS) + { + // color table consists of 3 DWORDS containing the color masks... + colorMasks.red = (*((PRUint32*)&(pBitMapInfo->bmiColors[0]))); + colorMasks.green = (*((PRUint32*)&(pBitMapInfo->bmiColors[1]))); + colorMasks.blue = (*((PRUint32*)&(pBitMapInfo->bmiColors[2]))); + CalcBitShift(&colorMasks); + buffer += 3 * sizeof(DWORD); + } + else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize) // BI_RGB can have a size of zero which means we figure it out + { + // XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row + imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight; + } + + // dump out some log information about the bit map info struct + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biBitCount: %u", bitCount)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap rowSize: %u", rowSize)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biCompression: %u", pBitMapInfo->bmiHeader.biCompression)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biWidth: %u", pBitMapInfo->bmiHeader.biWidth)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biHeight: %u", pBitMapInfo->bmiHeader.biHeight)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biClrUsed: %u", pBitMapInfo->bmiHeader.biClrUsed)); + + InvertRows(buffer, imageSize, rowSize); + + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap bytesPerPixel: %u", bytesPerPixel)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap calculated imageSize: %u", imageSize)); + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("nsJPEGEncoder::ConvertColorBitMap biSizeImage: %u", pBitMapInfo->bmiHeader.biSizeImage)); + + if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS) + { + PRUint32 index = 0; + PRUint32 writeIndex = 0; + + unsigned char redValue, greenValue, blueValue; + PRUint8 colorTableEntry = 0; + PRInt8 bit; // used for grayscale bitmaps where each bit is a pixel + PRUint32 numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row + PRUint32 pos = 0; + + while (index < imageSize) + { + switch (bitCount) + { + case 1: + for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--) + { + colorTableEntry = (buffer[index] >> bit) & 1; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue; + numPixelsLeftInRow--; + } + pos += 1; + break; + case 4: + { + // each buffer[index] entry contains data for two pixels. + // read the first pixel + colorTableEntry = buffer[index] >> 4; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue; + numPixelsLeftInRow--; + + if (numPixelsLeftInRow) // now read the second pixel + { + colorTableEntry = buffer[index] & 0xF; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue; + numPixelsLeftInRow--; + } + pos += 1; + } + break; + case 8: + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[buffer[index]].rgbRed; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[buffer[index]].rgbGreen; + outBuffer[writeIndex++] = pBitMapInfo->bmiColors[buffer[index]].rgbBlue; + numPixelsLeftInRow--; + pos += 1; + break; + case 16: + { + PRUint16 num = 0; + num = (PRUint8) buffer[index+1]; + num <<= 8; + num |= (PRUint8) buffer[index]; + + redValue = ((PRUint32) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16; + greenValue = ((PRUint32)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8; + blueValue = ((PRUint32)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF); + + // now we have the right RGB values... + outBuffer[writeIndex++] = redValue; + outBuffer[writeIndex++] = greenValue; + outBuffer[writeIndex++] = blueValue; + numPixelsLeftInRow--; + pos += 2; + } + break; + case 32: + case 24: + if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS) + { + PRUint32 val = *((PRUint32*) (buffer + index) ); + outBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift; + outBuffer[writeIndex++] = (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift; + outBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift; + numPixelsLeftInRow--; + pos += 4; // we read in 4 bytes of data in order to process this pixel + } + else + { + outBuffer[writeIndex++] = buffer[index+2]; + outBuffer[writeIndex++] = buffer[index+1]; + outBuffer[writeIndex++] = buffer[index]; + numPixelsLeftInRow--; + pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)... + } + break; + default: + // This is probably the wrong place to check this... + return NS_ERROR_FAILURE; + } + + index += bytesPerPixel; // increment our loop counter + + if (!numPixelsLeftInRow) + { + if (rowSize != pos) + { + // advance index to skip over remaining padding bytes + index += (rowSize - pos); + } + numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; + pos = 0; + } + + } // while we still have bytes to process + } + + PR_LOG(gJPEGEncoderLog, PR_LOG_ALWAYS, ("exiting nsJPEGEncoder::ConvertColorBitMap")); + + return NS_OK; +} + +static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength) +{ + // find the rightmost 1 + PRUint8 pos; + PRBool started = PR_FALSE; + aBegin = aLength = 0; + for (pos = 0; pos <= 31; pos++) + { + if (!started && (aMask & (1 << pos))) + { + aBegin = pos; + started = PR_TRUE; + } + else if (started && !(aMask & (1 << pos))) + { + aLength = pos - aBegin; + break; + } + } +} + +void CalcBitShift(bitFields * aColorMask) +{ + PRUint8 begin, length; + // red + calcBitmask(aColorMask->red, begin, length); + aColorMask->redRightShift = begin; + aColorMask->redLeftShift = 8 - length; + // green + calcBitmask(aColorMask->green, begin, length); + aColorMask->greenRightShift = begin; + aColorMask->greenLeftShift = 8 - length; + // blue + calcBitmask(aColorMask->blue, begin, length); + aColorMask->blueRightShift = begin; + aColorMask->blueLeftShift = 8 - length; +} + +/******************************************************************************/ +/* data destination manager method + Initialize the destination buffer the JPEG library should write compressed bits into +*/ +METHODDEF(void) +init_destination (j_compress_ptr jd) +{ + nsJPEGEncoder * encoder = getEncoderForCompressionInfoStruct(jd); + if (!encoder) + return; + + if (!encoder->mBuffer) + { + encoder->mBuffer = (JOCTET *)PR_Malloc(OUTPUT_BUF_SIZE); + encoder->mBufferSize = OUTPUT_BUF_SIZE; + } + + jd->dest->next_output_byte = encoder->mBuffer; + jd->dest->free_in_buffer = OUTPUT_BUF_SIZE; + +} + +// called by the JPEG library when our working output buffer is full. We need to take the bits and write +// them to our destination stream. return true if buffer was dumped successfully otherwise return +METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo) +{ + nsJPEGEncoder * encoder = getEncoderForCompressionInfoStruct(cinfo); + if (!encoder) + return PR_TRUE; + + PRUint32 written; + encoder->mOutputStream->Write((const char*) encoder->mBuffer, encoder->mBufferSize, &written); + + // XXX: what do we do if we did write the # of bytes we thought we should write? + + // now reset the jpeg pointers to the start of the buffer + cinfo->dest->next_output_byte = encoder->mBuffer; + cinfo->dest->free_in_buffer = OUTPUT_BUF_SIZE; + + return PR_TRUE; +} + + +/* Terminate destination --- called by jpeg_finish_compress()() after all + * data has been written to clean up JPEG destination manager. NOT called by + * jpeg_abort() or jpeg_destroy(). +*/ +METHODDEF(void) term_destination (j_compress_ptr cinfo) +{ + nsJPEGEncoder * encoder = getEncoderForCompressionInfoStruct(cinfo); + if (!encoder) + return; + + // flush whatever is left in the buffer + PRUint32 written; + encoder->mOutputStream->Write((const char*) encoder->mBuffer, encoder->mBufferSize - cinfo->dest->free_in_buffer , &written); + + // if we were an asynch process making calls back to an observer, we would + // make the notification saying we were all done in this method. Since we are blocking, + // do nothing. +} + +/* Override the standard error method in the IJG JPEG decoder code. + */ +METHODDEF(void) my_error_exit (j_common_ptr cinfo) +{ + nsresult error_code; + encoder_error_mgr *err = (encoder_error_mgr *) cinfo->err; + + /* Convert error to a browser error code */ + switch (cinfo->err->msg_code) { + case JERR_OUT_OF_MEMORY: + error_code = NS_ERROR_OUT_OF_MEMORY; + default: + error_code = NS_ERROR_FAILURE; + } + +#ifdef DEBUG + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + fprintf(stderr, "JPEG decoding error:\n%s\n", buffer); +#endif + + /* Return control to the setjmp point. */ + longjmp(err->setjmp_buffer, error_code); +} diff --git a/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h b/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h new file mode 100755 index 00000000000..866f52a1df6 --- /dev/null +++ b/mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h @@ -0,0 +1,91 @@ +/* -*- 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 the JPEG image encoder. + * + * The Initial Developer of the Original Code is + * Scott MacGregor . + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsJPEGEncoder_h_ +#define nsJPEGEncoder_h_ + +#include "imgIEncoder.h" +#include "nsIOutputStream.h" + +#include // stgmedium + +#include "nsCOMPtr.h" + +extern "C" { +#include "jpeglib.h" +} + +#include + +#define NS_JPEGENCODER_CID \ +{ /* 13784154-1C73-4635-B75F-F1F21755E1C1 */ \ + 0x13784154, \ + 0x1c73, \ + 0x4635, \ + {0xb7, 0x5f, 0xf1, 0xf2, 0x17, 0x55, 0xe1, 0xc1} \ +} + +// helper structs for interacting with the jpeg library +typedef struct { + struct jpeg_error_mgr pub; /* "public" fields for IJG library*/ + jmp_buf setjmp_buffer; /* For handling catastropic errors */ +} encoder_error_mgr; + + +class nsJPEGEncoder : public imgIEncoder +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IMGIENCODER + + nsJPEGEncoder(); + virtual ~nsJPEGEncoder(); + +public: + encoder_error_mgr mErr; + struct jpeg_compress_struct mInfo; + + JOCTET *mBuffer; // temporary buffer the jpeg library writes the compressed data to before we write it out to disk + PRUint32 mBufferLen; // amount of data currently in mBuffer + PRUint32 mBufferSize; // size in bytes what mBuffer was created with + nsCOMPtr mOutputStream; + +protected: + nsresult initCompressionInfo(); +}; + +#endif // nsJPEGEncoder_h_ diff --git a/mozilla/modules/libpr0n/public/Makefile.in b/mozilla/modules/libpr0n/public/Makefile.in index 9af5774fa1a..ab8f11cd87e 100644 --- a/mozilla/modules/libpr0n/public/Makefile.in +++ b/mozilla/modules/libpr0n/public/Makefile.in @@ -56,6 +56,7 @@ XPIDLSRCS = \ imgILoad.idl \ imgILoader.idl \ imgIRequest.idl \ + imgIEncoder.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/modules/libpr0n/public/imgIEncoder.idl b/mozilla/modules/libpr0n/public/imgIEncoder.idl new file mode 100755 index 00000000000..b073885918e --- /dev/null +++ b/mozilla/modules/libpr0n/public/imgIEncoder.idl @@ -0,0 +1,58 @@ +/* -*- 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 image encoder interface. + * + * The Initial Developer of the Original Code is Scott MacGregor . + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 "nsISupports.idl" + +interface nsIClipboardImage; +interface nsIFile; + +/** + * imgIEncoder interface + * Currently this is a very specific encoder designed to encode a native clipboard image as a JPEG out to disk. + * It is not intended to be a generic image encoder. + * + */ + +[scriptable, uuid(CCC5B3AD-3E67-4e3d-97E1-B06B2E96FEF8)] +interface imgIEncoder : nsISupports +{ + /** + Encode a native clipboard image + **/ + + void encodeClipboardImage(in nsIClipboardImage aClipboardImage, out nsIFile aImageFile); + +}; diff --git a/mozilla/widget/public/nsIClipboard.idl b/mozilla/widget/public/nsIClipboard.idl index e505703c9e4..407ae780240 100644 --- a/mozilla/widget/public/nsIClipboard.idl +++ b/mozilla/widget/public/nsIClipboard.idl @@ -105,6 +105,22 @@ interface nsIClipboard : nsISupports boolean supportsSelectionClipboard ( ) ; }; +// Interface to a native image format such as the format stored on the clipboard +[scriptable, uuid(DB21EB6C-AEBB-4d16-94EC-BCD8BBF513AE)] +interface nsIClipboardImage : nsISupports +{ + // the idl compiler complains if these two methods are scriptable. need to figure out why + [noscript] void setNativeImage(in voidPtr aNativeImageData); + + // caller must later call releaseNativeImage to release their reference to the image. nsIClipboardImage + // will keep its own reference until it is destroyed. + [noscript] void getNativeImage(in voidPtr aNativeImageData); + + // releaseNativeImage should only be called if you used getNativeImageData. You should pass in the same + // object to both methods. (this routine exists so callers do not have to link in urlmon.lib just to release + // the stgmedium object on windows). + [noscript] void releaseNativeImage(in voidPtr aNativeImageData); +}; %{ C++ diff --git a/mozilla/widget/public/nsWidgetsCID.h b/mozilla/widget/public/nsWidgetsCID.h index 59821be5dd3..353d3e061b3 100644 --- a/mozilla/widget/public/nsWidgetsCID.h +++ b/mozilla/widget/public/nsWidgetsCID.h @@ -154,6 +154,10 @@ #define NS_CLIPBOARD_CID \ { 0x8b5314ba, 0xdb01, 0x11d2, { 0x96, 0xce, 0x0, 0x60, 0xb0, 0xfb, 0x99, 0x56 } } +// {B655157E-D264-4d24-B9C9-1E213276AB5A} +#define NS_CLIPBOARDIMAGE_CID \ +{ 0xb655157e, 0xd264, 0x4d24, { 0xb9, 0xc9, 0x1e, 0x21, 0x32, 0x76, 0xab, 0x5a } } + // {77221D5A-1DD2-11B2-8C69-C710F15D2ED5} #define NS_CLIPBOARDHELPER_CID \ { 0x77221d5a, 0x1dd2, 0x11b2, { 0x8c, 0x69, 0xc7, 0x10, 0xf1, 0x5d, 0x2e, 0xd5 } } diff --git a/mozilla/widget/src/build/Makefile.in b/mozilla/widget/src/build/Makefile.in index 8c62be6a1a4..8c38bc44f26 100644 --- a/mozilla/widget/src/build/Makefile.in +++ b/mozilla/widget/src/build/Makefile.in @@ -78,6 +78,10 @@ ifneq ($(OS_ARCH), WINCE) OS_LIBS += $(call EXPAND_LIBNAME, comctl32 comdlg32 shell32 gdi32 imm32 ) endif +ifndef GNU_CC +OS_LIBS += $(call EXPAND_LIBNAME, urlmon) +endif + SHARED_LIBRARY_LIBS = \ $(DIST)/lib/$(LIB_PREFIX)widget_windows.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)xpwidgets_s.$(LIB_SUFFIX) \ diff --git a/mozilla/widget/src/build/nsWinWidgetFactory.cpp b/mozilla/widget/src/build/nsWinWidgetFactory.cpp index e99f0106554..26d7d2fa90a 100644 --- a/mozilla/widget/src/build/nsWinWidgetFactory.cpp +++ b/mozilla/widget/src/build/nsWinWidgetFactory.cpp @@ -70,6 +70,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper) #ifndef WINCE NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardImage) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard) #endif @@ -109,6 +110,10 @@ static const nsModuleComponentInfo components[] = // "@mozilla.org/widget/sound/win;1" "@mozilla.org/sound;1", nsSoundConstructor }, + { "nsClipboardImage", + NS_CLIPBOARDIMAGE_CID, + "@mozilla.org/widget/clipboardimage;1", + nsClipboardImageConstructor }, { "Drag Service", NS_DRAGSERVICE_CID, // "@mozilla.org/widget/dragservice/win;1", diff --git a/mozilla/widget/src/windows/nsClipboard.cpp b/mozilla/widget/src/windows/nsClipboard.cpp index 998649ef437..2a6e7bc77f2 100644 --- a/mozilla/widget/src/windows/nsClipboard.cpp +++ b/mozilla/widget/src/windows/nsClipboard.cpp @@ -60,8 +60,9 @@ #include "nsPrimitiveHelpers.h" #include "nsImageClipboard.h" #include "nsIWidget.h" -#include "nsIComponentManager.h" +#include "nsComponentManagerUtils.h" #include "nsWidgetsCID.h" +#include "nsGfxCIID.h" #include "nsCRT.h" #include "nsNetUtil.h" @@ -112,7 +113,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr) else if (strcmp(aMimeStr, kUnicodeMime) == 0) format = CF_UNICODETEXT; #ifndef WINCE - else if (strcmp(aMimeStr, kJPEGImageMime) == 0) + else if (strcmp(aMimeStr, kJPEGImageMime) == 0 || + strcmp(aMimeStr, kNativeImageMime) == 0) format = CF_DIB; else if (strcmp(aMimeStr, kFileMime) == 0 || strcmp(aMimeStr, kFilePromiseMime) == 0) @@ -478,20 +480,16 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT #ifndef WINCE case CF_DIB : { - HGLOBAL hGlobal = stm.hGlobal; - BYTE * pGlobal = (BYTE *) GlobalLock (hGlobal) ; - BITMAPV4HEADER * header = (BITMAPV4HEADER *)pGlobal; + nsIClipboardImage * nativeImageWrapper = nsnull; // don't use a nsCOMPtr here + result = CallCreateInstance("@mozilla.org/widget/clipboardimage;1", &nativeImageWrapper); - nsImageFromClipboard converter ( header ); - nsIImage* image; - converter.GetImage ( &image ); // addrefs for us, don't release - if ( image ) { - *aData = image; - *aLen = sizeof(nsIImage*); + if (nativeImageWrapper) + { + nativeImageWrapper->SetNativeImage((void *) &stm); + *aData = nativeImageWrapper; // note that we never release our ref to nativeImageWrapper. We pass it on to the owner of *aData + *aLen = sizeof(nsIClipboardImage *); result = NS_OK; } - - GlobalUnlock (hGlobal) ; } break; case CF_HDROP : @@ -651,6 +649,11 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, else continue; // something wrong with this flavor, keep looking for other data } + else if ( strcmp(flavorStr, kJPEGImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0) { + // we have image data. We don't want to attempt any conversions here + nsIClipboardImage * image = NS_REINTERPRET_CAST(nsIClipboardImage*, data); + genericDataWrapper = do_QueryInterface(image); + } else { // we probably have some form of text. The DOM only wants LF, so convert from Win32 line // endings to DOM line endings. @@ -664,6 +667,8 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, NS_ASSERTION ( genericDataWrapper, "About to put null data into the transferable" ); aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLen); + // don't free data if it is an image object + if (strcmp(flavorStr, kJPEGImageMime) && strcmp(flavorStr, kNativeImageMime)) nsMemory::Free ( NS_REINTERPRET_CAST(char*, data) ); res = NS_OK; @@ -909,3 +914,75 @@ NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(nsISupportsArray *aFlavorList, return NS_OK; } + + +nsClipboardImage::nsClipboardImage() +{ + memset(&mStgMedium, 0, sizeof(STGMEDIUM)); +} + +nsClipboardImage :: ~nsClipboardImage() +{ + if(mStgMedium.hGlobal) + ReleaseStgMedium(&mStgMedium); +} + +NS_IMPL_ISUPPORTS1(nsClipboardImage, nsIClipboardImage) + +static HGLOBAL CopyGlobalMemory(HGLOBAL hSource) +{ + if (hSource == NULL) + return NULL; + + DWORD nSize = (DWORD)::GlobalSize(hSource); + HGLOBAL hDest = ::GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, nSize); + if (hDest == NULL) + return NULL; + + // copy the bits + LPVOID lpSource = ::GlobalLock(hSource); + LPVOID lpDest = ::GlobalLock(hDest); + memcpy(lpDest, lpSource, nSize); + ::GlobalUnlock(hDest); + ::GlobalUnlock(hSource); + + return hDest; +} + +NS_IMETHODIMP nsClipboardImage::SetNativeImage(void * aNativeImageData) +{ + STGMEDIUM * stg = (STGMEDIUM *)aNativeImageData; + + HGLOBAL hDest = CopyGlobalMemory(stg->hGlobal); + if (!hDest) + return NS_ERROR_OUT_OF_MEMORY; + + if(mStgMedium.hGlobal) + ReleaseStgMedium(&mStgMedium); + + mStgMedium = *stg; + mStgMedium.hGlobal = hDest; + return NS_OK; +} + +NS_IMETHODIMP nsClipboardImage::GetNativeImage(void * aNativeImageData) +{ + // the caller should be passing in a STGMEDIUM object which we can copy into + HGLOBAL hDest = CopyGlobalMemory(mStgMedium.hGlobal); + if (!hDest) + return NS_ERROR_OUT_OF_MEMORY; + + STGMEDIUM * stg = (STGMEDIUM *)aNativeImageData; + + *stg = mStgMedium; + stg->hGlobal = hDest; + return NS_OK; +} + +NS_IMETHODIMP nsClipboardImage::ReleaseNativeImage(void * aNativeImageData) +{ + STGMEDIUM * stg = (STGMEDIUM *) aNativeImageData; + if (stg) + ReleaseStgMedium(stg); + return NS_OK; +} diff --git a/mozilla/widget/src/windows/nsClipboard.h b/mozilla/widget/src/windows/nsClipboard.h index 9b20046ffe4..3a26b8e7ffe 100644 --- a/mozilla/widget/src/windows/nsClipboard.h +++ b/mozilla/widget/src/windows/nsClipboard.h @@ -42,6 +42,7 @@ #include "nsIObserver.h" #include "nsIURI.h" #include +#include class nsITransferable; class nsIClipboardOwner; @@ -100,6 +101,19 @@ protected: }; +class nsClipboardImage : public nsIClipboardImage { +public: + nsClipboardImage(); + ~nsClipboardImage(); + + NS_DECL_ISUPPORTS + + NS_DECL_NSICLIPBOARDIMAGE + +protected: + STGMEDIUM mStgMedium; +}; + #define SET_FORMATETC(fe, cf, td, asp, li, med) \ {\ (fe).cfFormat=cf;\