/* PIC3.C - second half of PIC.C - split because too big for diffL */

/******************************/
/*  L P C H  I N C R
/*  %%Function:  LpchIncr  %%Owner:  marksea       */
//
// return(lpch + cch), adjusting for segment boundaries

LPCH LpchIncr(lpch, cch)
char far *lpch;
unsigned cch;
{
	extern int	vcbitSegmentShift;

	long	lT;

// this macro is more efficent than HIWORD and can be used as an lvar
#define MYHIWORD(l)	(*(((WORD *)&(l)) + 1))

	lT = (long)LOWORD(lpch) + (long)cch;
	MYHIWORD(lT) = (MYHIWORD(lT) << vcbitSegmentShift) + MYHIWORD(lpch);
	return(lT);
}

	
/*  %%Function:  PictError   %%Owner:  bobz       */

PictError (eid)
int eid;
{
	if (eid != eidNil && !PdodMother(vfli.doc)->fHadPicAlert)
		{
		if (eid == eidNoMemPict)
			ErrorNoMemory (eid);
		else
			ErrorEid (eid, "DrawChPic");
		PdodMother(vfli.doc)->fHadPicAlert = fTrue;  /* display once. period. */
		}


}


/*  %%Function:  FDrawMetafile  %%Owner:  bobz       */

FDrawMetafile(hdc, ppicrc, ww, peid)
HDC hdc;
struct PICRC *ppicrc;
int ww;
int *peid;
{
	extern HBRUSH vhbrWhite;

	int dypPicScl, dxpPicScl;
	int fDrawn = fFalse;
	HANDLE hbm=NULL;
	 // hBits will be NULL unless filled in by FOurPlayMetafile
	HANDLE hBits=NULL;
	HDC hMDC=NULL;
	struct FTI *pfti;
	int mm = vpicFetch.mfp.mm;
	int iLevel = 0;


#ifdef DEBUG
	int iDrawFailed = 0;
#endif /* DEBUG */

#ifdef DEBUG
	if (mm >= MM_META_MAX)
		{
		CommSzNum(SzShared("FDrawMetafile vpicFetch.mfp.mm: "), mm);
		Assert (fFalse);
		}
#endif /* DEBUG */

	/* Display the picture */

	dxpPicScl = ppicrc->picScl.xpRight - ppicrc->picScl.xpLeft;
	dypPicScl = ppicrc->picScl.ypBottom - ppicrc->picScl.ypTop;

	vfGrInterrupt = fFalse;

	/* Case 1: non-scalable metafile pictures which we are, for
		user interface consistency, scaling by force using StretchBlt, or
		Print Preview mode munging for all but ANISOTROPIC metafiles    */


	if ( (mm < MM_ISOTROPIC  &&
			(vpicFetch.mx != mx100Pct || vpicFetch.my != my100Pct ||
			vlm == lmPreview || vfli.fFormatAsPrint)) ||
			(mm == MM_TEXT && !vfli.fPrint) ||
			(mm == MM_ISOTROPIC && vlm == lmPreview) )
		{

		int dypOrig, dxpOrig;

		/* Compute original size of picture (in device pixels) */
		/* MM_ANISOTROPIC and MM_ISOTROPIC pictures have no original size */

		switch ( mm )
			{
		case MM_ANISOTROPIC:
			break;
		case MM_TEXT:
			/* These are pixels, and at print time they are printer pixels
				so we must treat them as such here. If no printer is
				available, we use screen pixels and the picture will likely
				clip on screen
			*/
			pfti = vfli.fFormatAsPrint ? &vftiDxt : &vfti;
			goto LGetOrigSize;

		default:
			pfti = &vfti;
LGetOrigSize:
			/* due to rounding error, we will almost never be able to treat non
			tropic metafiles as unscaled unless we use the same calculation
			that we use to get picScl, which involves the conversion of the
			xExt and yExt to twips, then to device pixels
			*/

			dxpOrig = UMultDiv (vpicFetch.dxaGoal,
					pfti->dxpInch, czaInch);
			dypOrig = UMultDiv (vpicFetch.dyaGoal,
					pfti->dypInch, czaInch);

			if (!dxpOrig || !dypOrig)
				{
				Debug0 (iDrawFailed = 2);
#ifdef XBZ
				CommSzNum(SzShared("FDrawMeta mm type: "), mm);
				CommSzNum(SzShared("FDrawMeta xext: "), vpicFetch.mfp.xExt);
				CommSzNum(SzShared("FDrawMeta yext: "), vpicFetch.mfp.yExt);
				CommSzNum(SzShared("FDrawMeta dxpOrig: "), dxpOrig);
				CommSzNum(SzShared("FDrawMeta dypOrig: "), dypOrig);
#endif
				goto DontDraw;
				}
			break;
			}

#ifdef DPICRC
		CommSzNum(SzShared("DrawChPic mm type: "), mm);
		CommSzNum(SzShared("DrawChPic mfp.xExt: "), vpicFetch.mfp.xExt);
		CommSzNum(SzShared("DrawChPic mfp.yExt: "), vpicFetch.mfp.yExt);
		CommSzNum(SzShared("DrawChPic dxpOrig: "), dxpOrig);
		CommSzNum(SzShared("DrawChPic dypOrig: "), dypOrig);
#endif


		if (
				( Debug0 (iDrawFailed = 11),
				((hMDC=CreateCompatibleDC( hdc)) != NULL) ) &&

				( Debug0 (iDrawFailed = 12),
				((hbm=CreateCompatibleBitmap( hdc, dxpOrig,
				dypOrig ))!=NULL) ) &&
				Debug((hbm == NULL) ? fTrue : (LogGdiHandle(hbm, 1010), fTrue) &&)
				( Debug0 (iDrawFailed = 13),
				SelectObject( hMDC, hbm ) ) &&
				( Debug0 (iDrawFailed = 14),
				FSelHdcForMf( hMDC ) ) ) 
			{
			struct RC rc;
			rc.xpLeft = rc.ypTop = 0;
			rc.xpRight = dxpOrig;
			rc.ypBottom = dypOrig;

			LogGdiHandle(hMDC, 1075);

			if (
					( Debug0 (iDrawFailed = 16),
					FSetupHdcForMf(hMDC, &rc, mm) ) &&
					( Debug0 (iDrawFailed = 17),
					FOurPlayMetaFile( hMDC, &hBits, ww ) ) )
				/* Because we pass pixels to StretchBlt */
				{
				SetMapMode( hMDC, MM_TEXT );

				if (mm == MM_ISOTROPIC)
					{
					/* may have been reset for isotropic */
					SetViewportOrg( hMDC, 0,0);
					SetWindowOrg( hMDC, 0,0);
					}
#ifdef DEBUG
				if (vdbs.fDumpPicInfo)
					DumpOrgExt(hMDC);
#endif /* BZ */
				Assert( hbm != NULL && hMDC != NULL );

				Debug0 (iDrawFailed = 25);
#ifdef DPICRC
				CommSzNum(SzShared("DrawChPic stretchblt dxpPicScl: "), dxpPicScl);
				CommSzNum(SzShared("DrawChPic stretchblt dypPicScl: "), dypPicScl);
				CommSzNum(SzShared("DrawChPic stretchblt dxporig: "), dxpOrig);
				CommSzNum(SzShared("DrawChPic stretchblt dyporig: "), dypOrig);
#endif

				fDrawn = StretchBlt( hdc, ppicrc->picScl.xpLeft,
						ppicrc->picScl.ypTop,
						dxpPicScl, dypPicScl,
						hMDC, 0, 0, dxpOrig, dypOrig,
						vsci.fMonochrome ?
						ropMonoBm : SRCCOPY );

				}  /* played metafile into dc */
			}  /* created bitmap, dc... */
		}      /* non-scalable metafile */

	/* Case 2: A metafile picture which can be directly scaled
		or does not need to be because its size has not changed.
		If we get here in Page Preview mode, we had better be ANISOTROPIC
	*/
	else
		{


#ifdef DEBUG
		if (vlm == lmPreview)
			Assert( mm == MM_ANISOTROPIC );
#endif /* DEBUG */

		/* save DC as guard against DC attribute alteration by a metafile */

		if ((iLevel = SaveDC (hdc)) == 0)
			{
			Debug0 (iDrawFailed = 26);
			goto DontDraw;
			}

		SelectObject( hdc, vsci.hpen );
		SelectObject( hdc, vlm != lmPreview ? vsci.hbrBkgrnd : vhbrWhite );

		{  // BLOCK
		struct RC rcViewport;
		if (vlm != lmPreview)
			{
			rcViewport = ppicrc->picScl;
			SetMapMode(hdc, mm);
			if (!FSetWinView(hdc, &rcViewport, mm))
				{
				Debug0 (iDrawFailed = 29);
				goto DontDraw;
				}
			}
		else
			{
			Assert(mm == MM_ANISOTROPIC);
            if (!FSetWindowOrgExt(hdc, mm) || 
			    !FScaleViewportForPrvw(hdc, &ppicrc->picScl, &rcViewport))
				{
				Debug0 (iDrawFailed = 29);
				goto DontDraw;
				}
			}
		}

		Debug0 (iDrawFailed = 27);
		  // play unscaled or scaleable metafile into bm cache if possible
        if ((vflm == flmDisplayAsPrint || vflm == flmDisplay) && vlm != lmPreview)
			fDrawn = FDrawPicCacheable(hdc, ppicrc, &iLevel, ww,
	   			          peid, &hBits, mm);
		else
			fDrawn = FOurPlayMetaFile(hdc, &hBits, ww);
		}

DontDraw:

	/* Clean up */

	if (iLevel > 0)
			RestoreDC (hdc, iLevel);

	if (hMDC != NULL)
		{
		UnlogGdiHandle(hMDC, 1075);
		AssertDo(DeleteDC( hMDC ));
		}
	if (hbm != NULL)
		{
		UnlogGdiHandle(hbm, 1010);
		DeleteObject( hbm );
		}
	if (hBits != NULL)
		GlobalFree( hBits );

	if (!fDrawn)
		if (!vfli.fPrint && vfGrInterrupt) /* interrupted by user */
			{
			fDrawn = fTrue;
			}
#ifdef BZ
		else
			{
			if (vfli.fPrint && !vfGrInterrupt) /* not interrupted by user */
				ReportSz("Warning - metafile not completely printed");
			else
				CommSzNum(SzShared("FDrawMetafile draw fail error index: "), iDrawFailed);
			}
#endif

	return fDrawn;
}


