You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
723 lines
22 KiB
723 lines
22 KiB
/*****************************************************************************
|
|
*
|
|
* regions - Entry points for Win32 to Win 16 converter
|
|
*
|
|
* Date: 7/1/91
|
|
* Author: Jeffrey Newman (c-jeffn)
|
|
*
|
|
* Copyright 1991 Microsoft Corp
|
|
*
|
|
* NOTES:
|
|
*
|
|
When there are no embedded metafiles we need to do the following:
|
|
|
|
1] Read the metafile data from the Win32 metafile. This
|
|
is done by the handler routines that in turn call these
|
|
routines.
|
|
|
|
2] Translate the Win32 metafile data into Win16 metafile data.
|
|
|
|
The region data for FillRgn, FrameRgn, InvertRgn, and PaintRgn
|
|
are in record-time world coordinates. The region data for
|
|
these region API's will have to be translated from record-time
|
|
-world coordinates to play-time-page coordinates
|
|
(XFORM_WORLD_TO_PAGE). The helperDC will be used for
|
|
this transformation.
|
|
|
|
The region data for SelectClipRgn and OffsetClipRgn are in
|
|
record-time device coordinates. The region data for these
|
|
APIs will be translated from record-time-device coordinates
|
|
to play-time-device coordinates.
|
|
|
|
3] Emit a Win16 create region metafile record.
|
|
|
|
4] Select the newly created region into the metafile.
|
|
|
|
5] Do the region function (FillRegion, FrameRegion, ...).
|
|
This means emit a FillRegion or FrameRegion drawing order
|
|
into the Win16 metafile.
|
|
|
|
6] Emit a Delete Region drawing order.
|
|
|
|
7] Clean up all the memory resources used.
|
|
|
|
When there are embedded metafiles things get a little more complicated.
|
|
Most of the complications are hidden in PlayMetafile record processing.
|
|
Items 1 thru 3 will be handled by the PlayMetafile Doer.
|
|
|
|
1] We need to keep the region from the previous DC level.
|
|
This can be done by the helper DC (SaveDC). We will have to
|
|
do a GetClipRgn and a SelectMetaRgn. A MetaRgn is the clip
|
|
region from the previous level.
|
|
|
|
2] We will have to intersect any clip regions from the current
|
|
level with any clip regions from the previous level. This can
|
|
be done by the helper DC (using the hrgnMeta & ExtCombineRegion)
|
|
|
|
3] When we pop out from this level we will have to restore the
|
|
previous saved region. This can be done by the helper DC.
|
|
(RestoreDC).
|
|
|
|
Since we do not know whether or not there will be an embedded metafile
|
|
in the metafile we are currently processing we will always shadow
|
|
the Clip Region call into the helper DC.
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
|
|
BOOL bEmitWin3Region(PLOCALDC pLocalDC, HRGN hrgn);
|
|
|
|
#define MIN_RGN_COORD16 -30000
|
|
#define MAX_RGN_COORD16 30000
|
|
|
|
/***************************************************************************
|
|
* DoDrawRgn
|
|
*
|
|
* CR1: This routine was added as part of the handle manager change.
|
|
* I noticed that almost all of the Region Rendering code was
|
|
* the same.
|
|
**************************************************************************/
|
|
BOOL APIENTRY DoDrawRgn
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
INT ihBrush,
|
|
INT nWidth,
|
|
INT nHeight,
|
|
INT cRgnData,
|
|
LPRGNDATA pRgnData,
|
|
INT mrType
|
|
)
|
|
{
|
|
BOOL b ;
|
|
HRGN hrgn = (HRGN) 0;
|
|
INT ihW16Rgn = -1,
|
|
ihW16Brush = -1;
|
|
|
|
b = FALSE ;
|
|
|
|
// Translate the Win32 region data from Metafile-World to
|
|
// Referencd-Page space.
|
|
// This is done by ExtCreateRegion's xform. The returned region
|
|
// is transformed.
|
|
|
|
hrgn = ExtCreateRegion(&pLocalDC->xformRWorldToPPage, cRgnData,
|
|
(LPRGNDATA) pRgnData);
|
|
if (!hrgn)
|
|
{
|
|
RIP("MF3216: DoDrawRgn, ExtCreateRegion failed\n") ;
|
|
goto error_exit ;
|
|
}
|
|
|
|
// Allocate a handle for the region.
|
|
// This is different from a normal handle allocation, because
|
|
// there is no region handle in Win32. We are using one of our
|
|
// extra slots here.
|
|
|
|
ihW16Rgn = iGetW16ObjectHandleSlot(pLocalDC, REALIZED_REGION) ;
|
|
if (ihW16Rgn == -1)
|
|
goto error_exit ;
|
|
|
|
// Emit a Win16 create region record for the region.
|
|
|
|
if (!bEmitWin3Region(pLocalDC, hrgn))
|
|
{
|
|
RIP("MF3216: DoDrawRgn, bEmitWin3Region failed\n") ;
|
|
goto error_exit ;
|
|
}
|
|
|
|
// Translate the W32 Brush object index to a W16 Brush object index.
|
|
|
|
if (ihBrush)
|
|
{
|
|
// Make sure that the W16 object exists. Stock brushes may not
|
|
// have been created and iValidateHandle will take care of creating
|
|
// them.
|
|
|
|
ihW16Brush = iValidateHandle(pLocalDC, ihBrush) ;
|
|
if (ihW16Brush == -1)
|
|
goto error_exit ;
|
|
}
|
|
|
|
// Emit the Region Record depending upon the function type.
|
|
|
|
switch (mrType)
|
|
{
|
|
case EMR_FILLRGN:
|
|
if(ihW16Brush == -1)
|
|
goto error_exit;
|
|
b = bEmitWin16FillRgn(pLocalDC,
|
|
LOWORD(ihW16Rgn),
|
|
LOWORD(ihW16Brush)) ;
|
|
break ;
|
|
|
|
case EMR_FRAMERGN:
|
|
nWidth = iMagnitudeXform (pLocalDC, nWidth, CX_MAG) ;
|
|
nHeight = iMagnitudeXform (pLocalDC, nHeight, CY_MAG) ;
|
|
if(ihW16Brush == -1)
|
|
goto error_exit;
|
|
|
|
b = bEmitWin16FrameRgn(pLocalDC,
|
|
LOWORD(ihW16Rgn),
|
|
LOWORD(ihW16Brush),
|
|
LOWORD(nWidth),
|
|
LOWORD(nHeight)) ;
|
|
break ;
|
|
|
|
case EMR_INVERTRGN:
|
|
b = bEmitWin16InvertRgn(pLocalDC,
|
|
LOWORD(ihW16Rgn)) ;
|
|
break ;
|
|
|
|
case EMR_PAINTRGN:
|
|
b = bEmitWin16PaintRgn(pLocalDC,
|
|
LOWORD(ihW16Rgn)) ;
|
|
break ;
|
|
|
|
default:
|
|
RIP("MF3216: DoDrawRgn, unknown type\n") ;
|
|
break ;
|
|
}
|
|
|
|
error_exit:
|
|
// Delete the W16 Region Object.
|
|
|
|
if (ihW16Rgn != -1)
|
|
bDeleteW16Object(pLocalDC, ihW16Rgn) ;
|
|
|
|
if (hrgn)
|
|
DeleteObject(hrgn) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* ExtSelectClipRgn - Win32 to Win16 Metafile Converter Entry Point
|
|
*
|
|
* History:
|
|
* Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
**************************************************************************/
|
|
|
|
BOOL WINAPI DoExtSelectClipRgn
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
INT cRgnData,
|
|
LPRGNDATA pRgnData,
|
|
INT iMode
|
|
)
|
|
{
|
|
HANDLE hrgn;
|
|
BOOL bRet;
|
|
BOOL bNoClipRgn ;
|
|
|
|
bNoClipRgn = bNoDCRgn(pLocalDC, DCRGN_CLIP);
|
|
|
|
// Do it to the helper DC.
|
|
|
|
if (cRgnData == 0) // default clipping
|
|
{
|
|
ASSERTGDI(iMode == RGN_COPY, "MF3216: DoExtSelectClipRgn: bad iMode\n");
|
|
|
|
// No work if no previous clip region.
|
|
|
|
if (bNoClipRgn)
|
|
return(TRUE);
|
|
|
|
bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, (HRGN)0, iMode) != ERROR);
|
|
}
|
|
else
|
|
{
|
|
|
|
// If there is no initial clip region and we are going to operate
|
|
// on the initial clip region, we have to
|
|
// create one. Otherwise, GDI will create some random default
|
|
// clipping region for us!
|
|
|
|
if (bNoClipRgn
|
|
&& (iMode == RGN_DIFF || iMode == RGN_XOR || iMode == RGN_OR))
|
|
{
|
|
HRGN hrgnDefault;
|
|
|
|
if (!(hrgnDefault = CreateRectRgn((int) (SHORT) MINSHORT,
|
|
(int) (SHORT) MINSHORT,
|
|
(int) (SHORT) MAXSHORT,
|
|
(int) (SHORT) MAXSHORT)))
|
|
{
|
|
ASSERTGDI(FALSE, "MF3216: CreateRectRgn failed");
|
|
return(FALSE);
|
|
}
|
|
|
|
bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgnDefault, RGN_COPY)
|
|
!= ERROR);
|
|
ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed");
|
|
|
|
if (!DeleteObject(hrgnDefault))
|
|
ASSERTGDI(FALSE, "MF3216: DeleteObject failed");
|
|
|
|
if (!bRet)
|
|
return(FALSE);
|
|
}
|
|
|
|
// Create a region from the region data passed in.
|
|
|
|
if (!(hrgn = ExtCreateRegion((LPXFORM) NULL, cRgnData, pRgnData)))
|
|
{
|
|
RIP("MF3216: DoExtSelectClipRgn, Create region failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgn, iMode) != ERROR);
|
|
|
|
ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed\n");
|
|
|
|
if (!DeleteObject(hrgn))
|
|
RIP("MF3216: DeleteObject failed\n");
|
|
}
|
|
|
|
// dump the clip region data.
|
|
|
|
if (bRet)
|
|
return(bDumpDCClipping(pLocalDC));
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* SetMetaRgn - Win32 to Win16 Metafile Converter Entry Point
|
|
*
|
|
* History:
|
|
* Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
**************************************************************************/
|
|
|
|
BOOL WINAPI DoSetMetaRgn(PLOCALDC pLocalDC)
|
|
{
|
|
// No work if the clip region does not exist.
|
|
|
|
if (bNoDCRgn(pLocalDC, DCRGN_CLIP))
|
|
return(TRUE);
|
|
|
|
// Do it to the helper DC.
|
|
|
|
if (!SetMetaRgn(pLocalDC->hdcHelper))
|
|
return(FALSE);
|
|
|
|
// Dump the clip region data.
|
|
|
|
return(bDumpDCClipping(pLocalDC));
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* OffsetClipRgn - Win32 to Win16 Metafile Converter Entry Point
|
|
*
|
|
* History:
|
|
* Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
**************************************************************************/
|
|
|
|
BOOL WINAPI DoOffsetClipRgn(PLOCALDC pLocalDC, INT x, INT y)
|
|
{
|
|
POINTL aptl[2];
|
|
BOOL b;
|
|
|
|
// Do it to the helper DC.
|
|
|
|
if (!OffsetClipRgn(pLocalDC->hdcHelper, x, y))
|
|
return(FALSE);
|
|
|
|
// Dump region if the meta region exists.
|
|
// We don't offset the meta region!
|
|
|
|
if (!bNoDCRgn(pLocalDC, DCRGN_META))
|
|
return(bDumpDCClipping(pLocalDC));
|
|
|
|
// Translate the record-time world offsets to play-time page offsets.
|
|
|
|
aptl[0].x = 0;
|
|
aptl[0].y = 0;
|
|
aptl[1].x = x;
|
|
aptl[1].y = y;
|
|
|
|
if (!bXformRWorldToPPage(pLocalDC, aptl, 2))
|
|
return(FALSE);
|
|
|
|
aptl[1].x -= aptl[0].x;
|
|
aptl[1].y -= aptl[0].y;
|
|
|
|
b = bEmitWin16OffsetClipRgn(pLocalDC, (SHORT) aptl[1].x, (SHORT) aptl[1].y);
|
|
ASSERTGDI(b, "MF3216: DoOffsetClipRgn, bEmitWin16OffsetClipRgn failed\n");
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* bNoDCRgn - Return TRUE if the dc clip region does not exist.
|
|
* Otherwise, return FALSE.
|
|
* This is TEMPORARY only. Get gdi to provide this functionality.
|
|
**************************************************************************/
|
|
|
|
BOOL bNoDCRgn(PLOCALDC pLocalDC, INT iType)
|
|
{
|
|
BOOL bRet = FALSE; // assume the dc region exists
|
|
HRGN hrgnTmp;
|
|
|
|
ASSERTGDI(iType == DCRGN_CLIP || iType == DCRGN_META,
|
|
"MF3216: bNoDCRgn, bad iType\n");
|
|
|
|
if (!(hrgnTmp = CreateRectRgn(0, 0, 0, 0)))
|
|
{
|
|
ASSERTGDI(FALSE, "MF3216: bNoDCRgn, CreateRectRgn failed\n");
|
|
return(bRet);
|
|
}
|
|
|
|
switch (GetRandomRgn(pLocalDC->hdcHelper,
|
|
hrgnTmp,
|
|
iType == DCRGN_CLIP ? 1 : 2
|
|
)
|
|
)
|
|
{
|
|
case -1: // error
|
|
ASSERTGDI(FALSE, "GetRandomRgn failed");
|
|
break;
|
|
case 0: // no dc region
|
|
bRet = TRUE;
|
|
break;
|
|
case 1: // has dc region
|
|
break;
|
|
}
|
|
|
|
if (!DeleteObject(hrgnTmp))
|
|
ASSERTGDI(FALSE, "DeleteObject failed");
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* bDumpDCClipping - Dump the DC clipping regions.
|
|
*
|
|
* History:
|
|
* Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
**************************************************************************/
|
|
|
|
BOOL bDumpDCClipping(PLOCALDC pLocalDC)
|
|
{
|
|
BOOL bRet = FALSE; // assume failure
|
|
HRGN hrgnRDev = (HRGN) 0;
|
|
HRGN hrgnPPage = (HRGN) 0;
|
|
HRGN hrgnPPageBounds = (HRGN) 0;
|
|
LPRGNDATA lprgnRDev = (LPRGNDATA) NULL;
|
|
LPRGNDATA lprgnPPage = (LPRGNDATA) NULL;
|
|
DWORD cRgnData;
|
|
INT i;
|
|
INT nrcl;
|
|
PRECTL prcl;
|
|
RECTL rclPPage;
|
|
|
|
// Since clipping region is not scalable in Win30, we do not emit
|
|
// SelectClipRgn record. Instead, we set the clipping to the default, i.e.
|
|
// no clipping, and then emit the scalable IntersectClipRect/ExcludeClipRect
|
|
// records to exclude clipping region. This will allow the win30 metafiles
|
|
// to be scalable.
|
|
|
|
// First, emit a default clipping region.
|
|
|
|
// On Win3.x, the META_SELECTCLIPREGION record only works if it has
|
|
// a NULL handle. The Win3x metafile driver does not translate the
|
|
// region handle at playback time!
|
|
|
|
if (!bW16Emit1(pLocalDC, META_SELECTCLIPREGION, 0))
|
|
goto ddcc_exit;
|
|
|
|
// Now find the clip and meta regions to be excluded from the default
|
|
// clipping region.
|
|
|
|
if (!(hrgnRDev = CreateRectRgn(0, 0, 0, 0)))
|
|
goto ddcc_exit;
|
|
|
|
switch (GetRandomRgn(pLocalDC->hdcHelper, hrgnRDev, 3)) // meta and clip
|
|
{
|
|
case -1: // error
|
|
ASSERTGDI(FALSE, "GetRandomRgn failed");
|
|
goto ddcc_exit;
|
|
case 0: // no clip region, we are done
|
|
bRet = TRUE;
|
|
goto ddcc_exit;
|
|
case 1: // has clip region
|
|
break;
|
|
}
|
|
|
|
// Get the clip region data.
|
|
// First query the size of the buffer required to hold the clip region data.
|
|
|
|
if (!(cRgnData = GetRegionData(hrgnRDev, 0, (LPRGNDATA) NULL)))
|
|
goto ddcc_exit;
|
|
|
|
// Allocate the memory for the clip region data buffer.
|
|
|
|
if (!(lprgnRDev = (LPRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData)))
|
|
goto ddcc_exit;
|
|
|
|
// Get clip region data.
|
|
|
|
if (GetRegionData(hrgnRDev, cRgnData, lprgnRDev) != cRgnData)
|
|
goto ddcc_exit;
|
|
|
|
// Create the clip region in the playtime page space.
|
|
|
|
if (!(hrgnPPage = ExtCreateRegion(&pLocalDC->xformRDevToPPage, cRgnData, lprgnRDev)))
|
|
goto ddcc_exit;
|
|
|
|
// Get the bounding box for the playtime clip region in page space.
|
|
|
|
if (GetRgnBox(hrgnPPage, (LPRECT) &rclPPage) == ERROR)
|
|
goto ddcc_exit;
|
|
|
|
// Bound it to 16-bit.
|
|
|
|
rclPPage.left = max(MIN_RGN_COORD16,rclPPage.left);
|
|
rclPPage.top = max(MIN_RGN_COORD16,rclPPage.top);
|
|
rclPPage.right = min(MAX_RGN_COORD16,rclPPage.right);
|
|
rclPPage.bottom = min(MAX_RGN_COORD16,rclPPage.bottom);
|
|
|
|
// Set the bounding box as the bounds for the clipping.
|
|
|
|
if (!bEmitWin16IntersectClipRect(pLocalDC,
|
|
(SHORT) rclPPage.left,
|
|
(SHORT) rclPPage.top,
|
|
(SHORT) rclPPage.right,
|
|
(SHORT) rclPPage.bottom))
|
|
goto ddcc_exit;
|
|
|
|
// Create the bounding region.
|
|
|
|
if (!(hrgnPPageBounds = CreateRectRgn(rclPPage.left,
|
|
rclPPage.top,
|
|
rclPPage.right,
|
|
rclPPage.bottom)))
|
|
goto ddcc_exit;
|
|
|
|
// Exclude the regions in playtime page space.
|
|
|
|
if (CombineRgn(hrgnPPage, hrgnPPageBounds, hrgnPPage, RGN_DIFF) == ERROR)
|
|
goto ddcc_exit;
|
|
|
|
// Finally, exclude the rectangles from the bounding box.
|
|
|
|
if (!(cRgnData = GetRegionData(hrgnPPage, 0, (LPRGNDATA) NULL)))
|
|
goto ddcc_exit;
|
|
|
|
if (!(lprgnPPage = (LPRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData)))
|
|
goto ddcc_exit;
|
|
|
|
if (GetRegionData(hrgnPPage, cRgnData, lprgnPPage) != cRgnData)
|
|
goto ddcc_exit;
|
|
|
|
// Get the number of rectangles in the transformed region.
|
|
|
|
nrcl = lprgnPPage->rdh.nCount;
|
|
prcl = (PRECTL) lprgnPPage->Buffer;
|
|
|
|
// Emit a series of Exclude Clip Rectangle Metafile records.
|
|
|
|
for (i = 0 ; i < nrcl; i++)
|
|
{
|
|
ASSERTGDI(prcl[i].left >= MIN_RGN_COORD16
|
|
&& prcl[i].top >= MIN_RGN_COORD16
|
|
&& prcl[i].right <= MAX_RGN_COORD16
|
|
&& prcl[i].bottom <= MAX_RGN_COORD16,
|
|
"MF3216: bad coord");
|
|
|
|
if (!bEmitWin16ExcludeClipRect(pLocalDC,
|
|
(SHORT) prcl[i].left,
|
|
(SHORT) prcl[i].top,
|
|
(SHORT) prcl[i].right,
|
|
(SHORT) prcl[i].bottom))
|
|
goto ddcc_exit;
|
|
}
|
|
|
|
bRet = TRUE; // we are golden!
|
|
|
|
// Cleanup all the resources used.
|
|
|
|
ddcc_exit:
|
|
|
|
if (hrgnRDev)
|
|
DeleteObject(hrgnRDev);
|
|
|
|
if (hrgnPPage)
|
|
DeleteObject(hrgnPPage);
|
|
|
|
if (hrgnPPageBounds)
|
|
DeleteObject(hrgnPPageBounds);
|
|
|
|
if (lprgnRDev)
|
|
LocalFree(lprgnRDev);
|
|
|
|
if (lprgnPPage)
|
|
LocalFree(lprgnPPage);
|
|
|
|
return(bRet) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Emit a 16-bit CreateRegion record for the given region.
|
|
*
|
|
* This code is copied from the 16-bit metafile driver in gdi.
|
|
*
|
|
**************************************************************************/
|
|
|
|
WIN3REGION w3rgnEmpty =
|
|
{
|
|
0, // nextInChain
|
|
6, // ObjType
|
|
0x2F6, // ObjCount
|
|
sizeof(WIN3REGION) - sizeof(SCAN) + 2,
|
|
// cbRegion
|
|
0, // cScans
|
|
0, // maxScan
|
|
{0,0,0,0}, // rcBounding
|
|
{0,0,0,{0,0},0} // aScans[]
|
|
};
|
|
|
|
BOOL bEmitWin3Region(PLOCALDC pLocalDC, HRGN hrgn)
|
|
{
|
|
/*
|
|
* in win2, METACREATEREGION records contained an entire region object,
|
|
* including the full header. this header changed in win3.
|
|
*
|
|
* to remain compatible, the region records will be saved with the
|
|
* win2 header. here we save our region with a win2 header.
|
|
*/
|
|
PWIN3REGION lpw3rgn;
|
|
DWORD cbNTRgnData;
|
|
DWORD curRectl;
|
|
WORD cScans;
|
|
WORD maxScanEntry;
|
|
WORD curScanEntry;
|
|
DWORD cbw3data;
|
|
PRGNDATA lprgn;
|
|
LPRECT lprc;
|
|
PSCAN lpScan;
|
|
BOOL bRet;
|
|
|
|
ASSERTGDI(hrgn, "MF3216: bEmitWin3Region, hrgn is NULL");
|
|
|
|
// Get the NT Region Data
|
|
cbNTRgnData = GetRegionData(hrgn, 0, NULL);
|
|
if (cbNTRgnData == 0)
|
|
return(FALSE);
|
|
|
|
lprgn = (PRGNDATA) LocalAlloc(LMEM_FIXED, cbNTRgnData);
|
|
if (!lprgn)
|
|
return(FALSE);
|
|
|
|
cbNTRgnData = GetRegionData(hrgn, cbNTRgnData, lprgn);
|
|
if (cbNTRgnData == 0)
|
|
{
|
|
LocalFree((HANDLE) lprgn);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Handle the empty region.
|
|
|
|
if (!lprgn->rdh.nCount)
|
|
{
|
|
bRet = bEmitWin16CreateRegion(pLocalDC, sizeof(WIN3REGION) - sizeof(SCAN), (PVOID) &w3rgnEmpty);
|
|
|
|
LocalFree((HANDLE)lprgn);
|
|
return(bRet);
|
|
}
|
|
|
|
lprc = (LPRECT)lprgn->Buffer;
|
|
|
|
// Create the Windows 3.x equivalent
|
|
|
|
// worst case is one scan for each rect
|
|
cbw3data = 2*sizeof(WIN3REGION) + (WORD)lprgn->rdh.nCount*sizeof(SCAN);
|
|
|
|
lpw3rgn = (PWIN3REGION)LocalAlloc(LMEM_FIXED, cbw3data);
|
|
if (!lpw3rgn)
|
|
{
|
|
LocalFree((HANDLE) lprgn);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Grab the bounding rect.
|
|
lpw3rgn->rcBounding.left = (SHORT)lprgn->rdh.rcBound.left;
|
|
lpw3rgn->rcBounding.right = (SHORT)lprgn->rdh.rcBound.right;
|
|
lpw3rgn->rcBounding.top = (SHORT)lprgn->rdh.rcBound.top;
|
|
lpw3rgn->rcBounding.bottom = (SHORT)lprgn->rdh.rcBound.bottom;
|
|
|
|
cbw3data = sizeof(WIN3REGION) - sizeof(SCAN) + 2;
|
|
|
|
// visit all the rects
|
|
curRectl = 0;
|
|
cScans = 0;
|
|
maxScanEntry = 0;
|
|
lpScan = lpw3rgn->aScans;
|
|
|
|
while(curRectl < lprgn->rdh.nCount)
|
|
{
|
|
LPWORD lpXEntry;
|
|
DWORD cbScan;
|
|
|
|
curScanEntry = 0; // Current X pair in this scan
|
|
|
|
lpScan->scnPntTop = (WORD)lprc[curRectl].top;
|
|
lpScan->scnPntBottom = (WORD)lprc[curRectl].bottom;
|
|
|
|
lpXEntry = (LPWORD) lpScan->scnPntsX;
|
|
|
|
// handle rects on this scan
|
|
do
|
|
{
|
|
lpXEntry[curScanEntry + 0] = (WORD)lprc[curRectl].left;
|
|
lpXEntry[curScanEntry + 1] = (WORD)lprc[curRectl].right;
|
|
curScanEntry += 2;
|
|
curRectl++;
|
|
} while ((curRectl < lprgn->rdh.nCount)
|
|
&& (lprc[curRectl-1].top == lprc[curRectl].top)
|
|
&& (lprc[curRectl-1].bottom == lprc[curRectl].bottom)
|
|
);
|
|
|
|
lpScan->scnPntCnt = curScanEntry;
|
|
lpXEntry[curScanEntry] = curScanEntry; // Count also follows Xs
|
|
cScans++;
|
|
|
|
if (curScanEntry > maxScanEntry)
|
|
maxScanEntry = curScanEntry;
|
|
|
|
// account for each new scan + each X1 X2 Entry but the first
|
|
cbScan = sizeof(SCAN)-(sizeof(WORD)*2) + (curScanEntry*sizeof(WORD));
|
|
cbw3data += cbScan;
|
|
lpScan = (PSCAN)(((LPBYTE)lpScan) + cbScan);
|
|
}
|
|
|
|
// Initialize the header
|
|
lpw3rgn->nextInChain = 0;
|
|
lpw3rgn->ObjType = 6; // old Windows OBJ_RGN identifier
|
|
lpw3rgn->ObjCount= 0x2F6; // any non-zero number
|
|
lpw3rgn->cbRegion = (WORD)cbw3data; // don't count type and next
|
|
lpw3rgn->cScans = cScans;
|
|
lpw3rgn->maxScan = maxScanEntry;
|
|
|
|
bRet = bEmitWin16CreateRegion(pLocalDC, cbw3data-2, (PVOID) lpw3rgn);
|
|
|
|
if (LocalFree((HANDLE)lprgn))
|
|
ASSERTGDI(FALSE, "bEmitWin3Region: LocalFree(lprgn) Failed\n");
|
|
if (LocalFree((HANDLE)lpw3rgn))
|
|
ASSERTGDI(FALSE, "bEmitWin3Region: LocalFree(lpw3rgn) Failed\n");
|
|
|
|
return(bRet);
|
|
}
|