gecko-dev/cmd/winfe/cxdc1.cpp
1998-06-05 01:03:18 +00:00

2263 lines
71 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "stdafx.h"
#include "cxdc.h"
#include "cntritem.h"
#include "intlwin.h"
#include "mainfrm.h"
#include "npapi.h"
#include "np.h"
#include "feembed.h"
#include "fmabstra.h"
#include "custom.h"
#include "prefapi.h"
#include "feimage.h"
#include "il_icons.h"
#include "prefinfo.h"
// Make an array of RGB colors that match the current palette.
// This array is used for contexts that don't employ DibPalColors.
// Returns TRUE on success, FALSE otherwise.
static const RGBQUAD rgbqWhite = {0xFF, 0xFF, 0xFF, 0};
static const RGBQUAD rgbqBlack = {0, 0, 0, 0};
//#define USE_IDENTITY_PALETTE
#ifdef XP_WIN32
//#define USE_DIB_SECTION
#endif
#ifdef USE_IDENTITY_PALETTE
# define PALETTEENTRY_FLAGS PC_NOCOLLAPSE
#else
# define PALETTEENTRY_FLAGS 0
#endif
extern "C"{
extern int gifAbort;
}
#define ROP_PSDPxax 0x00B8074AL
// Alters the transparent part of the source image (already selected into
// pSrcDC) with the specified brush
//
// Make sure that the WHOLE image is changed and not just the part that
// needs to be displayed; otherwise things will get out of sync
static BOOL
CopyPaletteToRGBArray(HPALETTE pPal, RGBQUAD *pRGBArray)
{
PALETTEENTRY *paletteEntries;
XP_ASSERT(pRGBArray);
paletteEntries = (PALETTEENTRY *)XP_ALLOC(sizeof(PALETTEENTRY) * 256);
if (!paletteEntries)
return FALSE;
// Copy existing palette
VERIFY(::GetPaletteEntries(pPal, 0, 256, paletteEntries) > 0);
for(int i = 0; i < 256; i++) {
pRGBArray[i].rgbRed = paletteEntries[i].peRed;
pRGBArray[i].rgbGreen = paletteEntries[i].peGreen;
pRGBArray[i].rgbBlue = paletteEntries[i].peBlue;
pRGBArray[i].rgbReserved = NULL;
}
XP_FREE(paletteEntries);
return TRUE;
}
void CDCCX::ImageComplete(NI_Pixmap* image)
{
FEBitmapInfo *imageInfo;
HDC hdc = GetContextDC();
if (!image || !hdc || IsPrintContext()) return;
imageInfo = (FEBitmapInfo*) image->client_data;
if(!imageInfo)
return;
#ifndef USE_DIB_SECTION
if(!imageInfo->hBitmap) {
// Attempt to create a bitmap
if (!imageInfo->IsMask ) {
imageInfo->hBitmap = ::CreateDIBitmap(hdc,
&(imageInfo->bmpInfo->bmiHeader),
CBM_INIT,
image->bits,
imageInfo->bmpInfo,
m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS);
if (imageInfo->hBitmap) {
// Free the image bits since we no longer need them
CDCCX::HugeFree(image->bits);
image->bits = NULL;
}
}
else {
// If there is a mask then create another bitmap
// Build a BITMAPINFO struct for mask
char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))];
LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask;
memcpy(pBmInfoMask, imageInfo->bmpInfo, sizeof(BITMAPINFOHEADER));
pBmInfoMask->bmiHeader.biBitCount = 1;
pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS
// Build a color table for monochrome mask. Image lib sets the foreground
// pixels to 1 and the background pixels to 0. We want the monochrome
// mask to be the same way
pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels
pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels
// Create the mask. It's important that we use the memory DC, because we
// want a momochrome bitmap
imageInfo->hBitmap = ::CreateDIBitmap(m_pImageDC,
(LPBITMAPINFOHEADER)pBmInfoMask,
CBM_INIT,
image->bits,
pBmInfoMask,
DIB_RGB_COLORS);
if (imageInfo->hBitmap) {
// Free the mask bits since we no longer need them
CDCCX::HugeFree(image->bits);
image->bits = NULL;
}
}
}
#else
HBITMAP oldBmp;
oldBmp = imageInfo->hBitmap;
if (!imageInfo->IsMask ) {
imageInfo->hBitmap = ::CreateDIBitmap(hdc,
&(imageInfo->bmpInfo->bmiHeader),
CBM_INIT,
image->bits,
imageInfo->bmpInfo,
m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS);
}
else {
// If there is a mask then create another bitmap
// Build a BITMAPINFO struct for mask
char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))];
LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask;
memcpy(pBmInfoMask, imageInfo->bmpInfo, sizeof(BITMAPINFOHEADER));
pBmInfoMask->bmiHeader.biBitCount = 1;
pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS
// Build a color table for monochrome mask. Image lib sets the foreground
// pixels to 1 and the background pixels to 0. We want the monochrome
// mask to be the same way
pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels
pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels
// Create the mask. It's important that we use the memory DC, because we
// want a momochrome bitmap
imageInfo->hBitmap = ::CreateDIBitmap(m_pImageDC,
(LPBITMAPINFOHEADER)pBmInfoMask,
CBM_INIT,
image->bits,
pBmInfoMask,
DIB_RGB_COLORS);
}
::DeleteObject(oldBmp);
image->bits = NULL;
#endif
ReleaseContextDC(hdc);
}
static WORD
GetBitCount(BITMAP &bmp)
{
WORD nBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
#ifdef XP_WIN32
if (nBits == 1)
nBits = 1;
else if (nBits <= 4)
nBits = 4;
else if (nBits <= 8)
nBits = 8;
else if (nBits <= 16)
nBits = 16;
else if (nBits <= 24)
nBits = 24;
else
nBits = 32;
#else
if (nBits == 1)
nBits = 1;
else if (nBits <= 4)
nBits = 4;
else if (nBits <= 8)
nBits = 8;
else
nBits = 24;
#endif
return nBits;
}
#ifndef XP_WIN32
/* Quaternary raster codes */
#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
#endif
BOOL CDCCX::CanWriteBitmapFile(LO_ImageStruct* pLOImage)
{
ASSERT(pLOImage);
if(!pLOImage) {
return(FALSE);
}
IL_Pixmap *pImage = IL_GetImagePixmap(pLOImage->image_req);
// Internal icons have no platform data.
FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data;
// We can't do anything if we don't have all the image bits
return imageinfo && imageinfo->hBitmap;
}
HANDLE CDCCX::WriteBitmapToMemory( IL_ImageReq *image_req, LO_Color* bg)
{
IL_Pixmap *pImage = IL_GetImagePixmap(image_req);
IL_Pixmap *pMask = IL_GetMaskPixmap(image_req);
// Windows bitmap file format looks like this:
//
// +------------------+
// | BITMAPFILEHEADER |
// |------------------|
// | BITMAPINFOHEADER |
// |------------------|
// | color table |
// |------------------|
// | image bits |
// +------------------+
FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data;
FEBitmapInfo* maskinfo = 0;
if (pMask)
maskinfo = (FEBitmapInfo*) pMask->client_data;
// We can't do anything if we don't have all the image bits
HGLOBAL hDib;
if (imageinfo && imageinfo->hBitmap) {
BITMAP bmp;
LPBITMAPINFOHEADER lpBmi;
WORD nBitCount;
LPBYTE lpBits;
int nColorTable;
// Determine the bits per pixel
if (!::GetObject(imageinfo->hBitmap, sizeof(bmp), &bmp))
return FALSE;
nBitCount = GetBitCount(bmp);
// We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to
// allocate room for 3 double-word color masks
if (nBitCount == 16 || nBitCount == 32)
nColorTable = 3;
else if (nBitCount < 16)
nColorTable = 1 << nBitCount;
else {
ASSERT(nBitCount == 24);
nColorTable = 0;
}
// Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure
// plus space for the color table)
WORD dwSize = sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD);
hDib = GlobalAlloc(GMEM_SHARE, dwSize);
lpBmi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
if (!lpBmi)
return FALSE;
// Initialize the BITMAPINFOHEADER structure
lpBmi->biSize = sizeof(BITMAPINFOHEADER);
lpBmi->biWidth = bmp.bmWidth;
lpBmi->biHeight = bmp.bmHeight;
lpBmi->biPlanes = 1;
lpBmi->biBitCount = nBitCount;
HDC hdc = GetContextDC();
// Note: NT 16-bit video mode won't work unless you use BI_BITFIELDS, and
// Win 95 probably won't work if you use BI_BITFIELDS. Win 3.x doesn't even
// support 16-bit DIBs, so it isn't an issue there
#ifdef XP_WIN32
if (sysInfo.m_bWinNT && (nBitCount == 16 || nBitCount == 32))
lpBmi->biCompression = BI_BITFIELDS;
else
lpBmi->biCompression = BI_RGB;
#else
lpBmi->biCompression = BI_RGB;
#endif
// Ask the driver to tell us the number of bits we need to allocate
::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, NULL, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
if (lpBmi->biSizeImage == 0) {
// The driver didn't tell us so we need to compute it ourselves
lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight;
}
GlobalUnlock(hDib);
hDib = GlobalReAlloc(hDib, lpBmi->biSizeImage + dwSize,0);
// Allocate space for the bits
lpBits = (LPBYTE)GlobalLock(hDib);
if (!lpBits) {
free(lpBmi);
ReleaseContextDC(hdc);
return FALSE;
}
// Windows bitmap files don't allow for a mask. Therefore we have to set the transparent
// parts of the image to be the appropriate color. This ensures that the bitmap file matches
// what the user sees on the screen
//
// ZZZ: This code should be shared with the code in _StretchBlt()
COLORREF bgColor = bg ? RGB(bg->red, bg->green, bg->blue) : m_rgbBackgroundColor;
if (maskinfo && maskinfo->hBitmap) {
HBRUSH hBrush;
HDC tempDC = ::CreateCompatibleDC(hdc);
HBITMAP tempBmp = ::CreateCompatibleBitmap(hdc, lpBmi->biWidth, lpBmi->biHeight);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp);
HBITMAP hOldBmp1 = (HBITMAP)::SelectObject(m_pImageDC, imageinfo->hBitmap);
if (m_iBitsPerPixel == 16)
// We don't want a dithered brush
hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, bgColor));
else
hBrush = ::CreateSolidBrush(0x02000000L | bgColor);
::BitBlt(tempDC, 0, 0,lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, SRCCOPY);
// Select the mask into the memory DC
::SelectObject(m_pImageDC, maskinfo->hBitmap);
// Change the transparent bits of the source bitmap to the desired background
// color by doing an AND raster op
//
// The mask is monochrome and will be converted to color to match the depth of
// the destination. The foreground pixels in the mask are set to 1, and the
// background pixels to 0. When converting to a color bitmap, white pixels (1)
// are set to the background color of the DC, and black pixels (0) are set to
// the text color of the DC
//
// Select the brush
HBRUSH hOldBrush = (HBRUSH)::SelectObject(tempDC, hBrush);
// Draw the brush where the mask is 0
::BitBlt(tempDC,
0,
0,
lpBmi->biWidth,
lpBmi->biHeight,
m_pImageDC,
0,
0,
MAKEROP4(SRCPAINT, R2_COPYPEN));
::SelectObject(tempDC, hOldBrush);
::DeleteObject(hBrush);
::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits + dwSize, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
::SelectObject(m_pImageDC, hOldBmp1);
::SelectObject(tempDC, hOldBmp);
::DeleteObject(tempBmp);
::DeleteDC(tempDC);
}
else
// This time have the driver give us the color table and the bits
::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, lpBits + dwSize, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
ReleaseContextDC(hdc);
GlobalUnlock(hDib);
return (hDib);
}
return (0);
}
BOOL CDCCX::WriteBitmapFile(LPCSTR lpszFileName, LO_ImageStruct* pLOImage)
{
ASSERT(pLOImage);
if(!pLOImage) {
return(FALSE);
}
IL_Pixmap *pImage = IL_GetImagePixmap(pLOImage->image_req);
IL_Pixmap *pMask = IL_GetMaskPixmap(pLOImage->image_req);
// Windows bitmap file format looks like this:
//
// +------------------+
// | BITMAPFILEHEADER |
// |------------------|
// | BITMAPINFOHEADER |
// |------------------|
// | color table |
// |------------------|
// | image bits |
// +------------------+
FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data;
FEBitmapInfo* maskinfo = 0;
if (pMask)
maskinfo = (FEBitmapInfo*) pMask->client_data;
// We can't do anything if we don't have all the image bits
if (imageinfo && imageinfo->hBitmap) {
BITMAP bmp;
LPBITMAPINFOHEADER lpBmi;
WORD nBitCount;
LPBYTE lpBits;
int nColorTable;
// Determine the bits per pixel
if (!::GetObject(imageinfo->hBitmap, sizeof(bmp), &bmp))
return FALSE;
nBitCount = GetBitCount(bmp);
// We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to
// allocate room for 3 double-word color masks
if (nBitCount == 16 || nBitCount == 32)
nColorTable = 3;
else if (nBitCount < 16)
nColorTable = 1 << nBitCount;
else {
ASSERT(nBitCount == 24);
nColorTable = 0;
}
// Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure
// plus space for the color table)
lpBmi = (LPBITMAPINFOHEADER)calloc(sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD), 1);
if (!lpBmi)
return FALSE;
// Initialize the BITMAPINFOHEADER structure
lpBmi->biSize = sizeof(BITMAPINFOHEADER);
lpBmi->biWidth = bmp.bmWidth;
lpBmi->biHeight = bmp.bmHeight;
lpBmi->biPlanes = 1;
lpBmi->biBitCount = nBitCount;
HDC hdc = GetContextDC();
// Note: NT 16-bit video mode won't work unless you use BI_BITFIELDS, and
// Win 95 probably won't work if you use BI_BITFIELDS. Win 3.x doesn't even
// support 16-bit DIBs, so it isn't an issue there
#ifdef XP_WIN32
if (sysInfo.m_bWinNT && (nBitCount == 16 || nBitCount == 32))
lpBmi->biCompression = BI_BITFIELDS;
else
lpBmi->biCompression = BI_RGB;
#else
lpBmi->biCompression = BI_RGB;
#endif
// Ask the driver to tell us the number of bits we need to allocate
::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, NULL, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
if (lpBmi->biSizeImage == 0) {
// The driver didn't tell us so we need to compute it ourselves
lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight;
}
// Allocate space for the bits
lpBits = (LPBYTE)HugeAlloc(lpBmi->biSizeImage, 1);
if (!lpBits) {
free(lpBmi);
ReleaseContextDC(hdc);
return FALSE;
}
// Windows bitmap files don't allow for a mask. Therefore we have to set the transparent
// parts of the image to be the appropriate color. This ensures that the bitmap file matches
// what the user sees on the screen
//
// ZZZ: This code should be shared with the code in _StretchBlt()
LO_Color* bg = (pLOImage->text_attr && !pLOImage->text_attr->no_background) ? &pLOImage->text_attr->bg : NULL;
COLORREF bgColor = bg ? RGB(bg->red, bg->green, bg->blue) : m_rgbBackgroundColor;
if (maskinfo && maskinfo->hBitmap) {
HBRUSH hBrush;
HDC tempDC = ::CreateCompatibleDC(hdc);
HBITMAP tempBmp = ::CreateCompatibleBitmap(hdc, lpBmi->biWidth, lpBmi->biHeight);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp);
HBITMAP hOldBmp1 = (HBITMAP)::SelectObject(m_pImageDC, imageinfo->hBitmap);
if (m_iBitsPerPixel == 16)
// We don't want a dithered brush
hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, bgColor));
else
hBrush = ::CreateSolidBrush(0x02000000L | bgColor);
::BitBlt(tempDC, 0, 0,lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, SRCCOPY);
// Select the mask into the memory DC
::SelectObject(m_pImageDC, maskinfo->hBitmap);
// Change the transparent bits of the source bitmap to the desired background
// color by doing an AND raster op
//
// The mask is monochrome and will be converted to color to match the depth of
// the destination. The foreground pixels in the mask are set to 1, and the
// background pixels to 0. When converting to a color bitmap, white pixels (1)
// are set to the background color of the DC, and black pixels (0) are set to
// the text color of the DC
//
// Select the brush
HBRUSH hOldBrush = (HBRUSH)::SelectObject(tempDC, hBrush);
// Draw the brush where the mask is 0
::BitBlt(tempDC,
0,
0,
lpBmi->biWidth,
lpBmi->biHeight,
m_pImageDC,
0,
0,
MAKEROP4(SRCPAINT, R2_COPYPEN));
::SelectObject(tempDC, hOldBrush);
::DeleteObject(hBrush);
::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
::SelectObject(m_pImageDC, hOldBmp1);
::SelectObject(tempDC, hOldBmp);
::DeleteObject(tempBmp);
::DeleteDC(tempDC);
}
else
// This time have the driver give us the color table and the bits
::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
ReleaseContextDC(hdc);
BITMAPFILEHEADER bf;
// Initialize the BITMAPFILEHEADER struct
bf.bfType = 0x4D42; // 'BM'
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
// Compute the offset to the bits. The bits are after the color table
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD);
// Compute the size of the file
bf.bfSize = bf.bfOffBits + lpBmi->biSizeImage;
// Open the file and start writing
CStdioFile file;
TRY {
#ifndef XP_WIN32
file.Open(lpszFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary);
#else
file.Open(lpszFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary | CFile::shareExclusive);
#endif
// Write the BITMAPFILEHEADER structure
file.Write(&bf, sizeof(bf));
// Write the BITMAPINFOHEADER and color table
file.Write(lpBmi, sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD));
// Write the bits
#ifdef XP_WIN32
file.Write(lpBits, lpBmi->biSizeImage);
#else
file.WriteHuge(lpBits, lpBmi->biSizeImage);
#endif
file.Close();
}
CATCH(CFileException, e) {
CDCCX::HugeFree(lpBits);
free(lpBmi);
return FALSE;
}
END_CATCH
// Free up everything and return success
CDCCX::HugeFree(lpBits);
free(lpBmi);
return TRUE;
}
return FALSE;
}
void CDCCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight) {
// Set up the width, height, and margins as defualt values here.
// These should have been set up in the Initialize() member of a derived
// class.
if (pContext->grid_children) {
XP_ListDestroy (pContext->grid_children);
pContext->grid_children = 0;
}
*pWidth = m_lWidth;
*pHeight = m_lHeight;
// No known margins, up to dervied classes to correctly set.
// Don't set the margins if non-zero, Layout has it's own ideas about this.
// Set ourselves to be at the top of the document.
m_lOrgX = 0;
m_lOrgY = 0;
// Document has no substance.
m_lDocWidth = 0;
m_lDocHeight = 0;
// Flush the background color.
COLORREF rgbColor = prefInfo.m_rgbBackgroundColor;
FE_SetBackgroundColor(pContext, GetRValue(rgbColor), GetGValue(rgbColor), GetBValue(rgbColor));
// We're loading a new page, so flush the previous page's
// fonts so that we don't keep building a huge font cache.
ClearFontCache();
}
#define LIGHT_GRAY RGB(192, 192, 192)
#define DARK_GRAY RGB(128, 128, 128)
#define WHITE RGB(255, 255, 255)
#define BLACK RGB(0, 0, 0)
static void
GetSystem3DColors(COLORREF rgbBackground, COLORREF& rgbLightColor, COLORREF& rgbDarkColor)
{
#ifdef XP_WIN32
if (sysInfo.IsWin4_32()) {
// These are Windows 95 only
rgbLightColor = ::GetSysColor(COLOR_3DLIGHT);
rgbDarkColor = ::GetSysColor(COLOR_3DSHADOW);
} else {
rgbLightColor = LIGHT_GRAY;
rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW);
}
#else
rgbLightColor = LIGHT_GRAY;
rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW);
#endif
// We need to make sure that both colors are visible against
// the background
if (rgbLightColor == rgbBackground)
rgbLightColor = rgbBackground == LIGHT_GRAY ? WHITE : LIGHT_GRAY;
if (rgbDarkColor == rgbBackground)
rgbDarkColor = rgbBackground == DARK_GRAY ? BLACK : DARK_GRAY;
}
// Constants for calculating Highlight (TS = "TopShadow") and
// shadow (BS = "BottomShadow") values relative to background
// Taken from UNIX version -- Eric Bina's Visual.c
//
// Bias brightness calculation by standard color-sensitivity values
// (Percents -- UNIX used floats, but we don't need to)
//
#define RED_LUMINOSITY 30
#define GREEN_LUMINOSITY 59
#define BLUE_LUMINOSITY 11
// Percent effect of intensity, light, and luminosity & on brightness,
#define INTENSITY_FACTOR 25
#define LIGHT_FACTOR 0
#define LUMINOSITY_FACTOR 75
// LITE color model percent to interpolate RGB towards black for BS, TS
#define COLOR_LITE_BS_FACTOR 45
#define COLOR_LITE_TS_FACTOR 70
// DARK color model - percent to interpolate RGB towards white for BS, TS
#define COLOR_DARK_BS_FACTOR 30
#define COLOR_DARK_TS_FACTOR 50
#define MAX_COLOR 255
#define COLOR_DARK_THRESHOLD 51
#define COLOR_LIGHT_THRESHOLD 204
void CDCCX::Compute3DColors(COLORREF rgbColor, COLORREF &rgbLight, COLORREF &rgbDark)
{
unsigned uRed, uGreen, uBlue;
unsigned uRedBack = GetRValue(rgbColor);
unsigned uGreenBack = GetGValue(rgbColor);
unsigned uBlueBack = GetBValue(rgbColor);
unsigned intensity = (uRedBack + uGreenBack + uBlueBack) / 3;
unsigned luminosity = ((RED_LUMINOSITY * uRedBack)/ 100)
+ ((GREEN_LUMINOSITY * uGreenBack)/ 100)
+ ((BLUE_LUMINOSITY * uBlueBack)/ 100);
unsigned backgroundBrightness = ((intensity * INTENSITY_FACTOR) +
(luminosity * LUMINOSITY_FACTOR)) / 100;
unsigned f;
if (backgroundBrightness < COLOR_DARK_THRESHOLD) {
// Dark Background - interpolate 30% toward black
uRed = uRedBack - (COLOR_DARK_BS_FACTOR * uRedBack / 100);
uGreen = uGreenBack - (COLOR_DARK_BS_FACTOR * uGreenBack / 100);
uBlue = uBlueBack - (COLOR_DARK_BS_FACTOR * uBlueBack / 100);
rgbDark = RGB(uRed, uGreen, uBlue);
// This interpolotes to 50% toward white
uRed = uRedBack + (COLOR_DARK_TS_FACTOR *
(MAX_COLOR - uRedBack) / 100);
uGreen = uGreenBack + (COLOR_DARK_TS_FACTOR *
(MAX_COLOR - uGreenBack) / 100);
uBlue = uBlueBack + (COLOR_DARK_TS_FACTOR *
(MAX_COLOR - uBlueBack) / 100);
} else if (backgroundBrightness > COLOR_LIGHT_THRESHOLD) {
// Interpolate 45% toward black
uRed = uRedBack - (COLOR_LITE_BS_FACTOR * uRedBack / 100);
uGreen = uGreenBack - (COLOR_LITE_BS_FACTOR * uGreenBack / 100);
uBlue = uBlueBack - (COLOR_LITE_BS_FACTOR * uBlueBack / 100);
rgbDark = RGB(uRed, uGreen, uBlue);
// Original algorithm (from X source: visual.c) used:
// uRed = uRedBack - (COLOR_LITE_TS_FACTOR * uRedBack / 100),
// where FACTOR is 20%, but that makes no sense!
// I think the intention was large interpolation toward white,
// so use max of "medium" range (70%) for smooth continuity across threshhold
uRed = uRedBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uRedBack) / 100);
uGreen = uGreenBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uGreenBack) / 100);
uBlue = uBlueBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uBlueBack) / 100);
} else {
// Medium Background
f = COLOR_DARK_BS_FACTOR + (backgroundBrightness
* ( COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR )
/ MAX_COLOR);
uRed = uRedBack - (f * uRedBack / 100);
uGreen = uGreenBack - (f * uGreenBack / 100);
uBlue = uBlueBack - (f * uBlueBack / 100);
rgbDark = RGB(uRed, uGreen, uBlue);
f = COLOR_DARK_TS_FACTOR + (backgroundBrightness
* ( COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR )
/ MAX_COLOR);
uRed = uRedBack + (f * (MAX_COLOR - uRedBack) / 100);
uGreen = uGreenBack + (f * (MAX_COLOR - uGreenBack) / 100);
uBlue = uBlueBack + (f * (MAX_COLOR - uBlueBack) / 100);
}
// Safety check for upper limit
uRed = min(MAX_COLOR, uRed);
uGreen = min(MAX_COLOR, uGreen);
uBlue = min(MAX_COLOR, uBlue);
rgbLight = RGB(uRed, uGreen, uBlue);
// If either of these colors is the same as the background color
// then use the system 3D element colors instead
if (rgbLight == m_rgbBackgroundColor || rgbDark == m_rgbBackgroundColor) {
GetSystem3DColors(m_rgbBackgroundColor, rgbLight, rgbDark);
}
}
void CDCCX::Set3DColors(COLORREF crBackground)
{
Compute3DColors(crBackground, m_rgbLightColor, m_rgbDarkColor);
}
void CDCCX::SetBackgroundColor(MWContext *pContext, uint8 uRed, uint8 uGreen, uint8 uBlue)
{
// Generate the color reference
COLORREF crBackground = ResolveBGColor(uRed, uGreen, uBlue);
if( crBackground != m_rgbBackgroundColor ){
// Recalculate the color only if it has changed
m_rgbBackgroundColor = crBackground;
Set3DColors(m_rgbBackgroundColor);
}
// Determine transparency.
ResolveTransparentColor(uRed, uGreen, uBlue);
// Set the background color in the DC.
HDC hdc = GetContextDC();
if (hdc) {
::SetBkColor(hdc, m_rgbBackgroundColor);
}
#ifdef DDRAW
if (GetPrimarySurface()) {
hdc = GetDispDC(); // set the background color for offscreen surface.
if (hdc) {
::SetBkColor(hdc, m_rgbBackgroundColor);
}
}
#endif
ReleaseContextDC(hdc);
// Have any views (ledges) clear.
// Only do the FE_VIEW, since there aren't any other ledges right now.
FE_ClearView(pContext, FE_VIEW);
}
void CDCCX::SetTransparentColor(BYTE red, BYTE green, BYTE blue)
{
rgbTransparentColor.red = red;
rgbTransparentColor.green = green;
rgbTransparentColor.blue = blue;
}
// Create the initial identity palette that contains just the system colors
// and the colors.
HPALETTE
CDCCX::InitPalette(HDC hdc)
{
int i;
HPALETTE hPal;
// Create an identity palette
LPLOGPALETTE pLogPal = (LPLOGPALETTE)XP_ALLOC(sizeof(LOGPALETTE)
+ 256 * sizeof(PALETTEENTRY));
if(pLogPal != NULL) {
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = 256;
// Get entries 0-9 and 246-255, which are the standard system colors
GetSystemPaletteEntries(hdc, 0, pLogPal->palNumEntries,
pLogPal->palPalEntry);
// Initialize palette entry flags
for (i = 10; i < 246; i++) {
pLogPal->palPalEntry[i].peFlags = PALETTEENTRY_FLAGS;
#ifndef USE_IDENTITY_PALETTE
// Collapse all unspecified entries to black so that we are
// friendlier to other applications sharing the palette.
if(i >= (iLowerColors + MAX_IMAGE_PALETTE_ENTRIES)) {
pLogPal->palPalEntry[i].peRed = 0;
pLogPal->palPalEntry[i].peGreen = 0;
pLogPal->palPalEntry[i].peBlue = 0;
}
#endif
}
// Now add in the animation colors
for(int iLowCnt = iLowerSystemColors, j = 0; iLowCnt <
iLowerColors; iLowCnt++, j++) {
pLogPal->palPalEntry[iLowCnt].peRed = animationPalette[j].red;
pLogPal->palPalEntry[iLowCnt].peGreen = animationPalette[j].green;
pLogPal->palPalEntry[iLowCnt].peBlue = animationPalette[j].blue;
pLogPal->palPalEntry[iLowCnt].peFlags = PC_NOCOLLAPSE;
}
if(!(hPal = ::CreatePalette(pLogPal))) {
hPal = NULL;
}
// Done with this.
XP_FREE(pLogPal);
}
return hPal;
}
HPALETTE CDCCX::CreateColorPalette(HDC hdc, IL_IRGB& transparentColor, int bitsPerPixel)
{
HPALETTE hPal;
// Set up the per-context palette.
// This is per-window since not everything goes to the screen, and therefore
// won't always have the screen's attributes. (printing, metafiles DCs, etc).
IL_ColorMap * defaultColorMap = IL_NewCubeColorMap(NULL, 0,
MAX_IMAGE_PALETTE_ENTRIES+1);
hPal = CDCCX::InitPalette(hdc);
CDCCX::SetColormap(hdc, defaultColorMap, transparentColor, hPal);
IL_DestroyColorMap (defaultColorMap);
return hPal;
}
void CDCCX::SetColormap(HDC hdc, NI_ColorMap *pMap, IL_IRGB& transparentColor, HPALETTE hPal) {
PALETTEENTRY paletteEntries[256];
int iExactMatches = 0; // # of color requests we were able to match
int iFirstImageColor = iLowerColors;
int iLastImageColor = iLowerColors + MAX_IMAGE_PALETTE_ENTRIES - 1;
// Copy existing palette to get system colors and animation colors
GetPaletteEntries(hPal, 0, 256, paletteEntries);
if (!pMap->index) { // setup the index array.
pMap->index = (unsigned char*)XP_ALLOC(MAX_IMAGE_PALETTE_ENTRIES+1);
for (int i = 0; i < MAX_IMAGE_PALETTE_ENTRIES; i++) {
pMap->index[i] = iLowerColors + i;
paletteEntries[iLowerColors + i].peRed = pMap->map[i].red;
paletteEntries[iLowerColors + i].peGreen = pMap->map[i].green;
paletteEntries[iLowerColors + i].peBlue = pMap->map[i].blue;
paletteEntries[iLowerColors + i].peFlags = PALETTEENTRY_FLAGS;
}
}
paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peRed = transparentColor.red;
paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peGreen = transparentColor.green;
paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peBlue = transparentColor.blue;
paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peFlags = PC_NOCOLLAPSE;
paletteEntries[255].peRed = 0xFF;
paletteEntries[255].peGreen = 0xFF;
paletteEntries[255].peBlue = 0xFF;
paletteEntries[255].peFlags = PALETTEENTRY_FLAGS;
::SetPaletteEntries(hPal, iFirstImageColor, MAX_IMAGE_PALETTE_ENTRIES,
&paletteEntries[iFirstImageColor]);
}
void CDCCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lLength) {
// Set the document height and width.
m_lDocWidth = lWidth;
m_lDocHeight = lLength;
}
void CDCCX::GetDocPosition(MWContext *pContext, int iLocation, int32 *lX_p, int32 *lY_p) {
*lX_p = m_lOrgX;
*lY_p = m_lOrgY;
}
BOOL CDCCX::OnOpenDocumentCX(const char *pPathName) {
// Should only happen with window contexts.
if(IsWindowContext() == FALSE) {
return(FALSE);
}
// Make sure there's something specified, otherwise just
// return sucess.
// Take passing in NULL as a request to initialize, which we do
// nothing with.
if(pPathName != NULL) {
// convert the path name to a URL.
CString csUrl;
WFE_ConvertFile2Url(csUrl, pPathName);
// Load it.
GetUrl(NET_CreateURLStruct(csUrl, NET_DONT_RELOAD), FO_CACHE_AND_PRESENT);
}
return(TRUE);
}
void CDCCX::ViewImages() {
#ifdef MOZ_NGLAYOUT
XP_ASSERT(0);
#else
if(IsDestroyed() == FALSE) {
// Tell layout that all images are to be force loaded.
LO_SetForceLoadImage(NULL, TRUE);
ExplicitlyLoadAllImages();
}
#endif /* MOZ_NGLAYOUT */
}
BOOL CDCCX::CanViewImages() {
BOOL bRetval;
if(prefInfo.m_bAutoLoadImages || IsDestroyed()) {
bRetval = FALSE;
}
else {
bRetval = TRUE;
}
return(bRetval);
}
// Set up the things that need to be in order to handle an OLE server
// metafile correctly.
void CDCCX::EnableOleServer()
{
TRACE("Enabling context as an OLE server\n");
// Mark a generic switch that can be checked elsewhere.
m_bOleServer = TRUE;
}
// Create a url struct from the history, with appropriate checking
// for NULL and such, so that we don't have this code scattered
// throughout the client.
// bClearStateData is a flag set to erase any data that can't be
// tossed around without upsetting the client (form data).
// It's off by default, so be careful out there.
URL_Struct *CDCCX::CreateUrlFromHist(BOOL bClearStateData, SHIST_SavedData *pSavedData, BOOL bWysiwyg)
{
// Make sure that we're not destroyed.
if(IsDestroyed()) {
return(NULL);
}
// Before we create the URL, we must save any state data of the current page
// that is needed to perform the next load (such as position)....
// Other's not dealing with history, save their data in the GetUrl call.
SHIST_SetPositionOfCurrentDoc(&(GetContext()->hist), 0);
#ifdef MOZ_NGLAYOUT
XP_ASSERT(0);
#else
if(GetOriginX() || GetOriginY()) {
#ifdef LAYERS
LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(GetDocumentContext(), GetOriginX(), GetOriginY(), NULL);
#else
LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(GetDocumentContext(), GetOriginX(), GetOriginY());
#endif /* LAYERS */
if(pAny != NULL) {
TRACE("Remembering document position at element id %ld\n", pAny->ele_id);
SHIST_SetPositionOfCurrentDoc(&(GetContext()->hist), pAny->ele_id);
}
}
#endif /* MOZ_NGLAYOUT */
// Call/return the base.
URL_Struct *pUrl = CStubsCX::CreateUrlFromHist(bClearStateData, pSavedData, bWysiwyg);
return(pUrl);
}
#ifndef MOZ_NGLAYOUT
//
// Make the given form element visible on the screen
//
void CDCCX::DisplayFormElement(MWContext *pContext, int iLocation, LO_FormElementStruct *pFormElement)
{
// Call the base.
CStubsCX::DisplayFormElement(pContext, iLocation, pFormElement);
// Figure the coordinates.
LTRB Rect;
// Note that we call this version of ResolveElement since we do
// something special for form elements. Note also that we don't
// check the return value since this function may be called before
// the form element is actually visible, but we have to correctly
// "display". In other words, this function is only called when the
// visibility or position of the form element changes and we need
// make the corresponding changes to the actual widget irrespective
// of whether it's visible or not.
ResolveElement(Rect, pFormElement);
SafeSixteen(Rect);
// Get our front end form element, and have it display itself at the given rectangle.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->DisplayFormElement(Rect);
}
}
void CDCCX::FormTextIsSubmit(MWContext *pContext, LO_FormElementStruct *pFormElement)
{
// Call the base.
CStubsCX::FormTextIsSubmit(pContext, pFormElement);
// Get our front end form element, and have it do it's thang.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->FormTextIsSubmit();
}
}
void CDCCX::GetFormElementInfo(MWContext *pContext, LO_FormElementStruct *pFormElement)
{
// Call the base.
CStubsCX::GetFormElementInfo(pContext, pFormElement);
// Get our front end form element, and have it do it's thang.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->GetFormElementInfo();
}
}
void CDCCX::GetFormElementValue(MWContext *pContext, LO_FormElementStruct *pFormElement, XP_Bool bTurnOff)
{
// Call the base.
CStubsCX::GetFormElementValue(pContext, pFormElement, bTurnOff);
// Get our front end form element, and have it do it's thang.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->GetFormElementValue(bTurnOff);
}
}
void CDCCX::ResetFormElement(MWContext *pContext, LO_FormElementStruct *pFormElement)
{
// Call the base.
CStubsCX::ResetFormElement(pContext, pFormElement);
// Get our front end form element, and have it do it's thang.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->ResetFormElement();
}
}
void CDCCX::SetFormElementToggle(MWContext *pContext, LO_FormElementStruct *pFormElement, XP_Bool iState)
{
// Call the base.
CStubsCX::SetFormElementToggle(pContext, pFormElement, iState);
// Get our front end form element, and have it do it's thang.
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement);
if(pFormClass != NULL) {
pFormClass->SetFormElementToggle(iState);
}
}
#endif
// Do a fill rect type operation.
void CDCCX::FloodRect(LTRB& Rect, HBRUSH hColor)
{
if(hColor) {
HDC hdc = GetContextDC();
if(hdc) {
RECT cr;
::SetRect(&cr, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
::FillRect(hdc, &cr, hColor);
ReleaseContextDC(hdc);
}
}
}
BITMAPINFO* CDCCX::FillBitmapInfoHeader(NI_Pixmap* pImage)
{
BITMAPINFO *pBMInfo;
NI_PixmapHeader* imageHeader = &pImage->header;
int pixmap_depth = imageHeader->color_space->pixmap_depth;
if (pixmap_depth == 24 || pixmap_depth == 32)
pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (1 * sizeof(RGBQUAD))); // space for header only
else if (pixmap_depth == 16)
pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (3 * sizeof(RGBQUAD)) ); // space for header and color masks
else if (pixmap_depth == 8)
pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (256 * sizeof(RGBQUAD)) ); // space for header and pallette
else if (pixmap_depth == 1)
pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (2 * sizeof(RGBQUAD)) ); // space for header and pallette
ASSERT(pixmap_depth < 32);
if (!pBMInfo) return NULL; // error occor.
pBMInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBMInfo->bmiHeader.biWidth = pImage->header.width;
pBMInfo->bmiHeader.biHeight = pImage->header.height;
pBMInfo->bmiHeader.biPlanes = 1;
pBMInfo->bmiHeader.biBitCount = (short)pixmap_depth;
#ifdef XP_WIN32
// Don't allow this to happen on OLE servers, as the metafiles can't
// handle it.
if ((pixmap_depth > 1 ) && m_bRGB565) {
pBMInfo->bmiHeader.biCompression = BI_BITFIELDS;
// Define the color masks for a RGB565 DIB
LPDWORD lpMasks = (LPDWORD)pBMInfo->bmiColors;
lpMasks[0] = 0xF800; // red color mask
lpMasks[1] = 0x07E0; // green color mask
lpMasks[2] = 0x001F; // blue color mask
} else {
if (pixmap_depth == 24 || pixmap_depth == 32) {
LPDWORD lpMasks = (LPDWORD)pBMInfo->bmiColors;
*lpMasks = NULL;
}
pBMInfo->bmiHeader.biCompression = BI_RGB;
}
#else
pBMInfo->bmiHeader.biCompression = BI_RGB;
#endif
//pBMInfo->bmiHeader.biSizeImage = NULL;
pBMInfo->bmiHeader.biSizeImage = pImage->header.widthBytes * pImage->header.height;
pBMInfo->bmiHeader.biXPelsPerMeter = 0;
pBMInfo->bmiHeader.biYPelsPerMeter = 0;
pBMInfo->bmiHeader.biClrUsed = 0; // default value
pBMInfo->bmiHeader.biClrImportant = 0; // all important
if(m_bUseDibPalColors) {
if (pixmap_depth == 1) {
// Build an index table for monochrome images. Only XBMs are
// monochome
WORD* pPalIndex = (WORD*)(pBMInfo->bmiColors);
pPalIndex[0] = 255; // palette index for WHITE
pPalIndex[1] = 0; // palette index for BLACK
} else {
// pImage->depth != 1
unsigned short nClrUsed = (unsigned short)(1 << pBMInfo->bmiHeader.biBitCount);
// DIB_PAL_COLORS expects an array of 16-bit unsigned integers that specify
// an index into the currently realized logical palette
WORD* pPalIndx = (WORD*)(((unsigned char*)pBMInfo) + pBMInfo->bmiHeader.biSize);
for (unsigned short index = 0; index < nClrUsed; index++, pPalIndx++)
*pPalIndx = index;
}
} else {
// Not using DIB_PAL_COLORS
if (pixmap_depth == 8) {
RGBQUAD RGBArray[256];
CopyPaletteToRGBArray(GetPalette(), RGBArray);
memcpy(&(pBMInfo->bmiColors[0]), RGBArray, (256 * sizeof(RGBQUAD)));
} else if (pixmap_depth == 1) {
// Build the color table for monochrome images. Only XBMs are monochrome
pBMInfo->bmiColors[0].rgbRed = 255;
pBMInfo->bmiColors[0].rgbGreen = 255;
pBMInfo->bmiColors[0].rgbBlue = 255;
pBMInfo->bmiColors[0].rgbReserved = 0;
pBMInfo->bmiColors[1].rgbRed = 0;
pBMInfo->bmiColors[1].rgbGreen = 0;
pBMInfo->bmiColors[1].rgbBlue = 0;
pBMInfo->bmiColors[1].rgbReserved = 0;
}
}
return pBMInfo;
}
static void replaceColorSpace(NI_Pixmap* pImage, NI_ColorSpace* curColorSpace, int devicePixmap)
{
NI_PixmapHeader* imageHeader = &pImage->header;
NI_ColorSpace* color_space = imageHeader->color_space;
ASSERT(color_space->pixmap_depth < 32);
if (color_space->pixmap_depth == 1)
return;
if ((color_space->pixmap_depth <= 8) || (devicePixmap < color_space->pixmap_depth)) {
IL_ReleaseColorSpace(color_space);
IL_AddRefToColorSpace(curColorSpace);
imageHeader->color_space = curColorSpace;
}
}
static BOOL
CanCreateBrush(HBITMAP hBitmap, int nBitsPerPixel)
{
BITMAP bitmap;
// Get the size of the bitmap
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
// We can create a brush if the bitmap is exacly 8x8 or we're on NT
if (sysInfo.m_bWinNT) {
if (nBitsPerPixel == 24) {
// There's a reported problem with 24bpp mode on NT, but I haven't
// seen it on NT 4.0
// if (sysInfo.m_dwMajor < 4)
return FALSE;
}
// Large brushes on NT are a performance hog, so place an upper
// limit on the brush size.
return bitmap.bmWidth <= 64 && bitmap.bmHeight <= 64;
}
return bitmap.bmWidth == 8 && bitmap.bmHeight == 8;
}
HBITMAP CDCCX::CreateBitmap(HDC hTargetDC, NI_Pixmap *image)
{
ASSERT(hTargetDC);
FEBitmapInfo *imageInfo = (FEBitmapInfo*)image->client_data;
BITMAPINFO *pBmInfo = imageInfo->bmpInfo;
ASSERT(pBmInfo);
return ::CreateDIBitmap(hTargetDC, &pBmInfo->bmiHeader,
CBM_INIT, image->bits,
pBmInfo, m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS);
}
int CDCCX::DisplayPixmap(NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, int32 lScaleWidth, int32 lScaleHeight, LTRB& Rect)
{
// If width and height are 0, then we assume the entire width and height.
// x and y are relative coords to the top left of the image.
HDC hdc;
#ifdef DDRAW
LPDIRECTDRAWSURFACE drawSurface = GetBackSurface();
#endif
hdc = GetDispDC();
FEBitmapInfo *imageInfo = (FEBitmapInfo*) image->client_data;
if (!imageInfo) return FALSE; // there is no image to display.
// set this flag, so the display boarder will not try to display the icon.
imageInfo->imageDisplayed = TRUE;
int xRepeat, yRepeat;
xRepeat = (CASTINT(width) + CASTINT(x_offset) + CASTINT(imageInfo->targetWidth) -1) / CASTINT(imageInfo->targetWidth);
yRepeat = (CASTINT(height) + CASTINT(y_offset) + CASTINT(imageInfo->targetHeight) -1) / CASTINT(imageInfo->targetHeight);
if (!ResolveElement(Rect, image, x_offset * m_lConvertX, y_offset *m_lConvertY,
x * m_lConvertX, y* m_lConvertY,
width* m_lConvertX, height* m_lConvertY,
lScaleWidth * m_lConvertX, lScaleHeight * m_lConvertY))
return FALSE;
SafeSixteen(Rect);
FEBitmapInfo *maskInfo = (FEBitmapInfo *)NULL;
if (mask) maskInfo = (FEBitmapInfo *)mask->client_data;
x_offset = (x_offset > 0) ? x_offset : 0;
y_offset = (y_offset > 0) ? y_offset : 0;
if ((xRepeat > 1) || (yRepeat > 1)) { // tiled
TileImage(hdc, Rect, image, mask, x * GetXConvertUnit(), y * GetYConvertUnit());
}
else {
if (maskInfo) {
if ((imageInfo->hBitmap) && (maskInfo->hBitmap)) {
#ifdef XP_WIN32
if (sysInfo.m_bWinNT && (GetContextType() != MetaFile) && !IsPrintContext()) {
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap);
// MaskBlt has two raster ops: one for the foreground pixels (value of 1)
// and one for the background pixels (value of 0). The raster op is
// specified using MAKEROP4(fore,back)
#ifdef USE_DIB_SECTION
if (image->bits)
::MaskBlt(hdc,
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
m_pImageDC, x_offset, y_offset,
maskInfo->hBitmap,
x_offset, y_offset,
MAKEROP4(SRCCOPY, 0x00AA0029)); // 0x00AA0029 is destination...
else
#endif
::MaskBlt(hdc,
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
m_pImageDC, x_offset, y_offset,
maskInfo->hBitmap,
x_offset, y_offset,
MAKEROP4(0x00AA0029, SRCCOPY)); // 0x00AA0029 is destination...
// Cleanup
::SelectObject(m_pImageDC, hOldBitmap);
}
else
#endif
StretchMaskBlt(hdc, imageInfo->hBitmap, maskInfo->hBitmap,
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
x_offset,
y_offset,
width,
height);
}
else {
_StretchDIBitsWithMask(hdc,
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
CASTINT(x_offset),
// the reason for this calculation is that Window's bitmap
// is reverse. The first scan line will be at the buttom of
// the bitmap buffer.
CASTINT(imageInfo->height - ((height ) + y_offset)),
CASTINT(width ),
CASTINT(height),
image,
mask);
}
}
else {
StretchPixmap(hdc, image,
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
x_offset,
y_offset,
width,
height);
}
}
ReleaseContextDC(hdc);
return 1;
}
///////////////////
// Destination coordinates are in the logical units of pDC, and
// the source coordinates are in device units
void CDCCX::StretchPixmap(HDC hTargetDC, NI_Pixmap* pImage,
int32 dx, int32 dy, int32 dw, int32 dh,
int32 sx, int32 sy, int32 sw, int32 sh)
{
// Clamp the width and height if necessary
if (sx < 0 || sy < 0)
return;
FEBitmapInfo *imageInfo = (FEBitmapInfo*)pImage->client_data;
BITMAPINFO *pBmInfo = imageInfo->bmpInfo;
if (imageInfo->hBitmap) {
HBITMAP hOldBitmap;
// If we are using this image as a tile, the bitmap will already be selected
// into the memory DC for us.
if (!imageInfo->IsTile)
hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap);
::StretchBlt(hTargetDC,
CASTINT(dx),
CASTINT(dy),
CASTINT(dw),
CASTINT(dh),
m_pImageDC,
CASTINT(sx),
CASTINT(sy),
CASTINT(sw),
CASTINT(sh),
pBmInfo->bmiHeader.biBitCount == 1 ? SRCAND : SRCCOPY);
// If we are using this image as a tile, the bitmap will be deselected for us.
if (!imageInfo->IsTile)
::SelectObject(m_pImageDC, hOldBitmap);
}
else {
// the reason for this calculation is because window's bmp is an
// upsidedown image. the bit in the pImage->bits does reflect
// this. So we need to sepcify the offset from the bottom up.
::StretchDIBits( hTargetDC,
CASTINT(dx),
CASTINT(dy),
CASTINT(dw),
CASTINT(dh),
CASTINT(sx),
CASTINT(imageInfo->height - (sh + sy)),
CASTINT(sw),
CASTINT(sh),
pImage->bits, // address of bitmap bits
imageInfo->bmpInfo, // address of bitmap data
CASTUINT(m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS),
pBmInfo->bmiHeader.biBitCount == 1 ? SRCAND : SRCCOPY);
}
}
HBITMAP CDCCX::CreateMask(HDC hTargetDC, NI_Pixmap* mask)
{
ASSERT(hTargetDC);
FEBitmapInfo *maskInfo = (FEBitmapInfo*)mask->client_data;
// Build a BITMAPINFO struct for mask
char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))];
LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask;
memcpy(pBmInfoMask, maskInfo->bmpInfo, sizeof(BITMAPINFOHEADER));
pBmInfoMask->bmiHeader.biBitCount = 1;
pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS
pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels
pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels
// Create the mask. It's important that we use the memory DC, because we
// want a momochrome bitmap
return ::CreateDIBitmap(hTargetDC,
(LPBITMAPINFOHEADER)pBmInfoMask,
CBM_INIT,
mask->bits,
pBmInfoMask,
// m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS);
DIB_RGB_COLORS);
}
// StretchBlt a DIB with a mask
// Destination coordinates are in the logical units of pDC, and
// the source coordinates are in device units
void WFE_StretchDIBitsWithMask(HDC hTargetDC,
BOOL isDeviceDC,
HDC hOffscreenDC,
int dx,
int dy,
int dw,
int dh,
int sx,
int sy,
int sw,
int sh,
void XP_HUGE *imageBit,
BITMAPINFO* lpImageInfo,
void XP_HUGE *maskBit,
BOOL bUseDibPalColors,
COLORREF fillWithBackground
)
{
// Tile the shadow bitmap with the backdrop
HBITMAP pSaveBmp;
HBITMAP bmpShadow;
HDC hTempDC;
int32 targetX, targetY;
HDC memDC;
if (isDeviceDC) {
if (hOffscreenDC)
memDC = hOffscreenDC;
else {
memDC = ::CreateCompatibleDC(hTargetDC);
}
if (!(bmpShadow = (HBITMAP)CreateCompatibleBitmap(hTargetDC, dw, dh))) {
TRACE("_StretchBltWithMask() can't create bitmap!\n");
return;
}
pSaveBmp = (HBITMAP) ::SelectObject(memDC, bmpShadow);
if (!fillWithBackground) {
::StretchBlt(memDC, // get the screen bit.
CASTINT(0), CASTINT(0),
CASTINT(dw), CASTINT(dh),
hTargetDC,
CASTINT(dx), CASTINT(dy),
CASTINT(dw), CASTINT(dh),
SRCCOPY);
}
else { // the background is solid color.
HBRUSH hbr = ::CreateSolidBrush(fillWithBackground);
RECT tempRect;
tempRect.left = tempRect.top = 0;
tempRect.right = dw;
tempRect.bottom = dh;
::FillRect(memDC, &tempRect, hbr);
::DeleteObject(hbr);
}
hTempDC = memDC;
targetX = targetY = 0;
}
else {
hTempDC = hTargetDC;
targetX = dx;
targetY = dy;
}
char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))];
LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask;
memcpy(pBmInfoMask, lpImageInfo, sizeof(BITMAPINFOHEADER));
pBmInfoMask->bmiHeader.biBitCount = 1;
pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS
// Build a color table for monochrome mask. The image library sets foreground
// pixels to 1 and background pixels to 0. We want it the other way around
// when doing the AND operation
pBmInfoMask->bmiColors[0] = rgbqWhite; // background pixels
pBmInfoMask->bmiColors[1] = rgbqBlack; // foreground pixels
pBmInfoMask->bmiHeader.biSizeImage = 0;
int err = ::StretchDIBits(hTempDC,
CASTINT(targetX), CASTINT(targetY),
CASTINT(dw), CASTINT(dh),
CASTINT(sx), CASTINT(sy),
CASTINT(sw), CASTINT(sh),
maskBit,
pBmInfoMask,
DIB_RGB_COLORS,
SRCAND);
err = ::StretchDIBits(hTempDC,
CASTINT(targetX), CASTINT(targetY),
CASTINT(dw), CASTINT(dh),
CASTINT(sx), CASTINT(sy),
CASTINT(sw), CASTINT(sh),
imageBit,
lpImageInfo,
bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS,
SRCPAINT);
if (isDeviceDC) {
::StretchBlt(hTargetDC,
CASTINT(dx), CASTINT(dy),
CASTINT(dw), CASTINT(dh),
memDC,
CASTINT(0), CASTINT(0),
CASTINT(dw),CASTINT(dh),
SRCCOPY);
::SelectObject(memDC, pSaveBmp);
VERIFY(::DeleteObject( bmpShadow));
if (!hOffscreenDC) { // Delete the temporary DC that we created.
::DeleteDC(memDC);
}
}
}
// StretchBlt a DIB with a mask
// Destination coordinates are in the logical units of pDC, and
// the source coordinates are in device units
void CDCCX::_StretchDIBitsWithMask(HDC hTargetDC,
int dx,
int dy,
int dw,
int dh,
int sx,
int sy,
int sw,
int sh,
NI_Pixmap *image,
NI_Pixmap *mask)
{
// Tile the shadow bitmap with the backdrop
FEBitmapInfo *imageInfo = (FEBitmapInfo*)image->client_data;
FEBitmapInfo *maskInfo = (FEBitmapInfo*)mask->client_data;
WFE_StretchDIBitsWithMask(hTargetDC, IsDeviceDC(), m_pImageDC,
dx, dy, dw, dh,
sx, sy, sw, sh,
image->bits,
imageInfo->bmpInfo,
mask->bits,
m_bUseDibPalColors);
}
void CDCCX::StretchMaskBlt(HDC hTargetDC, HBITMAP theBitmap, HBITMAP theMask,
int32 dx, int32 dy, int32 dw, int32 dh,
int32 sx, int32 sy, int32 sw, int32 sh)
{
// Tile the shadow bitmap with the backdrop
HDC memDC = NULL;
HBITMAP pSaveBmp;
HBITMAP bmpShadow;
HPALETTE hOldPal1 = NULL;
int32 targetX, targetY;
if (IsDeviceDC()) {
if (!(bmpShadow = (HBITMAP)CreateCompatibleBitmap(hTargetDC, CASTINT(dw), CASTINT(dh)))) {
TRACE("_StretchBltWithMask() can't create bitmap!\n");
return;
}
// Create memory DC
if (!(memDC=CreateCompatibleDC(hTargetDC))) {
TRACE("_StretchBltWithMask() can't create compatible memory DC!\n");
return;
}
if (m_bUseDibPalColors && m_pPal) {
hOldPal1 = (HPALETTE)::SelectPalette(memDC, m_pPal, FALSE);
}
pSaveBmp = (HBITMAP) ::SelectObject(memDC, bmpShadow);
::StretchBlt(memDC,
CASTINT(0), CASTINT(0),
CASTINT(dw), CASTINT(dh),
hTargetDC,
CASTINT(dx), CASTINT(dy),
CASTINT(dw), CASTINT(dh),
SRCCOPY);
targetX = targetY = 0;
}
else {
memDC = hTargetDC;
targetX = dx;
targetY = dy;
}
HBITMAP old = (HBITMAP)::SelectObject(m_pImageDC, theMask);
::StretchBlt(memDC,
CASTINT(targetX), CASTINT(targetY),
CASTINT(dw), CASTINT(dh),
m_pImageDC,
CASTINT(sx), CASTINT(sy),
CASTINT(sw), CASTINT(sh),
SRCAND);
// load the bitmap into the cached image CDC
::SelectObject(m_pImageDC, theBitmap);
::StretchBlt(memDC,
CASTINT(targetX), CASTINT(targetY),
CASTINT(dw), CASTINT(dh),
m_pImageDC,
CASTINT(sx), CASTINT(sy),
CASTINT(sw), CASTINT(sh),
SRCPAINT);
if (IsDeviceDC()) {
::StretchBlt(hTargetDC,
CASTINT(dx), CASTINT(dy),
CASTINT(dw), CASTINT(dh),
memDC,
CASTINT(0), CASTINT(0),
CASTINT(dw),CASTINT(dh),
SRCCOPY);
::SelectObject(memDC, pSaveBmp);
if (m_bUseDibPalColors && hOldPal1) {
::SelectPalette(memDC, hOldPal1, FALSE);
}
VERIFY(::DeleteDC(memDC));
VERIFY(::DeleteObject( bmpShadow));
}
::SelectObject(m_pImageDC, old);
}
// We need to allocate the space for the image decoding ourselves because it
// depends on what size machine we are on how we want to do it
BITMAPINFO *CDCCX::NewPixmap(NI_Pixmap *pImage, BOOL mask)
{
if(mask == FALSE) {
replaceColorSpace(
pImage,
/*this->*/curColorSpace,
/*this->*/m_iBitsPerPixel);
}
NI_PixmapHeader& header = pImage->header;
NI_ColorSpace *& color_space = header.color_space;
uint8& pixmap_depth = color_space->pixmap_depth;
if(pImage->bits == NULL) {
header.widthBytes = header.width;
header.widthBytes *= pixmap_depth;
if(pixmap_depth < 8) {
header.widthBytes += 7;
}
header.widthBytes /= 8;
// Make sure image width is 4byte aligned
int iAlign = CASTINT(header.widthBytes % 4);
if(iAlign) {
header.widthBytes += 4;
header.widthBytes -= iAlign;
}
//#ifndef XP_WIN32
#ifndef USE_DIB_SECTION
// The image buffer might need to be really big (i.e. over 32K)
// We need to use a huge memory allocation on the 16-bit version
pImage->bits = HugeAlloc(header.widthBytes * header.height, 1);
// Note: It's possible that the image is so huge that we can't allocate enough
// memory for it, especially under Win16 (e.g. 18 Mb images)
if(pImage->bits == NULL) {
return(NULL);
}
return(FillBitmapInfoHeader(pImage));
#else // for use with createDibSection.
BITMAPINFO* pbmInfo = FillBitmapInfoHeader(pImage);
FEBitmapInfo *imageInfo;
imageInfo = (FEBitmapInfo*) pImage->client_data;
HDC hdc = GetContextDC();
imageInfo->hBitmap = CreateDIBSection(hdc,
pbmInfo, // pointer to structure containing bitmap size, format, and color data
m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS,
&pImage->bits, // pointer to variable to receive a pointer to the bitmap's bit values
NULL, // optional handle to a file mapping object
NULL // offset to the bitmap bit values within the file mapping object
);
ReleaseContextDC(hdc);
#ifdef DEBUG
// If this assert fires, please be sure to report the following
// information: pixmap_depth, header.widthBytes, header.height
// and the current display setting - kevina.
XP_ASSERT(pImage->bits);
if (pImage->bits) {
// Check whether the pointer is currently valid.
XP_ASSERT(!IsBadWritePtr((void *)pImage->bits,
(uint)(header.widthBytes*header.height)));
XP_ASSERT(!IsBadReadPtr((void *)pImage->bits,
(uint)(header.widthBytes*header.height)));
// For testing. Purify sometimes gets confused and complains that
// the shared memory pointer returned by CreateDIBSection is
// invalid, even though the previous assertions don't fire. If
// this happens, expect Purify to complain whenever the ImageLib
// accesses the bits pointer.
// memset(pImage->bits, ~0, (header.widthBytes * header.height));
memset(pImage->bits, ~0, 1);
}
#endif // DEBUG
if (!imageInfo->hBitmap) {
return FALSE;
}
else
return pbmInfo;
#endif
}
return NULL;
}
// Create a larger tile from a smaller one. The dimensions of the larger
// tile must be a multiple of the dimensions of the smaller tile.
static HBITMAP CreateLargerTile(HDC pDC, HDC pMemDCNew, HDC pMemDCOld,
NI_Pixmap *pImage, BOOL bUseDibPalColors,
int iOldWidth, int iOldHeight,
int iNewWidth, int iNewHeight)
{
int x, y;
HBITMAP pNewTile;
HGDIOBJ pSavedObj1, pSavedObj2;
FEBitmapInfo *imageInfo = (FEBitmapInfo *)pImage->client_data;
pNewTile = CreateCompatibleBitmap(pDC, iNewWidth, iNewHeight);
if (!pNewTile)
return NULL;
pSavedObj1 = (HGDIOBJ)::SelectObject(pMemDCNew, pNewTile);
if (imageInfo->hBitmap) {
pSavedObj2 = (HGDIOBJ)::SelectObject(pMemDCOld, imageInfo->hBitmap);
::BitBlt(pMemDCNew, 0, 0, iOldWidth, iOldHeight, pMemDCOld, 0, 0, SRCCOPY);
}
else {
uint iUsage = bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS;
::StretchDIBits(pMemDCNew, 0, 0, iOldWidth, iOldHeight, 0, 0, iOldWidth, iOldHeight,
pImage->bits, imageInfo->bmpInfo, iUsage, SRCCOPY);
}
// Fill up the new tile exponentially for speed.
for (x = iOldWidth; x < iNewWidth; x *= 2) {
::BitBlt(pMemDCNew, x, 0, MIN(x,iNewWidth-x), iOldHeight, pMemDCNew, 0, 0, SRCCOPY);
}
for (y = iOldHeight; y < iNewHeight; y *= 2) {
::BitBlt(pMemDCNew, 0, y, iNewWidth, MIN(y,iNewHeight-y), pMemDCNew, 0, 0, SRCCOPY);
}
::SelectObject(pMemDCNew, pSavedObj1);
if (imageInfo->hBitmap)
::SelectObject(pMemDCOld, pSavedObj2);
return pNewTile;
}
#ifdef DDRAW
/*
* DDColorMatch
*
* convert a RGB color to a pysical color.
*
* we do this by leting GDI SetPixel() do the color matching
* then we lock the memory and see what it got mapped to.
*/
static DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb)
{
COLORREF rgbT;
HDC hdc;
DWORD dw = CLR_INVALID;
DDSURFACEDESC ddsd;
HRESULT hres;
//
// use GDI SetPixel to color match for us
//
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
{
rgbT = GetPixel(hdc, 0, 0); // save current pixel value
SetPixel(hdc, 0, 0, rgb); // set our value
pdds->ReleaseDC(hdc);
}
//
// now lock the surface so we can read back the converted color
//
ddsd.dwSize = sizeof(ddsd);
while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
;
if (hres == DD_OK)
{
dw = *(DWORD *)ddsd.lpSurface; // get DWORD
dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1; // mask it to bpp
pdds->Unlock(NULL);
}
//
// now put the color that was there back.
//
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
{
SetPixel(hdc, 0, 0, rgbT);
pdds->ReleaseDC(hdc);
}
return dw;
}
// MWH this funtion only work when there is directDraw support. It use the transColor for
// transparent blt. if releaseTempSurf == FALSE. It is caller's responsibility to release
// the surf.
BOOL CDCCX::TransparentBlt(int dx,
int dy,
int dw,
int dh,
int sx,
int sy,
int sw,
int sh,
NI_Pixmap *image,
COLORREF transColor,
LPDIRECTDRAWSURFACE surf)
{
if (!GetPrimarySurface()) return FALSE;
LPDDSURFACEDESC ddesc = GetSurfDesc();
RECT rect;
HRESULT err = 1;
rect.left = rect.top = 0;
rect.bottom = dy + dh;
rect.right = dx + dw;
BOOL needRelease = TRUE;
LPDIRECTDRAWSURFACE tempsurf;
if (!surf) {
tempsurf = CreateOffscreenSurface(rect);
}
else {
tempsurf = surf;
needRelease = FALSE;
}
HDC tempDC;
FEBitmapInfo *imageInfo;
imageInfo = (FEBitmapInfo*) image->client_data;
if (tempsurf) {
tempsurf->GetDC(&tempDC);
::StretchDIBits(tempDC,
CASTINT(dx), CASTINT(dy),
CASTINT(dw), CASTINT(dh),
CASTINT(sx), CASTINT(sy),
CASTINT(sw), CASTINT(sh),
image->bits,
imageInfo->bmpInfo,
DIB_RGB_COLORS,
SRCCOPY);
ReleaseOffscreenSurfDC();
rect.left = dx;
rect.top = dy;
tempsurf->ReleaseDC(tempDC);
DDCOLORKEY colorKey;
if (ddesc->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { //palette device
colorKey.dwColorSpaceLowValue = ::GetNearestPaletteIndex(GetPalette(), transColor);
colorKey.dwColorSpaceHighValue = ::GetNearestPaletteIndex(GetPalette(), transColor);
}
else {
colorKey.dwColorSpaceLowValue = DDColorMatch(tempsurf, transColor);
colorKey.dwColorSpaceHighValue = DDColorMatch(tempsurf, transColor);
}
tempsurf->SetColorKey(DDCKEY_SRCBLT, &colorKey);
err = GetBackSurface()->Blt(&rect, tempsurf, &rect, DDBLT_KEYSRC , NULL);
if (err == DDERR_SURFACELOST) {
RestoreAllDrawSurface();
err = GetBackSurface()->Blt(&rect, tempsurf, &rect, DDBLT_KEYSRC , NULL);
}
if (needRelease) {
tempsurf->Release();
}
LockOffscreenSurfDC();
}
if (err != 0) return FALSE;
else
return TRUE;
}
#endif
#define ROUNDUP(_x,_toMultipleOf) (((_x)+(_toMultipleOf)-1)/(_toMultipleOf)*(_toMultipleOf))
void CDCCX::TileImage(HDC hdc, LTRB& Rect, NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y)
{
int iMinTileWidth, iMinTileHeight, iTileWidth, iTileHeight;
int iRectWidth, iRectHeight, iOrigWidth, iOrigHeight;
HBITMAP pTmpImageBitmap = NULL, pTmpMaskBitmap = NULL, pSavedImageBitmap, pSavedMaskBitmap;
HGDIOBJ pOldObj;
FEBitmapInfo *imageInfo;
FEBitmapInfo *maskInfo;
imageInfo = (FEBitmapInfo*) image->client_data;
int32 lDrawingOrgX, lDrawingOrgY;
GetDrawingOrigin(&lDrawingOrgX, &lDrawingOrgY);
// If we a backdrop image has been explicitly specified and
// it is transparent, then don't use the NT brush feature,
// since it doesn't support masks.
if ((!mask) && (imageInfo->hBitmap) && (CanCreateBrush(imageInfo->hBitmap, m_iBitsPerPixel))) {
CPoint brushOrg(CASTINT(lDrawingOrgX - m_lOrgX), CASTINT(lDrawingOrgY - m_lOrgY));
HBRUSH hBrush = CreatePatternBrush(imageInfo->hBitmap);
ASSERT(hBrush);
// We need to align the brush properly. The values to SetBrushOrg() specifiy
// where the brush origin (i.e. the point (0, 0) of the brush) will be mapped.
// The coordinates must be in device units
::LPtoDP(hdc, &brushOrg, 1);
brushOrg.x %= (imageInfo->width * GetXConvertUnit());
brushOrg.y %= (imageInfo->height * GetYConvertUnit());
POINT tempPoint;
#ifdef _WIN32
::SetBrushOrgEx(hdc,brushOrg.x, brushOrg.y, &tempPoint);
#else
::SetBrushOrg( hdc, brushOrg.x, brushOrg.y );
#endif
// Erase the background
::FillRect(hdc, (RECT*)&Rect, hBrush);
VERIFY(::DeleteObject(hBrush));
#ifdef _WIN32
// Restore the brush origin
::SetBrushOrgEx(hdc, tempPoint.x, tempPoint.y, NULL);
#endif
ReleaseContextDC(hdc);
return;
}
if (mask) {
maskInfo = (FEBitmapInfo*) mask->client_data;
}
// If the width (or height) of the image is less than the smaller of
// 32 and half the width (or height) of the area to be tiled, then tile the
// image into a larger temporary bitmap and use the temporary bitmap
// as the tile. We also limit the actual area of the temporary tile to 4096.
iOrigWidth = imageInfo->width * GetXConvertUnit();
iOrigHeight = imageInfo->height *GetYConvertUnit();
iRectWidth = Rect.right - Rect.left;
iRectHeight = Rect.bottom - Rect.top;
iMinTileWidth = MIN(32,MAX(iRectWidth/2,1)); // Tile must be at least this wide.
iMinTileHeight = MIN(32,MAX(iRectHeight/2,1)); // Tile must be at least this high.
iTileWidth = ROUNDUP(iMinTileWidth, iOrigWidth); // Actual width of temporary tile.
iTileHeight = ROUNDUP(iMinTileHeight, iOrigHeight); // Actual height of temporary tile.
if ((iOrigWidth < iMinTileWidth || iOrigHeight < iMinTileHeight) &&
(iTileWidth * iTileHeight < 4096)) {
HDC pTmpDC = NULL;
// Create a temporary larger tile and use it instead of the original tile.
HDC hhDC = GetContextDC();
pTmpDC = CreateCompatibleDC(hhDC);
ReleaseContextDC(hhDC);
if (!pTmpDC)
return;
HPALETTE hOldPal;
if (m_bUseDibPalColors)
hOldPal = ::SelectPalette(pTmpDC, GetPalette(), FALSE);
pTmpImageBitmap = CreateLargerTile(hhDC, pTmpDC, m_pImageDC,
image, m_bUseDibPalColors,
iOrigWidth, iOrigHeight,
iTileWidth, iTileHeight);
if (!pTmpImageBitmap) { // OOM
if (m_bUseDibPalColors)
::SelectPalette(pTmpDC, hOldPal, FALSE);
VERIFY(::DeleteDC(pTmpDC));
return;
}
if (mask) {
pTmpMaskBitmap = CreateLargerTile(hhDC, pTmpDC, m_pImageDC,
mask, m_bUseDibPalColors,
iOrigWidth, iOrigHeight,
iTileWidth, iTileHeight);
if (!pTmpMaskBitmap) { // OOM
if (m_bUseDibPalColors)
::SelectPalette(pTmpDC, hOldPal, FALSE);
VERIFY(::DeleteDC(pTmpDC));
VERIFY(::DeleteObject(pTmpImageBitmap));
return;
}
}
pSavedImageBitmap = imageInfo->hBitmap;
imageInfo->hBitmap = pTmpImageBitmap;
imageInfo->width = iTileWidth;
imageInfo->height = iTileHeight;
if (mask) {
pSavedMaskBitmap = maskInfo->hBitmap;
maskInfo->hBitmap = pTmpMaskBitmap;
maskInfo->width = iTileWidth;
maskInfo->height = iTileHeight;
}
if (m_bUseDibPalColors)
::SelectPalette(pTmpDC, hOldPal, FALSE);
VERIFY(::DeleteDC(pTmpDC));
}
// Set a flag to indicate that we are in the tiling code.
imageInfo->IsTile = TRUE;
if (mask)
maskInfo->IsTile = TRUE;
// If we are going to call StretchPixmap, avoid selecting the image bitmap
// into the memory DC each time.
if (!mask && imageInfo->hBitmap)
pOldObj = ::SelectObject(m_pImageDC, imageInfo->hBitmap);
// We need to properly align the backdrop vertically (in logical units)
int srcY = CASTINT((((Rect.top - GetTopMargin())/ GetYConvertUnit()) - lDrawingOrgY + m_lOrgY ) % (imageInfo->height));
int dstHeight = CASTINT((imageInfo->height* GetYConvertUnit()) - (srcY * GetYConvertUnit()));
// MWH -- this loop needs a rewrite. I just do this for first pass on win16 compiler.
// Should not check for the which Blt we want to use inside the loop.
// Redraw the backdrop from left to right and top to bottom
for (int currentY = CASTINT(Rect.top); currentY < CASTINT(Rect.bottom);) {
// We need to properly align the backdrop horizontally (in logical units)
int srcX = CASTINT((((Rect.left - GetLeftMargin()) / GetXConvertUnit()) - lDrawingOrgX + m_lOrgX)% (imageInfo->width));
int dstWidth = CASTINT((imageInfo->width * GetXConvertUnit()) - srcX * GetXConvertUnit());
// Only draw as far down as we've been asked to draw
if (CASTINT(currentY + dstHeight) > CASTINT(Rect.bottom))
dstHeight = CASTINT(Rect.bottom - currentY);
// Loop across the row
for (int currentX = CASTINT(Rect.left); currentX < CASTINT(Rect.right);) {
// Only draw as far across as we've been asked to draw
if (currentX + dstWidth > Rect.right)
dstWidth = CASTINT(Rect.right - currentX);
// m_pImageDC is in device space, so we need to convert coordinates
RECT srcRect;
::SetRect(&srcRect, srcX, srcY, srcX + (dstWidth/ GetXConvertUnit()), srcY + (dstHeight/ GetYConvertUnit()));
if (mask) {
if (imageInfo->hBitmap && maskInfo->hBitmap) {
#ifdef _WIN32
if (sysInfo.m_bWinNT && (GetContextType() != MetaFile)) {
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap);
#ifdef USE_DIB_SECTION
if (image->bits)
MaskBlt(hdc,
currentX, currentY,
dstWidth,
dstHeight,
m_pImageDC, srcRect.left, srcRect.top,
maskInfo->hBitmap,
srcRect.left, srcRect.top,
MAKEROP4(SRCCOPY, 0x00AA0029)); // 0x00AA0029 is destination...
else
#endif
MaskBlt(hdc,
currentX, currentY,
dstWidth,
dstHeight,
m_pImageDC, srcRect.left, srcRect.top,
maskInfo->hBitmap,
srcRect.left, srcRect.top,
MAKEROP4(0x00AA0029, SRCCOPY)); // 0x00AA0029 is destination...
::SelectObject(m_pImageDC, hOldBitmap);
}
else
#endif
StretchMaskBlt(hdc,
imageInfo->hBitmap, maskInfo->hBitmap,
currentX, currentY,
dstWidth,
dstHeight,
srcRect.left, srcRect.top,
srcRect.right - srcRect.left,
srcRect.bottom - srcRect.top);
}
else { // blt bitmap with mask.
_StretchDIBitsWithMask(hdc,
currentX, currentY,
dstWidth,
dstHeight,
srcRect.left,
// the reason for this calculation is that Window's bitmap
// is reverse. The first scan line will be at the bottom of
// the bitmap buffer.
imageInfo->height - srcRect.bottom,
srcRect.right - srcRect.left,
srcRect.bottom - srcRect.top,
image,
mask);
}
}
else {
StretchPixmap(hdc, image,
currentX, currentY,
dstWidth,
dstHeight,
srcRect.left, srcRect.top,
srcRect.right - srcRect.left,
srcRect.bottom - srcRect.top);
}
currentX += dstWidth;
srcX = 0;
dstWidth = imageInfo->width * GetXConvertUnit();
}
currentY += dstHeight;
srcY = 0;
dstHeight = imageInfo->height * GetYConvertUnit();
}
// If we called StretchPixmap, restore the memory DC to its previous state.
if (!mask && imageInfo->hBitmap)
::SelectObject(m_pImageDC, pOldObj);
// If we created a temporary tile, then restore the original bitmaps.
if (pTmpImageBitmap) {
imageInfo->width = iOrigWidth;
imageInfo->height = iOrigHeight;
imageInfo->hBitmap = pSavedImageBitmap;
VERIFY(::DeleteObject(pTmpImageBitmap));
}
if (pTmpMaskBitmap) {
maskInfo->width = iOrigWidth;
maskInfo->height = iOrigHeight;
maskInfo->hBitmap = pSavedMaskBitmap;
VERIFY(::DeleteObject(pTmpMaskBitmap));
}
// Reset the flags to indicate that we are done tiling.
imageInfo->IsTile = FALSE;
if (mask)
maskInfo->IsTile = FALSE;
}