/*  %%Function:  FSelHdcForMf  %%Owner:  bobz       */
FSelHdcForMf( hMDC )
HDC hMDC;
{
	extern HBRUSH vhbrWhite;

	  // ok if these fail bz

	SetTextColor(hMDC, vsci.rgbText);
	SetBkColor(hMDC, vsci.rgbBkgrnd);

	if (SelectObject(hMDC, vsci.hpen) &&
			 SelectObject(hMDC,
				vlm != lmPreview ? vsci.hbrBkgrnd : vhbrWhite))
	   {
	   return fTrue;
	   }

	return fFalse;
}

/*  %%Function:  FSetupHdcForMf  %%Owner:  bobz       */
FSetupHdcForMf(hMDC, prc, mm)
HDC hMDC;
struct RC *prc;
int mm;
{

	if (PatBlt(hMDC, prc->xpLeft, prc->ypTop,
		    prc->xpRight - prc->xpLeft, prc->ypBottom - prc->ypTop,
			vsci.ropErase) &&
		SetMapMode(hMDC, mm) &&
		/* To cover StretchBlt calls within the metafile */
		SetStretchBltMode(hMDC, BLACKONWHITE) &&
		FSetWinView(hMDC, prc, mm) )
	   {
	   return fTrue;
	   }

	return fFalse;
}



/*  %%Function:  WLoadMF  %%Owner:  bobz       */
/* loads bitmap bits into the hbm selected into hdc */
/* return: true if ok, false if bad, GRINTERRUPT if interrupted */
WLoadMF(hdc, ppicrc, ww, peid, phBits, mm, fDcCache)
HDC hdc;
struct PICRC *ppicrc;
int ww;
int *peid;
HANDLE *phBits;
int mm;
BOOL fDcCache;
{
	BOOL fRet = fFalse;

	if (fDcCache) // setup bitmap in memory dc
		{
		struct RC rc;
		rc.xpLeft = rc.ypTop = 0;
		rc.xpRight = ppicrc->picScl.xpRight - ppicrc->picScl.xpLeft;
		rc.ypBottom = ppicrc->picScl.ypBottom - ppicrc->picScl.ypTop;

		if (!FSelHdcForMf(hdc) || !FSetupHdcForMf(hdc, &rc, mm))
			goto LRetCache;
		}

   	fRet = FOurPlayMetaFile(hdc, phBits, ww);
	if (vfGrInterrupt)
		fRet = GRINTERRUPT;


	if (fDcCache) // restore memory dc xfor bitblt
		{
LRetCache:
		SetMapMode( hdc, MM_TEXT );
	  	// in case they got changed
   		SetViewportOrg( hdc, 0, 0);
   		SetWindowOrg( hdc, 0, 0);
		}

	return fRet;
}


/* C B  D I B  H E A D E R */
/*  Determine the size of the DIB header + RGB data
    (the offset to the bitmap bits array)

	 The function works for BITMAPCOREHEADERs and BITMAPINFOHEADERs.
	 The number of bitmap planes must be 1.
	 The number of Bits/Pixel must be 1, 4, 8 or 24
	 Zero is returned if there is a problem with the data
*/
/*  %%Function:  CbDIBHeader   %%Owner: RobD       */

int CbDIBHeader(lpbi)
LPBITMAPINFOHEADER lpbi;
{
#define cbInfoHeader sizeof(BITMAPINFOHEADER)
#define cbCoreHeader sizeof(BITMAPCOREHEADER)
#define cbRGBQUAD    sizeof(RGBQUAD)
#define cbRGBTRIPLE  sizeof(RGBTRIPLE)

#define lpbc ((LPBITMAPCOREHEADER) lpbi)

	if (lpbi->biSize == cbInfoHeader)			/** Win 3.0 **/
		{
		if (lpbi->biPlanes != 1)
			return 0;

		/* REVIEW: (RobD)  What about biClrUsed ?? */
		if (lpbi->biClrUsed == 0)
			{
			switch (lpbi->biBitCount)
				{
			case 1:
				return (2 * cbRGBQUAD) + cbInfoHeader;
			case 4:
				return (16 * cbRGBQUAD) + cbInfoHeader;
			case 8:
				return (256 * cbRGBQUAD) + cbInfoHeader;
			case 24:
				return cbInfoHeader;
			default:
				return 0;	/* Invalid Bits/Pixel */
				}
			}
		else
			{
			return ((lpbi->biClrUsed * cbRGBQUAD) + cbInfoHeader);
			}
		}
	else if (lpbc->bcSize == cbCoreHeader)		/** Old Style - PM 1.1/1.2 **/
		{
		if (lpbc->bcPlanes != 1)
			return 0;

		switch (lpbc->bcBitCount)
			{
		case 1:
			return (2 * cbRGBTRIPLE) + cbCoreHeader;
		case 4:
			return (16 * cbRGBTRIPLE) + cbCoreHeader;
		case 8:
			return (256 * cbRGBTRIPLE) + cbCoreHeader;
		case 24:
			return cbCoreHeader;
		default:
			return 0;	/* Invalid Bits/Pixel */
			}
		}
	else
		return 0;	/* Invalid header size */

#undef cbInfoHeader
#undef cbCoreHeader
#undef cbRGBQUAD
#undef cbRGBTRIPLE
#undef lpbc

}	/* CbDIBHeader */


/* ******************************* */
/*  %%Function:  FSetWinView  %%Owner:  bobz       */

FSetWinView(hdc, prc, mm)
HDC hdc;
struct RC *prc;
int mm;
{

	Assert (mm < MM_META_MAX);
	if (!FSetWindowOrgExt(hdc, mm))
		return (fFalse);

	if (!FSetViewport(hdc, prc))
		return (fFalse);

	return (fTrue);
}


/* ******************************* */
/*  %%Function:  FSetWindowOrgExt  %%Owner:  bobz       */

