|
|
/************************************************************/
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */ /************************************************************/
/* picture.c -- MW format and display routines for pictures */
//#define NOGDICAPMASKS
#define NOWINMESSAGES
#define NOVIRTUALKEYCODES
#define NOWINSTYLES
#define NOCLIPBOARD
#define NOCTLMGR
#define NOSYSMETRICS
#define NOMENUS
#define NOICON
#define NOKEYSTATE
//#define NOATOM
#define NOCREATESTRUCT
#define NODRAWTEXT
#define NOFONT
#define NOMB
#define NOMENUS
#define NOOPENFILE
#define NOREGION
#define NOSCROLL
#define NOSOUND
#define NOWH
#define NOWINOFFSETS
#define NOWNDCLASS
#define NOCOMM
#include <windows.h>
#include "mw.h"
#define NOKCCODES
#include "ch.h"
#include "docdefs.h"
#include "fmtdefs.h"
#include "dispdefs.h"
#include "cmddefs.h"
#include "propdefs.h"
#include "stcdefs.h"
#include "wwdefs.h"
#include "filedefs.h"
#include "editdefs.h"
/* #include "str.h" */ #include "prmdefs.h"
/* #include "fkpdefs.h" */ /* #include "macro.h" */ #include "winddefs.h"
#if defined(OLE)
#include "obj.h"
#endif
extern typeCP cpMacCur; extern int docCur; extern int vfSelHidden; extern struct WWD rgwwd[]; extern int wwCur; extern int wwMac; extern struct FLI vfli; extern struct SEL selCur; extern struct WWD *pwwdCur; extern struct PAP vpapCache; extern typeCP vcpFirstParaCache; extern typeCP vcpLimParaCache; extern int vfPictSel; extern struct PAP vpapAbs; extern struct SEP vsepAbs; extern struct SEP vsepPage; extern struct DOD (**hpdocdod)[]; extern unsigned cwHeapFree; extern int vfInsertOn; extern int vfPMS; extern int dxpLogInch; extern int dypLogInch; extern int dxaPrPage; extern int dyaPrPage; extern int dxpPrPage; extern int dypPrPage; extern HBRUSH hbrBkgrnd; extern long ropErase; extern int vdocBitmapCache; extern typeCP vcpBitmapCache; extern HBITMAP vhbmBitmapCache; extern BOOL vfBMBitmapCache; extern HCURSOR vhcIBeam; extern BOOL vfMonochrome;
/* Used in this module only */ #ifdef DEBUG
#define STATIC static
#else
#define STATIC
#endif
STATIC RECT rcPictInvalid; /* Rectangle (in window coords) that needs refresh */ int vfWholePictInvalid = TRUE;
FreeBitmapCache() { vdocBitmapCache = docNil; if (vhbmBitmapCache != NULL) { DeleteObject( vhbmBitmapCache ); vhbmBitmapCache = NULL; } }
MarkInvalidDlPict( ww, dlPict ) int ww; int dlPict; { /* Mark the passed dl (presumed to be part of a picture) as requiring
eventual update, when DisplayGraphics is called */
register struct WWD *pwwd = &rgwwd [ww]; struct EDL (**hdndl)[] = pwwd->hdndl; struct EDL *pedl = &(**hdndl)[ dlPict ]; RECT rcDl;
SetRect( (LPRECT) &rcDl, 0, pedl->yp - pedl->dyp, pwwd->xpMac, pedl->yp );
if (vfWholePictInvalid) { CopyRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcDl ); vfWholePictInvalid = FALSE; } else { RECT rcT;
rcT = rcPictInvalid; /* Necessary? i.e. can UnionRect handle
source == destination */ UnionRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcT, (LPRECT) &rcDl ); } }
DisplayGraphics( ww, dl, fDontDisplay ) int ww; int dl; int fDontDisplay; { /* Display a line of graphics info */ struct WWD *pwwd = &rgwwd[ww]; struct EDL *pedl; typeCP cpPictStart; typeCP cp; typeCP cpMac = (**hpdocdod)[vfli.doc].cpMac; struct PICINFOX picInfo; RECT rcEnclose; RECT rcPict; HANDLE hBits=NULL; HDC hMDC=NULL; HDC hMDCCache=NULL; HANDLE hbm=NULL; HDC hDC=pwwd->hDC; int cchRun; unsigned long cbPict=0; int dxpOrig; /* Size of picture in the original */ int dypOrig; int dxpDisplay; /* Size of picture as we want to show it */ int dypDisplay; int fBitmap; int ilevel=0; /* THIS ROUTINE COULD USE SOME GDI-CALL ERROR CHECKING! ..pault */
int fDrew=false;
/* In the case of monochrome devices, this raster op will map white in
the bitmap to the background color and black to the foreground color. */ #define ropMonoBm 0x00990066
Assert( dl >= 0 && dl < pwwd->dlMax );
MarkInvalidDlPict( ww, dl );
if (fDontDisplay) { return; }
Diag(CommSz("DisplayGraphics: \n\r"));
FreezeHp(); pedl = &(**(pwwd->hdndl))[dl]; cpPictStart=pedl->cpMin;
GetPicInfo( cpPictStart, cpMac, vfli.doc, &picInfo );
/* Compute desired display size of picture (in device pixels) */
ComputePictRect( &rcPict, &picInfo, pedl, ww ); dxpDisplay = rcPict.right - rcPict.left; dypDisplay = rcPict.bottom - rcPict.top;
/* Compute original size of picture (in device pixels) */ /* MM_ANISOTROPIC and MM_ISOTROPIC pictures have no original size */
switch ( picInfo.mfp.mm ) { case MM_ISOTROPIC: case MM_ANISOTROPIC: break; case MM_BITMAP: dxpOrig = picInfo.bm.bmWidth; dypOrig = picInfo.bm.bmHeight; break; #if defined(OLE)
case MM_OLE: { extern BOOL vfObjDisplaying;
if (lpOBJ_QUERY_INFO(&picInfo) == NULL) goto DontDraw;
/* just to be safe */ if (!CheckPointer(lpOBJ_QUERY_INFO(&picInfo),1)) goto DontDraw;
if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL) { typeCP cpRet;
/* this can require memory, so unlock heap */ MeltHp(); vfObjDisplaying = TRUE;
cpRet = ObjLoadObjectInDoc(&picInfo,vfli.doc,cpPictStart);
vfObjDisplaying = FALSE; FreezeHp(); pedl = &(**(pwwd->hdndl))[dl];
if (cpRet == cp0) goto DontDraw; } } break; #endif
default: dxpOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.xExt, GetDeviceCaps( hDC, HORZRES ), GetDeviceCaps( hDC, HORZSIZE ) ); dypOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.yExt, GetDeviceCaps( hDC, VERTRES ), GetDeviceCaps( hDC, VERTSIZE ) ); if (! (dxpOrig && dypOrig) ) { goto DontDraw; } break; }
/* Save DC as a guard against DC attribute alteration by a metafile */ #ifdef WINDOWS_BUG_FIXED /* Currently 0 is a valid level for Own DC's */
if ((ilevel=SaveDC( hDC )) == 0) goto DontDraw; #endif
ilevel = SaveDC( hDC ); SetStretchBltMode( hDC, BLACKONWHITE );
/* Clip out top bar, selection bar */
IntersectClipRect( hDC, ((wwCur == wwClipboard) ? 0 : xpSelBar), pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
if (!vfWholePictInvalid) /* Repainting less than the whole picture; clip out
what we're not drawing */ IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top, rcPictInvalid.right, rcPictInvalid.bottom );
/* Build rcEnclose, a rect enclosing the picture that
includes the "space before" and "space after" fields */
rcEnclose.left = xpSelBar; if ((rcEnclose.top = rcPict.top - DypFromDya( vpapAbs.dyaBefore, FALSE )) < pwwd->ypMin) rcEnclose.top = pwwd->ypMin; rcEnclose.right = pwwd->xpMac; if ((rcEnclose.bottom = rcPict.bottom + DypFromDya( vpapAbs.dyaAfter, FALSE )) > pwwd->ypMac) rcEnclose.bottom = pwwd->ypMac;
/* White out enclosing rect */
PatBlt( hDC, rcEnclose.left, rcEnclose.top, rcEnclose.right - rcEnclose.left, rcEnclose.bottom - rcEnclose.top, ropErase );
/* If we have it cached, do display the easy way */
if (pwwd->doc == vdocBitmapCache && cpPictStart == vcpBitmapCache) { Assert( pwwd->doc != docNil && vhbmBitmapCache != NULL);
if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) && SelectObject( hMDC, vhbmBitmapCache )) { Diag(CommSz("DisplayGraphics: BitBlt\n\r")); BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay, dypDisplay, hMDC, 0, 0, vfMonochrome && vfBMBitmapCache ? ropMonoBm : SRCCOPY ); fDrew = TRUE; goto DontDraw; } else { /* Using the cache failed -- empty it
(SelectObject will fail if bitmap was discarded) */ FreeBitmapCache(); } }
StartLongOp(); /* Put up an hourglass */
/* Build up all bytes associated with the picture (except the header)
into the global Windows handle hBits */
if ( picInfo.mfp.mm != MM_OLE) { if ((hBits=GlobalAlloc( GMEM_MOVEABLE, (long)picInfo.cbSize )) == NULL) { /* Not enough global heap space to load bitmap/metafile */ goto DontDraw; }
#ifdef DCLIP
{ char rgch[200]; wsprintf(rgch,"DisplayGraphics: picinfo.cbSize %lu \n\r", picInfo.cbSize); CommSz(rgch); } #endif
for ( cbPict = 0, cp = cpPictStart + picInfo.cbHeader; cbPict < picInfo.cbSize; cbPict += cchRun, cp += (typeCP) cchRun ) { CHAR rgch[ 256 ]; #if WINVER >= 0x300
HPCH lpch; #else
LPCH lpch; #endif
#define ulmin(a,b) ((unsigned long)(a) < (unsigned long)(b) ? \
(unsigned long)(a) : (unsigned long)(b))
FetchRgch( &cchRun, rgch, vfli.doc, cp, cpMac, (int) ulmin( picInfo.cbSize - cbPict, 256 ) ); if ((lpch=GlobalLock( hBits )) != NULL) { #ifdef DCLIP
{ char rgch[200]; wsprintf(rgch," copying %d bytes from %lX to %lX \n\r",cchRun,(LPSTR)rgch,lpch+cbPict); CommSz(rgch); }
{ char rgchT[200]; int i; for (i = 0; i< min(20,cchRun); i++,i++) { wsprintf(rgchT,"%X ",* (int *) &(rgch[i])); CommSz(rgchT); } CommSz("\n\r"); } #endif
#if WINVER >= 0x300
bltbh( (LPSTR)rgch, lpch+cbPict, cchRun ); #else
bltbx( (LPSTR)rgch, lpch+cbPict, cchRun ); #endif
GlobalUnlock( hBits ); } else { goto DontDraw; } } }
/* Display the picture */
MeltHp();
#if defined(OLE)
/* CASE 0: OLE */ if (picInfo.mfp.mm == MM_OLE) { Diag(CommSz("Case 0:\n\r")); if (ObjDisplayObjectInDoc(&picInfo, vfli.doc, cpPictStart, hDC, &rcPict) == FALSE) goto DontDraw; fDrew = true; } else #endif
/* CASE 1: Bitmap */ if (fBitmap = (picInfo.mfp.mm == MM_BITMAP)) { Diag(CommSz("Case 1: \n\r")); if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) && ((picInfo.bm.bmBits = GlobalLock( hBits )) != NULL) && ((hbm=CreateBitmapIndirect((LPBITMAP)&picInfo.bm))!=NULL)) { picInfo.bm.bmBits = NULL; GlobalUnlock( hBits ); GlobalFree( hBits ); /* Free handle to bits to allow max room */ hBits = NULL; SelectObject( hMDC, hbm );
goto CacheIt; } }
/* Case 2: non-scalable metafile pictures which we are, for
user interface consistency, scaling by force using StretchBlt */
else if ( ((dxpDisplay != dxpOrig) || (dypDisplay != dypOrig)) && (picInfo.mfp.mm != MM_ISOTROPIC) && (picInfo.mfp.mm != MM_ANISOTROPIC) ) {
Diag(CommSz("Case 2: \n\r")); if (((hMDC=CreateCompatibleDC( hDC)) != NULL) && ((hbm=CreateCompatibleBitmap( hDC, dxpOrig, dypOrig ))!=NULL) && SelectObject( hMDC, hbm ) && SelectObject( hMDC, hbrBkgrnd )) { extern int vfOutOfMemory;
PatBlt( hMDC, 0, 0, dxpOrig, dypOrig, ropErase ); SetMapMode( hMDC, picInfo.mfp.mm ); /* To cover StretchBlt calls within the metafile */ SetStretchBltMode( hMDC, BLACKONWHITE ); PlayMetaFile( hMDC, hBits ); /* Because we pass pixels to StretchBlt */ SetMapMode( hMDC, MM_TEXT );
CacheIt: Assert( hbm != NULL && hMDC != NULL );
if (vfOutOfMemory) goto NoCache; #ifndef NOCACHE
FreeBitmapCache(); /* Among other things, this code caches the current picture.
Notice that there are two assumptions: (1) all bitmaps are monochrome, and (2) a newly created memory DC has a monochrome bitmap selected in. */ if ( ((hMDCCache = CreateCompatibleDC( hDC )) != NULL) && ((vhbmBitmapCache = CreateDiscardableBitmap( fBitmap ? hMDCCache : hDC, dxpDisplay, dypDisplay )) != NULL) && SelectObject( hMDCCache, vhbmBitmapCache )) { if (!StretchBlt( hMDCCache, 0, 0, dxpDisplay, dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, SRCCOPY )) { /* may get here if memory is low */ DeleteDC( hMDCCache ); hMDCCache = NULL; DeleteObject( vhbmBitmapCache ); vhbmBitmapCache = NULL; goto NoCache; }
#ifdef DCLIP
if (vfMonochrome && fBitmap) CommSzNum("BitBlt using ropMonoBm == ",ropMonoBm); #endif
BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay, dypDisplay, hMDCCache, 0, 0, vfMonochrome && fBitmap ? ropMonoBm : SRCCOPY );
/* Cached bitmap OK, make cache valid */ vdocBitmapCache = pwwd->doc; vcpBitmapCache = cpPictStart; vfBMBitmapCache = fBitmap; } else #endif /* ndef NOCACHE */
{ NoCache: StretchBlt( hDC, rcPict.left, rcPict.top, dxpDisplay, dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, vfMonochrome && fBitmap ? ropMonoBm : SRCCOPY ); } fDrew = TRUE; } }
/* Case 3: A metafile picture which can be directly scaled
or does not need to be because its size has not changed */ else { fDrew = true; Diag(CommSz("Case 3:\n\r")); SetMapMode( hDC, picInfo.mfp.mm );
SetViewportOrg( hDC, rcPict.left, rcPict.top ); switch( picInfo.mfp.mm ) { case MM_ISOTROPIC: if (picInfo.mfp.xExt && picInfo.mfp.yExt) /* So we get the correct shape rectangle when
SetViewportExt gets called */ SetWindowExt( hDC, picInfo.mfp.xExt, picInfo.mfp.yExt ); /* FALL THROUGH */ case MM_ANISOTROPIC: /** (9.17.91) v-dougk
Set the window extent in case the metafile is bad and doesn't call it itself. This will prevent possible gpfaults in GDI **/ SetWindowExt( hDC, dxpDisplay, dypDisplay );
SetViewportExt( hDC, dxpDisplay, dypDisplay ); break; }
PlayMetaFile( hDC, hBits ); } DontDraw:
/* Clean up */ if ( *(pLocalHeap+1) ) MeltHp();
if (ilevel > 0) RestoreDC( hDC, ilevel ); if (hMDCCache != NULL) DeleteDC( hMDCCache ); if (hMDC != NULL) DeleteDC( hMDC ); if (hbm != NULL) DeleteObject( hbm ); if (hBits != NULL) { if (fBitmap && picInfo.bm.bmBits != NULL) GlobalUnlock( hBits ); GlobalFree( hBits ); }
if (!fDrew) { void DrawBlank(HDC hDC, RECT FAR *rc); DrawBlank(hDC,&rcPict); }
/* Invert the selection */ if (ww == wwDocument && !vfSelHidden && !vfPMS) { extern int vypCursLine;
ilevel = SaveDC( hDC ); /* Because of clip calls below */
if (!vfWholePictInvalid) /* Repainting less than the whole picture; clip out
what we're not drawing */ IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top, rcPictInvalid.right, rcPictInvalid.bottom );
/* Clip out top bar, selection bar */
IntersectClipRect( hDC, xpSelBar, pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
if (selCur.cpLim > cpPictStart && selCur.cpFirst <= cpPictStart) { /* Take into account 'space before' field */ rcEnclose.left = rcPict.left; rcEnclose.right = rcPict.right; InvertRect( hDC, (LPRECT) &rcEnclose ); } else if ((selCur.cpLim == selCur.cpFirst) && (selCur.cpFirst == cpPictStart) && (vfWholePictInvalid || rcPictInvalid.top < vypCursLine)) { /* We erased the insert point */ vfInsertOn = fFalse; } RestoreDC( hDC, ilevel ); }
vfWholePictInvalid = TRUE; /* Next picture, start invalidation anew */ { extern int vfPMS; extern HCURSOR vhcPMS;
EndLongOp( vfPMS ? vhcPMS : vhcIBeam ); } }
#ifdef ENABLE /* Don't use this anymore */
int FPointInPict(pt) POINT pt; { /* Return true if point is within the picture frame */ struct EDL *pedl; struct PICINFOX picInfo; RECT rcPict;
GetPicInfo(selCur.cpFirst, cpMacCur, docCur, &picInfo);
if (!FGetPictPedl(&pedl)) return false;
ComputePictRect( &rcPict, &picInfo, pedl, wwCur );
return PtInRect( (LPRECT)&rcPict, pt ); } #endif /* ENABLE */
/* C O M P U T E P I C T R E C T */ ComputePictRect( prc, ppicInfo, pedl, ww ) RECT *prc; register struct PICINFOX *ppicInfo; struct EDL *pedl; int ww; { /* Compute rect containing picture indicated by passed ppicInfo,
pedl, in the indicated ww. Return the computed rect through prc. picInfo structure is not altered. */
int dypTop, xaLeft; struct WWD *pwwd = &rgwwd[ww]; int xaStart; int dxaText, dxa; int dxpSize, dypSize; int dxaSize, dyaSize;
CacheSectPic(pwwd->doc, pedl->cpMin);
if (ppicInfo->mfp.mm == MM_BITMAP && ((ppicInfo->dxaSize == 0) || (ppicInfo->dyaSize == 0))) { GetBitmapSize( &dxpSize, &dypSize, ppicInfo, FALSE ); dxaSize = DxaFromDxp( dxpSize, FALSE ); dyaSize = DyaFromDyp( dypSize, FALSE ); } #if defined(OLE)
else if (ppicInfo->mfp.mm == MM_OLE) { dxpSize = DxpFromDxa(ppicInfo->dxaSize, FALSE ); dypSize = DypFromDya(ppicInfo->dyaSize, FALSE ); dxpSize = MultDiv( dxpSize, ppicInfo->mx, mxMultByOne ); dypSize = MultDiv( dypSize, ppicInfo->my, myMultByOne ); dxaSize = DxaFromDxp( dxpSize, FALSE ); dyaSize = DyaFromDyp( dypSize, FALSE ); } #endif
else {
dxpSize = DxpFromDxa( dxaSize = ppicInfo->dxaSize, FALSE ); dypSize = DypFromDya( dyaSize = ppicInfo->dyaSize, FALSE ); }
dypTop = pedl->dcpMac != 0 ? /* Last line of picture */ DypFromDya( dyaSize + vpapAbs.dyaAfter, FALSE ) : (pedl->ichCpMin + 1) * dypPicSizeMin; dypTop = pedl->yp - dypTop;
xaStart = DxaFromDxp( xpSelBar - (int) pwwd->xpMin, FALSE ); dxaText = vsepAbs.dxaText; switch (vpapAbs.jc) { case jcBoth: case jcLeft: dxa = ppicInfo->dxaOffset; break; case jcCenter: dxa = (dxaText - (int)vpapAbs.dxaRight + (int)vpapAbs.dxaLeft - dxaSize) / 2; break; case jcRight: dxa = dxaText - (int)vpapAbs.dxaRight - dxaSize; break; }
xaLeft = xaStart + max( (int)vpapAbs.dxaLeft, dxa );
prc->right = (prc->left = DxpFromDxa( xaLeft, FALSE )) + dxpSize; prc->bottom = (prc->top = dypTop) + dypSize; }
FGetPictPedl(ppedl) struct EDL **ppedl; { int dlLim = pwwdCur->dlMac; int dl; typeCP cpFirst = selCur.cpFirst; struct EDL *pedl;
//Assert(vfPictSel);
if (!vfPictSel) return FALSE;
pedl = &(**(pwwdCur->hdndl)[0]);
for (dl = 0; dl < dlLim; ++dl, ++pedl) { //if (!pedl->fValid)
//return false;
if (pedl->cpMin == cpFirst) break; } if (dl >= dlLim) return false; /* No part of picture is on screen */
*ppedl = pedl; return true; }
/* C P W I N G R A P H I C */ typeCP CpWinGraphic(pwwd) struct WWD *pwwd; { int cdlPict, dl; struct EDL *dndl = &(**(pwwd->hdndl))[0];
Assert( !pwwd->fDirty ); /* So we can rely on dl info */ CachePara(pwwd->doc, dndl->cpMin); for (dl = 0; (dl < pwwd->dlMac - 1 && dndl[dl].fIchCpIncr); ++dl) ; Assert(dndl[dl].fGraphics); cdlPict = dndl[dl].ichCpMin + 1; return (dndl[0].cpMin + (vcpLimParaCache - vcpFirstParaCache) * dndl[0].ichCpMin / cdlPict); }
CacheSectPic(doc, cp) int doc; typeCP cp; { /* Cache section and para props, taking into account that footnotes take props
from the reference point */ #ifdef FOOTNOTES
struct DOD *pdod = &(**hpdocdod)[doc]; struct FNTB (**hfntb) = pdod->hfntb; #endif
CachePara(doc, cp);
#ifdef FOOTNOTES
if ( (hfntb != 0) && (cp >= (**hfntb).rgfnd[0].cpFtn) ) CacheSect( doc, CpRefFromFtn( doc, cp ) ) else #endif
CacheSect(doc, cp); /* Normal text */ }
void DrawBlank(HDC hDC, RECT FAR *rc) { /* To tell us when the draw tried but failed */ int xpMid=rc->left + (rc->right-rc->left)/2; int ypMid=rc->top + (rc->bottom - rc->top)/2; int dxpQ=(rc->right-rc->left)/4; int dypQ=(rc->bottom-rc->top)/4; HPEN hOldPen; HBRUSH hOldBrush;
hOldPen = SelectObject( hDC, GetStockObject( BLACK_PEN ) ); hOldBrush = SelectObject( hDC, GetStockObject( WHITE_BRUSH ) ); Rectangle(hDC,rc->left,rc->top,rc->right,rc->bottom); MoveTo( hDC, rc->left, rc->top ); LineTo( hDC, rc->right, rc->bottom ); MoveTo( hDC, rc->left, rc->bottom ); LineTo( hDC, rc->right, rc->top ); MoveTo( hDC, xpMid, rc->top ); LineTo( hDC, xpMid, rc->bottom ); MoveTo( hDC, rc->left, ypMid ); LineTo( hDC, rc->right, ypMid ); Ellipse( hDC, xpMid-dxpQ, ypMid-dypQ, xpMid+dxpQ, ypMid+dypQ ); SelectObject( hDC, hOldPen ); SelectObject( hDC, hOldBrush ); }
|