netscape-revival
sun-java/awt/windows/awt_image.cpp
/*
* @(#)awt_image.cpp 1.39 96/01/05 Patrick P. Chan
*
* Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
/*
NOTE: ALL THE DITHERING CODE WAS QUICKLY SLAPPED TOGETHER. IT NEEDS
A LOT OF CLEAN-UP WORK AND TESTING.
*/
#include "stdafx.h"
#include "awt.h"
#include "awtapp.h"
#include "awt_image.h"
#include "awt_graphics.h"
#include "math.h"
#include "malloc.h"
#include "awt_imagescale.h"
#ifdef ENABLE_DEBUG_NEW
#define new DEBUG_NEW
#endif
#include "java_awt_image_ImageConsumer.h"
#define HINTS_DITHERFLAGS (java_awt_image_ImageConsumer_TOPDOWNLEFTRIGHT)
#define HINTS_SCANLINEFLAGS (java_awt_image_ImageConsumer_COMPLETESCANLINES)
const int COLOR4 = 0;
const int COLOR8 = 1;
ColorInfo g_colorInfo[2];
/* efficiently map an RGB value to a pixel value */
#define RGBMAP(pColorInfo, r, g, b) \
((pColorInfo)->m_rgbCube[(int)((r) + CMAP_BIAS) >> (int)(8 - CMAP_BITS)]\
[(int)((g) + CMAP_BIAS) >> (int)(8 - CMAP_BITS)]\
[(int)((b) + CMAP_BIAS) >> (int)(8 - CMAP_BITS)])
#define COMPOSE24(I, r, g, b) \
((((b) & 0xff) << ((I)->bOff)) | \
(((g) & 0xff) << ((I)->gOff)) | \
(((r) & 0xff) << ((I)->rOff)))
// Initialize static variables
HPALETTE AwtImage::m_hPal = NULL;
int AwtImage::m_bitspixel = 0;
// This is data structure holds the common colormap that is used to paint
// all images. When an image is painted, the BITMAPINFOHEADER of
// the image is copied into gpBitmapInfo and then gpBitmapInfo is used to
// paint the image. This strategy eliminates an alloc/free when painting
// an image.
BITMAPINFO *gpBitmapInfo = NULL;
BITMAPINFO *gpTransMaskInfo = NULL;
AwtImage::AwtImage()
{
// Add the new object to the list of all AWT objects (debug only)
INITIALIZE_AWT_LIST_LINK("AwtImage");
m_nSrcW = 0;
m_nSrcH = 0;
m_nDstW = 0;
m_nDstH = 0;
m_pBitmapData = NULL;
m_hBitmap = NULL;
m_bHasTransparentPixels = FALSE;
m_hTransparencyMask = NULL;
m_pTransparencyData = NULL;
m_bgcolor = 0;
m_pRecode = NULL;
m_pIsRecoded = NULL;
m_pDitherErrors = NULL;
m_pAlphaErrors = NULL;
m_hIcon = NULL;
m_pSharedDC = NULL;
m_nLastLine = 0;
m_pSeen = NULL;
m_hRgn = NULL;
}
AwtImage::~AwtImage()
{
if (m_hBitmap != NULL) {
VERIFY(::DeleteObject(m_hBitmap));
}
if (m_hTransparencyMask != NULL) {
VERIFY(::DeleteObject(m_hTransparencyMask));
}
if (m_pSharedDC != NULL) {
m_pSharedDC->Detach(NULL);
m_pSharedDC = NULL;
}
if (m_pDitherErrors) {
delete []m_pDitherErrors;
}
if (m_pAlphaErrors) {
delete []m_pAlphaErrors;
}
if (m_pRecode) {
delete []m_pRecode;
}
if (m_pIsRecoded) {
delete []m_pIsRecoded;
}
if (m_pSeen) {
delete []m_pSeen;
}
if (m_hRgn) {
VERIFY(::DeleteObject(m_hRgn));
}
// m_pBitmapData is deleted when m_hBitmap is deleted
// m_pTransparencyData is deleted when m_hTransparencyMask is deleted
// Remove the object from the list of all AWT objects (debug only)
REMOVE_AWT_LIST_LINK;
}
int AwtImage::BufInit(int x1, int y1, int x2, int y2)
{
if (m_pBitmapData == NULL) {
m_nBufScan = (m_nDstW + 3) & (~3);
gpBitmapInfo->bmiHeader.biWidth = m_nBufScan;
gpBitmapInfo->bmiHeader.biHeight = -m_nDstH;
HDC hDC = ::CreateDC("DISPLAY", NULL, NULL, NULL);
m_hBitmap = ::CreateDIBSection(hDC, gpBitmapInfo, DIB_RGB_COLORS,
&m_pBitmapData, NULL, 0);
::DeleteDC(hDC);
}
return (int) m_pBitmapData;
}
MaskBits *AwtImage::GetMaskBuf(BOOL create) {
if (m_pTransparencyData == NULL && create) {
int nPaddedWidth = (m_nDstW + 31) & (~31);
gpTransMaskInfo->bmiHeader.biWidth = nPaddedWidth;
gpTransMaskInfo->bmiHeader.biHeight = -m_nDstH;
HDC hDC = ::CreateDC("DISPLAY", NULL, NULL, NULL);
m_hTransparencyMask = ::CreateDIBSection(hDC, gpTransMaskInfo,
DIB_RGB_COLORS,
&m_pTransparencyData,
NULL, 0);
if (m_pTransparencyData != NULL) {
if ((m_nHints & HINTS_SCANLINEFLAGS) != 0) {
memset(m_pTransparencyData, 0xff, (nPaddedWidth*m_nDstH)>>3);
} else {
memset(m_pTransparencyData, 0x0, (nPaddedWidth*m_nDstH)>>3);
if (m_hRgn != NULL) {
HDC hMemDC = ::CreateCompatibleDC(hDC);
::SelectObject(hMemDC, m_hTransparencyMask);
::SelectClipRgn(hMemDC, m_hRgn);
HBRUSH hBrush = (HBRUSH)::GetStockObject( BLACK_BRUSH );
::FillRect(hMemDC, CRect(0, 0, m_nDstW, m_nDstH), hBrush);
VERIFY(::DeleteDC(hMemDC));
// The HBRUSH is a stock object, so dont delete it
}
}
}
VERIFY(::DeleteDC(hDC));
}
// Getting the mask data invalidates the values of the transparent pixels
m_bgcolor = 0;
return (MaskBits *) m_pTransparencyData;
}
DitherError *AwtImage::GetDitherBuf(int x1, int y1, int x2, int y2)
{
if ((m_nHints & HINTS_DITHERFLAGS) != 0) {
if (m_pDitherErrors == 0) {
int size = sizeof(DitherError) * (m_nDstW + 2);
m_pDitherErrors = new DitherError[m_nDstW + 2];
if (m_pDitherErrors) {
memset(m_pDitherErrors, 0, size);
}
}
}
return m_pDitherErrors;
}
AlphaError *AwtImage::AlphaSetup(int x1, int y1, int x2, int y2, BOOL create)
{
if ((m_nHints & HINTS_DITHERFLAGS) != 0) {
if (create && m_pAlphaErrors == 0) {
int size = sizeof(AlphaError) * (m_nDstW + 2);
m_pAlphaErrors = new AlphaError[m_nDstW + 2];
if (m_pAlphaErrors) {
memset(m_pAlphaErrors, 0, size);
}
}
}
return m_pAlphaErrors;
}
void AwtImage::BufDone(int x1, int y1, int x2, int y2) {
int ytop = y1;
if ((m_nHints & HINTS_SCANLINEFLAGS) != 0) {
int l;
if (m_pSeen == NULL) {
m_pSeen = new char[m_nDstH];
memset(m_pSeen, 0, m_nDstH);
}
char *pB = ((char *) m_pBitmapData) + y1 * m_nBufScan;
char *pM = (char *) m_pTransparencyData;
int tscan;
if (pM != NULL) {
tscan = ((m_nDstW + 31) & (~31)) >> 3;
pM += y1 * tscan;
}
for (l = y1 - 1; l >= 0; l--) {
if (m_pSeen[l]) {
break;
}
memcpy(pB - m_nBufScan, pB, m_nBufScan);
pB -= m_nBufScan;
if (pM != NULL) {
memcpy(pM - tscan, pM, tscan);
pM -= tscan;
}
ytop = l;
}
for (l = y1; l < y2; l++) {
m_pSeen[l] = 1;
}
} else {
HRGN hR = ::CreateRectRgn(x1, y1, x2, y2);
if (m_hRgn == NULL) {
m_hRgn = hR;
} else {
::CombineRgn(m_hRgn, m_hRgn, hR, RGN_OR);
::DeleteObject(hR);
}
}
if (m_nLastLine < y2) {
m_nLastLine = y2;
}
Hjava_awt_Rectangle *newbits = unhand(m_pJavaObject)->newbits;
if (newbits != 0) {
Classjava_awt_Rectangle *pNB = unhand(newbits);
pNB->x = x1;
pNB->y = ytop;
pNB->width = x2 - x1;
pNB->height = y2 - ytop;
}
};
void AwtImage::Init(Hsun_awt_image_ImageRepresentation *pJavaObject)
{
m_pJavaObject = pJavaObject;
m_nDstW = pJavaObject->obj->width;
m_nDstH = pJavaObject->obj->height;
m_nSrcW = pJavaObject->obj->srcW;
m_nSrcH = pJavaObject->obj->srcH;
m_nHints = pJavaObject->obj->hints;
}
BOOL AwtImage::Create(Hsun_awt_image_ImageRepresentation *pJavaObject,
long nW, long nH)
{
long nPaddedWidth = (nW + 3) & ~0x3;
m_pJavaObject = pJavaObject;
m_nDstW = m_nSrcW = nW;
m_nDstH = m_nSrcH = nH;
HDC hDC = ::CreateDC("DISPLAY", NULL, NULL, NULL);
m_hBitmap = ::CreateCompatibleBitmap(hDC, nW, nH);
if (m_hBitmap) {
HDC hMemDC = ::CreateCompatibleDC(hDC);
// The bitmap should be initially all white
::SelectObject(hMemDC, m_hBitmap);
::FillRect(hMemDC, CRect(0, 0, nW, nH),
(HBRUSH)::GetStockObject( WHITE_BRUSH ));
VERIFY(::SetBkMode(hMemDC, TRANSPARENT) != NULL);
::SelectObject(hMemDC, ::GetStockObject(NULL_BRUSH));
::SelectObject(hMemDC, ::GetStockObject(NULL_PEN));
m_pSharedDC = new AwtSharedDC(NULL, hMemDC);
}
::DeleteDC(hDC);
return (m_hBitmap != NULL);
}
BOOL AwtImage::freeRenderData(BOOL force) {
if (m_pDitherErrors) {
delete []m_pDitherErrors;
m_pDitherErrors = NULL;
}
if (m_pAlphaErrors) {
delete []m_pAlphaErrors;
m_pAlphaErrors = NULL;
}
if (m_pRecode) {
delete []m_pRecode;
m_pRecode = NULL;
}
if (m_pIsRecoded) {
delete []m_pIsRecoded;
m_pIsRecoded = NULL;
}
if (m_pSeen) {
delete []m_pSeen;
m_pSeen = NULL;
}
if (m_hRgn) {
VERIFY(::DeleteObject(m_hRgn));
m_hRgn = NULL;
}
BOOL ret = (!force && (m_nHints & HINTS_DITHERFLAGS) == 0);
m_nHints |= HINTS_DITHERFLAGS;
return ret;
}
// <<Not properly cleaning up icons.>>
// <<Also, we're redithering which isn't great>>
HICON AwtImage::ToIcon() {
if (m_hIcon != NULL) {
return m_hIcon;
}
if (m_pBitmapData != NULL) {
int nW = ::GetSystemMetrics(SM_CXICON);
int nH = ::GetSystemMetrics(SM_CYICON);
BYTE *pMask = NULL;
HDC hDC;
ICONINFO iconInfo;
HBITMAP hMask;
// Invert the bitmap data.
hMask = m_hTransparencyMask;
if (!hMask) {
pMask = new BYTE[nW * nH / 8];
memset(pMask, 0, nW * nH / 8);
hMask= ::CreateBitmap(nW, nH, 1, 1, pMask);
}
iconInfo.fIcon = TRUE;
iconInfo.hbmMask = hMask;
VERIFY(hDC = ::CreateDC("DISPLAY", NULL, NULL, NULL));
iconInfo.hbmColor = GetDDB(hDC);
VERIFY(::DeleteDC(hDC));
m_hIcon = ::CreateIconIndirect(&iconInfo);
VERIFY(::DeleteObject(hMask));
// free resources.
if (pMask) {
delete [] pMask;
}
}
if (m_hIcon == NULL) {
m_hIcon = ((CAwtApp *)AfxGetApp())->GetAwtIcon();
}
return m_hIcon;
}
/*
* A note on the rop codes used below:
*
* In BitBlt, Windows uses the low order 8 bits of the high order word
* (bits 16-23) to control how to combine the current brush, the source
* bitmap, and the destination device. Each bit refers to what to set
* the resulting bit to based on a particular combination of 1 or 0 bits
* in the 3 inputs as follows:
*
* B0 - brush bit is 0, B1 - brush bit is 1
* S0 - source bit is 0, S1 - source bit is 1
* D0 - dest bit is 0, D1 - dest bit is 1
*
* bit 16 - B0, S0, D0
* bit 17 - B0, S0, D1
* bit 18 - B0, S1, D0
* bit 19 - B0, S1, D1
* bit 20 - B1, S0, D0
* bit 21 - B1, S0, D1
* bit 22 - B1, S1, D0
* bit 23 - B1, S1, D1
*
* Thus, if bit 16 is 1, then a 1 bit is stored in the destination if
* B0, S0, D0, that is all 3 corresponding bits of the brush, the source
* bitmap, and the original destination pixel are 0.
*/
void AwtImage::Draw(HDC hDC, long nX, long nY,
int xormode, COLORREF xorcolor, HBRUSH xorBrush,
struct Hjava_awt_Color *c)
{
HDC hMemDC;
HBITMAP hOldBmp = NULL;
BOOL bRealizePalette = TRUE;
if (bRealizePalette) {
VERIFY(::SelectPalette(hDC, m_hPal, FALSE));
UINT result = ::RealizePalette(hDC);
}
VERIFY(hMemDC = ::CreateCompatibleDC(hDC));
HBITMAP hBitmap = GetDDB(hDC);
if (m_hTransparencyMask) {
hOldBmp = (HBITMAP)::SelectObject(hMemDC, m_hTransparencyMask);
COLORREF color;
HBRUSH hBrush;
int rop;
if (xormode) {
hBrush = xorBrush;
color = xorcolor;
rop = 0x00e20000;
} else if (c == 0) {
hBrush = NULL;
color = PALETTERGB(0, 0, 0);
rop = 0x00220000;
} else {
hBrush = NULL;
Classjava_awt_Color *pColor = (Classjava_awt_Color *)c->obj;
color = PALETTERGB((pColor->value>>16)&0xff,
(pColor->value>>8)&0xff,
(pColor->value)&0xff);
rop = 0x00e20000;
}
if (color != m_bgcolor) {
HDC hMemDC2;
HBITMAP hOldBitmap2;
HBRUSH hOldBrush;
hOldBmp = (HBITMAP)::SelectObject(hMemDC, m_hTransparencyMask);
if (!xormode && c != 0) {
hBrush = ::CreateSolidBrush(color);
}
VERIFY(hMemDC2 = ::CreateCompatibleDC(hDC));
hOldBitmap2 = (HBITMAP) ::SelectObject(hMemDC2, hBitmap);
if (hBrush != NULL) {
hOldBrush = (HBRUSH) ::SelectObject(hMemDC2, hBrush);
}
VERIFY(::BitBlt(hMemDC2, 0, 0, m_nDstW, m_nLastLine,
hMemDC, 0, 0, rop));
if (hBrush != NULL) {
VERIFY(::SelectObject(hMemDC2, hOldBrush));
}
VERIFY(::SelectObject(hMemDC2, hOldBitmap2));
VERIFY(::DeleteDC(hMemDC2));
if (!xormode && c != 0) {
VERIFY(::DeleteObject(hBrush));
}
m_bgcolor = color;
}
if (xormode || c != 0) {
::SelectObject(hMemDC, hBitmap);
VERIFY(::BitBlt(hDC, nX, nY, m_nDstW, m_nLastLine,
hMemDC, 0, 0,
xormode ? 0x00960000 : SRCCOPY));
} else {
VERIFY(::BitBlt(hDC, nX, nY, m_nDstW, m_nLastLine,
hMemDC, 0, 0, SRCAND));
::SelectObject(hMemDC, hBitmap);
VERIFY(::BitBlt(hDC, nX, nY, m_nDstW, m_nLastLine,
hMemDC, 0, 0, SRCPAINT));
}
} else {
int hasRgn;
HRGN hR;
if (m_hRgn != NULL) {
hR = ::CreateRectRgn(0, 0, 0, 0);
hasRgn = ::GetClipRgn(hDC, hR);
VERIFY(::OffsetClipRgn(hDC, -nX, -nY) != ERROR);
VERIFY(::ExtSelectClipRgn(hDC, m_hRgn, RGN_AND) != ERROR);
VERIFY(::OffsetClipRgn(hDC, nX, nY) != ERROR);
}
hOldBmp = (HBITMAP)::SelectObject(hMemDC, hBitmap);
VERIFY(::BitBlt(hDC, nX, nY, m_nDstW, m_nLastLine,
hMemDC, 0, 0,
xormode ? 0x00960000 : SRCCOPY));
if (m_hRgn != NULL) {
if (hasRgn) {
VERIFY(::SelectClipRgn(hDC, hR) != ERROR);
} else {
VERIFY(::SelectClipRgn(hDC, NULL) != ERROR);
}
}
}
VERIFY(::SelectObject(hMemDC, hOldBmp) != NULL);
VERIFY(::DeleteDC(hMemDC));
}
#define SET_BYTE_PIXELS_SIG "(IIIILjava/awt/image/ColorModel;[BII)V"
#define HINTS_OFFSCREENSEND (java_awt_image_ImageConsumer_TOPDOWNLEFTRIGHT | \
java_awt_image_ImageConsumer_COMPLETESCANLINES | \
java_awt_image_ImageConsumer_SINGLEPASS)
extern "C" {
#define AWT_LOCK() GetApp()->MonitorEnter()
#define AWT_UNLOCK() GetApp()->MonitorExit()
}
void AwtImage::sendPixels(Classsun_awt_image_OffScreenImageSource *osis)
{
struct Hjava_awt_image_ImageConsumer *ich = osis->theConsumer;
struct execenv *ee;
struct Hjava_awt_image_ColorModel *cm;
HObject *pixh;
char *buf;
int i;
HDC hDC;
ee = EE();
if (osis->theConsumer == 0) {
return;
}
cm = getColorModel();
execute_java_dynamic_method(ee, (HObject *) osis->theConsumer,
"setColorModel",
"(Ljava/awt/image/ColorModel;)V",
cm);
if (osis->theConsumer == 0 || exceptionOccurred(ee)) {
return;
}
execute_java_dynamic_method(ee, (HObject *) osis->theConsumer,
"setHints",
"(I)V",
HINTS_OFFSCREENSEND);
if (osis->theConsumer == 0 || exceptionOccurred(ee)) {
return;
}
int nPaddedWidth = (m_nDstW + 3) & (~3);
pixh = (HObject *) ArrayAlloc(T_BYTE, nPaddedWidth);
buf = (char *) unhand(pixh);
VERIFY(hDC = ::CreateDC("DISPLAY", NULL, NULL, NULL));
BITMAPINFO *pBitmapInfo = (BITMAPINFO*) malloc(sizeof(BITMAPINFO)
+ 256*sizeof(RGBQUAD));
pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBitmapInfo->bmiHeader.biWidth = m_nDstW;
pBitmapInfo->bmiHeader.biHeight = m_nDstH;
pBitmapInfo->bmiHeader.biPlanes = 1;
pBitmapInfo->bmiHeader.biBitCount = 0;
pBitmapInfo->bmiHeader.biCompression = BI_RGB;
pBitmapInfo->bmiHeader.biSizeImage = nPaddedWidth * m_nDstH;
pBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
pBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
pBitmapInfo->bmiHeader.biClrUsed = 256;
pBitmapInfo->bmiHeader.biClrImportant = 256;
AWT_LOCK();
VERIFY(::GetDIBits(hDC, m_hBitmap, 0, m_nDstH, NULL,
pBitmapInfo, DIB_RGB_COLORS));
BYTE *pTemp = new BYTE[nPaddedWidth * pBitmapInfo->bmiHeader.biHeight];
pBitmapInfo->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
VERIFY(::GetDIBits(hDC, m_hBitmap, 0, m_nDstH, pTemp,
pBitmapInfo, DIB_RGB_COLORS));
AWT_UNLOCK();
for (i = 0; i < m_nDstH; i++) {
if (osis->theConsumer == 0) {
break;
}
memcpy(buf, &pTemp[i * nPaddedWidth], m_nDstW);
execute_java_dynamic_method(ee, (HObject *) osis->theConsumer,
"setPixels",
SET_BYTE_PIXELS_SIG,
0, i, m_nDstW, 1,
cm, pixh, 0, nPaddedWidth);
if (exceptionOccurred(ee)) {
break;
}
}
delete [] pTemp;
VERIFY(::DeleteDC(hDC));
free(pBitmapInfo);
if (buf == 0) {
/* This can never happen, but we need to make a reference to buf
* at the bottom of this function so the buffer doesn't move
* while we are using it.
*/
SignalError(0, JAVAPKG "NullPointerException", 0);
return;
}
}
// First check to see if (r,g,b) has been allocated in 'pPalEntries'.
// If not, allocate the color. If the 'pPalEntries' is full, return -1.
// If the peFlags field is not-zero, it means it has been allocated.
int AllocateColor(PALETTEENTRY *pPalEntries, int nPaletteSize, int r, int g, int b)
{
int i;
int firstEmpty = -1;
r = min(255, r);
g = min(255, g);
b = min(255, b);
for (i=0; i<nPaletteSize; i++) {
if (firstEmpty < 0 && pPalEntries[i].peFlags == 0) {
firstEmpty = i;
}
if (pPalEntries[i].peFlags != 0
&& pPalEntries[i].peRed == r
&& pPalEntries[i].peGreen == g
&& pPalEntries[i].peBlue == b) {
return i;
}
}
if (firstEmpty < 0) {
return -1;
}
pPalEntries[firstEmpty].peRed = r;
pPalEntries[firstEmpty].peGreen = g;
pPalEntries[firstEmpty].peBlue = b;
pPalEntries[firstEmpty].peFlags = PC_NOCOLLAPSE;
return firstEmpty;
}
#define SetRGBQUAD(p, r, g, b) \
{ \
(p)->rgbRed = r; \
(p)->rgbGreen = g; \
(p)->rgbBlue = b; \
(p)->rgbReserved = 0; \
}
//
// Initialize the Awt palette from a prototype color palette.
//
void AwtImage::InitializePalette(HPALETTE hPal)
{
int i, ri, gi, bi;
ColorInfo *pColorInfo;
pColorInfo = &g_colorInfo[COLOR8];
gpBitmapInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFO)+256*sizeof(RGBQUAD));
gpBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
gpBitmapInfo->bmiHeader.biWidth = 0;
gpBitmapInfo->bmiHeader.biHeight = 0;
gpBitmapInfo->bmiHeader.biPlanes = 1; //nb: NOT equal to planes from GIF
gpBitmapInfo->bmiHeader.biBitCount = 8;
gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
gpBitmapInfo->bmiHeader.biSizeImage = 0;
gpBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
gpBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
gpBitmapInfo->bmiHeader.biClrUsed = 256;
gpBitmapInfo->bmiHeader.biClrImportant = 256;
pColorInfo->m_pPaletteColors = (RGBQUAD*)((LPSTR)gpBitmapInfo + sizeof(BITMAPINFOHEADER));
// Create a BitmapInfo object for transparency masks
gpTransMaskInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFO)+2*sizeof(RGBQUAD));
gpTransMaskInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
gpTransMaskInfo->bmiHeader.biWidth = 0;
gpTransMaskInfo->bmiHeader.biHeight = 0;
gpTransMaskInfo->bmiHeader.biPlanes = 1;
gpTransMaskInfo->bmiHeader.biBitCount = 1;
gpTransMaskInfo->bmiHeader.biCompression = BI_RGB;
gpTransMaskInfo->bmiHeader.biSizeImage = 0;
gpTransMaskInfo->bmiHeader.biXPelsPerMeter = 0;
gpTransMaskInfo->bmiHeader.biYPelsPerMeter = 0;
gpTransMaskInfo->bmiHeader.biClrUsed = 2;
gpTransMaskInfo->bmiHeader.biClrImportant = 2;
SetRGBQUAD(&(gpTransMaskInfo->bmiColors[0]), 255, 255, 255);
SetRGBQUAD(&(gpTransMaskInfo->bmiColors[1]), 0, 0, 0);
// Create and initialize a palette
HDC hDC = ::GetDC( ::GetDesktopWindow() );
int nEntries = max(256, ::GetDeviceCaps(hDC, SIZEPALETTE));
m_bitspixel = ::GetDeviceCaps(hDC, BITSPIXEL);
::DeleteDC(hDC);
int nIndex = 0;
char *buf = new char[sizeof(LOGPALETTE) + nEntries * sizeof(PALETTEENTRY)];
LOGPALETTE *pLogPal = (LOGPALETTE*)buf;
PALETTEENTRY *pPalEntries = (PALETTEENTRY *)(&(pLogPal->palPalEntry[0]));
int result = max(256, ::GetPaletteEntries(hPal, 0, nEntries, pPalEntries));
if (result == 256 ) {
// Copy the colors from the prototype palette
for ( i=0; i<nEntries; i++) {
pColorInfo->m_pPaletteColors[i].rgbRed = pPalEntries[i].peRed;
pColorInfo->m_pPaletteColors[i].rgbGreen = pPalEntries[i].peGreen,
pColorInfo->m_pPaletteColors[i].rgbBlue = pPalEntries[i].peBlue;
pColorInfo->m_pPaletteColors[i].rgbReserved = 0;
}
//
// Match colors for the color cube to the closest color in the
// prototype palette
for (bi = 0 ; bi <= CMAP_COLS ; bi += 1) {
int b = bi << (8 - CMAP_BITS);
for (gi = 0 ; gi <= CMAP_COLS ; gi += 1) {
int g = gi << (8 - CMAP_BITS);
for (ri = 0 ; ri <= CMAP_COLS ; ri += 1) {
int r = ri << (8 - CMAP_BITS);
pColorInfo->m_rgbCube[ri][gi][bi] =
AwtImage::ClosestMatchPalette(pColorInfo->m_pPaletteColors, 256, r, g, b);
}
}
}
}
pLogPal->palNumEntries = 256;
pLogPal->palVersion = 0x300;
m_hPal = ::CreatePalette(pLogPal);
delete buf;
}
void AwtImage::InitializePalette(HDC hDC)
{
int i, ri, gi, bi;
ColorInfo *pColorInfo;
pColorInfo = &g_colorInfo[COLOR8];
gpBitmapInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFO)+256*sizeof(RGBQUAD));
gpBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
gpBitmapInfo->bmiHeader.biWidth = 0;
gpBitmapInfo->bmiHeader.biHeight = 0;
gpBitmapInfo->bmiHeader.biPlanes = 1; //nb: NOT equal to planes from GIF
gpBitmapInfo->bmiHeader.biBitCount = 8;
gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
gpBitmapInfo->bmiHeader.biSizeImage = 0;
gpBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
gpBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
gpBitmapInfo->bmiHeader.biClrUsed = 256;
gpBitmapInfo->bmiHeader.biClrImportant = 256;
pColorInfo->m_pPaletteColors = (RGBQUAD*)((LPSTR)gpBitmapInfo + sizeof(BITMAPINFOHEADER));
// Create a BitmapInfo object for transparency masks
gpTransMaskInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFO)+2*sizeof(RGBQUAD));
gpTransMaskInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
gpTransMaskInfo->bmiHeader.biWidth = 0;
gpTransMaskInfo->bmiHeader.biHeight = 0;
gpTransMaskInfo->bmiHeader.biPlanes = 1;
gpTransMaskInfo->bmiHeader.biBitCount = 1;
gpTransMaskInfo->bmiHeader.biCompression = BI_RGB;
gpTransMaskInfo->bmiHeader.biSizeImage = 0;
gpTransMaskInfo->bmiHeader.biXPelsPerMeter = 0;
gpTransMaskInfo->bmiHeader.biYPelsPerMeter = 0;
gpTransMaskInfo->bmiHeader.biClrUsed = 2;
gpTransMaskInfo->bmiHeader.biClrImportant = 2;
SetRGBQUAD(&(gpTransMaskInfo->bmiColors[0]), 255, 255, 255);
SetRGBQUAD(&(gpTransMaskInfo->bmiColors[1]), 0, 0, 0);
m_bitspixel = ::GetDeviceCaps(hDC, BITSPIXEL);
// Create and initialize a palette
int nEntries = max(256, ::GetDeviceCaps(hDC, SIZEPALETTE));
int nIndex = 0;
char *buf = new char[sizeof(LOGPALETTE) + nEntries * sizeof(PALETTEENTRY)];
LOGPALETTE *pLogPal = (LOGPALETTE*)buf;
PALETTEENTRY *pPalEntries = (PALETTEENTRY *)(&(pLogPal->palPalEntry[0]));
int result = max(256, ::GetSystemPaletteEntries(hDC, 0, nEntries, pPalEntries));
if (result == nEntries) {
if (result == 256 ) {
// Temporarily use the peFlags field to indicate whether or not a color has been allocated
for (i=0; i<256; i++) {
pPalEntries[i].peFlags = 0;
}
for (i=0; i<10; i++) {
pPalEntries[i].peFlags = 1;
pPalEntries[255-i].peFlags = 1;
}
// Allocate special colors.
AllocateColor(pPalEntries, 256, 255, 255, 255);
AllocateColor(pPalEntries, 256, 255, 0, 0);
AllocateColor(pPalEntries, 256, 0, 255, 0);
AllocateColor(pPalEntries, 256, 0, 0, 255);
AllocateColor(pPalEntries, 256, 255, 255, 0);
AllocateColor(pPalEntries, 256, 255, 0, 255);
AllocateColor(pPalEntries, 256, 0, 255, 255);
AllocateColor(pPalEntries, 256, 235, 235, 235);
AllocateColor(pPalEntries, 256, 224, 224, 224);
AllocateColor(pPalEntries, 256, 214, 214, 214);
AllocateColor(pPalEntries, 256, 192, 192, 192);
AllocateColor(pPalEntries, 256, 162, 162, 162);
AllocateColor(pPalEntries, 256, 128, 128, 128);
AllocateColor(pPalEntries, 256, 105, 105, 105);
AllocateColor(pPalEntries, 256, 64, 64, 64);
AllocateColor(pPalEntries, 256, 32, 32, 32);
AllocateColor(pPalEntries, 256, 255, 128, 128);
AllocateColor(pPalEntries, 256, 128, 255, 128);
AllocateColor(pPalEntries, 256, 128, 128, 255);
AllocateColor(pPalEntries, 256, 255, 255, 128);
AllocateColor(pPalEntries, 256, 255, 128, 255);
AllocateColor(pPalEntries, 256, 128, 255, 255);
// Allocate some colors.
for (bi = 0 ; bi <= CMAP_COLS ; bi += 2) {
int b = bi << (8 - CMAP_BITS);
for (gi = 0 ; gi <= CMAP_COLS ; gi += 2) {
int g = gi << (8 - CMAP_BITS);
for (ri = 0; ri <= CMAP_COLS ; ri += 1) {
int r = ri << (8 - CMAP_BITS);
if (pColorInfo->m_rgbCube[ri][gi][bi] == 0) {
pColorInfo->m_rgbCube[ri][gi][bi] = AllocateColor(pPalEntries, 256, r, g, b);
}
}
}
}
// Match remainder.
BOOL bFull = FALSE;
for (bi = 0 ; bi <= CMAP_COLS ; bi += 1) {
int b = bi << (8 - CMAP_BITS);
for (gi = 0 ; gi <= CMAP_COLS ; gi += 1) {
int g = gi << (8 - CMAP_BITS);
for (ri = 0 ; ri <= CMAP_COLS ; ri += 1) {
int r = ri << (8 - CMAP_BITS);
if (pColorInfo->m_rgbCube[ri][gi][bi] == 0) {
if (bFull) {
pColorInfo->m_rgbCube[ri][gi][bi] =
AwtImage::ClosestMatchPalette(pColorInfo->m_pPaletteColors, 256, r, g, b);
} else {
int loc = AllocateColor(pPalEntries, 256, r, g, b);
if (loc >= 0) {
pColorInfo->m_rgbCube[ri][gi][bi] = loc;
} else {
// If color couldn't be allocated, match it.
// Initialize m_paletteColors8.
for ( i=0; i<nEntries; i++) {
pColorInfo->m_pPaletteColors[i].rgbRed = pPalEntries[i].peRed;
pColorInfo->m_pPaletteColors[i].rgbGreen = pPalEntries[i].peGreen,
pColorInfo->m_pPaletteColors[i].rgbBlue = pPalEntries[i].peBlue;
pColorInfo->m_pPaletteColors[i].rgbReserved = 0;
}
pColorInfo->m_rgbCube[ri][gi][bi] =
AwtImage::ClosestMatchPalette(pColorInfo->m_pPaletteColors, 256, r, g, b);
bFull = TRUE;
}
}
}
}
}
}
// Now clear flags of system colors.
for (i=0; i<10; i++) {
pPalEntries[i].peFlags = 0;
pPalEntries[255-i].peFlags = 0;
}
}
pLogPal->palNumEntries = 256;
pLogPal->palVersion = 0x300;
m_hPal = ::CreatePalette(pLogPal);
}
delete buf;
// Now allocate the 4-bit color palette.
pColorInfo = &g_colorInfo[COLOR4];
pColorInfo->m_pPaletteColors = (RGBQUAD*)malloc(16*sizeof(RGBQUAD));
/* 9: 166, 202, 240 246: 255 251 240 -- non-VGA colors */
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[0]), 0, 0, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[1]), 128, 0, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[2]), 0, 128, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[3]), 128, 128, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[4]), 0, 0, 128);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[5]), 128, 0, 128);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[6]), 0, 128, 128);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[7]), 192, 192, 192);
//SetRGBQUAD(&(pColorInfo->m_pPaletteColors[*]), 192, 220, 192); // non-VGA colors
//SetRGBQUAD(&(pColorInfo->m_pPaletteColors[*]), 160, 160, 164);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[8]), 128, 128, 128);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[9]), 255, 0, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[10]), 0, 255, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[11]), 255, 255, 0);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[12]), 0, 0, 255);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[13]), 255, 0,255);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[14]), 0, 255, 255);
SetRGBQUAD(&(pColorInfo->m_pPaletteColors[15]), 255, 255, 255);
for (bi = 0 ; bi <= CMAP_COLS ; bi += 1) {
int b = bi << (8 - CMAP_BITS);
for (gi = 0 ; gi <= CMAP_COLS ; gi += 1) {
int g = gi << (8 - CMAP_BITS);
for (ri = 0 ; ri <= CMAP_COLS ; ri += 1) {
int r = ri << (8 - CMAP_BITS);
if (pColorInfo->m_rgbCube[ri][gi][bi] == 0) {
pColorInfo->m_rgbCube[ri][gi][bi] =
AwtImage::ClosestMatchPalette(pColorInfo->m_pPaletteColors, 16, r, g, b);
}
}
}
}
}
void AwtImage::DisposePalette()
{
free(gpBitmapInfo);
free(gpTransMaskInfo);
if (m_hPal != NULL) {
::DeleteObject(m_hPal);
}
free(g_colorInfo[COLOR4].m_pPaletteColors);
}
int AwtImage::ClosestMatchPalette(RGBQUAD *p, int nPaletteSize, int r, int g, int b)
{
int mindist = 256 * 256 * 256, besti = 0;
int i, t, d;
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
for (i = 0 ; i < nPaletteSize ; i++, p++) {
t = p->rgbRed - r;
d = t * t;
if (d >= mindist)
continue;
t = p->rgbGreen- g;
d += t * t;
if (d >= mindist)
continue;
t = p->rgbBlue- b;
d += t * t;
if (d >= mindist)
continue;
if (d == 0) {
return i;
}
if (d < mindist) {
besti = i;
mindist = d;
}
}
return besti;
}
struct Hjava_awt_image_ColorModel *AwtImage::getColorModel()
{
struct Hjava_awt_image_ColorModel *awt_colormodel;
HArrayOfByte *hR = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
HArrayOfByte *hG = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
HArrayOfByte *hB = (HArrayOfByte *) ArrayAlloc(T_BYTE, 256);
char *aBase, *a;
RGBQUAD *c, *cBase;
cBase = g_colorInfo[1].m_pPaletteColors;
/* These loops copy backwards so that the aBase pointer won't
* be dropped by the optimizer and allow the garbage collector
* to move the array being initialized.
*/
aBase = unhand(hR)->body;
for (a = aBase + 255, c = cBase + 255; a >= aBase; a--, c--) {
*a = c->rgbRed;
}
aBase = unhand(hG)->body;
for (a = aBase + 255, c = cBase + 255; a >= aBase; a--, c--) {
*a = c->rgbGreen;
}
aBase = unhand(hB)->body;
for (a = aBase + 255, c = cBase + 255; a >= aBase; a--, c--) {
*a = c->rgbBlue;
}
awt_colormodel = (struct Hjava_awt_image_ColorModel *)
execute_java_constructor(EE(),
"java/awt/image/IndexColorModel",
0, "(II[B[B[B)",
8, 256, hR, hG, hB);
return awt_colormodel;
}