FSetWindowOrgExt(hdc, mm)
HDC hdc;
int mm;
{

	Assert (mm < MM_META_MAX);
	if (mm == MM_ISOTROPIC)
		{
		/* if 0, no suggested size or aspect ratio */
		/* for non zero, sets up aspect ratio */
		if (vpicFetch.mfp.xExt && vpicFetch.mfp.yExt)
			{
			/* So we get the correct shape rectangle when
				SetViewportExt gets called */
			if (SetWindowExt( hdc, vpicFetch.mfp.xExt, vpicFetch.mfp.yExt ) == 0L)
				return (fFalse);
			}
		}
	else if (mm == MM_ANISOTROPIC)
		{
		int dxp, dyp;
		/* the rc is all 0's except in special import field case (non-tiff) */
		SetWindowOrg(hdc, vpicFetch.rcWinMF.xpLeft, vpicFetch.rcWinMF.ypTop);
		/* these can be in funny units corresponding to the source */
		dxp = vpicFetch.rcWinMF.xpRight - vpicFetch.rcWinMF.xpLeft;
		dyp = vpicFetch.rcWinMF.ypBottom - vpicFetch.rcWinMF.ypTop;
		if (dxp && dyp && SetWindowExt(hdc, dxp, dyp) == 0L)
				return (fFalse);
		}

	return (fTrue);
}




/*  %%Function:  FSetViewport  %%Owner:  bobz       */

FSetViewport(hdc, prc)
HDC hdc;
struct RC *prc;
{
	Assert (vpicFetch.mfp.mm < MM_META_MAX);

	SetViewportOrg( hdc, prc->xpLeft, prc->ypTop);

	/* for Isotropic, assumes window org/ext already set */

	switch (vpicFetch.mfp.mm)
		{
	case MM_ISOTROPIC:
	case MM_ANISOTROPIC:
		if  (SetViewportExt( hdc, prc->xpRight - prc->xpLeft, prc->ypBottom - prc->ypTop) == 0L)
			return (fFalse);
		break;
		}

	return (fTrue);
}


/* ******************************* */
/*  %%Function:  FScaleViewportForPrvw  %%Owner:  bobz       */

FScaleViewportForPrvw(hdc, prcIn, prcOut)
HDC hdc;
struct RC *prcIn;
struct RC *prcOut;
{
	extern PVS vpvs; /* rcPagePrint in normal page coordinates */
	struct RC  rcView; /* viewport rect */
	DWORD extViewport;
	DWORD orgViewport;

	Assert (vlm == lmPreview);
	Assert (prcIn != NULL && prcOut != NULL);

	/* we want to scale the pic rect to the rect set up by preview
		and set the viewport to that scaled rectangle. Note that the hdc was
		saved by the caller.
	*/
	extViewport = GetViewportExt(hdc);
	orgViewport = GetViewportOrg(hdc);

	rcView.xpLeft =   LOWORD(orgViewport);
	rcView.ypTop =    HIWORD(orgViewport);
	rcView.xpRight =  LOWORD(extViewport) + LOWORD(orgViewport);
	rcView.ypBottom = HIWORD(extViewport) + HIWORD(orgViewport);

	*prcOut = *prcIn;
	/* map picture rect into preview draw rect */
	MapRect(prcOut, &vpvs.rcPagePrint, &rcView);

	if (!SetViewportOrg( hdc, prcOut->xpLeft, prcOut->ypTop))
		return (fFalse);

	if (!SetViewportExt( hdc, prcOut->xpRight - prcOut->xpLeft, prcOut->ypBottom - prcOut->ypTop))
		return (fFalse);

	return (fTrue);
}


/* ******************************* */
/* F  E N H A N C E  W W  */
/*  %%Function:  FEnhanceWw   %%Owner:  bobz       */

FEnhanceWw (ww)
int ww;
{
	int fDone;

	/* Display enhancement routine for pictures. If window was
		dirtied and there are lines with pictures whose display
		was postponed, do the full display now.
	
		Can use this routine for gray-scale fonts too.
	
		Returns true if entire ww enhanced, else false if interrupted
	*/


	Assert (mpwwhwwd[ww] != hNil);

	/* will cause real pictures to draw, not just frames */
	vfDrawPics = fTrue;
	vfGrInterrupt = fFalse;
	fDone = FEnhanceHpldr(ww, HwwdWw(ww) /*hpldr*/);
	vfGrInterrupt = fFalse;
	vfDrawPics = fFalse;

	return (fDone);
}

/******************************/
/* F E N H A N C E  H P L D R */
/*  %%Function:  FEnhanceHpldr  %%Owner:  bobz       */

FEnhanceHpldr(ww, hpldr)
int ww;
struct PLDR **hpldr;
{
	/* Returns true if entire ww enhanced, else false if interrupted */

	int dl, dlMac;
	struct PLCEDL **hplcedl;
	struct EDL edl;
	struct DR *pdr;
	int idr, idrMac;
	struct DRF drfFetch;

	idrMac = (*hpldr)->idrMac;
	for (idr = 0; idr < idrMac; FreePdrf(&drfFetch), idr++)
		{
		pdr = PdrFetch(hpldr, idr, &drfFetch);
		Assert(pdr->hplcedl);
		dlMac = IMacPlc(hplcedl = pdr->hplcedl);

		for (dl = 0; dl < dlMac; dl++)
			{
			GetPlc(hplcedl, dl, &edl);
			if (edl.fEnd)
				break;

			if (edl.hpldr != hNil)
				{
				if (!FEnhanceHpldr(ww, edl.hpldr))
					{
LRetFalse:
					FreePdrf(&drfFetch);
					return fFalse;
					}
				}
			else  if (edl.fNeedEnhance)
				{
				/* bz 10/11/89 removed fmsgpresent call. We could get
				   into trouble with outside calls that use pdrgalley, and
				   all pictures can safely interrupt during displayfli
				*/

				if (ww == vwwClipboard)
					{
					Assert( PwwdWw(vwwClipboard)->hdc == NULL);
					if (!FGetClipboardDC())
						goto LRetFalse;
					}
				FormatLineDr(ww, CpPlc(hplcedl, dl), pdr);
				/* DisplayFli will turn edl.fNeedEnhance off */
				DisplayFli(ww, hpldr, idr, dl, edl.ypTop + vfli.dypLine);
				if (ww == vwwClipboard)
					ReleaseClipboardDC();

				if (vfGrInterrupt)
					goto LRetFalse;
				}
			}
		}
	return fTrue;
}


/********************************/
/* H i l i t e  P i c  S e l */
/*  %%Function:  HilitePicSel  %%Owner:  bobz       */

EXPORT HilitePicSel(psel, prcwPic)
struct SEL *psel;
struct RC *prcwPic;
{
	HilitePicSel1(psel, prcwPic, NULL /* prcwClip */);
}


/********************************/
/* H i l i t e  P i c  S e l 1 */
/*  %%Function:  HilitePicSel1  %%Owner:  bobz       */

EXPORT HilitePicSel1(psel, prcwPic, prcwClip)
struct SEL *psel;
struct RC *prcwPic;
struct RC *prcwClip;
{
	struct RC rcwClip;
	struct RC rc;
	struct PICRC picrc;
	int fCrop;
	int iLevel = 0;
	struct SEL selT;
	CP cpImport;

	/* see if pic is an import field; if so, set up sel to point to
		pic char in import field, otherwise leave sel as is. We
		can get here and fail FCaIsGraphics if an import field char
		is not visible, so just return in that case. 
	*/

	if (!(FCaIsGraphics(&psel->ca, psel->ww, &cpImport)))
		return;

	selT = *psel;
	if (cpImport != cpNil)  /* import field - change ca in selT */
		{
		selT.cpFirst = cpImport;
		selT.cpLim = cpImport + 1;
		}

	/* get picture rectangle.  */
	/* returns ffalse if couldn't get rect */

	if (prcwPic == 0)
		{
		if (!FFetchSelPicRc (&selT, &picrc, &fCrop,
				picgFrOut | picgFrIn /* frame rects only */,
				fFalse /* fInterrupt */))
			{
			return;
			}
		}
	else
		{
		/* get chp; can't use selT.chp since it is never set up to be
			fSpec.
		*/

		Assert (selT.fGraphics);
		FetchCpAndParaCa(&selT.ca, fcmProps);
		Assert(vchpFetch.fSpec);
		/* Note:
		FetchCp never sets fnPic since it is possible for
		fnPic to change during the lifetime of the fetch.
		All users of pic chps are required to set fnPic to
		fnFetch. This is one case where it is acceptable to
		modify vchpFetch without trashing the fetch.    bz
		*/

		vchpFetch.fnPic = fnFetch;

		if (!FGetPicRc (&picrc, &fCrop, &vchpFetch,
				prcwPic->xwLeft, prcwPic->ywBottom,  &selT,
				picgFrOut | picgFrIn /* frame rects only */))
			{
			return;
			}
		}

