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
This commit is contained 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:
|
||||
|
||||
@@ -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<nsIClipboardImage> clipboardImage (do_QueryInterface(genericDataObj));
|
||||
if (clipboardImage)
|
||||
{
|
||||
// invoke image encoder
|
||||
nsCOMPtr<imgIEncoder> imgEncoder (do_CreateInstance("@mozilla.org/image/encoder;2?type=image/jpeg"));
|
||||
if (imgEncoder)
|
||||
{
|
||||
nsCOMPtr<nsIFile> clipboardImageFile;
|
||||
rv = imgEncoder->EncodeClipboardImage(clipboardImage, getter_AddRefs(clipboardImageFile));
|
||||
|
||||
if (NS_FAILED(rv) || !clipboardImageFile)
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewFileURI(getter_AddRefs(uri), clipboardImageFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURL> fileURL(do_QueryInterface(uri));
|
||||
if (fileURL)
|
||||
{
|
||||
nsCAutoString urltext;
|
||||
rv = fileURL->GetSpec(urltext);
|
||||
if (NS_SUCCEEDED(rv) && !urltext.IsEmpty())
|
||||
{
|
||||
stuffToPaste.AssignLiteral("<IMG src=\"");
|
||||
AppendUTF8toUTF16(urltext, stuffToPaste);
|
||||
stuffToPaste.AppendLiteral("\" alt=\"\" >");
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = InsertHTMLWithContext(stuffToPaste,
|
||||
nsString(), nsString(), NS_LITERAL_STRING(kFileMime),
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIExternalAppLauncher> 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<nsISupportsArray> flavorsList =
|
||||
do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
567
mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp
Executable file
567
mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.cpp
Executable file
@@ -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 <mscott@mozilla.org>.
|
||||
* 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 <stdio.h>
|
||||
#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<nsIFile> fileToUse;
|
||||
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(fileToUse));
|
||||
|
||||
fileToUse->Append(NS_LITERAL_STRING("moz-screenshot.jpg"));
|
||||
nsCOMPtr<nsILocalFile> 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);
|
||||
}
|
||||
91
mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h
Executable file
91
mozilla/modules/libpr0n/decoders/jpeg/nsJPEGEncoder.h
Executable file
@@ -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 <mscott@mozilla.org>.
|
||||
* 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 <ole2.h> // stgmedium
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
extern "C" {
|
||||
#include "jpeglib.h"
|
||||
}
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#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<nsIOutputStream> mOutputStream;
|
||||
|
||||
protected:
|
||||
nsresult initCompressionInfo();
|
||||
};
|
||||
|
||||
#endif // nsJPEGEncoder_h_
|
||||
@@ -56,6 +56,7 @@ XPIDLSRCS = \
|
||||
imgILoad.idl \
|
||||
imgILoader.idl \
|
||||
imgIRequest.idl \
|
||||
imgIEncoder.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
58
mozilla/modules/libpr0n/public/imgIEncoder.idl
Executable file
58
mozilla/modules/libpr0n/public/imgIEncoder.idl
Executable file
@@ -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 <mscott@mozilla.org>.
|
||||
* 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);
|
||||
|
||||
};
|
||||
@@ -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++
|
||||
|
||||
|
||||
@@ -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 } }
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIURI.h"
|
||||
#include <windows.h>
|
||||
#include <ole2.h>
|
||||
|
||||
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;\
|
||||
|
||||
Reference in New Issue
Block a user