2296 lines
55 KiB
C
2296 lines
55 KiB
C
/*****************************************************************************
|
|
* *
|
|
* BITMAP.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1989. *
|
|
* All Rights reserved. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Module Intent *
|
|
* This module will read graphics in from the file system, provide *
|
|
* the layout engine with the correct information to lay them out, and *
|
|
* then display the graphic. It currently handles bitmaps and metafiles. *
|
|
*****************************************************************************/
|
|
|
|
#include "help.h"
|
|
#include "inc\_bitmap.h"
|
|
#include "inc\shed.h"
|
|
|
|
#define MAXBMP_CACHED 30 // Maximum number of cached bitmaps
|
|
|
|
#define PALVERSION 0x300
|
|
#define MAXPALETTE 256 // max. # supported palette entries
|
|
|
|
// Metafile handle
|
|
|
|
// Display information for bitmaps and metafiles
|
|
|
|
typedef struct {
|
|
int cxDest, cyDest; // Size of final layout rectangle
|
|
int cxSrc, cySrc; // Size of source bitmap in the case of bitmaps
|
|
/* Contains logical size of the picture in case */
|
|
/* metafiles */
|
|
int mm; // Mapping mode (metafile only)
|
|
} DI;
|
|
|
|
/*
|
|
* Bitmap Access information. Contains information necessary to draw
|
|
* the bitmap.
|
|
*/
|
|
|
|
typedef GH HHSI; // Handle to hotspot information
|
|
typedef struct {
|
|
HBM hbm; // Bitmap handle, if already loaded
|
|
HPALETTE hpal; // palette, if there is one
|
|
HMETAFILE hmf; // Metafile handle.
|
|
HHSI hhsi; // Hotspot information
|
|
DI di; // Display information
|
|
BOOL fMonochrome; // TRUE if monochrome bitmap
|
|
int cBitmap; // Bitmap number in filesystem (-1 if inline)
|
|
int bmFormat; // indicates if metafile or bitmap.
|
|
int idOom; // id resource to display for bad bitmap
|
|
} BMA, * QBMA;
|
|
|
|
// Information about bitmaps on disk. Used in the bitmap cache.
|
|
|
|
typedef struct {
|
|
int cBitmap; // bitmap number from disk
|
|
DWORD ref; // LRU reference tag
|
|
HBMH hbmh;
|
|
LONG lcbSize;
|
|
LONG lcbOffset;
|
|
DI di; // Display information
|
|
HBM hbmCached; // Discardable bitmap created out of Metafile
|
|
// for performance reasons.
|
|
COLORREF hbmCachedColor; // Cached bitmap's background color.
|
|
} BMI, * QBMI;
|
|
|
|
/*
|
|
* Table of information about bitmaps on disk. This is the bitmap cache
|
|
* kept with each DE.
|
|
*/
|
|
typedef struct {
|
|
DWORD ref; // Incrementing reference counter
|
|
LONG cbAllocated;
|
|
BMI abmi[MAXBMP_CACHED];
|
|
} BM_CACHE, * PBM_CACHE;
|
|
#define HBM_CACHE GH
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static const char txtDisplay[] = "DISPLAY";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
int cSystemColors;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
static VOID STDCALL DeallocQbmi(QBMI, PBM_CACHE);
|
|
static QBMI FASTCALL GetCachedBmi(PBM_CACHE, int);
|
|
INLINE static QBMI STDCALL GetLruBmi(PBM_CACHE);
|
|
static VOID FASTCALL UpdateReference(QBMI, PBM_CACHE);
|
|
|
|
#ifdef _X86_
|
|
static int CSelectBitmap(QBGH, int, int, int, int);
|
|
#else
|
|
static int CSelectBitmap(QBGH, QV, int, int, int, int);
|
|
#endif
|
|
static VOID DeleteGraphic(QBMA);
|
|
static DI DiFromQbmh(QBMH, QDE qde);
|
|
static HBGH HbghReadBitmapHfs(HFS, int, LONG *);
|
|
static DWORD WValueQbmh(QBMH, int, int, int, int);
|
|
|
|
static HPALETTE STDCALL CreateBIPalette(LPBITMAPINFOHEADER lpbihd);
|
|
static HBITMAP STDCALL HbmFromQbmh(QBMH, HDC, HPALETTE);
|
|
static HHSI HhsiFromQbmh(QBMH);
|
|
INLINE static HMETAFILE HmfFromQbmh(QBMH);
|
|
static void STDCALL InitializeQbma(QBMH qbmh, QBMA qbma, QDE qde);
|
|
static VOID MakeOOMBitmap(QBMA, HDC, int idResource);
|
|
static VOID RenderOOMBitmap(QBMA, HDC, PT, BOOL);
|
|
static DWORD STDCALL SizeMetaFilePict (HDC hdc, METAFILEPICT mfp);
|
|
|
|
#ifndef _X86_
|
|
HBGH HbghFromQIsdff( QB, SDFF_FILEID);
|
|
#endif
|
|
|
|
#ifndef _X86_
|
|
|
|
QV QVSkipQGA(QV qga, QW qw)
|
|
{
|
|
WORD wTmp;
|
|
|
|
if( *((QB)qga) & 1 ) {
|
|
MoveMemory( &wTmp, qga, sizeof( WORD ) );
|
|
*qw = wTmp >> 1;
|
|
return( ((QW)qga) + 1 );
|
|
}
|
|
else {
|
|
*qw = *((QB)qga) >> 1;
|
|
return( ((QB)qga) + 1 );
|
|
}
|
|
}
|
|
|
|
QV QVSkipQGB(QV qgb, QL ql)
|
|
{
|
|
if (*((QB) qgb) & 1) {
|
|
DWORD dwTmp;
|
|
|
|
MoveMemory(&dwTmp, qgb, sizeof(DWORD));
|
|
*ql = dwTmp >> 1;
|
|
return(((QUL) qgb) + 1);
|
|
}
|
|
else {
|
|
WORD wTmp;
|
|
|
|
MoveMemory( &wTmp, qgb, sizeof( WORD ) );
|
|
*ql = wTmp >> 1;
|
|
return( ((QW)qgb) + 1 );
|
|
}
|
|
}
|
|
|
|
#endif // _X86_
|
|
/***************************************************************************
|
|
*
|
|
- Name HtbmiAlloc
|
|
-
|
|
* Purpose
|
|
* Allocates space for the bitmaps cache, so they don't have to be
|
|
* read off disk every time the topic is laid out.
|
|
*
|
|
* Arguments
|
|
* qde - A pointer to the display environment.
|
|
*
|
|
* Returns
|
|
* A handle to the bitmap cache.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* Bitmaps contained in the cache are specific to the display surface
|
|
* used. This should never change while using the same cache.
|
|
*
|
|
***************************************************************************/
|
|
|
|
HGLOBAL STDCALL HtbmiAlloc(const QDE qde)
|
|
{
|
|
QBMI qbmi;
|
|
PBM_CACHE pCache = (PBM_CACHE) GhAlloc(GPTR, sizeof(BM_CACHE));
|
|
|
|
if (pCache) {
|
|
pCache->ref = 1;
|
|
for (qbmi = &pCache->abmi[0];
|
|
qbmi < &pCache->abmi[MAXBMP_CACHED];
|
|
++qbmi) {
|
|
qbmi->cBitmap = -1;
|
|
qbmi->hbmCachedColor = qde->coBack;
|
|
}
|
|
}
|
|
|
|
return (HGLOBAL) pCache;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name DestroyHtbmi
|
|
-
|
|
* Purpose
|
|
* Frees the bitmap cache, and all the bitmaps in it.
|
|
*
|
|
* Arguments
|
|
* Handle to the bitmap cache.
|
|
*
|
|
* Returns
|
|
* Nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
VOID STDCALL DestroyHtbmi(HBM_CACHE htbmi)
|
|
{
|
|
BMI* pbmi;
|
|
PBM_CACHE pCache;
|
|
|
|
if (htbmi) {
|
|
pCache = PtrFromGh (htbmi);
|
|
for (pbmi = &pCache->abmi[0];
|
|
pbmi < &pCache->abmi[MAXBMP_CACHED];
|
|
++pbmi)
|
|
DeallocQbmi(pbmi, pCache);
|
|
FreeGh(htbmi);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: DeallocQbmi
|
|
-
|
|
* Purpose:
|
|
* Deallocates the memory associated with a BMI
|
|
*
|
|
* Arguments:
|
|
* qbmi - far pointer to the bmi
|
|
*
|
|
* Returns:
|
|
* nothing
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
static VOID STDCALL DeallocQbmi(QBMI qbmi, PBM_CACHE pCache)
|
|
{
|
|
if (qbmi->hbmh)
|
|
FreeHbmh(qbmi->hbmh);
|
|
|
|
SafeDeleteObject(qbmi->hbmCached);
|
|
|
|
qbmi->ref = 0;
|
|
qbmi->hbmh = NULL;
|
|
qbmi->hbmCached = NULL;
|
|
qbmi->cBitmap = -1;
|
|
pCache->cbAllocated -= qbmi->lcbSize;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name DiscardBitmapsHde
|
|
-
|
|
* Purpose
|
|
* Discards all the bitmaps in the bitmap cache. For debugging
|
|
* purposes only.
|
|
*
|
|
* Arguments
|
|
* Handle to the display environment.
|
|
*
|
|
* Returns
|
|
* Nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* Since we cannot actually cause Windows to discard the handles
|
|
* (GlobalDiscard just reallocs it to zero length), we fake it by
|
|
* setting hbmh to -1. This will cause us to execute the same
|
|
* code as if it were discarded.
|
|
*
|
|
***************************************************************************/
|
|
|
|
void STDCALL DiscardBitmapsHde(QDE qde)
|
|
{
|
|
if (QDE_HTBMI(qde)) {
|
|
DestroyHtbmi(QDE_HTBMI(qde));
|
|
QDE_HTBMI(qde) = HtbmiAlloc(qde);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HbmaAlloc
|
|
-
|
|
* Purpose
|
|
* This function is called by the layout engine to load a given
|
|
* bitmap and prepare it for display. The bitmap may be selected
|
|
* from a group based upon the display surface given in the qde.
|
|
*
|
|
* Arguments
|
|
* QDE: Pointer to the display environment.
|
|
* QOBM: Pointer to the bitmap object. This may contain the
|
|
* bitmap directly, or refer to a bitmap on disk.
|
|
*
|
|
* Returns
|
|
* A handle to bitmap access information, which may later be used
|
|
* to get more layout information, or to display the bitmap.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
int cxAspect, cyAspect, cBitCount, cPlanes;
|
|
|
|
HBMA STDCALL HbmaAlloc(QDE qde, QOBM qobm)
|
|
{
|
|
HBMA hbma;
|
|
QBMA qbma;
|
|
HBGH hbgh;
|
|
QBGH qbgh;
|
|
HBMH hbmh;
|
|
QBMH qbmh;
|
|
#ifndef _X86_
|
|
GH hData;
|
|
QV qData;
|
|
OBM obm;
|
|
#endif
|
|
BYTE bmFormat;
|
|
int cBest;
|
|
LONG lcb;
|
|
|
|
ASSERT(qde != NULL);
|
|
ASSERT(qde->hdc != NULL);
|
|
|
|
hbma = GhAlloc(GPTR, sizeof(BMA)); // must be zero-initialized
|
|
if (hbma == NULL)
|
|
return NULL;
|
|
|
|
qbma = PtrFromGh(hbma);
|
|
|
|
qbma->cBitmap = -1;
|
|
|
|
#ifndef _X86_
|
|
// qobm is a disk image!!
|
|
// The OBM should be made an SDFF structure
|
|
|
|
// Lynn - why are we doing this? QOBM is a structure with 2 shorts. There
|
|
// should be no alignment problems with that. We're ending up with an awful
|
|
// lot of conditionalized code here just to get two longs instead of two
|
|
// shorts. If that's really a problem, then let's just create an OBM32 for
|
|
// x86, assign the values and toss all this conditionalized code
|
|
|
|
(QB)qobm += LcbQuickMapSDFF(ISdffFileIdHfs(QDE_HFS(qde)), TE_WORD, &obm.fInline, qobm);
|
|
/* Note that if obm.fInline, qobm now points to the BGH */
|
|
if (!obm.fInline)
|
|
(QB)qobm += LcbQuickMapSDFF(ISdffFileIdHfs(QDE_HFS(qde)), TE_SHORT, &obm.cBitmap, qobm);
|
|
|
|
// Check for error in compile:
|
|
if (!obm.fInline && obm.cBitmap < 0) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BITMAP);
|
|
return hbma;
|
|
}
|
|
#else
|
|
|
|
// Check for error in compile:
|
|
if (!qobm->fInline && qobm->cBitmap < 0) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BITMAP);
|
|
return hbma;
|
|
}
|
|
#endif
|
|
|
|
if (!cxAspect) {
|
|
cxAspect = GetDeviceCaps(qde->hdc, LOGPIXELSX);
|
|
cyAspect = GetDeviceCaps(qde->hdc, LOGPIXELSY);
|
|
cBitCount = GetDeviceCaps(qde->hdc, BITSPIXEL);
|
|
cPlanes = GetDeviceCaps(qde->hdc, PLANES);
|
|
}
|
|
|
|
/*
|
|
* Check to see if bitmap should go into cache. Note that the bitmap
|
|
* cache is a device specific entity, and cannot be used while printing.
|
|
*/
|
|
|
|
#ifdef _X86_
|
|
if (!qobm->fInline && QDE_HTBMI(qde) && (qde->deType != dePrint)) {
|
|
PBM_CACHE pCache;
|
|
QBMI qbmi;
|
|
|
|
pCache = PtrFromGh(QDE_HTBMI(qde)); // Get pointer to our cache
|
|
|
|
// Point qbmi at the correct cached entry
|
|
|
|
qbmi = (QBMI) GetCachedBmi(pCache, qobm->cBitmap);
|
|
|
|
// If bitmap has not been cached, then do so
|
|
|
|
if (!qbmi) {
|
|
qbmi = GetLruBmi(pCache);
|
|
DeallocQbmi(qbmi, pCache);
|
|
qbmi->cBitmap = qobm->cBitmap;
|
|
UpdateReference(qbmi, pCache);
|
|
|
|
hbgh = HbghReadBitmapHfs(QDE_HFS(qde), qobm->cBitmap, &lcb);
|
|
if (hbgh == NULL) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BMP_READ);
|
|
DeallocQbmi(qbmi, pCache);
|
|
return hbma;
|
|
}
|
|
qbgh = PtrFromGh(hbgh);
|
|
#else
|
|
if (!obm.fInline && QDE_HTBMI(qde) && (qde->deType != dePrint)) {
|
|
PBM_CACHE pCache;
|
|
QBMI qbmi;
|
|
|
|
pCache = PtrFromGh(QDE_HTBMI(qde)); // Get pointer to our cache
|
|
|
|
// Point qbmi at the correct cached entry
|
|
|
|
qbmi = (QBMI) GetCachedBmi(pCache, obm.cBitmap);
|
|
|
|
// If bitmap has not been cached, then do so
|
|
|
|
if (!qbmi) {
|
|
qbmi = GetLruBmi(pCache);
|
|
DeallocQbmi(qbmi, pCache);
|
|
qbmi->cBitmap = obm.cBitmap;
|
|
UpdateReference(qbmi, pCache);
|
|
|
|
hData = HbghReadBitmapHfs(QDE_HFS(qde), obm.cBitmap, &lcb);
|
|
if (hData == NULL) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BMP_READ);
|
|
DeallocQbmi(qbmi, pCache);
|
|
return hbma;
|
|
}
|
|
qData = PtrFromGh(hData);
|
|
hbgh = HbghFromQIsdff( qData, ISdffFileIdHfs(QDE_HFS(qde)) );
|
|
qbgh = PtrFromGh(hbgh);
|
|
#endif
|
|
|
|
if (qbgh->wVersion != wBitmapVersion2 &&
|
|
qbgh->wVersion != wBitmapVersion3) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_UNSUPPORTED_BMP);
|
|
FreeGh(hbgh);
|
|
DeallocQbmi(qbmi, pCache);
|
|
return hbma;
|
|
}
|
|
|
|
// Select best bitmap
|
|
|
|
#ifdef _X86_
|
|
cBest = CSelectBitmap(qbgh,cxAspect, cyAspect, cPlanes, cBitCount);
|
|
#else
|
|
cBest = CSelectBitmap(qbgh, qData, cxAspect, cyAspect, cPlanes, cBitCount);
|
|
#endif
|
|
if (cBest == -1) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_MRB);
|
|
FreeGh(hbgh);
|
|
DeallocQbmi(qbmi, pCache);
|
|
return hbma;
|
|
}
|
|
|
|
// Save size and offset of that bitmap
|
|
|
|
qbmi->lcbOffset = qbgh->rglcbBmh[cBest];
|
|
if (cBest == qbgh->cbmhMac - 1)
|
|
qbmi->lcbSize = lcb - qbmi->lcbOffset;
|
|
else
|
|
qbmi->lcbSize = qbgh->rglcbBmh[cBest + 1] - qbmi->lcbOffset;
|
|
pCache->cbAllocated += qbmi->lcbSize;
|
|
|
|
// Expand bitmap data into handle
|
|
|
|
#ifdef _X86_
|
|
qbmi->hbmh = HbmhExpandQv(RFromRCb(qbgh, qbgh->rglcbBmh[cBest]));
|
|
#else
|
|
qbmi->hbmh = HbmhExpandQv(RFromRCb(qData, qbgh->rglcbBmh[cBest]),
|
|
ISdffFileIdHfs(QDE_HFS(qde)) );
|
|
#endif
|
|
FreeGh(hbgh);
|
|
|
|
if (qbmi->hbmh == hbmhInvalid)
|
|
qbmi->hbmh = hbmhOOM;
|
|
if (qbmi->hbmh == hbmhOOM) {
|
|
MakeOOMBitmap(qbma, qde->hdc, -1);
|
|
DeallocQbmi(qbmi, pCache);
|
|
return hbma;
|
|
}
|
|
|
|
qbmh = PtrFromGh(qbmi->hbmh);
|
|
bmFormat = qbmh->bmFormat;
|
|
qbmi->di = DiFromQbmh(qbmh, qde);
|
|
}
|
|
else {
|
|
UpdateReference(qbmi, pCache);
|
|
}
|
|
|
|
// Copy information into qbma
|
|
|
|
#ifdef _X86_
|
|
qbma->cBitmap = qobm->cBitmap;
|
|
#else
|
|
qbma->cBitmap = obm.cBitmap;
|
|
#endif
|
|
qbma->di = qbmi->di;
|
|
qbmh = PtrFromGh(qbmi->hbmh);
|
|
if (qbmh) {
|
|
qbma->hhsi = HhsiFromQbmh(qbmh);
|
|
|
|
/*
|
|
* Since we will be shortly displaying this, let's initialize
|
|
* the stuff. This takes care of the case where the cached
|
|
* information is discarded before we can display it.
|
|
*/
|
|
|
|
InitializeQbma(qbmh, qbma, qde);
|
|
}
|
|
else {
|
|
qbma->hhsi = NULL;
|
|
qbma->hbm = NULL;
|
|
qbma->hmf = NULL;
|
|
}
|
|
|
|
return hbma;
|
|
}
|
|
|
|
// Get pointer to group header
|
|
|
|
#ifdef _X86_
|
|
if (qobm->fInline)
|
|
qbgh = (QBGH) &qobm->cBitmap;
|
|
else {
|
|
hbgh = HbghReadBitmapHfs(QDE_HFS(qde), qobm->cBitmap, NULL);
|
|
if (hbgh == NULL) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BMP_READ);
|
|
return hbma;
|
|
}
|
|
qbgh = PtrFromGh(hbgh);
|
|
}
|
|
#else
|
|
if (obm.fInline)
|
|
qData = qobm;
|
|
else {
|
|
hData = HbghReadBitmapHfs(QDE_HFS(qde), obm.cBitmap, NULL);
|
|
if (hData == NULL) {
|
|
MakeOOMBitmap(qbma, qde->hdc, wERRS_BAD_BMP_READ);
|
|
return hbma;
|
|
}
|
|
qData = PtrFromGh(hData);
|
|
}
|
|
hbgh = HbghFromQIsdff( qData, ISdffFileIdHfs(QDE_HFS(qde)) );
|
|
qbgh = PtrFromGh(hbgh);
|
|
#endif
|
|
|
|
// Select bitmap to use
|
|
|
|
#ifdef _X86_
|
|
cBest = CSelectBitmap(qbgh, cxAspect, cyAspect, cPlanes, cBitCount);
|
|
if (cBest == -1 || (hbmh = HbmhExpandQv(
|
|
RFromRCb(qbgh, qbgh->rglcbBmh[cBest]))) == hbmhOOM ||
|
|
hbmh == hbmhInvalid) {
|
|
MakeOOMBitmap(qbma, qde->hdc, (hbmh != hbmhOOM) ? wERRS_BAD_MRB : -1);
|
|
}
|
|
#else
|
|
cBest = CSelectBitmap(qbgh, qData, cxAspect, cyAspect, cPlanes, cBitCount);
|
|
if (cBest == -1 || (hbmh = HbmhExpandQv(
|
|
RFromRCb(qbgh, qbgh->rglcbBmh[cBest]),ISdffFileIdHfs(QDE_HFS(qde)))) == hbmhOOM ||
|
|
hbmh == hbmhInvalid) {
|
|
MakeOOMBitmap(qbma, qde->hdc, (hbmh != hbmhOOM) ? wERRS_BAD_MRB : -1);
|
|
}
|
|
#endif
|
|
else {
|
|
qbmh = PtrFromGh(hbmh);
|
|
InitializeQbma(qbmh, qbma, qde);
|
|
qbma->di = DiFromQbmh(qbmh, qde);
|
|
qbma->hhsi = HhsiFromQbmh(qbmh);
|
|
FreeHbmh(hbmh);
|
|
}
|
|
|
|
// Free resources and return
|
|
|
|
#ifdef _X86_
|
|
if (!qobm->fInline)
|
|
#else
|
|
if (!obm.fInline)
|
|
#endif
|
|
FreeGh(hbgh);
|
|
return hbma;
|
|
}
|
|
|
|
static HHSI HhsiFromQbmh(QBMH qbmh)
|
|
{
|
|
HHSI hhsi;
|
|
|
|
if (qbmh->lcbSizeExtra == 0L)
|
|
return NULL;
|
|
|
|
hhsi = (HHSI) GhAlloc(GPTR, qbmh->lcbSizeExtra);
|
|
if (hhsi == NULL)
|
|
return NULL;
|
|
MoveMemory(PtrFromGh(hhsi), RFromRCb(qbmh, qbmh->lcbOffsetExtra),
|
|
qbmh->lcbSizeExtra);
|
|
return hhsi;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name DiFromQbmh
|
|
-
|
|
* Purpose
|
|
* This function calculates and returns the display information,
|
|
* including destination rectangle, from the bitmap header. Works
|
|
* for bitmaps and metafiles.
|
|
*
|
|
* Arguments
|
|
* A pointer to the bitmap header, and a handle to the display
|
|
* surface.
|
|
*
|
|
* Returns
|
|
* The display information for the given graphic.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* For bitmaps, display information consists of the size of the
|
|
* source and destination rectangles. For metafiles, it is the size
|
|
* of the destination rectangle, and the mapping mode.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static DI DiFromQbmh(QBMH qbmh, QDE qde)
|
|
{
|
|
DI di;
|
|
DWORD lext;
|
|
HDC hdc = qde->hdc;
|
|
|
|
switch (qbmh->bmFormat) {
|
|
case bmDIB:
|
|
case bmWbitmap:
|
|
di.cxSrc = qbmh->w.dib.biWidth;
|
|
di.cySrc = qbmh->w.dib.biHeight;
|
|
|
|
#ifdef _DEBUG
|
|
if (qbmh->w.dib.biXPelsPerMeter != 0 &&
|
|
qbmh->w.dib.biYPelsPerMeter != 0) {
|
|
if (qbmh->w.dib.biXPelsPerMeter < 72 ||
|
|
qbmh->w.dib.biXPelsPerMeter > 150 ||
|
|
qbmh->w.dib.biYPelsPerMeter < 72 ||
|
|
qbmh->w.dib.biYPelsPerMeter > 150) {
|
|
char szBuf[256];
|
|
wsprintf(szBuf, "Bad aspect ratio: %u x %u",
|
|
qbmh->w.dib.biXPelsPerMeter,
|
|
qbmh->w.dib.biYPelsPerMeter);
|
|
DBWIN(szBuf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (qbmh->w.dib.biXPelsPerMeter == 0 ||
|
|
qbmh->w.dib.biYPelsPerMeter == 0) {
|
|
if (qde->deType != dePrint) {
|
|
di.cxDest = qbmh->w.dib.biWidth;
|
|
di.cyDest = qbmh->w.dib.biHeight;
|
|
}
|
|
else {
|
|
di.cxDest = qbmh->w.dib.biWidth * cxAspect / 96;
|
|
di.cyDest = qbmh->w.dib.biHeight * cyAspect / 96;
|
|
}
|
|
}
|
|
else {
|
|
di.cxDest = qbmh->w.dib.biWidth *
|
|
cxAspect /
|
|
qbmh->w.dib.biXPelsPerMeter;
|
|
di.cyDest = qbmh->w.dib.biHeight *
|
|
cyAspect /
|
|
qbmh->w.dib.biYPelsPerMeter;
|
|
}
|
|
if (qde->deType == dePrint) {
|
|
if (di.cxDest > RECT_WIDTH(qde->rct))
|
|
di.cxDest = RECT_WIDTH(qde->rct);
|
|
if (di.cyDest > RECT_HEIGHT(qde->rct))
|
|
di.cyDest = RECT_HEIGHT(qde->rct);
|
|
}
|
|
break;
|
|
|
|
case bmWmetafile:
|
|
di.mm = (INT16) qbmh->w.mf.mm;
|
|
lext = SizeMetaFilePict(hdc, qbmh ->w.mf);
|
|
di.cxDest = LOWORD(lext);
|
|
di.cyDest = HIWORD(lext);
|
|
di.cxSrc = qbmh->w.mf.xExt; // logical width
|
|
di.cySrc = qbmh->w.mf.yExt; // logical height
|
|
break;
|
|
}
|
|
|
|
return di;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name DeleteGraphic
|
|
-
|
|
* Purpose
|
|
* Deletes the hbm and/or hmf fields from the given qbma.
|
|
*
|
|
* Arguments
|
|
* A pointer to the bitmap access information.
|
|
*
|
|
* Returns
|
|
* Nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* I don't think that both objects can be simultaneously non-nil.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static VOID DeleteGraphic(QBMA qbma)
|
|
{
|
|
SafeDeleteObject(qbma->hbm);
|
|
SafeDeleteObject(qbma->hpal);
|
|
qbma->hbm = NULL;
|
|
qbma->hpal = NULL;
|
|
|
|
if (qbma->hmf != NULL) {
|
|
DeleteMetaFile(qbma->hmf);
|
|
qbma->hmf = NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name FreeHbma
|
|
-
|
|
* Purpose
|
|
* Frees all the resources allocated in the hbma, and then frees
|
|
* the hbma itself.
|
|
*
|
|
* Arguments
|
|
* A handle to the bitmap access information.
|
|
*
|
|
* Returns
|
|
* Nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
void STDCALL FreeHbma(HBMA hbma)
|
|
{
|
|
QBMA qbma;
|
|
|
|
ASSERT(hbma);
|
|
|
|
qbma = PtrFromGh(hbma);
|
|
|
|
DeleteGraphic(qbma);
|
|
|
|
if (qbma->hhsi != NULL)
|
|
FreeGh(qbma->hhsi);
|
|
FreeGh(hbma);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HbghReadBitmapHfs
|
|
-
|
|
* Purpose
|
|
* Reads in the given bitmap from the given filesystem, and optionally
|
|
* returns its size.
|
|
*
|
|
* Arguments
|
|
* hfs: The filesystem handle containing the bitmap.
|
|
* cBitmap: The number of the bitmap within that file system.
|
|
* plcb: A pointer to a long. This may be nil.
|
|
*
|
|
* Returns
|
|
* A handle to the bitmap group header, followed by all the uncompressed
|
|
* bitmaps. If plcb is not nil, it returns the size of all the data in
|
|
* *plcb. Returns NULL on error (out of memory, or file does not exist.)
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static HBGH HbghReadBitmapHfs(HFS hfs, int cBitmap, LONG* plcb)
|
|
{
|
|
char szBuffer[15];
|
|
HBGH hbgh;
|
|
QBGH qbgh;
|
|
HF hf;
|
|
LONG lcb;
|
|
|
|
// Open file in file system
|
|
|
|
wsprintf(szBuffer, "|bm%d", cBitmap);
|
|
hf = HfOpenHfs(hfs, szBuffer, fFSOpenReadOnly);
|
|
|
|
// Check for 3.0 file naming conventions:
|
|
|
|
if (hf == NULL && RcGetFSError() == rcNoExists)
|
|
hf = HfOpenHfs(hfs, szBuffer + 1, fFSOpenReadOnly);
|
|
|
|
// If file does not exist, just make OOM bitmap:
|
|
|
|
// ASSERT(hf);
|
|
if (hf == NULL)
|
|
return NULL;
|
|
|
|
// Allocate global handle
|
|
|
|
lcb = ((QRWFO) PtrFromGh(hf)) ->lcbFile;
|
|
hbgh = (HBGH) GhAlloc(GPTR, lcb);
|
|
ASSERT(hbgh);
|
|
if (hbgh == NULL) {
|
|
RcCloseHf(hf);
|
|
return NULL;
|
|
}
|
|
|
|
// Read in data
|
|
|
|
qbgh = PtrFromGh(hbgh);
|
|
if (LcbReadHf(hf, qbgh, lcb) != lcb)
|
|
ASSERT(FALSE);
|
|
if (plcb != NULL)
|
|
*plcb = lcb;
|
|
|
|
RcCloseHf(hf);
|
|
return hbgh;
|
|
}
|
|
#ifndef _X86_
|
|
/***************************************************************************
|
|
*
|
|
- HbghFromQIsdff
|
|
-
|
|
* Purpose:
|
|
* extracts an hbgh from the given memory. Runs the data through SDFF
|
|
* to accomplish this in the correct way.
|
|
*
|
|
* Arguments:
|
|
* qv - the memory to decode
|
|
* isdff - the sdff reference to use for decoding
|
|
*
|
|
* Returns:
|
|
* a handle to the SDFFed copy of the hbgh found at *qv or hNil if
|
|
* there's a problem, like OOM.
|
|
*
|
|
* Globals Used:
|
|
* none
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
HBGH HbghFromQIsdff( QB qb, SDFF_FILEID isdff )
|
|
{
|
|
BGH bgh;
|
|
DWORD FAR * qdw;
|
|
LONG lcb;
|
|
HBGH hbgh;
|
|
QBGH qbgh;
|
|
|
|
qb += LcbMapSDFF(isdff, SE_BGH, &bgh, qb);
|
|
|
|
/* allocate space to put the whole structure in including that pesky
|
|
variable length table of offsets */
|
|
lcb = sizeof(BGH) + (bgh.cbmhMac) * sizeof(DWORD);
|
|
|
|
hbgh = (HBGH) GhAlloc(GPTR, lcb);
|
|
if (hbgh == NULL)
|
|
return NULL;
|
|
qbgh = (QBGH) PtrFromGh(hbgh);
|
|
|
|
*qbgh = bgh;
|
|
|
|
if (bgh.cbmhMac > 0) /* check instead above? */
|
|
{
|
|
qdw = &qbgh->rglcbBmh[0];
|
|
while (bgh.cbmhMac-- > 0)
|
|
qb += LcbQuickMapSDFF(isdff, TE_DWORD, qdw++, qb);
|
|
}
|
|
//UnlockGh(hbgh);
|
|
|
|
return hbgh;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name WValueQbmh
|
|
-
|
|
* Purpose
|
|
* Determines the appropriateness of the given bitmap for a
|
|
* device with the given characteristics.
|
|
*
|
|
* Arguments
|
|
* qbmh: Pointer to the uncompressed bitmap header.
|
|
* cxAspect, cyAspect, cBitCount, cPlanes: Characteristics of
|
|
* the device the bitmap will be displayed on.
|
|
*
|
|
* Returns
|
|
* This function returns a value corresponding to the "fit" of the
|
|
* given bitmap to the given display device. The lower the value,
|
|
* the better the fit. A value of 0xFFFF means that this picture
|
|
* should not be displayed on this device, even if it is the only
|
|
* one available.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
* The order of priority for "fits" should be:
|
|
* 1) Bitmaps with the correct aspect values and correct number of colors.
|
|
* 2) Bitmaps with the correct aspect values and fewer colors.
|
|
* 3) Metafiles.
|
|
* 4) Bitmaps with the correct aspect values and more colors.
|
|
* 5) Bitmaps with the wrong aspect values.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static DWORD WValueQbmh(QBMH qbmh, int cxAspect, int cyAspect,
|
|
int cBitCount, int cPlanes)
|
|
{
|
|
DWORD wValue = 0;
|
|
int biXPelsPerMeter, biYPelsPerMeter;
|
|
INT16 biPlanes, biBitCount; // Must remain 16-bit
|
|
QV qv;
|
|
|
|
if (qbmh->bmFormat == bmWmetafile)
|
|
|
|
// BUGBUG: bad news if you try to combined multipe-resolution
|
|
// metafiles.
|
|
|
|
return 50;
|
|
|
|
if( qbmh->bmFormat != bmWbitmap &&
|
|
qbmh->bmFormat != bmDIB )
|
|
return (DWORD) -1;
|
|
|
|
qv = RFromRCb(qbmh, sizeof(WORD));
|
|
qv = QVSkipQGB(qv, (&biXPelsPerMeter));
|
|
qv = QVSkipQGB(qv, (&biYPelsPerMeter));
|
|
qv = QVSkipQGA(qv, (&biPlanes));
|
|
qv = QVSkipQGA(qv, (&biBitCount));
|
|
|
|
if (biXPelsPerMeter != cxAspect || biYPelsPerMeter != cyAspect)
|
|
if (biXPelsPerMeter == biYPelsPerMeter && cxAspect == cyAspect)
|
|
wValue += 100;
|
|
else
|
|
wValue += 200;
|
|
if (biBitCount != cBitCount || biPlanes != cPlanes) {
|
|
if (biBitCount * biPlanes <= cBitCount * cPlanes) {
|
|
wValue += 25;
|
|
|
|
// The closer we match color depth, the better
|
|
|
|
if (biBitCount < cBitCount)
|
|
wValue += (cBitCount - biBitCount);
|
|
}
|
|
else
|
|
wValue += 75;
|
|
}
|
|
|
|
#ifdef _DEBUG // Code to check bitmap selection
|
|
{
|
|
// char szBuf[256];
|
|
// wsprintf(szBuf, "X = %d, Y = %d, BC = %d, P = %d, value = %d.\n\r",
|
|
// biXPelsPerMeter, biYPelsPerMeter, biBitCount, biPlanes, wValue );
|
|
// DBWIN(szBuf);
|
|
}
|
|
#endif
|
|
|
|
return wValue;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name CSelectBitmap
|
|
-
|
|
* Purpose
|
|
* Chooses the most appropriate bitmap from a bitmap group.
|
|
*
|
|
* Arguments
|
|
* qbgh: A pointer to the bitmap group header, followed by the
|
|
* uncompressed bitmap headers.
|
|
* cxAspect, cyAspect, cPlanes, cBitCount: Characteristics of the
|
|
* display surface the bitmap will be drawn on.
|
|
*
|
|
* Returns
|
|
* The index of the most appropriate bitmap, or -1 if none are
|
|
* appropriate.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* This function makes the optimization of not calling WValueQbmh
|
|
* if the bitmap group only contains one bitmap, but instead returning
|
|
* 0 if the bitmap is in a supported format, and -1 if it is not.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#ifdef _X86_
|
|
static int CSelectBitmap(QBGH qbgh, int cxAspect, int cyAspect,
|
|
int cPlanes, int cBitCount)
|
|
#else
|
|
static int CSelectBitmap(QBGH qbgh,QV qv, int cxAspect, int cyAspect,
|
|
int cPlanes, int cBitCount)
|
|
#endif
|
|
{
|
|
int ibmh, ibmhBest;
|
|
DWORD wValue, wValueBest;
|
|
QBMH qbmh;
|
|
|
|
if (qbgh->cbmhMac == 1) {
|
|
#ifdef _X86_
|
|
qbmh = QFromQCb(qbgh, qbgh->rglcbBmh[0]);
|
|
#else
|
|
qbmh = QFromQCb(qv, qbgh->rglcbBmh[0]);
|
|
#endif
|
|
if (qbmh->bmFormat == bmWbitmap || qbmh->bmFormat == bmDIB
|
|
|| qbmh->bmFormat == bmWmetafile)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CHECKMRBSELECTION // Code to check bitmap selection
|
|
{
|
|
char szBuf[256];
|
|
wsprintf(rgchUg, "Monitor: X = %d, Y = %d, BC = %d, P = %d.",
|
|
cxAspect, cyAspect, cBitCount, cPlanes);
|
|
DBWIN(szBuf);
|
|
#endif // CHECKMRBSELECTION
|
|
|
|
ibmhBest = -1;
|
|
wValueBest = (DWORD) -1;
|
|
|
|
ASSERT(qbgh->wVersion == wBitmapVersion2 ||
|
|
qbgh->wVersion == wBitmapVersion3);
|
|
|
|
for (ibmh = 0; ibmh < qbgh->cbmhMac; ++ibmh) {
|
|
#ifdef _X86_
|
|
wValue = WValueQbmh(RFromRCb(qbgh, qbgh->rglcbBmh[ibmh]),
|
|
cxAspect, cyAspect, cBitCount, cPlanes);
|
|
#else
|
|
wValue = WValueQbmh(RFromRCb(qv, qbgh->rglcbBmh[ibmh]),
|
|
cxAspect, cyAspect, cBitCount, cPlanes);
|
|
#endif
|
|
if (wValue < wValueBest) {
|
|
wValueBest = wValue;
|
|
ibmhBest = ibmh;
|
|
}
|
|
}
|
|
return ibmhBest;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HmgFromHbma
|
|
-
|
|
* Purpose
|
|
* Returns information appropriate for laying out the given bitmap.
|
|
*
|
|
* Arguments
|
|
* hbma: A handle to the bitmap access information.
|
|
*
|
|
* Returns
|
|
* A "handle" to layout information. Currently, this is a point
|
|
* containing the size of the bitmap, in pixels.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* In future implementations, the HMG will contain hotspot information.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#ifdef _X86_
|
|
HMG STDCALL HmgFromHbma(HBMA hbma)
|
|
#else
|
|
HMG STDCALL HmgFromHbma(QDE qde, HBMA hbma)
|
|
#endif
|
|
{
|
|
QBMA qbma;
|
|
HMG hmg;
|
|
QMBMR qmbmr;
|
|
|
|
ASSERT(hbma != NULL);
|
|
|
|
hmg = (HMG) GhAlloc(GPTR, sizeof(MBMR));
|
|
if (hmg == NULL)
|
|
return NULL;
|
|
qmbmr = (QMBMR) PtrFromGh(hmg);
|
|
|
|
qbma = (QBMA) PtrFromGh(hbma);
|
|
|
|
// REVIEW. Currently unused
|
|
|
|
qmbmr->bVersion = 0;
|
|
|
|
/*
|
|
* NOTE: The dx,dy fields should have the same meaning whether the
|
|
* graphic is a bitmap or a metafile.
|
|
*/
|
|
|
|
qmbmr->dxSize = qbma->di.cxDest;
|
|
qmbmr->dySize = qbma->di.cyDest;
|
|
|
|
// REVIEW. Currently unused
|
|
|
|
qmbmr->wColor = (WORD) 0;
|
|
qmbmr->cHotspots = 0;
|
|
qmbmr->lcbData = 0L;
|
|
if (qbma->hhsi != NULL) {
|
|
WORD wHotspot;
|
|
QMBHS qmbhs;
|
|
#ifdef _X86_
|
|
LPHSH lphsh;
|
|
QMBHS qmbhsSHED;
|
|
#else
|
|
SDFF_FILEID isdff;
|
|
QB qbSrc;
|
|
HSH hsh;
|
|
MBHS mbhsT;
|
|
#endif
|
|
|
|
/*
|
|
* NOTE: The following code parses the hotspot info following the
|
|
* bitmap image. It uses the structures defined in the SHED
|
|
* directory.
|
|
*/
|
|
#ifdef _X86_
|
|
lphsh = (LPHSH) PtrFromGh(qbma->hhsi);
|
|
ASSERT(lphsh->bHotspotVersion == bHotspotVersion1);
|
|
|
|
// Resize the Goo handle to append the extra MBHS records
|
|
hmg = (HMG) GhResize(hmg, 0, sizeof(MBMR) +
|
|
lphsh->wcHotspots * sizeof(MBHS) + lphsh->lcbData);
|
|
#else
|
|
isdff = QDE_ISDFFTOPIC(qde);
|
|
qbSrc = (QB) PtrFromGh(qbma->hhsi);
|
|
qbSrc += LcbMapSDFF(isdff, SE_HSH, &hsh, qbSrc);
|
|
ASSERT(hsh.bHotspotVersion == bHotspotVersion1);
|
|
|
|
// Resize the Goo handle to append the extra MBHS records
|
|
hmg = (HMG) GhResize(hmg, 0, sizeof(MBMR) +
|
|
hsh.wcHotspots * sizeof(MBHS) + hsh.lcbData);
|
|
#endif
|
|
|
|
if (hmg != NULL) {
|
|
qmbmr = (QMBMR) PtrFromGh(hmg);
|
|
qmbhs = (QMBHS) ((QB)qmbmr + sizeof(MBMR));
|
|
#ifdef _X86_
|
|
qmbhsSHED = (QMBHS) ((QB)lphsh + sizeof(HSH));
|
|
for (wHotspot = 0; wHotspot < lphsh->wcHotspots; wHotspot++) {
|
|
// REVIEW: Future unpack?
|
|
*qmbhs = *qmbhsSHED;
|
|
|
|
// Now fix-up rectangle coordinates
|
|
|
|
qmbhs->xPos = qmbhsSHED->xPos * qbma->di.cxDest /
|
|
qbma->di.cxSrc;
|
|
qmbhs->yPos = qmbhsSHED->yPos * qbma->di.cyDest /
|
|
qbma->di.cySrc;
|
|
qmbhs->dxSize = qmbhsSHED->dxSize * qbma->di.cxDest /
|
|
qbma->di.cxSrc;
|
|
qmbhs->dySize = qmbhsSHED->dySize * qbma->di.cyDest /
|
|
qbma->di.cySrc;
|
|
|
|
++qmbhs;
|
|
++qmbhsSHED;
|
|
}
|
|
if (lphsh->lcbData != 0L)
|
|
MoveMemory((QB) qmbhs, (QB) qmbhsSHED, lphsh->lcbData);
|
|
qmbmr->cHotspots = lphsh->wcHotspots;
|
|
qmbmr->lcbData = lphsh->lcbData;
|
|
#else
|
|
for (wHotspot = 0; wHotspot < hsh.wcHotspots; wHotspot++) {
|
|
qbSrc += LcbMapSDFF(isdff, SE_MBHS, &mbhsT, qbSrc);
|
|
mbhsT.lBinding = LQuickMapSDFF(isdff, TE_LONG, &mbhsT.lBinding);
|
|
// REVIEW: Future unpack?
|
|
*qmbhs = mbhsT;
|
|
|
|
// Now fix-up rectangle coordinates
|
|
|
|
qmbhs->xPos = mbhsT.xPos * qbma->di.cxDest /
|
|
qbma->di.cxSrc;
|
|
qmbhs->yPos = mbhsT.yPos * qbma->di.cyDest /
|
|
qbma->di.cySrc;
|
|
qmbhs->dxSize = mbhsT.dxSize * qbma->di.cxDest /
|
|
qbma->di.cxSrc;
|
|
qmbhs->dySize = mbhsT.dySize * qbma->di.cyDest /
|
|
qbma->di.cySrc;
|
|
|
|
++qmbhs;
|
|
}
|
|
if (hsh.lcbData != 0L)
|
|
MoveMemory((QB) qmbhs, (QB) qbSrc, hsh.lcbData);
|
|
|
|
qmbmr->cHotspots = hsh.wcHotspots;
|
|
qmbmr->lcbData = hsh.lcbData;
|
|
#endif
|
|
}
|
|
|
|
// REVIEW: if hmg is NULL, what then?
|
|
|
|
}
|
|
return hmg;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HbmFromQbmh
|
|
-
|
|
* Purpose
|
|
* Used to obtain a bitmap handle from the bitmap header.
|
|
*
|
|
* Arguments
|
|
* qbmh: Pointer to bitmap header.
|
|
* hdc: Display surface that the bitmap will be drawn on.
|
|
*
|
|
* Returns
|
|
* A bitmap handle. Will return NULL if qbmh is nil, or if it
|
|
* points to a metafile.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* If the bitmap is a DIB, containing the two colors white and
|
|
* black, we will create a monochrome bitmap (resulting in using
|
|
* default foreground and background colors) rather than a two
|
|
* color bitmap.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static HBITMAP STDCALL HbmFromQbmh(QBMH qbmh, HDC hdc, HPALETTE hpal)
|
|
{
|
|
HPALETTE hpalOld;
|
|
HBITMAP hbmp;
|
|
|
|
if (qbmh == NULL)
|
|
return NULL;
|
|
|
|
switch (qbmh->bmFormat) {
|
|
case bmWbitmap:
|
|
return CreateBitmap(qbmh->w.dib.biWidth,
|
|
qbmh->w.dib.biHeight,
|
|
qbmh->w.dib.biPlanes,
|
|
qbmh->w.dib.biBitCount,
|
|
RFromRCb(qbmh, qbmh->lcbOffsetBits));
|
|
|
|
case bmDIB:
|
|
|
|
// Is this a monochrome bitmap with black and white colors?
|
|
|
|
if (qbmh->w.dib.biClrUsed == 2 &&
|
|
qbmh->rgrgb[0].rgbRed == 0 &&
|
|
qbmh->rgrgb[0].rgbGreen == 0 &&
|
|
qbmh->rgrgb[0].rgbBlue == 0 &&
|
|
qbmh->rgrgb[1].rgbRed == 0xff &&
|
|
qbmh->rgrgb[1].rgbGreen == 0xff &&
|
|
qbmh->rgrgb[1].rgbBlue == 0xff) {
|
|
|
|
HBITMAP hbmp = CreateBitmap(qbmh->w.dib.biWidth,
|
|
qbmh->w.dib.biHeight, 1, 1, NULL);
|
|
if (hbmp != NULL)
|
|
SetDIBits(hdc, hbmp, 0, qbmh->w.dib.biHeight,
|
|
RFromRCb(qbmh, qbmh->lcbOffsetBits),
|
|
(QV) &qbmh->w.dib,
|
|
DIB_RGB_COLORS);
|
|
return hbmp;
|
|
}
|
|
|
|
if (qbmh->w.dib.biClrImportant == 1) {
|
|
COLORREF clr =
|
|
(COLORREF) GetWindowLong(ahwnd[iCurWindow].hwndTopic, GTWW_COBACK);
|
|
clr &= 0x00FFFFFF;
|
|
if (!clr)
|
|
clr = GetSysColor(COLOR_WINDOW);
|
|
|
|
qbmh->w.dib.biClrImportant = 0;
|
|
|
|
qbmh->rgrgb[15].rgbRed = GetRValue(clr);
|
|
qbmh->rgrgb[15].rgbGreen = GetGValue(clr);
|
|
qbmh->rgrgb[15].rgbBlue = GetBValue(clr);
|
|
}
|
|
|
|
if (!hpal)
|
|
return CreateDIBitmap(hdc, &qbmh->w.dib, CBM_INIT,
|
|
QFromQCb(qbmh, qbmh->lcbOffsetBits),
|
|
(BITMAPINFO FAR*) &qbmh->w.dib, DIB_RGB_COLORS);
|
|
|
|
hpalOld = SelectPalette(hdc, hpal, FALSE);
|
|
|
|
RealizePalette(hdc);
|
|
|
|
hbmp = CreateDIBitmap(hdc, &qbmh->w.dib, CBM_INIT,
|
|
QFromQCb(qbmh, qbmh->lcbOffsetBits),
|
|
(BITMAPINFO FAR*) &qbmh->w.dib, DIB_RGB_COLORS);
|
|
|
|
SelectPalette(hdc, hpalOld, FALSE);
|
|
return hbmp;
|
|
|
|
case bmWmetafile:
|
|
return NULL;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name HmfFromQbmh
|
|
-
|
|
* Purpose
|
|
* Creates a metafile handle from a bitmap header, if that header
|
|
* contains a metafile.
|
|
*
|
|
* Arguments
|
|
* qbmh: A pointer to a bitmap header.
|
|
* hdc: The display surface the bitmap will be drawn on.
|
|
*
|
|
* Returns
|
|
* A handle to a playable metafile.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
* Will return NULL if the bitmap data contains a bitmap rather than
|
|
* a metafile. Will also return NULL if this is compiled under PM.
|
|
* REVIEW: Could this be moved to the layer directory?
|
|
* A Windows MetaFile is an alias for the bits that describe it.
|
|
* Since we would rather treat the metafile as separate from the
|
|
* description, like bitmaps are, we actually copy the description
|
|
* before aliasing it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
// BUGBUG: So how do we support enhanced metafiles?
|
|
|
|
INLINE static HMETAFILE HmfFromQbmh(QBMH qbmh)
|
|
{
|
|
if (qbmh != NULL && qbmh->bmFormat == bmWmetafile) {
|
|
#ifdef _DEBUG
|
|
int cbMetaBits = GhSize(qbmh->w.mf.hMF);
|
|
PBYTE pbits = PtrFromGh(qbmh->w.mf.hMF);
|
|
#endif
|
|
return SetMetaFileBitsEx(GhSize(qbmh->w.mf.hMF),
|
|
PtrFromGh(qbmh->w.mf.hMF));
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name MakeOOMBitmap
|
|
-
|
|
* Purpose
|
|
* Fills the given qbma with the right information to display the
|
|
* "Unable to display picture" graphic.
|
|
*
|
|
* Arguments
|
|
* qbma: A pointer to the bitmap access information.
|
|
* hdc: A handle to the display surface to draw the bitmap.
|
|
*
|
|
* Returns
|
|
* Nothing. This function will fill the qbma with the layout
|
|
* values for this graphic.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static VOID MakeOOMBitmap(QBMA qbma, HDC hdc, int idResource)
|
|
{
|
|
DWORD lExtent;
|
|
|
|
lExtent = LGetOOMPictureExtent(hdc, idResource);
|
|
qbma->di.cxDest = LOWORD(lExtent);
|
|
qbma->di.cyDest = HIWORD(lExtent);
|
|
qbma->idOom = idResource;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name RenderOOMBitmap
|
|
-
|
|
* Purpose
|
|
* Draws the "Unable to display bitmap" string, with a box around it.
|
|
*
|
|
* Arguments
|
|
* qbma: A pointer to the bitmap access information.
|
|
* hdc: Display surface to draw on.
|
|
* pt: Point at which to draw the OOM bitmap.
|
|
* fHighlight: Flag indicating whether the bitmap should be
|
|
* highlighted for hotspot tabbing.
|
|
*
|
|
* Returns
|
|
* Nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static VOID RenderOOMBitmap(QBMA qbma, HDC hdc, POINT pt, BOOL fHighlight)
|
|
{
|
|
RECT rc;
|
|
|
|
rc.left = pt.x;
|
|
rc.top = pt.y;
|
|
rc.right = pt.x + qbma->di.cxDest;
|
|
rc.bottom = pt.y + qbma->di.cyDest;
|
|
RenderOOMPicture(hdc, &rc, fHighlight, qbma->idOom);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name FRenderBitmap
|
|
-
|
|
* Purpose
|
|
* Draws the bitmap or metafile in the given display environment.
|
|
*
|
|
* Arguments
|
|
* hbma: Handle to bitmap access information.
|
|
* qde: Pointer to the display environment.
|
|
* pt: Point at which to draw the bitmap, in device units.
|
|
* fHighlight: Flag indicating whether the bitmap should be
|
|
* highlighted for hotspot tabbing.
|
|
*
|
|
* Returns
|
|
* TRUE if successful, FALSE if we had to draw the OOM bitmap.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes I think I know how this is working, and I think it would
|
|
* be valuable to record my experience. -russpj
|
|
* The bma has two fields for bitmaps, hbm and hbmCached.
|
|
* The hbm holds the bitmap in Windows format just as it came
|
|
* off of the disk. The hbmCached is a discardable bitmap
|
|
* that has the disk imaged resized and formatted (color-
|
|
* wise) for the display. If the hbmCached does not exist,
|
|
* then an attempt is made to create it (from the hbm or
|
|
* metafile). If this fails (low memory, perhaps), the
|
|
* desired rendering can still work, but the cached bitmap
|
|
* will not be saved for future rendering. Since printing
|
|
* is assumed to be a one-time wonder, we will not even
|
|
* attempt to create the cached bitmap for the object.
|
|
* In fact, some drivers seem to have trouble with the very
|
|
* large bitmaps that would be created by such an effort.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL FRenderBitmap(HBMA hbma, QDE qde, POINT pt, BOOL fHighlight)
|
|
{
|
|
QBMA qbma;
|
|
HDC hdc = NULL;
|
|
HDC hdcDest = NULL;
|
|
PBM_CACHE pCache;
|
|
QBMI qbmi; // cached BMI of bitmap requested
|
|
QBMH qbmh;
|
|
HDC hdcMem = NULL;
|
|
POINT ptDest;
|
|
HPALETTE hpalOld;
|
|
BOOL fActiveWindow;
|
|
HWND hwndParent;
|
|
#ifdef _DEBUG
|
|
HWND hwndActive;
|
|
#endif
|
|
|
|
ASSERT(hbma != NULL);
|
|
|
|
// Lock the bitmap access data
|
|
|
|
#ifdef BIDI
|
|
if (pt.x < 0)
|
|
pt.x = 0;
|
|
#endif
|
|
|
|
qbma = PtrFromGh(hbma);
|
|
|
|
// Check for rendering OOM bitmap
|
|
|
|
if (qbma->cBitmap < 0 && qbma->hbm == NULL && qbma->hmf == NULL) {
|
|
RenderOOMBitmap(qbma, qde->hdc, pt, fHighlight);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* 05-Mar-1994 [ralphw] I added this code to speed things up and to
|
|
* avoid keeping duplicate bitmaps lying around. Old code would duplicate
|
|
* the bitmap even if it did nothing to it. We assume that if it isn't
|
|
* monochrome, and the aspect ratio is right, then all we need to do is
|
|
* blit it to the device.
|
|
*/
|
|
|
|
else if (qbma->hbm && !qbma->fMonochrome &&
|
|
qbma->di.cxDest == qbma->di.cxSrc &&
|
|
qbma->di.cyDest == qbma->di.cySrc) {
|
|
if ((hdcMem = CreateCompatibleDC(qde->hdc)) == NULL)
|
|
goto NonRenderable;
|
|
if (SelectObject(hdcMem, qbma->hbm))
|
|
goto DoBitBlt;
|
|
|
|
NonRenderable:
|
|
RenderOOMBitmap(qbma, qde->hdc, pt, fHighlight);
|
|
if (qbma->cBitmap >= 0)
|
|
DeleteGraphic(qbma);
|
|
if (hdcMem != NULL)
|
|
DeleteDC(hdcMem);
|
|
return FALSE;
|
|
}
|
|
|
|
pCache = PtrFromGh(QDE_HTBMI(qde));
|
|
|
|
if (pCache != NULL)
|
|
qbmi = GetCachedBmi(pCache, qbma->cBitmap);
|
|
else
|
|
qbmi = NULL;
|
|
|
|
if (qbmi) {
|
|
if (qbmi->hbmCached) {
|
|
|
|
// see if discarded
|
|
|
|
hdcMem = CreateCompatibleDC(qde->hdc);
|
|
|
|
if (qbmi ->hbmCachedColor != qde->coBack)
|
|
goto DeleteCache;
|
|
|
|
if (hdcMem) {
|
|
if (!SelectObject(hdcMem, qbmi->hbmCached)) {
|
|
DeleteCache:
|
|
SafeDeleteObject(qbmi->hbmCached);
|
|
qbmi->hbmCached = NULL;
|
|
if (qbma -> bmFormat == bmWmetafile) {
|
|
|
|
// check if the hmf is discarded?
|
|
|
|
#ifdef _DEBUG
|
|
if ((qbma->hmf == (HMETAFILE) -1))
|
|
#endif
|
|
goto BuildFromDisk;
|
|
}
|
|
}
|
|
else // bitmap selected in, so blit it to the device
|
|
goto DoBitBlt;
|
|
}
|
|
}
|
|
} // if (qbmi)
|
|
|
|
// If bitmap hasn't been created yet, then create it now.
|
|
|
|
if ((qbma->hbm == NULL && qbma->hmf == NULL)
|
|
#ifdef _DEBUG
|
|
|| (qbma->hmf == (HMETAFILE) -1 ) || ( qbma -> hbm == (HMETAFILE) -1 )
|
|
#endif
|
|
)
|
|
{
|
|
BuildFromDisk:
|
|
ASSERT(qbma->cBitmap >= 0);
|
|
|
|
if (pCache) {
|
|
qbmi = GetCachedBmi(pCache, qbma->cBitmap);
|
|
if (qbmi)
|
|
qbmh = PtrFromGh(qbmi->hbmh);
|
|
else
|
|
qbmh = NULL;
|
|
}
|
|
else
|
|
qbmh = NULL;
|
|
|
|
ASSERT(qbma->hbm == NULL);
|
|
ASSERT(qbma->hmf == NULL);
|
|
if (qbmh) {
|
|
InitializeQbma(qbmh, qbma, qde);
|
|
}
|
|
else {
|
|
qbma->hhsi = NULL;
|
|
qbma->bmFormat = 0;
|
|
}
|
|
|
|
if (qbma->hbm == NULL && qbma->hmf == NULL) {
|
|
RenderOOMBitmap( qbma, qde->hdc, pt, fHighlight );
|
|
if (hdcMem != NULL)
|
|
DeleteDC( hdcMem );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Select proper colors for monochrome bitmaps
|
|
|
|
SetTextColor(qde->hdc, qde->coFore);
|
|
SetBkColor(qde->hdc, qde->coBack);
|
|
|
|
if ((qbma->bmFormat == bmDIB) || (qbma -> bmFormat == bmWbitmap)) {
|
|
if ((hdc = CreateCompatibleDC(qde->hdc)) == NULL ||
|
|
SelectObject(hdc, qbma->hbm) == NULL) {
|
|
RenderOOMBitmap(qbma, qde->hdc, pt, fHighlight);
|
|
if (qbma->cBitmap >= 0)
|
|
DeleteGraphic(qbma);
|
|
if (hdc != NULL)
|
|
DeleteDC(hdc);
|
|
return FALSE;
|
|
}
|
|
|
|
hdcDest = qde->hdc;
|
|
ptDest = pt;
|
|
|
|
// create a discardable bitmap.
|
|
|
|
if (qbmi) {
|
|
|
|
if (qde->deType != dePrint) {
|
|
|
|
/*
|
|
* 05-Mar-1994 [ralphw] -- I changed this to stop caching
|
|
* non-monochome, non-stretched bitmaps. The system is already
|
|
* storing the bitmap for us, so we don't need to cache a copy when
|
|
* we don't do anything different with it.
|
|
*/
|
|
|
|
if (!qbma->fMonochrome && qbma->di.cxDest == qbma->di.cxSrc &&
|
|
qbma->di.cyDest == qbma->di.cySrc)
|
|
goto DoBitBlt;
|
|
|
|
qbmi->hbmCached = CreateDiscardableBitmap(qde->hdc,
|
|
qbma->di.cxDest, qbma->di.cyDest);
|
|
}
|
|
if (qbmi->hbmCached) {
|
|
if (!hdcMem)
|
|
hdcMem = CreateCompatibleDC(qde -> hdc);
|
|
|
|
if (hdcMem && SelectObject(hdcMem, qbmi->hbmCached)) {
|
|
RECT rct;
|
|
HBRUSH hBrush;
|
|
|
|
hdcDest = hdcMem;
|
|
ptDest.x = ptDest.y = 0;
|
|
|
|
// initialize memory
|
|
|
|
qbmi -> hbmCachedColor = qde->coBack;
|
|
|
|
// set the background color.
|
|
|
|
if (hBrush = CreateSolidBrush(qde->coBack)) {
|
|
rct.left = rct.top = 0;
|
|
rct.right = qbma ->di.cxDest;
|
|
rct.bottom = qbma ->di.cyDest;
|
|
FillRect(hdcDest, &rct, hBrush);
|
|
SafeDeleteObject(hBrush);
|
|
}
|
|
}
|
|
else {
|
|
|
|
// we don't have memory, so try to play the metafile.
|
|
|
|
SafeDeleteObject(qbmi->hbmCached);
|
|
qbmi->hbmCached = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------*\
|
|
| I think that hdcDest is used to create the target size
|
|
| cached bitmap. It is a color bitmap, and the source bitmap
|
|
| is strblted into it if necessary. -RussPJ
|
|
\*------------------------------------------------------------*/
|
|
|
|
// Select proper colors for monochrome bitmaps
|
|
|
|
SetTextColor(hdcDest, qde->coFore);
|
|
SetBkColor(hdcDest, qde->coBack);
|
|
|
|
if (qbma->di.cxDest == qbma->di.cxSrc &&
|
|
qbma->di.cyDest == qbma->di.cySrc)
|
|
BitBlt(hdcDest, ptDest.x, ptDest.y, qbma->di.cxDest, qbma->di.cyDest,
|
|
hdc, 0, 0, SRCCOPY);
|
|
else {
|
|
SetStretchBltMode(hdcDest, COLORONCOLOR);
|
|
StretchBlt(hdcDest, ptDest.x, ptDest.y, qbma->di.cxDest,
|
|
qbma->di.cyDest,
|
|
hdc, 0, 0, qbma->di.cxSrc, qbma->di.cySrc, SRCCOPY);
|
|
}
|
|
|
|
DeleteDC(hdc);
|
|
if (hdcDest == hdcMem)
|
|
goto DoBitBlt;
|
|
}
|
|
|
|
// metafile
|
|
|
|
else {
|
|
int level;
|
|
BOOL fPlay;
|
|
|
|
ASSERT(qbma->hmf);
|
|
|
|
// initialize the display context handle on which metafile will be played.
|
|
hdcDest = qde -> hdc;
|
|
|
|
if (qbmi) {
|
|
if (qbmi -> hbmCached) {
|
|
|
|
// check if discarded
|
|
|
|
if (hdcMem)
|
|
goto DoBitBlt;
|
|
else {
|
|
|
|
// we don't have memory, so try to play the metafile.
|
|
|
|
SafeDeleteObject(qbmi->hbmCached);
|
|
qbmi -> hbmCached = NULL;
|
|
goto PlayMeta;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 13-Jun-1995 [ralphw] Don't cache metafiles until you figure out how
|
|
* to get the palette right.
|
|
*/
|
|
|
|
#if 0
|
|
|
|
if (qbmi && !qbmi->hbmCached && qde->deType != dePrint) {
|
|
|
|
// Try to create a discardable bitmap.
|
|
|
|
qbmi -> hbmCached = CreateDiscardableBitmap(qde -> hdc,
|
|
qbma -> di.cxDest, qbma -> di.cyDest);
|
|
if (qbmi -> hbmCached) {
|
|
if (hdcMem == NULL)
|
|
hdcMem = CreateCompatibleDC(qde -> hdc);
|
|
if (hdcMem && (SelectObject(hdcMem, qbmi -> hbmCached))) {
|
|
RECT rct;
|
|
HBRUSH hBrush;
|
|
|
|
hdcDest = hdcMem;
|
|
qbmi -> hbmCachedColor = qde -> coBack;
|
|
|
|
// set the background color.
|
|
|
|
if (hBrush = CreateSolidBrush(qde -> coBack)) {
|
|
rct.left = rct.top = 0;
|
|
rct.right = qbma ->di.cxDest;
|
|
rct.bottom = qbma ->di.cyDest;
|
|
FillRect(hdcDest, &rct, hBrush);
|
|
SafeDeleteObject(hBrush);
|
|
}
|
|
else {
|
|
// just don't bother as we may be OOM.
|
|
// accept whatever default color we have already set.
|
|
}
|
|
}
|
|
else
|
|
goto OOM;
|
|
}
|
|
// else play the metafile and don't cache as we cannot due to OOM.
|
|
}
|
|
#endif
|
|
|
|
PlayMeta:
|
|
fPlay = FALSE;
|
|
if ((level = SaveDC(hdcDest)) != 0) {
|
|
WaitCursor();
|
|
SetMapMode(hdcDest, qbma->di.mm);
|
|
if (hdcDest == qde -> hdc)
|
|
SetViewportOrgEx(hdcDest, pt.x, pt.y, NULL);
|
|
if (qbma ->di.mm == MM_ISOTROPIC) {
|
|
|
|
// set the window extent.
|
|
|
|
SetWindowExtEx(hdcDest, qbma -> di.cxSrc, qbma -> di.cySrc, NULL);
|
|
}
|
|
if (qbma->di.mm == MM_ISOTROPIC || qbma->di.mm == MM_ANISOTROPIC) {
|
|
|
|
// set the viewport extent.
|
|
|
|
SetViewportExtEx(hdcDest, qbma->di.cxDest, qbma->di.cyDest, NULL);
|
|
}
|
|
|
|
fPlay = PlayMetaFile(hdcDest, qbma->hmf);
|
|
|
|
#if 0
|
|
|
|
/*
|
|
* 13-Jun-1995 [ralphw] This should get the palette from the bitmap
|
|
* we just drew into hdcDest. But it doesn't work -- or rather, it works,
|
|
* but the palette it generates is wrong.
|
|
*/
|
|
|
|
if (!cSystemColors) {
|
|
HDC hdc = CreateIC(txtDisplay, NULL, NULL, NULL);
|
|
if (!hdc)
|
|
return NULL;
|
|
cSystemColors = GetDeviceCaps(hdc, NUMCOLORS);
|
|
if (cSystemColors == 20)
|
|
cSystemColors = 256;
|
|
}
|
|
|
|
if (fPlay && cSystemColors == 256 && qbmi->hbmCached) {
|
|
PLOGPALETTE pPal = (PLOGPALETTE) lcCalloc(sizeof (LOGPALETTE) +
|
|
MAXPALETTE * sizeof(PALETTEENTRY));
|
|
BITMAP bmp;
|
|
int cColors;
|
|
PBITMAPINFO pbmi;
|
|
PBITMAPINFOHEADER pbih;
|
|
|
|
GetObject(qbmi->hbmCached, sizeof(BITMAP), &bmp);
|
|
|
|
// 24-bit images don't have a color palette
|
|
|
|
if (bmp.bmBitsPixel > 8)
|
|
cColors = 0;
|
|
else
|
|
cColors = 1 << (UINT) (bmp.bmPlanes * bmp.bmBitsPixel);
|
|
|
|
pbmi = (PBITMAPINFO) lcCalloc(sizeof(BITMAPINFOHEADER) +
|
|
sizeof(RGBQUAD) * cColors);
|
|
pbih = (PBITMAPINFOHEADER) pbmi;
|
|
pbih->biPlanes = 1;
|
|
pbih->biBitCount = 8;
|
|
|
|
pbih->biSize = sizeof(BITMAPINFOHEADER);
|
|
pbih->biWidth = bmp.bmWidth;
|
|
pbih->biHeight = bmp.bmHeight;
|
|
pbih->biCompression = BI_RGB;
|
|
pbih->biClrUsed = 256;
|
|
|
|
GetDIBits(hdcDest, qbmi->hbmCached, 0,
|
|
(UINT) bmp.bmHeight, NULL, pbmi, DIB_RGB_COLORS);
|
|
|
|
qbma->hpal = CreateBIPalette(pbih); // will return NULL for mono
|
|
lcFree(pbmi);
|
|
lcFree(pPal);
|
|
}
|
|
#endif
|
|
|
|
RestoreDC(hdcDest, level);
|
|
RemoveWaitCursor();
|
|
}
|
|
|
|
// OOM case
|
|
if (!fPlay) {
|
|
// OOM:
|
|
// metafile cannot be played because of OOM may be.
|
|
RenderOOMBitmap(qbma, qde->hdc, pt, fHighlight);
|
|
if (hdcDest == hdcMem) {
|
|
DeleteDC(hdcDest);
|
|
}
|
|
if (qbmi && qbmi -> hbmCached) {
|
|
SafeDeleteObject(qbmi->hbmCached);
|
|
qbmi->hbmCached = NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (hdcDest == hdcMem) {
|
|
DoBitBlt:
|
|
|
|
/*
|
|
* Determine if this hdc is for an active window. If not, we want
|
|
* to make the palette a background palette.
|
|
*/
|
|
|
|
hwndParent = qde->hwnd;
|
|
ASSERT(IsValidWindow(hwndParent));
|
|
if (GetWindowLong(hwndParent, GWL_STYLE) & WS_CHILD) {
|
|
HWND hwnd = GetParent(hwndParent);
|
|
while (hwnd && GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) {
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
hwnd = hwndParent;
|
|
}
|
|
if (IsValidWindow(hwnd))
|
|
hwndParent = hwnd;
|
|
}
|
|
#ifdef _DEBUG
|
|
hwndActive = GetActiveWindow();
|
|
#endif
|
|
|
|
fActiveWindow = (GetActiveWindow() == hwndParent);
|
|
|
|
if (qbma->hpal) {
|
|
hpalOld = SelectPalette(qde->hdc, qbma->hpal, !fActiveWindow);
|
|
RealizePalette(qde->hdc);
|
|
}
|
|
|
|
BitBlt(qde->hdc, pt.x, pt.y, qbma->di.cxDest, qbma->di.cyDest,
|
|
hdcMem, 0, 0, SRCCOPY);
|
|
|
|
if (qbma->hpal)
|
|
SelectPalette(qde->hdc, hpalOld, !fActiveWindow);
|
|
}
|
|
}
|
|
|
|
if (hdcMem != NULL)
|
|
DeleteDC(hdcMem);
|
|
|
|
if (fHighlight) {
|
|
RECT rc;
|
|
ASSERT(qde->deType != dePrint);
|
|
SetRect(&rc, pt.x, pt.y, pt.x + qbma->di.cxDest, pt.y + qbma->di.cyDest);
|
|
InvertRect(qde->hdc, &rc);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name SizeMetaFilePict()
|
|
-
|
|
* Purpose
|
|
* Finds out the metafile size in pixels when drawn.
|
|
*
|
|
* Arguments
|
|
* hdc: Display context handle.
|
|
* mfp: Metafile picture structure.
|
|
*
|
|
* Returns
|
|
* Returns the size as DWORD where the LOWORD contains width and
|
|
* HIWORD contains the height.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes
|
|
*
|
|
***************************************************************************/
|
|
|
|
static DWORD STDCALL SizeMetaFilePict (HDC hdc, METAFILEPICT mfp)
|
|
{
|
|
int level;
|
|
DWORD dwExtent = 0;
|
|
POINT pt;
|
|
|
|
if ((level = SaveDC(hdc)) != 0) {
|
|
|
|
// Compute size of picture to be displayed
|
|
|
|
switch (mfp.mm) {
|
|
default:
|
|
SetMapMode(hdc, mfp.mm);
|
|
SetWindowOrgEx(hdc, 0, 0, NULL);
|
|
pt.x = mfp.xExt;
|
|
pt.y = mfp.yExt;
|
|
LPtoDP(hdc, (LPPOINT)&pt, 1);
|
|
if (mfp.mm != MM_TEXT)
|
|
pt.y *= -1;
|
|
break;
|
|
|
|
case MM_ISOTROPIC:
|
|
case MM_ANISOTROPIC:
|
|
if (mfp.xExt > 0 && mfp.yExt > 0) {
|
|
|
|
// suggested size They are in HI-METRICS unit
|
|
|
|
pt.x = MulDiv(mfp.xExt, cxAspect, 2540);
|
|
pt.y = MulDiv(mfp.yExt, cyAspect, 2540);
|
|
}
|
|
else {
|
|
/*
|
|
* no suggested sizes, use a default size like the
|
|
* current window size. etc..
|
|
*/
|
|
|
|
pt.x = pt.y = 200;
|
|
}
|
|
break;
|
|
}
|
|
dwExtent = MAKELONG(pt.x, pt.y);
|
|
RestoreDC(hdc, level);
|
|
}
|
|
return dwExtent;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: GetCachedBmi
|
|
-
|
|
* Purpose:
|
|
* Locates the referenced bitmap in the cache.
|
|
*
|
|
* Arguments:
|
|
* qtbmi - table of bitmap information.
|
|
* cBitmap - bitmap number desired
|
|
*
|
|
* Returns:
|
|
* a qbmi if successfull, else NULL
|
|
*
|
|
***************************************************************************/
|
|
|
|
static QBMI FASTCALL GetCachedBmi(PBM_CACHE pCache, int cBitmap)
|
|
{
|
|
QBMI qbmi;
|
|
|
|
if (cBitmap == -1)
|
|
return NULL;
|
|
|
|
for (qbmi = &pCache->abmi[0]; qbmi < &pCache->abmi[MAXBMP_CACHED]; qbmi++) {
|
|
if (qbmi->cBitmap == cBitmap)
|
|
return qbmi;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: GetLruBmi
|
|
-
|
|
* Purpose:
|
|
* Locates the LRU slot in the bitmap cache
|
|
*
|
|
* Arguments:
|
|
* qtbmi - pointer to bitmap cache
|
|
*
|
|
* Returns:
|
|
* qbmi of LRU position.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define MAX_CACHE_ALLOCATION (1024 * 2048) // 2 megs
|
|
|
|
INLINE static QBMI STDCALL GetLruBmi(PBM_CACHE pCache)
|
|
{
|
|
QBMI qbmi;
|
|
QBMI qbmiLRU;
|
|
|
|
/*
|
|
* If we've used more then MAX_CACHE_ALLOCATION then we don't cache
|
|
* any more bitmaps, and simply replace an existing one.
|
|
*/
|
|
|
|
if (pCache->cbAllocated > MAX_CACHE_ALLOCATION) {
|
|
for (qbmiLRU = qbmi = &pCache->abmi[0];
|
|
qbmi < &pCache->abmi[MAXBMP_CACHED];
|
|
qbmi++) {
|
|
if (qbmi->ref < qbmiLRU->ref && qbmi->ref != 0)
|
|
qbmiLRU = qbmi;
|
|
}
|
|
}
|
|
else {
|
|
for (qbmiLRU = qbmi = &pCache->abmi[0];
|
|
qbmi < &pCache->abmi[MAXBMP_CACHED];
|
|
qbmi++) {
|
|
if (qbmi->ref < qbmiLRU->ref)
|
|
qbmiLRU = qbmi;
|
|
}
|
|
}
|
|
return qbmiLRU;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: UpdateReference
|
|
-
|
|
* Purpose:
|
|
* Notes a reference to a QBMI for caching purposes.
|
|
*
|
|
* Arguments:
|
|
* qbmi - pointer to BMI being referenced
|
|
* qtbmi - pointer to the bitmap cache from which it came
|
|
*
|
|
* Returns:
|
|
* nothing.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
* We do LRU by a simple reference tag kept with each item. A global
|
|
* reference tag is kept for the cache, and incremented on each reference.
|
|
* Individual items get current reference tag on each reference, and thus
|
|
* those most recently referenced have higher tags than those not as
|
|
* recently referenced.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static VOID FASTCALL UpdateReference(QBMI qbmi, PBM_CACHE pCache)
|
|
{
|
|
qbmi->ref = pCache->ref;
|
|
pCache->ref++;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CreateBIPalette
|
|
|
|
PURPOSE: Creates a Palette from a BITMAPINFOHEADER
|
|
|
|
PARAMETERS:
|
|
lpbihd Pointer to BITMAPINFOHEADER structure
|
|
|
|
RETURNS: Handle to a palette
|
|
|
|
COMMENTS:
|
|
You can also CreateBIPalette with a HBITMAP parameter -- see
|
|
following function.
|
|
|
|
MODIFICATION DATES:
|
|
20-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
const RGBQUAD DefColors[] = {
|
|
{ 0, 0, 0, 0 },
|
|
{ 128, 0, 0, 0 },
|
|
{ 0, 128, 0, 0 },
|
|
{ 128, 128, 0, 0 },
|
|
{ 0, 0, 128, 0 },
|
|
{ 128, 0, 128, 0 },
|
|
{ 0, 128, 128, 0 },
|
|
{ 128, 128, 128, 0 },
|
|
{ 192, 192, 192, 0 },
|
|
{ 255, 0, 0, 0 },
|
|
{ 0, 255, 0, 0 },
|
|
{ 255, 255, 0, 0 },
|
|
{ 0, 0, 255, 0 },
|
|
{ 255, 0, 255, 0 },
|
|
{ 0, 255, 255, 0 },
|
|
{ 255, 255, 255, 0 }
|
|
};
|
|
|
|
static HPALETTE STDCALL CreateBIPalette(LPBITMAPINFOHEADER lpbihd)
|
|
{
|
|
LOGPALETTE *pPal;
|
|
HPALETTE hpal;
|
|
int i;
|
|
RGBQUAD *pRgb;
|
|
DWORD cClrBits;
|
|
|
|
// Don't use a palette for monochrome bitmaps
|
|
|
|
if (lpbihd->biClrImportant == 1 || lpbihd->biClrImportant == 2 ||
|
|
(lpbihd->biPlanes == 1 && lpbihd->biBitCount == 1))
|
|
return NULL;
|
|
|
|
if (!cSystemColors) {
|
|
HDC hdc = CreateIC(txtDisplay, NULL, NULL, NULL);
|
|
if (!hdc)
|
|
return NULL;
|
|
cSystemColors = GetDeviceCaps(hdc, NUMCOLORS);
|
|
if (cSystemColors == 20)
|
|
cSystemColors = 256;
|
|
}
|
|
|
|
/*
|
|
* For 24-bit drivers, we don't need a palette. For < 256, a palette
|
|
* won't really do us any good.
|
|
*/
|
|
|
|
if (cSystemColors != 256)
|
|
return NULL;
|
|
|
|
ASSERT(lpbihd);
|
|
|
|
// Get a pointer to the color table and the number of colors in it
|
|
|
|
pRgb = (RGBQUAD *)(((LPBYTE) lpbihd) + lpbihd->biSize);
|
|
|
|
cClrBits = lpbihd->biClrImportant ?
|
|
lpbihd->biClrImportant : lpbihd->biClrUsed;
|
|
|
|
/*
|
|
* 16-color bitmaps that contain only standard colors don't need
|
|
* a palette. Test every color entry to see if there's a match in
|
|
* the standard color table. If all entries match, return NULL
|
|
* rather then creating a palette.
|
|
*/
|
|
|
|
if (cClrBits == 16) {
|
|
int i, j;
|
|
for (i = 0; i < 16; i++) {
|
|
for (j = 0; j < 16; j++) {
|
|
if (*((COLORREF*) &pRgb[i]) == *((COLORREF*) &DefColors[j]))
|
|
break;
|
|
}
|
|
if (j == 16)
|
|
break; // couldn't find a standard color
|
|
}
|
|
if (i == 16)
|
|
return NULL; // standard 16-color bitmap, so no palette
|
|
}
|
|
|
|
if (cClrBits > 0) {
|
|
|
|
// Allocate for the logical palette structure
|
|
|
|
pPal = (LOGPALETTE *) LhAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
|
|
cClrBits * sizeof(PALETTEENTRY));
|
|
ASSERT(pPal);
|
|
|
|
pPal->palNumEntries = (WORD) cClrBits;
|
|
pPal->palVersion = PALVERSION;
|
|
|
|
/*
|
|
* Fill in the palette entries from the DIB color table and
|
|
* create a logical color palette.
|
|
*/
|
|
|
|
for (i = 0; i < (int) cClrBits; i++) {
|
|
pPal->palPalEntry[i].peRed = pRgb[i].rgbRed;
|
|
pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
|
|
pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue;
|
|
pPal->palPalEntry[i].peFlags = (BYTE) 0;
|
|
}
|
|
hpal = CreatePalette(pPal);
|
|
FreeLh((HLOCAL) pPal);
|
|
}
|
|
else if (lpbihd->biBitCount == 24) {
|
|
BYTE red;
|
|
BYTE green;
|
|
BYTE blue;
|
|
|
|
/*
|
|
* A 24 bitcount DIB has no color table entries, so set the
|
|
* number to the maximum value (256).
|
|
*/
|
|
|
|
cClrBits = MAXPALETTE;
|
|
pPal = (LOGPALETTE *) LhAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
|
|
cClrBits * sizeof(PALETTEENTRY));
|
|
ASSERT(pPal);
|
|
|
|
pPal->palNumEntries = (WORD) cClrBits;
|
|
pPal->palVersion = PALVERSION;
|
|
|
|
red = 0;
|
|
green = 0;
|
|
blue = 0;
|
|
|
|
/*
|
|
* Generate 256 (= 8*8*4) RGB combinations to fill the palette
|
|
* entries.
|
|
*/
|
|
|
|
for (i = 0; i < pPal->palNumEntries; i++) {
|
|
pPal->palPalEntry[i].peRed = red;
|
|
pPal->palPalEntry[i].peGreen = green;
|
|
pPal->palPalEntry[i].peBlue = blue;
|
|
pPal->palPalEntry[i].peFlags = (BYTE)0;
|
|
|
|
if (!(red += 32))
|
|
if (!(green += 32))
|
|
blue += 64;
|
|
}
|
|
hpal = CreatePalette(pPal);
|
|
FreeLh((HLOCAL) pPal);
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
return hpal;
|
|
}
|
|
|
|
static void STDCALL InitializeQbma(QBMH qbmh, QBMA qbma, QDE qde)
|
|
{
|
|
if (qbmh->bmFormat == bmWmetafile)
|
|
qbma->hmf = HmfFromQbmh(qbmh);
|
|
else {
|
|
if (qbmh->bmFormat == bmDIB) {
|
|
qbma->fMonochrome = (qbmh->w.dib.biClrImportant > 2) ? FALSE : TRUE;
|
|
qbma->hpal = CreateBIPalette(&qbmh->w.dib); // will return NULL for mono
|
|
}
|
|
qbma->hbm = HbmFromQbmh(qbmh, qde->hdc, qbma->hpal);
|
|
}
|
|
qbma->bmFormat = qbmh->bmFormat;
|
|
}
|