	Assert(vchpFetch.fSpec);
		  /* don't bother if invisible */
	if (vchpFetch.fVanish)
		return;

	if (cpImport == cpNil && !FVisibleCp (selT.ww, selT.doc, selT.cpFirst))
		return;

	if (prcwClip == NULL)
		if (!FClipRcPic(&selT, &picrc.frOut, &rcwClip))
			return;	/* not visible */

	HilitePicSel2(&selT, prcwPic, &picrc,
			prcwClip == NULL ? &rcwClip : prcwClip);
}


/*****************************/
/* H i l i t e  P i c  S e l 2 */
/* Send this routine the clip rect for the graphic */
/* Only called from HilitePicSel1 */
/*  %%Function:  HilitePicSel2  %%Owner:  bobz       */

EXPORT HilitePicSel2(psel, prcwPic, ppicrc, prcwClip)
struct SEL *psel;
struct RC *prcwPic;
struct PICRC *ppicrc;
struct RC *prcwClip;
{
	struct RC rcBrdr;
	struct RC rcDrag;
	struct RC rcLine;
	struct BRDR brdr;
	HDC hdc;
	int ircs;
	int ibrdr;
	int iLevel = 0;

	hdc = (*HwwdWw(psel->ww))->hdc;

	/* save DC since clipping */
	if ((iLevel = SaveDC (hdc)) == 0)
		{
		return;
		}
#ifdef XBZ
		{
		struct RC rcT;
		GetClipBox (hdc, (LPRECT)&rcT);
		CommSzRgNum(SzShared("HilitePicSel1 hdc clip rect before clip: "),
				&rcT, 4);
		}
#endif
	IntersectClipRect(hdc, prcwClip->xwLeft, prcwClip->ywTop,
			prcwClip->xwRight, prcwClip->ywBottom);

	/* draw in a single border if none; else use the one we have */

	SelectObject(hdc, vsci.hbrText);

	if (vpicFetch.brcl == brclNone)
		{
		/* No border, so draw one using the outside frame rect.
			Then adjust the inside frame rect to allow for a
			single border. Use the
			DrawPatternLine methods so we can invert 
		*/

		DrawXorFrame (hdc, &ppicrc->frOut, ipatHorzBlack, ipatVertBlack);

		ppicrc->frIn.xwLeft   += vsci.dxpBorder;
		ppicrc->frIn.ywTop    += vsci.dypBorder;
		ppicrc->frIn.xwRight  -= vsci.dxpBorder;
		ppicrc->frIn.ywBottom -= vsci.dypBorder;
		}

#ifdef XBZ
		{
		CommSzRgNum(SzShared("HilitePicSel1 clip rect: "),
				prcwClip, 4);
		CommSzRgNum(SzShared("HilitePicSel1 frOut rect size = "),
				&ppicrc->frOut, 4);
		CommSzRgNum(SzShared("HilitePicSel1 frIn rect size = "),
				&ppicrc->frIn, 4);
		}
#endif

	/* draw drag rectangles. Note we use the inside frame rect here */
	for (ircs = 0; ircs < ircsMax; ircs++)
		{
		GetDragRc(ircs, &rcDrag, &ppicrc->frIn);
		/* use multiple calls since it can only deal with 1 brdr size
			or double width at a time. Draw several vertical lines.
			Drag box must be a multiple of 2 * border widths wide
		*/

		for (ibrdr = 0; ibrdr < (cbrDragBox >> 1); ibrdr ++)
			{
			DrawPatternLine( hdc, rcDrag.xpLeft, rcDrag.ypTop,
					dypDragBox, ipatVertBlack, pltInvert | pltVert | pltDouble );
			rcDrag.xpLeft += 2 * vsci.dxpBorder;
			}

		}

	Assert (iLevel > 0);
	RestoreDC (hdc, iLevel);

}


/***********************/
/* F   C L I P  R C  P I C */
/* get clipping rect for a picture based on the dr clip rect and
	the line height restriction effect on the picture rectangle
*/
/*  %%Function:  FClipRcPic  %%Owner:  bobz       */

BOOL FClipRcPic(psel, prcPic, prcClip)
struct SEL *psel;
struct RC *prcPic, *prcClip;
{
	int dl, idr;
	struct PLDR **hpldr;
	struct RC rc;
	struct DRC drcp;
	struct EDL edl;
	struct DR *pdr;
	struct DRF drf;

	dl = DlWhereDocCp(psel->ww, psel->doc, psel->cpFirst, psel->fInsEnd,
			&hpldr, &idr, NULL, NULL, fTrue);
	if (dl == dlNil)
		return (fFalse);	/* not visible */

#ifdef DISABLE_DRM   /* from Mac */
	rc = *prcPic;
	RcwToRcp(hpldr, idr, &rc, &drcp);
	drcp.dxp -= drcp.xp;
	drcp.dyp -= drcp.yp;
#endif
	pdr = PdrFetch(hpldr, idr, &drf);
	GetPlc(pdr->hplcedl, dl, &edl);
	FreePdrf(&drf);
	drcp = edl.drcp;

	ClipRectFromDr(HwwdWw(psel->ww), hpldr, idr, &drcp, prcClip);

	/* adjust clip rect for neg line spacing */
	if (vpapFetch.dyaLine < 0)
		{
		rc = *prcPic;
		AdjustRcLine(&rc);
		prcClip->ypTop = max(prcClip->ypTop, rc.ypTop);
		}

	return (fTrue);
}


/***********************/
/* G e t  D r a g  R c */
/*  %%Function:  GetDragRc  %%Owner:  bobz       */

GetDragRc(ircs, prcDrag, prcFrame)
int ircs;
struct RC *prcDrag, *prcFrame;
{
/* return the rectangle for one of the seven drag areas on the frame-
*/
	switch (ircs)
		{
	case ircsTL:
	case ircsTC:
	case ircsTR:
		prcDrag->ypTop = prcFrame->ypTop;
		break;
	case ircsCL:
	case ircsCR:
		prcDrag->ypTop =
				(prcFrame->ypTop + prcFrame->ypBottom - dypDragBox) >> 1;
		break;
	case ircsBL:
	case ircsBC:
	case ircsBR:
		prcDrag->ypTop = prcFrame->ypBottom - dypDragBox;
		break;
		}
	switch (ircs)
		{
	case ircsTL:
	case ircsCL:
	case ircsBL:
		prcDrag->xpLeft = prcFrame->xpLeft;
		break;
	case ircsTC:
	case ircsBC:
		prcDrag->xpLeft =
				(prcFrame->xpLeft + prcFrame->xpRight - dxpDragBox) >> 1;
		break;
	case ircsTR:
	case ircsCR:
	case ircsBR:
		prcDrag->xpLeft = prcFrame->xpRight - dxpDragBox;
		break;
		}

	prcDrag->ypBottom = prcDrag->ypTop + dypDragBox;
	prcDrag->xpRight = prcDrag->xpLeft + dxpDragBox;
}


/*****************************/
/* A d j u s t	R c  L i n e */
/*  %%Function:  AdjustRcLine  %%Owner:  bobz       */

AdjustRcLine(prc)
struct RC *prc; 	/* rectangle of picture */
{
/* adjust rectangle to enclose only portion of picture showing in a line
	whose height is controlled by vpapFetch.dyaLine < 0 */
	int dyp;
	int hps;

	if (hps = selCur.chp.hpsPos)
		OffsetRect((LPSTR)prc, 0,
				NMultDiv(((hps < 128) ? (hps)  /* superscript */
				: -(256 - hps)) * (dyaPoint / 2),
				vfli.dxuInch, dxaInch));

/* now rectangle is sitting on baseline */
	dyp = DysFromDya(abs(vpapFetch.dyaLine));

#ifdef MACONLY
	prc->ypBottom += dyp / 5;     /* bottom of line */
#endif

	prc->ypTop = prc->ypBottom - dyp;
}


/***********************/
/* D R A W  X O R  F R A M E */
/* draw a single border sized frame in xor mode around the rect, using
	the specified patterns from DrawPatternLine
*/
/*  %%Function:  DrawXorFrame   %%Owner:  bobz       */

DrawXorFrame (hdc, prc, ipatHorz, ipatVert)
HDC hdc;
struct RC *prc;
int ipatHorz, ipatVert;
{
	/* top */
	DrawPatternLine( hdc, prc->xpLeft, prc->ypTop,
			prc->xpRight - prc->xpLeft,
			ipatHorz, pltInvert | pltHorz );
	/* bottom */
	DrawPatternLine( hdc, prc->xpLeft,
			prc->ypBottom - vsci.dypBorder,
			prc->xpRight - prc->xpLeft,
			ipatHorz, pltInvert | pltHorz );
	/* left */
	DrawPatternLine( hdc, prc->xpLeft,
			prc->ypTop + vsci.dypBorder,
			prc->ypBottom - prc->ypTop
			- (vsci.dypBorder << 1),
			ipatVert, pltInvert | pltVert);
	/* right */
	DrawPatternLine( hdc, prc->xpRight - vsci.dxpBorder,
			prc->ypTop + vsci.dypBorder,
			prc->ypBottom - prc->ypTop
			- (vsci.dypBorder << 1),
			ipatVert, pltInvert | pltVert);
}


/********************************/
/*  %%Function:  GetBitmapSize  %%Owner:  bobz       */

GetBitmapSize(pdxt, pdyt)
int  *pdxt;
int  *pdyt;
{

	int dxtT, dytT;
	unsigned  mx, my;

	Assert (vpicFetch.mfp.mm == MM_BITMAP || vpicFetch.mfp.mm == MM_TIFF);

	dxtT = vpicFetch.bm.bmWidth;
	dytT = vpicFetch.bm.bmHeight;

	/* we want to use printer values if display as print */


	GetBestWholeMxMy( (vfli.fFormatAsPrint | vfli.fPrint), /* fPrinter */
			dxtT, dytT, vpicFetch.dxaGoal, vpicFetch.dyaGoal, &mx, &my );

#ifdef XBZ
	CommSzNum(SzShared("GetBitmapSize dxaGoal: "), vpicFetch.dxaGoal);
	CommSzNum(SzShared("GetBitmapSize dyaGoal: "), vpicFetch.dyaGoal);
	CommSzNum(SzShared("GetBitmapSize bmWidth: "), dxtT);
	CommSzNum(SzShared("GetBitmapSize bmHeight: "), dytT);
	CommSzNum(SzShared("GetBitmapSize mx: "), mx);
	CommSzNum(SzShared("GetBitmapSize my: "), my);
#endif

	dxtT = (mx == 1 ? dxtT : dxtT * mx);
	dytT = (my == 1 ? dytT : dytT * my);

#ifdef XBZ
	CommSzNum(SzShared("GetBitmapSize dxtt after rescale, 1st mx: "), dxtT);
	CommSzNum(SzShared("GetBitmapSize dytt after rescale, 1st my: "), dytT);
#endif

	/* NOTE: we are not converting xt units back to screen for display as
		print. That is done by the caller, FCropGetPicSizes, who wants to
		do all the scaling and cropping on the unscaled values before scaling
		back for the screen.
	*/

	*pdxt = dxtT;
	*pdyt = dytT;


}


/********************************/
/*  %%Function:  GetBestWholeMxMy  %%Owner:  bobz       */

GetBestWholeMxMy( fPrinter, dxpOrig, dypOrig, dxaGoal, dyaGoal, pmx, pmy )
BOOL fPrinter;
int dxpOrig, dypOrig;
int dxaGoal, dyaGoal;
unsigned *pmx, *pmy;

/* Return the "best" integer bit-multiples to use when displaying a bitmap
	of size { dxpOrig, dypOrig } on device hdc.
	multiples are returned through *pmx (x-multiple), *pmy (y-multiple)
	caller is guaranteed nonzero return values
	Factors taken into account are:
		(1) Desired size of bitmap is { dxaGoal, dyaGoal }
		(2) Matching aspect ratio given by { dxaGoal, dyaGoal } is
			very desirable.
		(3) A scaling factor may be required for devices (like the LaserJet)
			for which Windows implements the "text and graphics have different
			pixel densities" hack.
		(4) Maximum size of a bitmap is 64K
			***   Max is no longer a restriction, though the size does
					have to fit in a long
			At some point we should determine the limiting Goal size that would cause
					overflow and abandon the multiply stuff if > than that
					value
*/

{

	int cx, cy;
	int cxBest, cyBest;
	int dcx=1, dcy=1;
	int dxmmOrig, dymmOrig;
	int dxmmGoal, dymmGoal;
	int dxmmDevice;
	int dymmDevice;
	int dxpDevice;
	int dypDevice;
	int cxMac, cyMac;
	int pctAspectBest, pctSizeBest;


	if (fPrinter)
		{
		Assert (vpri.hszPrinter != hNil);

		dxmmDevice = vpri.dxmmRealPage * 10;  /* want in .1mm units */
		dymmDevice = vpri.dymmRealPage * 10;
		dxpDevice =  vpri.dxpRealPage;
		dypDevice =  vpri.dypRealPage;


#ifdef NOTUSED  /* bobz if we skip this size is same across printer resolutions */
		/* Get scale factor if printing
				(dcx, dcy, our minimum scale multiple)
		*/

		dcx = 1 << vpri.ptScaleFactor.xp;
		dcy = 1 << vpri.ptScaleFactor.yp;
#endif /* BZ */


		}
	else  /* for screen */
		
		{
		dxmmDevice = vsci.dxmmScreen * 10;  /* want in .1mm units */
		dymmDevice = vsci.dymmScreen * 10;
		dxpDevice =  vsci.dxpScreen;
		dypDevice =  vsci.dypScreen;
		}

	/* Compute size of unscaled picture on device in 0.1 mm units */

	if (dxpDevice <= 0 || dypDevice <= 0)
		goto MxMyFail;

	/* some rounding loss here is reconversion (was originally .1mm,
		converted to twips, now back)
	*/
	dxmmGoal = UMultDiv (dxaGoal, 100, czaCm);
	dymmGoal = UMultDiv (dyaGoal, 100, czaCm);

	/* Goal size not supplied; return 100%  */

	if (dxmmGoal <= 0 || dymmGoal <= 0)
		goto MxMyFail;


	dxmmOrig = UMultDiv( dxpOrig, dxmmDevice, dxpDevice );
	dymmOrig = UMultDiv( dypOrig, dymmDevice, dypDevice );

	if (dxmmOrig <= 0 || dymmOrig <= 0)
		goto MxMyFail;

	/* Compute absolute maximums for cx, cy */
	/* 2nd term of min restricts search space by refusing to consider
	more tham one size above the Goal
	*/

	cxMac = min ( (dxmmDevice / dxmmOrig) + 1, (dxmmGoal / dxmmOrig) + 2 );
	cyMac = min ( (dymmDevice / dymmOrig) + 1, (dymmGoal / dymmOrig) + 2 );

#ifdef XBZ
	CommSzNum(SzShared("GetBestWholeMxMy dxmmDevice: "), dxmmDevice);
	CommSzNum(SzShared("GetBestWholeMxMy dymmDevice: "), dymmDevice);
	CommSzNum(SzShared("GetBestWholeMxMy dxpDevice: "),  dxpDevice);
	CommSzNum(SzShared("GetBestWholeMxMy dypDevice: "),  dypDevice);
	CommSzNum(SzShared("GetBestWholeMxMy dxmmOrig: "),   dxmmOrig);
	CommSzNum(SzShared("GetBestWholeMxMy dymmOrig: "),   dymmOrig);
	CommSzNum(SzShared("GetBestWholeMxMy dxmmGoal: "),   dxmmGoal);
	CommSzNum(SzShared("GetBestWholeMxMy dymmGoal: "),   dymmGoal);
#endif


	/* Search all possible multiplies to see what would be best */

	cxBest = dcx;
	cyBest = dcy;
	pctAspectBest = pctSizeBest = 32767;

	for ( cx = dcx ; cx < cxMac; cx += dcx )
		for ( cy = dcy ; cy < cyMac; cy += dcy )
			{
			int dxmm = dxmmOrig * cx;
			int dymm = dymmOrig * cy;
			int pctAspect = PctDiffUl( (ul) dxmmGoal * (ul) dymm,
					(ul) dymmGoal * (ul) dxmm );
			int pctSize = PctDiffUl( (ul) dxmmGoal * (ul) dymmGoal,
					(ul)dxmm * (ul)dymm );

		/* ??? Strategy for loss on one, gain on the other ??? */

			if (pctAspect <= pctAspectBest && pctSize <= pctSizeBest )
				{
#ifdef XBZ
				CommSzNum(SzShared("GetBestWholeMxMy pctAspect: "), pctAspect);
				CommSzNum(SzShared("GetBestWholeMxMy pctSize: "), pctSize);
#endif
				cxBest = cx;
				cyBest = cy;
				pctAspectBest = pctAspect;
				pctSizeBest = pctSize;
				}
			}

	Assert( cxBest > 0 && cyBest > 0 );

	*pmx = cxBest;
	*pmy = cyBest;
	return;

MxMyFail:
	*pmx = dcx;
	*pmy = dcy;
}



/********************************/
/*  %%Function:  PctDiffUl  %%Owner:  bobz       */

int PctDiffUl( ul1, ul2 )
ul ul1, ul2;
	{   /* Return a number that is proportional to the percentage
	of difference between the two numbers */
	/* Will not work for > 0x7fffffff */

#define dulMaxPrec  1000     /* # of "grains" of response possible */
#define dulLim 4294967       /* FFFFFFFF/1000; compiler won't do unsigned division */

	ul ulAvg = (ul1 >> 1) + (ul2 >> 1);
	ul ulDiff = (ul1 > ul2) ? ul1 - ul2 : ul2 - ul1;
	ul ulRet;

	if (ulAvg == 0)
		ulRet = (ul1 == ul2) ? 0 : dulMaxPrec;
	else if (ulDiff > dulLim || ulDiff < 0L)
		ulRet = dulMaxPrec;
	else
		ulRet = ((ulDiff * (ul)dulMaxPrec) / ulAvg);

#ifdef XBZ
	CommSzLong(SzShared("PctUl ulAvg: "), ulAvg);
	CommSzLong(SzShared("PctUl ulDiff: "), ulDiff);
	CommSzLong(SzShared("PctUl ulRet: "), ulRet);
	CommSzNum(SzShared("PctUl (int)ulRet: "), (int)ulRet);
#endif

	if (ulRet > 32767L || ulRet < 0L)
		return 32767;
	else
		return (int)ulRet;
}



/********************************/
/*  %%Function:  FComputePictSize  %%Owner:  bobz       */

FComputePictSize( pmfp, pdxa, pdya )
register METAFILEPICT *pmfp;
int *pdxa;
int *pdya;
	{   /* Compute an initial size, in twips, for the picture described by the
		passed metafile picture structure. Return the size through
		parameters.  Return fFalse if the metafile picture structure
		contained bad information, fTrue otherwise
	*/

	int mm = pmfp->mm;

	unsigned wMult;
	unsigned wDivX;
	unsigned wDivY;


	switch ( mm ) 
		{
	case MM_HIMETRIC:
		wMult = czaCm;
		wDivX = wDivY = 1000;
		break;
	case MM_LOMETRIC:
		wMult = czaCm;
		wDivX = wDivY = 100;
		break;
	case MM_HIENGLISH:
		wMult = czaInch;
		wDivX = wDivY = 1000;
		break;
	case MM_LOENGLISH:
		wMult = czaInch;
		wDivX = wDivY = 100;
		break;
	case MM_DIB: /* we may not get this, but take care of it as well */
	case MM_BITMAP:       /* note pixel based use SCREEN pixels */
	case MM_TEXT:
		wMult = czaInch;
		wDivX = vfli.dxsInch;
		wDivY = vfli.dysInch;
		break;
	case MM_TWIPS:  /* no conversion required */
		*pdxa = pmfp->xExt;
		*pdya = pmfp->yExt;
		goto GoodValues;
	case MM_ISOTROPIC:
	case MM_ANISOTROPIC:
		if (! ((pmfp->xExt > 0) && (pmfp->yExt > 0)))
			{   /* No "Suggested Size" given */
			/* Use dzPicBase" for largest size, dzPicBase" or as dictated by */
			/* aspect ratio for other side */
			if ((pmfp->xExt == 0) || (pmfp->yExt == 0))
				{
				/* No aspect ratio info given -- use 1" square */
				*pdya = *pdxa = dzPicBase * czaInch;
				}
			else
				{
				if (abs(pmfp->xExt) > abs(pmfp->yExt))
					{
					*pdxa = dzPicBase * czaInch;
					/* Info has neg #'s; use to compute aspect ratio */
					*pdya = UMultDiv (dzPicBase * czaInch, (abs(pmfp->yExt)),
							(abs(pmfp->xExt)));
					if (*pdya <= 0)
						*pdya = dzPicBase * czaInch;
					}
				else
					{
					*pdya = dzPicBase * czaInch;
					/* Info has neg #'s; use to compute aspect ratio */
					*pdxa = UMultDiv (dzPicBase * czaInch, (abs(pmfp->xExt)),
							(abs(pmfp->yExt)));
					if (*pdxa <= 0)
						*pdxa = dzPicBase * czaInch;
					}

				}
			goto GoodValues;
			}
		else
			{     /* have values - treat as himetric */
			wMult = czaCm;
			wDivX = wDivY = 1000;
			break;
			}
	default:
		ReportSz("Warning - bad mapping mode. Metafile discarded");
		*pdxa = *pdya = 0;
		return (fFalse);
		}

	if (pmfp->xExt <= 0 || pmfp->yExt <= 0)
		{
BadValues:
		/* assume we can live with this, and just use the default size */
		*pdya = *pdxa = dzPicBase * czaInch;
		return (fTrue);
		}

	*pdxa = UMultDiv (pmfp->xExt, wMult, wDivX);
	*pdya = UMultDiv (pmfp->yExt, wMult, wDivY);

#ifdef DPICRC
	CommSzNum(SzShared("FComputePicSize xext: "), pmfp->xExt);
	CommSzNum(SzShared("FComputePicSize yext: "), pmfp->yExt);
	CommSzNum(SzShared("FComputePicSize wMult: "), wMult);
	CommSzNum(SzShared("FComputePicSize wDivX: "), wDivX);
	CommSzNum(SzShared("FComputePicSize wDivY: "), wDivY);
	CommSzNum(SzShared("FComputePicSize dxa: "),  *pdxa);
	CommSzNum(SzShared("FComputePicSize dya: "),  *pdya);
#endif

	/* FFFF is failure return from UMultDiv */
	if (*pdxa == 0xFFFF || *pdya == 0xFFFF)
		goto BadValues;

GoodValues:
	/* restrict to min sizes for formatting */
	if (*pdxa < dxaPicMin)
		*pdxa = dxaPicMin;
	else  if (*pdxa > dxaPicMax)
		*pdxa = dxaPicMax;

	if (*pdya < dyaPicMin)
		*pdya = dyaPicMin;
	else  if (*pdya > dyaPicMax)
		*pdya = dyaPicMax;

	return fTrue;

}


#ifdef NOTUSED
/* REVIEW bobz (tdk) This routine is not currently used */
/********************************/
/* D z p  F r o m  M m  Z e x t */
/* Convert x or y coordinate from its GDI mapping mode (mm) to pixels */
/* on a device with pixel-to-absolute measurements given by DeviceRes parms */
/*  %%Function:  DzpFromMmZext  %%Owner:  bobz       */

int DzpFromMmZext( mm, val, pxlDeviceRes, milDeviceRes )
int mm;
int val;
int pxlDeviceRes;
int milDeviceRes;
	{   /* Return the # of pixels spanned by val, a measurement in coordinates
		appropriate to mapping mode mm.  pxlDeviceRes gives the resolution
		of the device in pixels, along the axis of val. milDeviceRes gives
		the same resolution measurement, but in millimeters.
	returns 0 on error */

	ul ulPxl;
	ul ulDenom;
	unsigned wMult=1;
	unsigned wDiv=1;


	if (milDeviceRes == 0)
		{   /* to make sure we don't get divide-by-0 */
		return 0;
		}

	switch ( mm ) 
		{
	case MM_LOMETRIC:
		wDiv = 10;
		break;
	case MM_HIMETRIC:
		wDiv = 100;
		break;
	case MM_TWIPS:
		wMult = 25;
		wDiv = 1440;
		break;
	case MM_LOENGLISH:
		wMult = 25;
		wDiv = 100;
		break;
	case MM_HIENGLISH:
		wMult = 25;
		wDiv = 1000;
		break;
	case MM_BITMAP:
	case MM_TEXT:
		return val;
	default:
		Assert( FALSE );        /* Bad mapping mode */
	case MM_ISOTROPIC:
	case MM_ANISOTROPIC:
		/* These picture types have no original size */
		return 0;
		}

/* Add Denominator - 1 to Numerator, to avoid rounding down */

	ulDenom = (ul) wDiv * (ul) milDeviceRes;
	ulPxl = ((ul) ((ul) wMult * (ul) val * (ul) pxlDeviceRes) + ulDenom - 1) /
			ulDenom;

	return (ulPxl > 32767L) ? 0 : (int) ulPxl;
}
#endif /* NOTUSED */


/**********************************/
/* F  C o n t e n t  H i t  P i c */
/*  %%Function:  FContentHitPic  %%Owner:  bobz       */

FContentHitPic(psel, ppt, fShift, fOption, fCommand)
struct SEL *psel;
struct PT *ppt;
int fShift, fOption, fCommand;
{
/* mouse click while a picture is selected - terminate the selection, change
	the size of the frame, or handle an interior click.
	Note that the selected picture may not be the one we clicked in. In that
	case we will return false here.
*/
	int ircs;
	struct RC rcDrag, rcLine;
	struct RC rcwClip;
	int fCrop;
	struct PICRC picrc;
	struct SEL selT;
	CP cpImport;

	/* see if pic is an import field; if so, set up sel to point to
		pic char in import field, otherwise leave sel as is. If pic
		is in a field and is not visible, we will get false back from
		FCaIsGraphics.
	*/

	if (!FCaIsGraphics(&psel->ca, psel->ww, &cpImport))
		goto LRet;

	selT = *psel;
	if (cpImport != cpNil)  /* import field - change ca in selT */
		{
		selT.cpFirst = cpImport;
		selT.cpLim = cpImport + 1;
		}

	/* Get inside frame rectangle for this stuff - want to see if hit is
		inside drag mark.
	*/

	if (!FFetchSelPicRc (&selT, &picrc, &fCrop, picgAll /* all 4 rects set up */,
			fFalse /* fInterrupt */))
		{
		goto LRet;
		}

	rcLine = picrc.frOut;
	/* CachePara is done in FFetchSelPicRc above */

	#ifdef OPUS_X64
	if (!FPtInRect(*ppt, &rcLine))
	#else
	if (!PtInRect((LPRECT)&rcLine, *ppt))
	#endif
		goto LRet;

	/* in the pic rect but part of that may be clipped. Clip rect
		includes adjustment for negative line spacing */

	if (!FClipRcPic(&selT, &rcLine, &rcwClip))
		goto LRet;  /* not visible */

	/* if in the pic rect, may be in part clipped out, so be sure
		it's there too (2 tests instead of clipping the rects and doing
		1 test)
	*/

	#ifdef OPUS_X64
	if (!FPtInRect(*ppt, &rcwClip))
	#else
	if (!PtInRect((LPRECT)&rcwClip, *ppt))
	#endif
		goto LRet;

/* in body of picture */

	if (PdodDoc(psel->doc)->fLockForEdit)
		{
		Beep();  /* can't drag or change pic if locked */
		return(fTrue);
		}

	if (vfDoubleClick)
		{
		if (GetKeyState(VK_CONTROL) < 0)
			{
			/* restore picture to its "normal" size */
			ChangePicFrame(NULL, vpicFetch.brcl, mx100Pct, my100Pct,
					0, 0, 0, 0  /* cropping values */);
			}
		else
			{
			CmdExecBcmKc(bcmEditPic, kcNil);
			}
		return(fTrue);
		}

/* look for hit on one of the drag handles */
	for (ircs = 0; ircs < ircsMax; ircs++)
		{
		GetDragRc(ircs, &rcDrag, &picrc.frIn);

		#ifdef OPUS_X64
		if (FPtInRect(*ppt, &rcDrag))
		#else
		if (PtInRect((LPRECT)&rcDrag, *ppt))
		#endif
			{
			/* note that the one we drag is the outside
				frame rect */
			DragPicFrame(ircs, *ppt, &picrc, fShift);
			return(fTrue);
			}
		}

	return(fTrue);

LRet:
	/* FUTURE: This if block was added to fix bug 3039; it is
		very tailored to the way Opus 1.0 CBT lesson on picture dragging
		is authored and may be totally invalid or unnecessary in future
		versions of the CBT  - rp */
	if (vhwndCBT && vfShiftKey &&
		!SendMessage(vhwndCBT, WM_CBTSEMEV, smvNonPicSel, 0L))
		{
		return(fTrue);
		}

	return(fFalse);
}


/***************************************/
/* C h a n g e  P i c  F r a m e */
/*  %%Function:  ChangePicFrame  %%Owner:  bobz       */

ChangePicFrame(pca, brcl, mx, my, wCropTop, wCropLeft, wCropBottom, wCropRight)
struct CA *pca;
int brcl;
unsigned mx, my;
int wCropTop;
int wCropLeft;
int wCropBottom;
int wCropRight;
{
	int rgw[8];
	int cb, cw;
	unsigned mxAdj, myAdj;
	struct CA *pcaT;
	CP cpImport;
	BOOL fScale;
	struct CA caT;
	struct SEL selT;

	unsigned MxRoundMx();

	/* Assumptions: */

	/* Assert must be true for MxRoundMx to work for an my */
	Assert( mx100Pct == my100Pct );

	/* the current selection is a picture and vpicFetch is the picture */
	Assert (pca != NULL || selCur.fGraphics);

	/* if we are to use selCur, and selCur is an import field, get the
	ca of the pic char to apply the props to.
	*/

	if (pca == NULL)
		{
		AssertDo(FCaIsGraphics(&selCur.ca, selCur.ww, &cpImport));
		if (cpImport != cpNil)  /* import field - use pic char for ca */
			{
			caT.cpFirst = cpImport;
			caT.cpLim = cpImport + 1;
			caT.doc = selCur.doc;
			}
		}

	/* assumptions made in handbullding the grpprl */
	Assert (sprmPicBrcl < sprmPicScale
			&& dnsprm[sprmPicBrcl].cch == 2
			&& dnsprm[sprmPicScale].cch == 0
			&& sizeof(rgw) >= 16);

	cb = 0;
	if (brcl != vpicFetch.brcl)
		{
		*((char *) rgw + 0) = sprmPicBrcl;
		*((char *) rgw + 1) = brcl;
		cb = 2;
		}


	/* Round multipliers if near an even multiple */

	mxAdj = MxRoundMx( mx );
	myAdj = MxRoundMx( my );

	fScale = (mxAdj != vpicFetch.mx) || (myAdj != vpicFetch.my);
	if ( fScale ||
			(wCropTop != vpicFetch.dyaCropTop) ||
			(wCropLeft != vpicFetch.dxaCropLeft) ||
			(wCropBottom != vpicFetch.dyaCropBottom) ||
			(wCropRight != vpicFetch.dxaCropRight) )
		{
		*((char *) rgw + cb++) = sprmPicScale;
		*((char *) rgw + cb++) = 12; /* length of arguments */
		Assert (!(cb % 2));
		cw = cb >> 1;
		rgw[cw++] = mxAdj;
		rgw[cw++] = myAdj;
		rgw[cw++] = wCropLeft;
		rgw[cw++] = wCropTop;
		rgw[cw++] = wCropRight;
		rgw[cw++] = wCropBottom;
		cb = cw << 1;
		}

	/* Prevent invalidating vhplbmc (the bitmap cache) if we are just
	   cropping or changing borders. */
	vrf.fBorderCropPic = !fScale;
	if (cb)
		{
		if (pca != NULL)
			{
			ApplyGrpprlCa(rgw, cb, pca);
			InvalCp(pca);
              /* again handled by its callers */
			}
		else
			{
			/* for an import field, selCur holds the range for the entire
				field. but we want to apply to and handle undo on the pic
				char only. Slam selCur temporarily with the pic ca, then restore
			*/
			if (cpImport != cpNil)  /* import field - use pic char for ca */
				{
				selT = selCur;  /* save */
				selCur.ca = caT;
				}
			ApplyGrpprlSelCur(rgw, cb, fTrue /* fSetUndo */);

			if (cpImport != cpNil)  /* import field - use pic char for ca */
				selCur = selT;  /* restore */

            /* since we could do something like apply a large crop to a picture,
               then try to do it to a small pic, makeing it negative sized,
               clobber again here. Format Pic is itself not repeatable
            */

			if (vmerr.fMemFail) /* applygrpprlselcur can set this */
				goto LRet;

			InvalAgain();

			}

		if ((*hwwdCur)->fPageView)
			InvalPageView(pca == NULL ? selCur.doc : pca->doc);
		}
LRet:
	vrf.fBorderCropPic = fFalse;
}


/*  %%Function:  SetfEnhanceEdlWw  %%Owner:  bobz       */

SetfEnhanceEdlWw(ww)
int ww;
{
	struct PLCEDL **hplcedl;
	struct EDL edl;
	struct DRF drfFetch;

	/* get edl and set flag pic enhance flag */
	/* vdrdl... set in displayfli. This routine
		may only be called when inside DisplayFliCore
		called by Displayfli. Do not call when printing,
		as vdrdlDisplayFli will be invalid.    */

	Assert(!vfli.fPrint);

	hplcedl = PdrFetch(vdrdlDisplayFli.hpldr,
			vdrdlDisplayFli.idr,&drfFetch)->hplcedl;
	Assert(hplcedl);
	/* set flag, store */
	GetPlc(hplcedl, vdrdlDisplayFli.dl, &edl);
	edl.fNeedEnhance = fTrue;
	PutPlc(hplcedl, vdrdlDisplayFli.dl, &edl);

	/* set flag in ww so idle will redraw */
	PwwdWw(ww)->fNeedEnhance = fTrue;
	FreePdrf(&drfFetch);
}


/*  %Function:  FOurPlayMetaFile  %%Owner:  bobz       */

FOurPlayMetaFile(hdc, phMF, ww)
HDC hdc;
HANDLE *phMF;
int ww;
{


	int rgw[3]; /* rgw[0] == ww;
                 rgw[1] == saved dc;
                 rgw[2] == fInterrupt;
              */
	struct METAHDR far * lpMH; /* metafile header */
	int mtVersion;

	/* may yield or interrupt during display */

	BOOL fRet;


	/* We might never have needed to read the bits in. If we do, we will
		set *phMF so we only need to do it once, if we are going through the cache.
		Build up all bytes associated with the picture (except the header)
		into the global Windows handle hMF
   	*/

	if (*phMF == NULL)
		{
		long  cfcPic;
		LPCH    lpch;
		FC fc, fcMacPic;
		long lcbCur;
		int fnPreloadSave;
		char rgch[256];
#ifdef DEBUG
		int iT;
#endif /* DEBUG */

		cfcPic = (vpicFetch.lcb - vpicFetch.cbHeader);  /* size of pic bytes */

		if ((*phMF =GlobalAlloc2( GMEM_MOVEABLE, cfcPic )) == NULL)
			{    /* Not enough global heap space to load metafile */
			return fFalse;
			}
		if ((lpch = GlobalLock (*phMF)) == NULL)
			{
			Assert (*phMF != NULL);
			GlobalFree( *phMF );
			*phMF = NULL;
			return fFalse;
			}
		lpMH = lpch; /* so we can check win 3 meta after loading */

		fnPreloadSave = vfnPreload;
		vfnPreload = fnFetch;
		fcMacPic = vfcFetchPic + cfcPic;
		for (fc = vfcFetchPic;
			fc < fcMacPic;
			fc += lcbCur, lpch = LpchIncr(lpch, (unsigned)lcbCur))
			{
			FetchPeData(fc, (char HUGE *)rgch,
					/* using CpMin since lmin() does not exist */
			lcbCur = CpMin((long)256, fcMacPic - fc));

			// since we are always moving 256 bytes or the remaining
			// data which we have allocated room for, we will never cross
			// a 64k boundary during a blt.
			// assert there is room in current segment so we can use 
		    // bltbx instead of bltbxHuge
			Assert ((unsigned)(-LOWORD(lpch)) >= (unsigned)lcbCur
				|| (unsigned)(-LOWORD(lpch)) == 0);
			bltbx((char far *)rgch, lpch, (unsigned)lcbCur);
			}

		vfnPreload = fnPreloadSave;
		// win2 can't handle win3 metafile. abandon them.
		mtVersion = lpMH->mtVersion;
#ifdef DEBUG
		iT = 
#endif
		 	GlobalUnlock (*phMF);
		Assert(!iT);

		if (vwWinVersion < 0x0300 && mtVersion != 0x100) 
			{
			/* we got win 3 metafile that we can not display in Win 2 */
			Assert (*phMF != NULL);
			GlobalFree( *phMF );
			*phMF = NULL;
			PictError (eidPicWrongWin);
			return fFalse;
			}
		}

		rgw[0] = ww;
		rgw[1] = SaveDC(hdc);
          /* if true, we will allow pic to be interrupted */
	    rgw[2] = (vfli.fPrint || vlm == lmPreview || vfDeactByOtherApp) ?
                  fFalse : fTrue;


#ifdef DEBUG
	if (vdbs.fDumpPicInfo)
		DumpOrgExt(hdc);
#endif /* DEBUG */


		fRet = EnumMetaFile(hdc, *phMF, lpFMFContinue, (BYTE FAR *)rgw);
		if (rgw[1])  /* interrupt may have cleared it */
			RestoreDC (hdc, rgw[1]);
		return fRet;

}


/* Called by EnumMetafile. */

/*  %%Function:  FMFContinue  %%Owner:  bobz       */

EXPORT BOOL FAR PASCAL FMFContinue(hdc, lpHTable, lpMFR, nObj, lpClientData)
HDC hdc;
LPHANDLETABLE lpHTable;
LPMETARECORD lpMFR;
int nObj;
int FAR *lpClientData;
{

	MSG msg;

             /* bz for fPrint we used to call FQueryAbortCheck but that could
                cause updateww which would call formatline and we
                are within displayfli. So only abort at the line
                level (let print code handle it); Peek here to yield.
                In preview and deactivate, messages flying around interrupt
                the pic when we don't want it to, and they never show up
                so yield but don't interrupt.
             */

	if (!lpClientData[2])  /* fInterrupt */
		PeekMessage((MSG far *)&msg, NULL, 0, 0, PM_NOREMOVE);
    else if (FMsgPresent (mtyLongDisp)) /* won't blink & cause formatline call */
		{
             
	    if (vfDeactByOtherApp)
			{
			 /* we may get deactivated in mid draw; if so stop checking
				for interrupt
			 */
		    lpClientData[2] = fFalse; /* fInterrupt */
			}
		else
			{
#ifdef BZ
			CommSz(SzShared("FMFContinue metafile interrupted\n"));
#endif /* BZ */

		    Assert (!(vfli.fPrint || vlm == lmPreview));
			vfGrInterrupt = fTrue;
			/* cause it to be retried later */
	    	SetfEnhanceEdlWw(lpClientData[0] /* ww */);
			/* restore to original dc level to avoid interrupted savedc problems */
			Assert (lpClientData[1] != 0); /* saved dc */
			RestoreDC (hdc, lpClientData[1]);
			lpClientData[1] = 0;

			return fFalse;
			}
		}

#ifdef DEBUG
	if (vdbs.fDumpPicInfo)
		DumpMetaRec(lpMFR);
#endif /* BZ */

	PlayMetaFileRecord(hdc, lpHTable, lpMFR, nObj);
	return fTrue;
}



/******************************/

/*  M X  R O U N D  M X  */
/*  %%Function:  MxRoundMx  %%Owner:  bobz       */

unsigned MxRoundMx( mx )
unsigned mx;
	{   /* If mx is near an "interesting" multiple, round it to be exactly that
		multiple.  Interesting multiples are:
	
					1 (m=mx100Pct), 2 (m=2 * mx100Pct), 3 , ...
					0.5 (m = .5 * mx100Pct)
	
		Need to keep unobtrusive so that dragging won't seem to round
		to easily, but this is useful if we are close to an integer
		multiply.
	
		This routine works for my, too, as long as mx100Pct == my100Pct
*/
	/* This means close enough to round (2 decimal place accuracy) */

#define dmxRound    (mx100Pct / 200)

	unsigned mxRemainder;

	if (mx >= mx100Pct - dmxRound)
		{   /* Multiplier > 1 -- look for rounding to integer multiple */
		UDiv(mx, mx100Pct, &mxRemainder);
		if (mxRemainder  < dmxRound)
			mx -= mxRemainder;
		else  if (mxRemainder >= mx100Pct - dmxRound)
			mx += (mx100Pct - mxRemainder);
		}
	else
		{   /* Multiplier < 1 -- look for multiplication by 1/2 */
		UDiv (mx, (mx100Pct >> 1), &mxRemainder);
		if (mxRemainder  < dmxRound)
			mx -= mxRemainder;
		else  if (mxRemainder >= ((mx100Pct >> 1) - dmxRound))
			mx += (mx100Pct >> 1) - mxRemainder;
		}

	return (mx);
}



