|
|
//
// OE.C
// Order Encoder
//
// Copyright(c) Microsoft 1997-
//
#include <as16.h>
//
// Define entries in the Font Alias table. This table is used to convert
// non-existant fonts (used by certain widely used applications) into
// something we can use as a local font.
//
// The font names that we alias are:
//
// "Helv"
// This is used by Excel. It is mapped directly onto "MS Sans Serif".
//
// "MS Dialog"
// This is used by Word. It is the same as an 8pt bold MS Sans Serif.
// We actually map it to a "MS Sans Serif" font that is one pel narrower
// than the metrics specify (because all matching is done on non-bold
// fonts) - hence the 1 value in the charWidthAdjustment field.
//
// "MS Dialog Light"
// Added as part of the Win95 performance enhancements...Presumably for
// MS-Word...
//
//
#define NUM_ALIAS_FONTS 3
char CODESEG g_szMsSansSerif[] = "MS Sans Serif"; char CODESEG g_szHelv[] = "Helv"; char CODESEG g_szMsDialog[] = "MS Dialog"; char CODESEG g_szMsDialogLight[] = "MS Dialog Light";
FONT_ALIAS_TABLE CODESEG g_oeFontAliasTable[NUM_ALIAS_FONTS] = { { g_szHelv, g_szMsSansSerif, 0 }, { g_szMsDialog, g_szMsSansSerif, 1 }, { g_szMsDialogLight, g_szMsSansSerif, 0 } };
//
// OE_DDProcessRequest()
// Handles OE escapes
//
BOOL OE_DDProcessRequest ( UINT fnEscape, LPOSI_ESCAPE_HEADER pResult, DWORD cbResult ) { BOOL rc = TRUE;
DebugEntry(OE_DDProcessRequest);
switch (fnEscape) { case OE_ESC_NEW_FONTS: { ASSERT(cbResult == sizeof(OE_NEW_FONTS));
OEDDSetNewFonts((LPOE_NEW_FONTS)pResult); } break;
case OE_ESC_NEW_CAPABILITIES: { ASSERT(cbResult == sizeof(OE_NEW_CAPABILITIES));
OEDDSetNewCapabilities((LPOE_NEW_CAPABILITIES)pResult); } break;
default: { ERROR_OUT(("Unrecognized OE escape")); rc = FALSE; } break; }
DebugExitBOOL(OE_DDProcessRequest, rc); return(rc); }
//
// OE_DDInit()
// This creates the patches we need.
//
BOOL OE_DDInit(void) { BOOL rc = FALSE; HGLOBAL hMem; UINT uSel; DDI_PATCH iPatch;
DebugEntry(OE_DDInit);
//
// lstrcmp(), like strcmp(), works numerically for US/Eng code page.
// But it's lexographic like Win32 lstrcmp() is all the time for non
// US.
//
// So we use MyStrcmp()
//
ASSERT(MyStrcmp("Symbol", "SYmbol") > 0);
//
// Allocate a cached selector. We use it when reading from swapped-out
// DCs. Therefore base it off of GDI's data segement, so it has the
// same access rights and limit.
//
g_oeSelDst = AllocSelector((UINT)g_hInstGdi16); g_oeSelSrc = AllocSelector((UINT)g_hInstGdi16); if (!g_oeSelDst || !g_oeSelSrc) { ERROR_OUT(("Out of selectors")); DC_QUIT; }
//
// Allocate g_poeLocalFonts--it's too big for our DS. We make it
// a very small size since on new fonts, we will realloc it.
//
hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE, sizeof(LOCALFONT)); if (!hMem) { ERROR_OUT(("OE_DDInit: Couldn't allocate font matching array")); DC_QUIT; } g_poeLocalFonts = MAKELP(hMem, 0);
//
// Create two patches for ChangeDisplaySettings/Ex and ENABLE them right
// away. We don't want you to be able to change your display when
// NetMeeting is running, regardless of whether you are in a share yet.
//
uSel = CreateFnPatch(ChangeDisplaySettings, DrvChangeDisplaySettings, &g_oeDisplaySettingsPatch, 0); if (!uSel) { ERROR_OUT(("CDS patch failed to create")); DC_QUIT; }
EnableFnPatch(&g_oeDisplaySettingsPatch, PATCH_ACTIVATE);
if (SELECTOROF(g_lpfnCDSEx)) { if (!CreateFnPatch(g_lpfnCDSEx, DrvChangeDisplaySettingsEx, &g_oeDisplaySettingsExPatch, uSel)) { ERROR_OUT(("CDSEx patch failed to create")); DC_QUIT; }
EnableFnPatch(&g_oeDisplaySettingsExPatch, PATCH_ACTIVATE); }
//
// Create patches.
// NOTE this code assumes that various groups of functions are in
// the same segment. CreateFnPatch has asserts to verify this.
//
// Rather than check each for failure (low on selectors), we try to
// create all the patches, then loop through looking for any that
// didn't succeed.
//
// Why do we do this? Because allocating 50 different selectors is
// not so hot when 16-bit selectors are the most precious resource on
// Win95 (most out-of-memory conditions that aren't blatant app errors
// are caused by a lack of selectors, not logical memory).
//
// _ARCDDA
uSel = CreateFnPatch(Arc, DrvArc, &g_oeDDPatches[DDI_ARC], 0); CreateFnPatch(Chord, DrvChord, &g_oeDDPatches[DDI_CHORD], uSel); CreateFnPatch(Ellipse, DrvEllipse, &g_oeDDPatches[DDI_ELLIPSE], uSel); CreateFnPatch(Pie, DrvPie, &g_oeDDPatches[DDI_PIE], uSel); CreateFnPatch(RoundRect, DrvRoundRect, &g_oeDDPatches[DDI_ROUNDRECT], uSel);
// IGROUP
uSel = CreateFnPatch(BitBlt, DrvBitBlt, &g_oeDDPatches[DDI_BITBLT], 0); CreateFnPatch(ExtTextOut, DrvExtTextOutA, &g_oeDDPatches[DDI_EXTTEXTOUTA], uSel); CreateFnPatch(InvertRgn, DrvInvertRgn, &g_oeDDPatches[DDI_INVERTRGN], uSel); CreateFnPatch(DeleteObject, DrvDeleteObject, &g_oeDDPatches[DDI_DELETEOBJECT], uSel); CreateFnPatch(Death, DrvDeath, &g_oeDDPatches[DDI_DEATH], uSel); CreateFnPatch(Resurrection, DrvResurrection, &g_oeDDPatches[DDI_RESURRECTION], uSel);
//
// Note: PatBlt and IPatBlt (internal PatBlt) jump to RealPatBlt, which
// is 3 bytes past PatBlt. So patch RealPatBlt, or we'll (1) fault with
// misaligned instructions and (2) miss many PatBlt calls. But our
// function needs to preserve CX since those two routines pass 0 for
// internal calls (EMF) and -1 for external calls.
//
g_lpfnRealPatBlt = (REALPATBLTPROC)((LPBYTE)PatBlt+3); CreateFnPatch(g_lpfnRealPatBlt, DrvPatBlt, &g_oeDDPatches[DDI_PATBLT], uSel); CreateFnPatch(StretchBlt, DrvStretchBlt, &g_oeDDPatches[DDI_STRETCHBLT], uSel); CreateFnPatch(TextOut, DrvTextOutA, &g_oeDDPatches[DDI_TEXTOUTA], uSel);
// _FLOODFILL
uSel = CreateFnPatch(ExtFloodFill, DrvExtFloodFill, &g_oeDDPatches[DDI_EXTFLOODFILL], 0); CreateFnPatch(FloodFill, DrvFloodFill, &g_oeDDPatches[DDI_FLOODFILL], uSel);
// _FONTLOAD
uSel = CreateFnPatch(g_lpfnExtTextOutW, DrvExtTextOutW, &g_oeDDPatches[DDI_EXTTEXTOUTW], 0); CreateFnPatch(g_lpfnTextOutW, DrvTextOutW, &g_oeDDPatches[DDI_TEXTOUTW], uSel);
// _PATH
uSel = CreateFnPatch(FillPath, DrvFillPath, &g_oeDDPatches[DDI_FILLPATH], 0); CreateFnPatch(StrokeAndFillPath, DrvStrokeAndFillPath, &g_oeDDPatches[DDI_STROKEANDFILLPATH], uSel); CreateFnPatch(StrokePath, DrvStrokePath, &g_oeDDPatches[DDI_STROKEPATH], uSel);
// _RGOUT
uSel = CreateFnPatch(FillRgn, DrvFillRgn, &g_oeDDPatches[DDI_FILLRGN], 0); CreateFnPatch(FrameRgn, DrvFrameRgn, &g_oeDDPatches[DDI_FRAMERGN], uSel); CreateFnPatch(PaintRgn, DrvPaintRgn, &g_oeDDPatches[DDI_PAINTRGN], uSel);
// _OUTMAN
uSel = CreateFnPatch(LineTo, DrvLineTo, &g_oeDDPatches[DDI_LINETO], 0); CreateFnPatch(Polyline, DrvPolyline, &g_oeDDPatches[DDI_POLYLINE], uSel); CreateFnPatch(g_lpfnPolylineTo, DrvPolylineTo, &g_oeDDPatches[DDI_POLYLINETO], uSel);
// EMF
uSel = CreateFnPatch(PlayEnhMetaFileRecord, DrvPlayEnhMetaFileRecord, &g_oeDDPatches[DDI_PLAYENHMETAFILERECORD], 0);
// METAPLAY
uSel = CreateFnPatch(PlayMetaFile, DrvPlayMetaFile, &g_oeDDPatches[DDI_PLAYMETAFILE], 0); CreateFnPatch(PlayMetaFileRecord, DrvPlayMetaFileRecord, &g_oeDDPatches[DDI_PLAYMETAFILERECORD], uSel);
// _POLYGON
uSel = CreateFnPatch(Polygon, DrvPolygon, &g_oeDDPatches[DDI_POLYGON], 0); CreateFnPatch(PolyPolygon, DrvPolyPolygon, &g_oeDDPatches[DDI_POLYPOLYGON], uSel);
// _BEZIER
uSel = CreateFnPatch(PolyBezier, DrvPolyBezier, &g_oeDDPatches[DDI_POLYBEZIER], 0); CreateFnPatch(PolyBezierTo, DrvPolyBezierTo, &g_oeDDPatches[DDI_POLYBEZIERTO], uSel);
// _WIN32
uSel = CreateFnPatch(g_lpfnPolyPolyline, DrvPolyPolyline, &g_oeDDPatches[DDI_POLYPOLYLINE], 0);
// _RECT
uSel = CreateFnPatch(Rectangle, DrvRectangle, &g_oeDDPatches[DDI_RECTANGLE], 0);
// _DIBITMAP
uSel = CreateFnPatch(SetDIBitsToDevice, DrvSetDIBitsToDevice, &g_oeDDPatches[DDI_SETDIBITSTODEVICE], 0); CreateFnPatch(StretchDIBits, DrvStretchDIBits, &g_oeDDPatches[DDI_STRETCHDIBITS], uSel);
// _DCSTUFF
uSel = CreateFnPatch(CreateSpb, DrvCreateSpb, &g_oeDDPatches[DDI_CREATESPB], 0);
// _PIXDDA
uSel = CreateFnPatch(SetPixel, DrvSetPixel, &g_oeDDPatches[DDI_SETPIXEL], 0);
// _PALETTE
uSel = CreateFnPatch(UpdateColors, DrvUpdateColors, &g_oeDDPatches[DDI_UPDATECOLORS], 0); CreateFnPatch(GDIRealizePalette, DrvGDIRealizePalette, &g_oeDDPatches[DDI_GDIREALIZEPALETTE], uSel); CreateFnPatch(RealizeDefaultPalette, DrvRealizeDefaultPalette, &g_oeDDPatches[DDI_REALIZEDEFAULTPALETTE], uSel);
// (User WINRARE)
uSel = CreateFnPatch(WinOldAppHackoMatic, DrvWinOldAppHackoMatic, &g_oeDDPatches[DDI_WINOLDAPPHACKOMATIC], 0);
//
// Loop through our patches and check for failure
//
for (iPatch = DDI_FIRST; iPatch < DDI_MAX; iPatch++) { if (!SELECTOROF(g_oeDDPatches[iPatch].lpCodeAlias)) { ERROR_OUT(("Patch %u failed to create", iPatch)); DC_QUIT; } }
rc = TRUE;
DC_EXIT_POINT: DebugExitBOOL(OE_DDInit, rc); return(rc); }
//
// OE_DDTerm()
// This destroys the patches we created.
//
void OE_DDTerm(void) { DDI_PATCH iPatch;
DebugEntry(OE_DDTerm);
//
// Destroying patches will also disable any still active.
//
for (iPatch = DDI_FIRST; iPatch < DDI_MAX; iPatch++) { // destroy patches
DestroyFnPatch(&g_oeDDPatches[iPatch]); }
//
// Destroy ChangeDisplaySettings patches
//
if (SELECTOROF(g_lpfnCDSEx)) DestroyFnPatch(&g_oeDisplaySettingsExPatch); DestroyFnPatch(&g_oeDisplaySettingsPatch);
//
// Free font memory
//
if (SELECTOROF(g_poeLocalFonts)) { GlobalFree((HGLOBAL)SELECTOROF(g_poeLocalFonts)); g_poeLocalFonts = NULL; }
//
// Free cached selectors
//
if (g_oeSelSrc) { FreeSelector(g_oeSelSrc); g_oeSelSrc = 0; }
if (g_oeSelDst) { FreeSelector(g_oeSelDst); g_oeSelDst = 0; }
DebugExitVOID(OE_DDTerm); }
//
// OE_DDViewing()
//
// Turns on/off patches for trapping graphic output.
//
void OE_DDViewing(BOOL fViewers) { DDI_PATCH patch;
DebugEntry(OE_DDViewing);
//
// Clear window and font caches
//
g_oeLastWindow = NULL; g_oeFhLast.fontIndex = 0xFFFF;
//
// Enable or disable GDI patches
//
for (patch = DDI_FIRST; patch < DDI_MAX; patch++) { EnableFnPatch(&g_oeDDPatches[patch], (fViewers ? PATCH_ACTIVATE : PATCH_DEACTIVATE)); }
//
// Do save bits & cursor patches too
//
SSI_DDViewing(fViewers); CM_DDViewing(fViewers);
if (fViewers) { //
// Our palette color array starts out as all black on each share.
// So force PMUpdateSystemColors() to do something.
//
ASSERT(g_asSharedMemory); g_asSharedMemory->pmPaletteChanged = TRUE; }
DebugExitVOID(OE_DDViewing); }
//
// FUNCTION: OEDDSetNewCapabilities
//
// DESCRIPTION:
//
// Set the new OE related capabilities
//
// RETURNS:
//
// NONE
//
// PARAMETERS:
//
// pDataIn - pointer to the input buffer
//
//
void OEDDSetNewCapabilities(LPOE_NEW_CAPABILITIES pCapabilities) { LPBYTE lpos16;
DebugEntry(OEDDSetNewCapabilities);
//
// Copy the data from the Share Core.
//
g_oeBaselineTextEnabled = pCapabilities->baselineTextEnabled;
g_oeSendOrders = pCapabilities->sendOrders;
g_oeTextEnabled = pCapabilities->textEnabled;
//
// The share core has passed down a pointer to it's copy of the order
// support array. We take a copy for the kernel here.
//
lpos16 = MapLS(pCapabilities->orderSupported); if (SELECTOROF(lpos16)) { hmemcpy(g_oeOrderSupported, lpos16, sizeof(g_oeOrderSupported)); UnMapLS(lpos16); } else { UINT i;
ERROR_OUT(("OEDDSetNewCaps: can't save new order array"));
for (i = 0; i < sizeof(g_oeOrderSupported); i++) g_oeOrderSupported[i] = FALSE; }
TRACE_OUT(( "OE caps: BLT %c Orders %c Text %c", g_oeBaselineTextEnabled ? 'Y': 'N', g_oeSendOrders ? 'Y': 'N', g_oeTextEnabled ? 'Y': 'N')); DebugExitVOID(OEDDSetNewCapabilities); }
//
// FUNCTION: OEDDSetNewFonts
//
// DESCRIPTION:
//
// Set the new font handling information to be used by the display driver.
//
// RETURNS:
//
// NONE
//
//
void OEDDSetNewFonts(LPOE_NEW_FONTS pRequest) { HGLOBAL hMem; UINT cbNewSize; LPVOID lpFontData; LPVOID lpFontIndex;
DebugEntry(OEDDSetNewFonts);
TRACE_OUT(( "New fonts %d", pRequest->countFonts));
//
// Initialize new number of fonts to zero in case an error happens.
// We don't want to use stale font info if so. And clear the font
// cache.
//
g_oeNumFonts = 0; g_oeFhLast.fontIndex = 0xFFFF;
g_oeFontCaps = pRequest->fontCaps;
//
// Can we get 16:16 addresses for font info?
//
lpFontData = MapLS(pRequest->fontData); lpFontIndex = MapLS(pRequest->fontIndex); if (!lpFontData || !lpFontIndex) { ERROR_OUT(("OEDDSetNewFonts: couldn't map flat addresses to 16-bit")); DC_QUIT; }
//
// Realloc our current font block if we need to. Always shrink it
// too, this thing can get large!
//
ASSERT(pRequest->countFonts <= (0xFFFF / sizeof(LOCALFONT))); cbNewSize = pRequest->countFonts * sizeof(LOCALFONT);
hMem = (HGLOBAL)SELECTOROF(g_poeLocalFonts);
hMem = GlobalReAlloc(hMem, cbNewSize, GMEM_MOVEABLE | GMEM_SHARE); if (!hMem) { ERROR_OUT(("OEDDSetNewFonts: can't allocate space for font info")); DC_QUIT; } else { g_poeLocalFonts = MAKELP(hMem, 0); }
//
// We got here, so everything is OK. Update the font info we have.
//
g_oeNumFonts = pRequest->countFonts;
hmemcpy(g_poeLocalFonts, lpFontData, cbNewSize);
hmemcpy(g_oeLocalFontIndex, lpFontIndex, sizeof(g_oeLocalFontIndex[0]) * FH_LOCAL_INDEX_SIZE);
DC_EXIT_POINT: if (lpFontData) UnMapLS(lpFontData);
if (lpFontIndex) UnMapLS(lpFontIndex);
DebugExitVOID(OEDDSetNewFonts); }
//
// UTILITY ROUTINES
//
//
// OEGetPolarity()
// Gets the axes polarity signs.
//
// NOTE that we fill in the ptPolarity field of our OESTATE global, to
// save on stack.
//
void OEGetPolarity(void) { SIZE WindowExtent; SIZE ViewportExtent;
DebugEntry(OEGetPolarity);
switch (GetMapMode(g_oeState.hdc)) { case MM_ANISOTROPIC: case MM_ISOTROPIC: GetWindowExtEx(g_oeState.hdc, &WindowExtent); GetViewportExtEx(g_oeState.hdc, &ViewportExtent);
if ((ViewportExtent.cx < 0) == (WindowExtent.cx < 0)) g_oeState.ptPolarity.x = 1; else g_oeState.ptPolarity.x = -1;
if ((ViewportExtent.cy < 0) == (WindowExtent.cy < 0)) g_oeState.ptPolarity.y = 1; else g_oeState.ptPolarity.y = -1; break;
case MM_HIENGLISH: case MM_HIMETRIC: case MM_LOENGLISH: case MM_LOMETRIC: case MM_TWIPS: g_oeState.ptPolarity.x = 1; g_oeState.ptPolarity.y = -1; break;
default: g_oeState.ptPolarity.x = 1; g_oeState.ptPolarity.y = 1; break; }
DebugExitVOID(OEGetPolarity); }
//
// OEGetState()
// This sets up the fields in the g_oeState global, depending on what
// a particular DDI needs. That is conveyed via the flags.
//
void OEGetState ( UINT uFlags ) { DWORD dwOrg;
DebugEntry(OEGetState);
if (uFlags & OESTATE_COORDS) { dwOrg = GetDCOrg(g_oeState.hdc); g_oeState.ptDCOrg.x = LOWORD(dwOrg); g_oeState.ptDCOrg.y = HIWORD(dwOrg);
OEGetPolarity(); }
if (uFlags & OESTATE_PEN) { // Try to get the pen data
if (!GetObject(g_oeState.lpdc->hPen, sizeof(g_oeState.logPen), &g_oeState.logPen)) { ERROR_OUT(("Couldn't get pen info")); g_oeState.logPen.lopnWidth.x = 1; g_oeState.logPen.lopnWidth.y = 1; g_oeState.logPen.lopnStyle = PS_NULL; uFlags &= ~OESTATE_PEN; } }
if (uFlags & OESTATE_BRUSH) { // Try to get the brush data
if (!GetObject(g_oeState.lpdc->hBrush, sizeof(g_oeState.logBrush), &g_oeState.logBrush)) { ERROR_OUT(("Couldn't get brush info")); g_oeState.logBrush.lbStyle = BS_NULL; uFlags &= ~OESTATE_BRUSH; } }
if (uFlags & OESTATE_FONT) { // Try to get the logfont data
if (!GetObject(g_oeState.lpdc->hFont, sizeof(g_oeState.logFont), &g_oeState.logFont)) { ERROR_OUT(("Gouldn't get font info"));
//
// Fill in an empty face name
//
g_oeState.logFont.lfFaceName[0] = 0; uFlags &= ~OESTATE_FONT; } else { GetTextMetrics(g_oeState.hdc, &g_oeState.tmFont); g_oeState.tmAlign = GetTextAlign(g_oeState.hdc); } }
if (uFlags & OESTATE_REGION) { DWORD cbSize;
cbSize = GetRegionData(g_oeState.lpdc->hRaoClip, sizeof(g_oeState.rgnData), (LPRGNDATA)&g_oeState.rgnData); if (cbSize > sizeof(g_oeState.rgnData)) { WARNING_OUT(("Clip region %04x is too big, unclipped drawing may result")); }
if (!cbSize || (cbSize > sizeof(g_oeState.rgnData))) { // Bound box is best we can do.
RECT rcBound;
if (GetRgnBox(g_oeState.lpdc->hRaoClip, &rcBound) <= NULLREGION) { WARNING_OUT(("Couldn't even get bounding box of Clip region")); SetRectEmpty(&rcBound); }
g_oeState.rgnData.rdh.iType = SIMPLEREGION; g_oeState.rgnData.rdh.nRgnSize = sizeof(RDH) + sizeof(RECTL); g_oeState.rgnData.rdh.nRectL = 1; RECT_TO_RECTL(&rcBound, &g_oeState.rgnData.rdh.arclBounds); RECT_TO_RECTL(&rcBound, g_oeState.rgnData.arclPieces); } }
g_oeState.uFlags |= uFlags;
DebugExitVOID(OEGetState); }
//
// OEPolarityAdjust()
// This swaps the coordinates of a rectangle based on the sign polarity.
//
// NOTE: We use the g_oeState polarity field. So this function assumes
// polarity is setup already.
//
void OEPolarityAdjust ( LPRECT aRects, UINT cRects ) { int tmp;
DebugEntry(OEPolarityAdjust);
ASSERT(g_oeState.uFlags & OESTATE_COORDS);
while (cRects > 0) { if (g_oeState.ptPolarity.x < 0) { // Swap left & right
tmp = aRects->left; aRects->left = aRects->right; aRects->right = tmp; }
if (g_oeState.ptPolarity.y < 0) { // Swap top & bottom
tmp = aRects->top; aRects->top = aRects->bottom; aRects->bottom = tmp; }
cRects--; aRects++; }
DebugExitVOID(OEPolarityAdjust); }
//
// OECheckOrder()
// This checks for the common stuff that all the DDIs do before deciding
// to send an order or accumulate screen data.
//
BOOL OECheckOrder ( DWORD order, UINT flags ) { if (!OE_SendAsOrder(order)) return(FALSE);
if ((flags & OECHECK_PEN) && !OECheckPenIsSimple()) return(FALSE);
if ((flags & OECHECK_BRUSH) && !OECheckBrushIsSimple()) return(FALSE);
if ((flags & OECHECK_CLIPPING) && OEClippingIsComplex()) return(FALSE);
return(TRUE); }
//
// OELPtoVirtual()
// Converts coords from logical to device (pixels). This does map mode
// then translation offsets.
//
void OELPtoVirtual ( HDC hdc, LPPOINT aPts, UINT cPts ) { LONG l; int s;
DebugEntry(OELPtoVirtual);
ASSERT(g_oeState.uFlags & OESTATE_COORDS);
ASSERT(hdc == g_oeState.hdc);
//
// Convert to pixels
//
LPtoDP(hdc, aPts, cPts);
//
// Use the device origin, so we can convert from DC-relative to screen
// coords.
//
while (cPts > 0) { //
// Prevent overflow
//
l = (LONG)aPts->x + (LONG)g_oeState.ptDCOrg.x; s = (int)l;
if (l == (LONG)s) { aPts->x = s; } else { //
// HIWORD(l) will be 1 for positive overflow, 0xFFFF for
// negative overflow. Therefore we will get 0x7FFE or 0x8000
// (+32766 or -32768).
//
aPts->x = 0x7FFF - HIWORD(l); TRACE_OUT(("adjusted X from %ld to %d", l, aPts->x)); }
//
// Look for int overflow in the Y coordinate
//
l = (LONG)aPts->y + (LONG)g_oeState.ptDCOrg.y; s = (int)l;
if (l == (LONG)s) { aPts->y = s; } else { //
// HIWORD(l) will be 1 for positive overflow, 0xFFFF for
// negative overflow. Therefore we will get 0x7FFE or 0x8000
// (+32766 or -32768).
//
aPts->y = 0x7FFF - HIWORD(l); TRACE_OUT(("adjusted Y from %ld to %d", l, aPts->y)); }
//
// Move on to the next point
//
--cPts; ++aPts; }
DebugExitVOID(OELPtoVirtual); }
//
// OELRtoVirtual
//
// Adjusts RECT in window coordinates to virtual coordinates. Clips the
// result to [+32766, -32768] which is near enough to [+32767, -32768]
//
// NB. This function takes a Windows rectangle (Exclusive coords) and
// returns a DC-Share rectangle (inclusive coords).
// This means that any calling function can safely convert to inclusive
// without having to worry above overflowing.
//
void OELRtoVirtual ( HDC hdc, LPRECT aRects, UINT cRects ) { int temp;
DebugEntry(OELRtoVirtual);
//
// Convert the points to screen coords, clipping to INT16s
//
OELPtoVirtual(hdc, (LPPOINT)aRects, 2 * cRects);
//
// Make each rectangle inclusive
//
while (cRects > 0) { //
// LAURABU BOGUS!
// Use OEPolarityAdjust() instead, this is safer.
//
//
// If the rect is bad then flip the edges. This will be the case
// if the LP coordinate system is running in a different direction
// than the device coordinate system.
//
if (aRects->left > aRects->right) { TRACE_OUT(("Flipping x coords"));
temp = aRects->left; aRects->left = aRects->right; aRects->right = temp; }
if (aRects->top > aRects->bottom) { TRACE_OUT(("Flipping y coords"));
temp = aRects->top; aRects->top = aRects->bottom; aRects->bottom = temp; }
aRects->right--; aRects->bottom--;
//
// Move on to the next rect
//
cRects--; aRects++; }
DebugExitVOID(OELRtoVirtual); }
//
// OE_SendAsOrder()
//
BOOL OE_SendAsOrder(DWORD order) { BOOL rc = FALSE;
DebugEntry(OE_SendAsOrder);
//
// Only check the order if we are allowed to send orders in the first
// place!
//
if (g_oeSendOrders) { TRACE_OUT(("Orders enabled"));
//
// We are sending some orders, so check individual flags.
//
rc = (BOOL)g_oeOrderSupported[HIWORD(order)]; TRACE_OUT(("Send order %lx HIWORD %u", order, HIWORD(order))); }
DebugExitDWORD(OE_SendAsOrder, rc); return(rc); }
//
// FUNCTION: OESendRop3AsOrder.
//
// DESCRIPTION:
//
// Checks to see if the rop uses the destination bits. If it does then
// returns FALSE unless the "send all rops" property flag is set.
//
// PARAMETERS: The rop3 to be checked (in protocol format ie a byte).
//
// RETURNS: TRUE if the rop3 should be sent as an order.
//
//
BOOL OESendRop3AsOrder(BYTE rop3) { BOOL rc = TRUE;
DebugEntry(OESendRop3AsOrder);
//
// Rop 0x5F is used by MSDN to highlight search keywords. This XORs
// a pattern with the destination, producing markedly different (and
// sometimes unreadable) shadow output. We special-case no-encoding for
// it.
//
if (rop3 == 0x5F) { WARNING_OUT(("Rop3 0x5F never encoded")); rc = FALSE; }
DebugExitBOOL(OESendRop3AsOrder, rc); return(rc); }
//
// OEPenWidthAdjust()
//
// Adjusts a rectangle to allow for the current pen width divided by
// the divisor, rounding up.
//
// NOTE: This routine uses the logPen and ptPolarity fields of g_oeState.
//
void OEPenWidthAdjust ( LPRECT lprc, UINT divisor ) { UINT width; UINT roundingFactor = divisor - 1;
DebugEntry(OEPenWidthAdjust);
width = max(g_oeState.logPen.lopnWidth.x, g_oeState.logPen.lopnWidth.y);
InflateRect(lprc, ((g_oeState.ptPolarity.x * width) + (g_oeState.ptPolarity.x * roundingFactor)) / divisor, ((g_oeState.ptPolarity.y * width) + (g_oeState.ptPolarity.x * roundingFactor)) / divisor);
DebugExitVOID(OEPenWidthAdjust); }
//
// Function: OEExpandColor
//
// Description: Converts a generic bitwise representation of an RGB color
// index into an 8-bit color index as used by the line
// protocol.
//
void OEExpandColor ( LPBYTE lpField, DWORD srcColor, DWORD mask ) { DWORD colorTmp;
DebugEntry(OEExpandColor);
//
// Different example bit masks:
//
// Normal 24-bit:
// 0x000000FF (red)
// 0x0000FF00 (green)
// 0x00FF0000 (blue)
//
// True color 32-bits:
// 0xFF000000 (red)
// 0x00FF0000 (green)
// 0x0000FF00 (blue)
//
// 5-5-5 16-bits
// 0x0000001F (red)
// 0x000003E0 (green)
// 0x00007C00 (blue)
//
// 5-6-5 16-bits
// 0x0000001F (red)
// 0x000007E0 (green)
// 0x0000F800 (blue)
//
//
// Convert the color using the following algorithm.
//
// <new color> = <old color> * <new bpp mask> / <old bpp mask>
//
// where:
//
// new bpp mask = mask for all bits at new setting (0xFF for 8bpp)
//
// This way maximal (eg. 0x1F) and minimal (eg. 0x00) settings are
// converted into the correct 8-bit maximum and minimum.
//
// Rearranging the above equation we get:
//
// <new color> = (<old color> & <old bpp mask>) * 0xFF / <old bpp mask>
//
// where:
//
// <old bpp mask> = mask for the color
//
//
// LAURABU BOGUS:
// We need to avoid overflow caused by the multiply. NOTE: in theory
// we should use a double, but that's painfully slow. So for now hack
// it. If the HIBYTE is set, just right shift 24 bits.
//
colorTmp = srcColor & mask; if (colorTmp & 0xFF000000) colorTmp >>= 24; else colorTmp = (colorTmp * 0xFF) / mask; *lpField = (BYTE)colorTmp;
TRACE_OUT(( "0x%lX -> 0x%X", srcColor, (WORD)*lpField));
DebugExitVOID(OEExpandColor); }
//
// OEConvertColor()
// Converts a PHYSICAL color to a real RGB
//
void OEConvertColor ( DWORD rgb, LPTSHR_COLOR lptshrDst, BOOL fAllowDither ) { DWORD rgbConverted; PALETTEENTRY pe; int pal; DWORD numColors;
DebugEntry(OEConvertColor);
rgbConverted = rgb;
//
// Get the current palette size.
//
GetObject(g_oeState.lpdc->hPal, sizeof(pal), &pal); if (pal == 0) { //
// GDI has a bug. It allows a ResizePalette() call to set a new
// size of zero for the palette. If you subsequently make
// certain palette manager calls on such a palette, GDI will fault.
//
// To avoid this problem, as seen in 3D Kitchen by Books that Work,
// we check for this case and simply return the input color.
//
WARNING_OUT(("Zero-sized palette")); DC_QUIT; }
if (g_oeState.lpdc->hPal == g_oeStockPalette) { //
// Quattro Pro and others put junk in the high bits of their colors.
// We need to mask it out.
//
if (rgb & 0xFC000000) { rgb &= 0x00FFFFFF; } else { if (rgb & PALETTERGB_FLAG) { //
// Using PALETTERGB is just like using an RGB, turn it off.
// The color will be dithered, if necessary, using the
// default system colors.
//
rgb &= 0x01FFFFFF;
} } }
if (rgb & COLOR_FLAGS) { if (rgb & PALETTERGB_FLAG) { pal = GetNearestPaletteIndex(g_oeState.lpdc->hPal, rgb); } else { ASSERT(rgb & PALETTEINDEX_FLAG); pal = LOWORD(rgb); }
//
// Look up entry in palette.
//
if (!GetPaletteEntries(g_oeState.lpdc->hPal, pal, 1, &pe)) { ERROR_OUT(("GetPaletteEntries failed for index %d", pal)); *((LPDWORD)&pe) = 0L; } else if (pe.peFlags & PC_EXPLICIT) { //
// If this is PC_EXPLICIT, it's an index into the system
// palette.
//
pal = LOWORD(*((LPDWORD)&pe));
if (g_osiScreenBPP < 32) { numColors = 1L << g_osiScreenBPP; } else { numColors = 0xFFFFFFFF; }
if (numColors > 256) { //
// We are on a direct color device. What does explicit
// mean in this case? The answer is, use the VGA color
// palette.
//
pe = g_osiVgaPalette[pal % 16]; } else { pal %= numColors;
GetSystemPaletteEntries(g_oeState.hdc, pal, 1, &pe); } }
rgbConverted = *((LPDWORD)&pe); }
DC_EXIT_POINT: //
// To get the correct results for any RGBs we send to true color systems,
// we need to normalize the RGB to an exact palette match on the local
// system. This is because we aren't guaranteed that the RGB on the
// local will have an exact match to the current system palette. If
// not, then GDI will convert them locally, but the orders will send
// to remotes will be displayed exactly, resulting in a mismatch.
//
if ((g_osiScreenBPP == 8) && !(rgb & COLOR_FLAGS) && (!fAllowDither || (g_oeState.lpdc->hPal != g_oeStockPalette))) { TSHR_RGBQUAD rgq;
rgbConverted &= 0x00FFFFFF;
//
// Common cases.
//
if ((rgbConverted == RGB(0, 0, 0)) || (rgbConverted == RGB(0xFF, 0xFF, 0xFF))) { goto ReallyConverted; }
//
// g_osiScreenBMI.bmiHeader is already filled in.
//
//
// NOTE:
// We don't need or want to realize any palettes. We want color
// mapping based on the current screen palette contents.
//
// We disable SetPixel() patch, or our trap will trash the
// variables for this call.
//
//
// g_osiMemoryDC() always has our 1x1 color bitmap g_osiMemoryBMP
// selected into it.
//
EnableFnPatch(&g_oeDDPatches[DDI_SETPIXEL], PATCH_DISABLE); SetPixel(g_osiMemoryDC, 0, 0, rgbConverted); EnableFnPatch(&g_oeDDPatches[DDI_SETPIXEL], PATCH_ENABLE);
//
// Get mapped color index
//
GetDIBits(g_osiMemoryDC, g_osiMemoryBMP, 0, 1, &pal, (LPBITMAPINFO)&g_osiScreenBMI, DIB_RGB_COLORS);
rgq = g_osiScreenBMI.bmiColors[LOBYTE(pal)];
OTRACE(("Mapped color %08lx to %08lx", rgbConverted, RGB(rgq.rgbRed, rgq.rgbGreen, rgq.rgbBlue)));
rgbConverted = RGB(rgq.rgbRed, rgq.rgbGreen, rgq.rgbBlue); }
ReallyConverted: lptshrDst->red = GetRValue(rgbConverted); lptshrDst->green = GetGValue(rgbConverted); lptshrDst->blue = GetBValue(rgbConverted);
DebugExitVOID(OEConvertColor); }
//
// OEGetBrushInfo()
// Standard brush goop
//
void OEGetBrushInfo ( LPTSHR_COLOR pBack, LPTSHR_COLOR pFore, LPTSHR_UINT32 pStyle, LPTSHR_UINT32 pHatch, LPBYTE pExtra ) { int iRow;
DebugEntry(OEGetBrushInfo);
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, pBack, FALSE);
*pStyle = g_oeState.logBrush.lbStyle;
if (g_oeState.logBrush.lbStyle == BS_PATTERN) { //
// We only track mono patterns, so the foreground color is the
// brush color.
//
OEConvertColor(g_oeState.lpdc->DrawMode.txColorL, pFore, FALSE);
// For pattern brushes, the hatch stores the 1st pattern byte,
// the Extra field the remaining 7 pattern bytes
*pHatch = g_oeState.logBrushExtra[0]; hmemcpy(pExtra, g_oeState.logBrushExtra+1, TRACKED_BRUSH_SIZE-1); } else { ASSERT(g_oeState.logBrush.lbStyle != BS_DIBPATTERN);
OEConvertColor(g_oeState.logBrush.lbColor, pFore, TRUE);
// The hatch is the hatch style
*pHatch = g_oeState.logBrush.lbHatch;
// Extra info is empty
for (iRow = 0; iRow < TRACKED_BRUSH_SIZE-1; iRow++) { pExtra[iRow] = 0; } }
DebugExitVOID(OEGetBrushInfo); }
//
// OEClippingIsSimple()
//
BOOL OEClippingIsSimple(void) { BOOL fSimple; RECT rc;
DebugEntry(OEClippingIsSimple);
ASSERT(g_oeState.uFlags & OESTATE_REGION);
fSimple = (g_oeState.rgnData.rdh.nRectL <= 1);
DebugExitBOOL(OEClippingIsSimple, fSimple); return(fSimple); }
//
// OEClippingIsComplex()
//
BOOL OEClippingIsComplex(void) { BOOL fComplex;
DebugEntry(OEClippingIsComplex);
ASSERT(g_oeState.uFlags & OESTATE_REGION);
fComplex = (g_oeState.rgnData.rdh.nRgnSize >= sizeof(RDH) + CRECTS_COMPLEX*sizeof(RECTL));
DebugExitBOOL(OEClippingIsComplex, fComplex); return(fComplex); }
//
// OECheckPenIsSimple()
//
BOOL OECheckPenIsSimple(void) { POINT ptArr[2]; BOOL fSimple;
DebugEntry(OECheckPenIsSimple);
if (g_oeState.uFlags & OESTATE_PEN) { ptArr[0].x = ptArr[0].y = 0; ptArr[1].x = g_oeState.logPen.lopnWidth.x; ptArr[1].y = 0;
LPtoDP(g_oeState.hdc, ptArr, 2);
fSimple = ((ptArr[1].x - ptArr[0].x) <= 1); } else { // The current pen in the DC is invalid
WARNING_OUT(("Invalid pen selected into DC")); fSimple = FALSE; }
DebugExitBOOL(OECheckPenIsSimple, fSimple); return(fSimple); }
//
// OECheckBrushIsSimple()
//
BOOL OECheckBrushIsSimple(void) { BOOL fSimple;
DebugEntry(OECheckBrushIsSimple);
// Assume not simple
fSimple = FALSE;
if (g_oeState.uFlags & OESTATE_BRUSH) { //
// If the brush is a pattern, it's OK if one of standard pattern
// brushes. If it comes from a DIB, it's never OK. All other
// brushes are OK.
//
if (g_oeState.logBrush.lbStyle == BS_PATTERN) { LPGDIHANDLE lpgh; LPBRUSH lpBrush; LPBITMAP lpPattern;
//
// For pattern brushes, the lbHatch field of the ilBrushOverhead
// item in the GDI local BRUSH object is a global handle to
// a memory block that is the BITMAP of the thing.
//
//
// BOGUS LAURABU:
// NM 2.0 Win95 went to a lot more work to check if a color bitmap
// pattern brush had only 2 colors and therefore was orderable. But
// I can't find a single that uses such a thing. So for now, we just
// care if the pattern bitmap is monochrome and the pattern is between 8x8 and
// 16x8.
//
// Get a pointer to the brush data
lpgh = MAKELP(g_hInstGdi16, g_oeState.lpdc->hBrush); ASSERT(!IsBadReadPtr(lpgh, sizeof(DWORD))); ASSERT(!(lpgh->objFlags & OBJFLAGS_SWAPPEDOUT));
lpBrush = MAKELP(g_hInstGdi16, lpgh->pGdiObj); ASSERT(!IsBadReadPtr(lpBrush, sizeof(BRUSH)));
// Get the bitmapinfo handle -- it's the lbHatch field
lpPattern = MAKELP(lpBrush->ilBrushOverhead.lbHatch, 0);
//
// Macromedia Director among others creates pattern brushes
// with no pattern. We therefore consider these objects to
// be too complex to send in an order
//
//
// Is this monochrome with a pattern between 8 and 16 pels?
// We save the left 8 pixel grid if so.
//
if (!IsBadReadPtr(lpPattern, sizeof(BITMAP)) && (lpPattern->bmWidth >= MIN_BRUSH_WIDTH) && (lpPattern->bmWidth <= MAX_BRUSH_WIDTH) && (lpPattern->bmHeight == TRACKED_BRUSH_HEIGHT) && (lpPattern->bmPlanes == 1) && (lpPattern->bmBitsPixel == 1)) { LPUINT lpRow; int iRow;
// Save the pattern away in logBrushExtra
lpRow = lpPattern->bmBits; ASSERT(!IsBadReadPtr(lpRow, TRACKED_BRUSH_HEIGHT*sizeof(UINT)));
//
// The pattern is always WORD aligned. But only the
// LOBYTE has meaning.
//
// NOTE:
// We fill the pattern in DIB order, namely bottom to
// top.
//
ASSERT(lpPattern->bmWidthBytes == 2); for (iRow = 0; iRow < TRACKED_BRUSH_HEIGHT; iRow++, lpRow++) { g_oeState.logBrushExtra[TRACKED_BRUSH_HEIGHT - 1 - iRow] = (BYTE)*lpRow; }
fSimple = TRUE; } } else if (g_oeState.logBrush.lbStyle != BS_DIBPATTERN) { fSimple = TRUE; } } else { WARNING_OUT(("Invalid brush selected into DC")); }
DebugExitBOOL(OECheckBrushIsSimple, fSimple); return(fSimple); }
//
// OEAddLine()
// This calculates the bounds of a line output call, and either adds an
// order or gets set for screen data accum.
//
void OEAddLine ( POINT ptStart, POINT ptEnd ) { LPINT_ORDER pOrder; LPLINETO_ORDER pLineTo;
DebugEntry(OEAddLine);
//
// Get the bounds
//
g_oeState.rc.left = min(ptStart.x, ptEnd.x); g_oeState.rc.top = min(ptStart.y, ptEnd.y); g_oeState.rc.right = max(ptStart.x, ptEnd.x); g_oeState.rc.bottom = max(ptStart.y, ptEnd.y);
//
// Adjust for axes polarity and pen dimensions
//
ASSERT(g_oeState.uFlags & OESTATE_COORDS);
OEPolarityAdjust(&g_oeState.rc, 1); OEPenWidthAdjust(&g_oeState.rc, 1);
//
// OEPenWidthAdjust returns an inclusive rect. But OELRtoVirtual
// expects an exclusive. After it returns, we need to add back
// the extra subtraction.
//
// NOTE that OELRtoVirtual also adjusts for virtual desktop origin.
//
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
g_oeState.rc.right++; g_oeState.rc.bottom++;
//
// Now we have the true draw bounds. Can we send this as an order?
//
pOrder = NULL;
if (OECheckOrder(ORD_LINETO, OECHECK_PEN | OECHECK_CLIPPING)) { //
// We can send an order.
//
pOrder = OA_DDAllocOrderMem(sizeof(LINETO_ORDER), 0); if (!pOrder) DC_QUIT;
pLineTo = (LPLINETO_ORDER)pOrder->abOrderData;
pLineTo->type = LOWORD(ORD_LINETO);
//
// Must do this first: oords in the LINETO order are 32-bit
//
OELPtoVirtual(g_oeState.hdc, &ptStart, 1); OELPtoVirtual(g_oeState.hdc, &ptEnd, 1);
pLineTo->nXStart = ptStart.x; pLineTo->nYStart = ptStart.y; pLineTo->nXEnd = ptEnd.x; pLineTo->nYEnd = ptEnd.y;
//
// This is a physical color
//
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, &pLineTo->BackColor, FALSE);
pLineTo->BackMode = g_oeState.lpdc->DrawMode.bkMode; pLineTo->ROP2 = g_oeState.lpdc->DrawMode.Rop2; pLineTo->PenStyle = g_oeState.logPen.lopnStyle;
//
// Currently only pen withs of 1 are supported. Unfortunately
// GDI left it up to the driver to decide on how to stroke the
// line, so we can't predict what pixels will be on or off for
// pen widths bigger.
//
pLineTo->PenWidth = 1;
//
// This is a logical color
//
OEConvertColor(g_oeState.logPen.lopnColor, &pLineTo->PenColor, FALSE);
//
// Store the general order data.
//
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
//
// This will add in OESTATE_SENTORDER if it succeeded.
// Then OEDDPostStopAccum() will ignore screen data, or
// will add our nicely calculated bounds above in instead.
//
OTRACE(("Line: Start {%d, %d}, End {%d, %d}", ptStart.x, ptStart.y, ptEnd.x, ptEnd.y)); OEClipAndAddOrder(pOrder, NULL); }
DC_EXIT_POINT: if (!pOrder) { OTRACE(("Line: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
DebugExitVOID(OEAddLine); }
//
// OEValidateDC()
// This makes sure the thing passed in is a valid DC and gets a pointer to
// the DC data structure in GDI if so. We need to handle the (rare) case
// of the DC being swapped out to GDI's extended flat memory space as well
// as the HDC being prsent in GDI's 16-bit dataseg
//
// NOTE:
// It is NOT valid to hang on to a LPDC around a GDI call. Something may
// be swapped out before the call, then get swapped in after the call.
// In which case the original based32 ptr gets freed. And vice-versa, the
// original GDI dc-16 localptr may get realloced small.
//
// In normal usage, this is very fast. Only in low memory (or when
// parameters are invalid) does doing this twice even matter.
//
LPDC OEValidateDC ( HDC hdc, BOOL fSrc ) { LPDC lpdc = NULL; LPGDIHANDLE lpgh; DWORD dwBase;
DebugEntry(OEDDValidateDC);
if (IsGDIObject(hdc) != GDIOBJ_DC) { //
// This is a metafile HDC, an IC, or just a plain old bad param.
//
DC_QUIT; }
//
// OK. The HDC is a local handle to two words in GDI's DS:
// * 1st is actual ptr of DC (or local32 handle if swapped out)
// * 2nd is flags
//
// NOTE:
// Gdi's data segment is already GlobalFixed(). So we don't have to
// worry about it moving.
//
lpgh = MAKELP(g_hInstGdi16, hdc); if (lpgh->objFlags & OBJFLAGS_SWAPPEDOUT) { UINT uSel;
//
// This is an error only so we can actually stop when we hit this
// rare case and make sure our code is working!
//
WARNING_OUT(("DC is swapped out, getting at far heap info"));
//
// Need to make our cached selector point at this thing. NOTE that
// in OEDDStopAccum, we need to reget lpdc since it will have been
// swapped in during the output call.
//
dwBase = GetSelectorBase((UINT)g_hInstGdi16); ASSERT(dwBase);
uSel = (fSrc ? g_oeSelSrc : g_oeSelDst); SetSelectorBase(uSel, dwBase + 0x10000);
//
// The pGdiObj is the local32 handle. GDI:10000+pGdiObj has a DWORD
// which is the based32 address, relative to GDI's dataseg, of the DC.
// We've set the base of our selector 64K higher than GDI, so we can
// use it as an offset directly.
//
ASSERT(!IsBadReadPtr(MAKELP(uSel, lpgh->pGdiObj), sizeof(DWORD))); dwBase = *(LPDWORD)MAKELP(uSel, lpgh->pGdiObj); //
// The 16-bit base is the nearest 64K less than this 32-bit pointer,
// above GDI's ds.
//
SetSelectorBase(uSel, GetSelectorBase((UINT)g_hInstGdi16) + (dwBase & 0xFFFF0000));
//
// Remainder is slop past 64K.
//
lpdc = MAKELP(uSel, LOWORD(dwBase)); } else { lpdc = MAKELP(g_hInstGdi16, lpgh->pGdiObj); }
ASSERT(!IsBadReadPtr(lpdc, sizeof(DC)));
DC_EXIT_POINT: DebugExitDWORD(OEDDValidateDC, (DWORD)lpdc); return(lpdc); }
//
// OEBeforeDDI()
//
// This does all the common stuff at the start of an intercepted DDI call:
// * Increment the reentrancy count
// * Disable the patch
// * Get a ptr to the DC structure (if valid)
// * Get some attributes about the DC (if valid)
// * Set up to get the drawing bounds calculated in GDI
//
BOOL OEBeforeDDI ( DDI_PATCH ddiType, HDC hdcDst, UINT uFlags ) { LPDC lpdc; BOOL fWeCare = FALSE;
DebugEntry(OEBeforeDDI);
EnableFnPatch(&g_oeDDPatches[ddiType], PATCH_DISABLE); if (++g_oeEnterCount > 1) { TRACE_OUT(("Skipping nested output call")); DC_QUIT; }
//
// Get a pointer to the destination DC. Since we may have an output
// call where both the source and dest are swapped out, we may need to
// use both our cached selectors. Thus, we must to tell OEValidateDC()
// which DC this is to avoid collision.
//
lpdc = OEValidateDC(hdcDst, FALSE); if (!SELECTOROF(lpdc)) { TRACE_OUT(("Bogus DC")); DC_QUIT; }
//
// Is this a screen DC w/o an active path? When a path is active, the
// output is being recorded into a path, which is like a region. Then
// stroking/filling the path can cause output.
//
if (!(lpdc->DCFlags & DC_IS_DISPLAY) || (lpdc->fwPath & DCPATH_ACTIVE)) { TRACE_OUT(("Not screen DC")); DC_QUIT; }
//
// Only if this is a screen DC do we care about where the output is
// going to happen. For memory DCs,
//
// If this is a bitmap DC or a path is active, we want to mess with
// the bitmap cache.
if (lpdc->DCFlags & DC_IS_MEMORY) { //
// No screen data or other goop accumulated for non-output calls
// We just want to do stuff in OEAfterDDI.
//
uFlags &= ~OESTATE_DDISTUFF; goto WeCareWeReallyCare; } else { //
// Is this a DC we care about? Our algorithm is:
// * If sharing the desktop, yes.
// * If no window associated with DC or window is desktop, maybe.
// * If window is ancestor of shared window, yes. Else no.
//
if (!g_hetDDDesktopIsShared) { HWND hwnd; HWND hwndP;
hwnd = WindowFromDC(hdcDst);
//
// LAURABU:
// Should we blow off painting into the desktop window? It's
// either clipped, in which case it's the shell background
// painting, or it's not, in which case it's the non-full drag
// dotted lines.
//
if (hwnd && (hwnd != g_osiDesktopWindow)) { //
// If this is our cache, the result is g_oeLastWindowShared.
// Otherwise, compute it.
//
// Note that the HET code clears the cache when the cached
// window
// goes away, or any window changes its sharing status since in
// that case this window may be a descendant and hence not shared.
//
if (hwnd != g_oeLastWindow) { TRACE_OUT(("oeLastWindow cache miss: %04x, now %04x", g_oeLastWindow, hwnd));
//
// Cache this dude. Note that we don't care about
// visibility, since we know we won't get real painting
// into an invisible window (it has an empty visrgn).
//
g_oeLastWindow = hwnd; g_oeLastWindowShared = HET_WindowIsHosted(hwnd); } else { TRACE_OUT(("oeLastWindow cache hit: %04x", g_oeLastWindow)); }
//
// This window isn't shared.
//
if (!g_oeLastWindowShared) { TRACE_OUT(("Output in window %04x: don't care", g_oeLastWindow)); DC_QUIT; } } } }
//
// Code from here to WeCareWeReallyCare() is only for screen DCs
//
//
// For the *TextOut* apis, we want to accumulate DCBs if the font is too
// complex.
//
if (uFlags & OESTATE_SDA_FONTCOMPLEX) { BOOL fComplex; POINT aptCheck[2];
fComplex = TRUE;
// Get the logfont info
if (!GetObject(lpdc->hFont, sizeof(g_oeState.logFont), &g_oeState.logFont) || (g_oeState.logFont.lfEscapement != 0)) goto FontCheckDone;
//
// The font is too complex if it has escapement or the logical units
// are bigger than pixels.
//
// NOTE that NM 2.0 had a bug--it used one point only for non
// MM_TEXT mode. They did this because they wouldn't get back
// the same thing passed in, forgetting that LPtoDP takes into
// account viewport and window origins in addition to scaling.
//
// So we do this the right way, using two points and looking at
// the difference.
//
aptCheck[0].x = 0; aptCheck[0].y = 0; aptCheck[1].x = 1000; aptCheck[1].y = 1000;
LPtoDP(hdcDst, aptCheck, 2);
if ((aptCheck[1].x - aptCheck[0].x <= 1000) || (aptCheck[1].y - aptCheck[0].y <= 1000)) { fComplex = FALSE; }
FontCheckDone: if (fComplex) { TRACE_OUT(("Font too complex for text order")); uFlags |= OESTATE_SDA_DCB; } }
//
// Some DDIs calculate their own bound rects, which is faster than
// GDI's BoundsRect() services. But some don't because it's too
// complicated. In that case, we do it for 'em.
//
if (uFlags & OESTATE_SDA_DCB) { //
// We don't have to worry about the mapping mode when getting the
// bounds. The only thing to note is that the return rect is
// relative to the window org of the DC, and visrgn/clipping occurs
//
g_oeState.uGetDCB = GetBoundsRect(hdcDst, &g_oeState.rcDCB, 0); g_oeState.uSetDCB = SetBoundsRect(hdcDst, NULL, DCB_ENABLE | DCB_RESET) & (DCB_ENABLE | DCB_DISABLE);
// No curpos needed if going as screen data, not order
uFlags &= ~OESTATE_CURPOS; }
if (uFlags & OESTATE_CURPOS) { GetCurrentPositionEx(hdcDst, &g_oeState.ptCurPos); }
WeCareWeReallyCare: fWeCare = TRUE; g_oeState.uFlags = uFlags; g_oeState.hdc = hdcDst;
DC_EXIT_POINT: DebugExitBOOL(OEBeforeDDI, fWeCare); return(fWeCare); }
//
// OEAfterDDI()
//
// This does all the common things right after a DDI call. It returns TRUE
// if output happened into a screen DC that we care about.
//
BOOL OEAfterDDI ( DDI_PATCH ddiType, BOOL fWeCare, BOOL fOutput ) { DebugEntry(OEAfterDDI);
//
// Reenable patch
//
EnableFnPatch(&g_oeDDPatches[ddiType], PATCH_ENABLE); --g_oeEnterCount;
if (!fWeCare) { //
// This was reentrant, we don't care about output into this
// DC, or something went wrong, bail out.
//
DC_QUIT; }
g_oeState.lpdc = OEValidateDC(g_oeState.hdc, FALSE); if (!SELECTOROF(g_oeState.lpdc)) { ERROR_OUT(("Bogus DC")); DC_QUIT; } ASSERT(g_oeState.lpdc->DCFlags & DC_IS_DISPLAY); ASSERT(!(g_oeState.lpdc->fwPath & DCPATH_ACTIVE));
//
// If this output happened into a memory bitmap, see if it affects
// SPBs or our sent bitmap cache
//
if (g_oeState.lpdc->DCFlags & DC_IS_MEMORY) { //
// Don't set fOutput to FALSE for SPB operations, we want
// BitBlt to look at it.
//
if (fOutput) { // If this is BitBlt, check for SPB creation
if ((ddiType != DDI_BITBLT) || (g_oeState.lpdc->hBitmap != g_ssiLastSpbBitmap)) { fOutput = FALSE; } } } else { //
// Drawing on the screen that isn't going to be handled in the DDI
// call.
//
if (fOutput && (g_oeState.uFlags & OESTATE_SDA_MASK)) { //
// We do some common tasks that several DDIs would have to do
// * take the screen bounds and add as SD
// * take the draw bounds and add as SD
//
OEGetState(OESTATE_COORDS | OESTATE_REGION);
if (g_oeState.uFlags & OESTATE_SDA_DCB) { //
// Get the drawing bounds
//
int mmMode; SIZE ptWindowExt; SIZE ptViewportExt; int uBoundsNew;
mmMode = GetMapMode(g_oeState.hdc); if (mmMode != MM_TEXT) { //
// Changing the map mode whacks the window/view exts
// So save them so we can replace them when done.
//
GetWindowExtEx(g_oeState.hdc, &ptWindowExt); GetViewportExtEx(g_oeState.hdc, &ptViewportExt);
SetMapMode(g_oeState.hdc, MM_TEXT); } //
// Get the drawing bounds and update them.
//
uBoundsNew = GetBoundsRect(g_oeState.hdc, &g_oeState.rc, DCB_RESET);
//
// If no drawing bounds updated, act like no output happened.
//
if ((uBoundsNew & DCB_SET) == DCB_RESET) { fOutput = FALSE; } else { OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1); }
if (mmMode != MM_TEXT) { SetMapMode(g_oeState.hdc, mmMode);
// Put back the window, viewport exts; SetMapMode wipes them out
SetWindowExt(g_oeState.hdc, ptWindowExt.cx, ptWindowExt.cy); SetViewportExt(g_oeState.hdc, ptViewportExt.cx, ptViewportExt.cy); } } else { ASSERT(g_oeState.uFlags & OESTATE_SDA_SCREEN);
g_oeState.rc.left = g_osiScreenRect.left; g_oeState.rc.top = g_osiScreenRect.top; g_oeState.rc.right = g_osiScreenRect.right - 1; g_oeState.rc.bottom = g_osiScreenRect.bottom - 1; }
if (fOutput) { if (g_oeState.uFlags & OESTATE_OFFBYONEHACK) g_oeState.rc.bottom++;
OEClipAndAddScreenData(&g_oeState.rc);
// This way caller won't do anything else.
fOutput = FALSE; }
//
// Put back the draw bounds if we'd turned them on.
//
if (g_oeState.uFlags & OESTATE_SDA_DCB) { if (g_oeState.uGetDCB == DCB_SET) { SetBoundsRect(g_oeState.hdc, &g_oeState.rcDCB, g_oeState.uSetDCB | DCB_ACCUMULATE); } else { SetBoundsRect(g_oeState.hdc, NULL, g_oeState.uSetDCB | DCB_RESET); } } } }
DC_EXIT_POINT: DebugExitBOOL(OEAfterDDI, (fWeCare && fOutput)); return(fWeCare && fOutput);
}
//
// OEClipAndAddScreenData()
//
void OEClipAndAddScreenData ( LPRECT lprcAdd ) { RECT rcSDA; RECT rcClipped; LPRECTL pClip; UINT iClip;
DebugEntry(OEClipAndAddScreenData);
ASSERT(g_oeState.uFlags & OESTATE_REGION);
//
// The rect passed is in virtual desktop inclusive coords. Convert to
// Windows screen coords
//
rcSDA.left = lprcAdd->left; rcSDA.top = lprcAdd->top; rcSDA.right = lprcAdd->right + 1; rcSDA.bottom = lprcAdd->bottom + 1;
//
// We've got our region data. In the case of a region that has more
// than 64 pieces, we just use the bound box (one piece), that's been
// set up for us already.
//
//
// Intersect each piece with the total bounds to product an SDA rect
// clipped appropriately.
//
for (iClip = 0, pClip = g_oeState.rgnData.arclPieces; iClip < g_oeState.rgnData.rdh.nRectL; iClip++, pClip++) { RECTL_TO_RECT(pClip, &rcClipped);
if (IntersectRect(&rcClipped, &rcClipped, &rcSDA)) { //
// Convert to virtual desktop inclusive coords
//
rcClipped.right -= 1; rcClipped.bottom -= 1;
BA_AddScreenData(&rcClipped); } }
DC_EXIT_POINT: DebugExitVOID(OEClipAndAddScreenData); }
//
// FUNCTION: OEClipAndAddOrder
//
// DESCRIPTION:
//
// Clips the supplied order to the current clip region in the DC. If this
// results in more than one clipped rectangle then the order is duplicated
// and multiple copies are added to the Order List (with the only
// difference between the orders being the destination rectangle).
//
// PARAMETERS: pOrder - a pointer to the order
//
// RETURNS: VOID
//
//
void OEClipAndAddOrder ( LPINT_ORDER pOrder, void FAR* lpExtraInfo ) { RECT rcOrder; RECT rcPiece; RECT rcClipped; LPRECTL pPiece; UINT iClip; BOOL fOrderClipped; LPINT_ORDER pNewOrder; LPINT_ORDER pLastOrder;
DebugEntry(OEClipAndAddOrder);
ASSERT(g_oeState.uFlags & OESTATE_REGION);
//
// If this fails somewhere, we accumulate screen data in the same place
// to spoil the order(s).
//
//
// NOTE:
// There are some VERY important things about the way this function
// works that you should be aware of:
//
// (1) Every time an order is allocated, it is added to the end of
// the order heap linked list
// (2) Appending an order commits it, that updates some total byte info.
// If the order is a spoiler, the append code will walk backwards from
// the order being appended and will wipe out orders whose bounds are
// completely contained within the rect of the current one.
//
// THEREFORE, it is important to append orders in the order they are
// allocated it. When we come into this function, one order is already
// allocated. Its rcsDst bound rect is uninitialized. When a second
// intersection with the visrgn occurs, we must allocate a new order,
// but append the previously allocated block with the previous rect
// info.
//
// Otherwise you will encounter the bug that took me a while to figure
// out:
// * Laura allocates an order in say PatBlt with a spoiler ROP
// * Laura calls OEClipAndAddOrder and of course the rcsDst field
// hasn't been initialized yet.
// * The order intersects two pieces of the visrgn. On the first
// intersection, we save that info away.
// * On the second, we allocate a new order block, fill in the NEW
// order's info by copying from the old, setting up the rect
// with the first intersection, and call OA_DDAddOrder.
// * This, as a spoiler, causes the OA_ code to walk backwards in
// the linked list looking for orders whose bounds are
// completely enclosed by this one.
// * It comes to the original order allocated, whose bounds are
// currently NOT initialized
// * It may find that these uninitialized values describe a rect
// contained within the new order's bounds
// * It frees this order but the order was not yet committed
// * The heap sizes and heap info no longer match, causing an
// error about the "List head wrong", the list to get reinited,
// and orders to be lost.
//
rcOrder.left = g_oeState.rc.left; rcOrder.top = g_oeState.rc.top; rcOrder.right = g_oeState.rc.right + 1; rcOrder.bottom = g_oeState.rc.bottom + 1;
pNewOrder = pOrder; fOrderClipped = FALSE; g_oaPurgeAllowed = FALSE;
//
// Intersect each piece rect with the draw bounds
//
for (iClip = 0, pPiece = g_oeState.rgnData.arclPieces; iClip < g_oeState.rgnData.rdh.nRectL; iClip++, pPiece++) { RECTL_TO_RECT(pPiece, &rcPiece);
if (!IntersectRect(&rcPiece, &rcPiece, &rcOrder)) continue;
if (fOrderClipped) { //
// This adds a clipped order for the LAST intersection, not
// the current one. We do this to avoid allocating an extra
// order when only ONE intersection occurs.
//
//
// The order has already been clipped once, so it actually
// intersects more than one clip rect. We cope with this
// by duplicating the order and clipping it again.
//
pNewOrder = OA_DDAllocOrderMem( pLastOrder->OrderHeader.Common.cbOrderDataLength, 0); if (pNewOrder == NULL) { WARNING_OUT(("OA alloc failed"));
//
// BOGUS LAURABU:
// If some order in the middle fails to be
// allocated, we need the previous order + the remaining
// intersections to be added as screen data!
//
// NT's code is bogus, it will miss some output.
//
//
// Allocation of memory for a duplicate order failed.
// Just add the original order as screen data, and free
// the original's memory. Note that g_oeState.rc has
// the proper bounds, so we can just call OEClipAndAddScreenData().
//
OA_DDFreeOrderMem(pLastOrder); OEClipAndAddScreenData(&g_oeState.rc); DC_QUIT; }
//
// Copy the header & data from the original order to this
// new one. Don't overwrite the list info at the start.
//
hmemcpy((LPBYTE)pNewOrder + FIELD_SIZE(INT_ORDER, OrderHeader.list), (LPBYTE)pLastOrder + FIELD_SIZE(INT_ORDER, OrderHeader.list), pLastOrder->OrderHeader.Common.cbOrderDataLength + sizeof(INT_ORDER_HEADER) - FIELD_SIZE(INT_ORDER, OrderHeader.list));
//
// Set the clip rect. NOTE: This is the clipped rect from
// LAST time.
//
pLastOrder->OrderHeader.Common.rcsDst.left = rcClipped.left; pLastOrder->OrderHeader.Common.rcsDst.top = rcClipped.top; pLastOrder->OrderHeader.Common.rcsDst.right = rcClipped.right - 1; pLastOrder->OrderHeader.Common.rcsDst.bottom = rcClipped.bottom - 1;
OTRACE(("Duplicate clipped order %08lx at {%d, %d, %d, %d}", pLastOrder, pLastOrder->OrderHeader.Common.rcsDst.left, pLastOrder->OrderHeader.Common.rcsDst.top, pLastOrder->OrderHeader.Common.rcsDst.right, pLastOrder->OrderHeader.Common.rcsDst.bottom));
OA_DDAddOrder(pLastOrder, lpExtraInfo); }
//
// Save the clipping rect for the NEXT dude.
//
CopyRect(&rcClipped, &rcPiece); fOrderClipped = TRUE; pLastOrder = pNewOrder; }
//
// We're out of the loop now.
//
if (fOrderClipped) { pLastOrder->OrderHeader.Common.rcsDst.left = rcClipped.left; pLastOrder->OrderHeader.Common.rcsDst.top = rcClipped.top; pLastOrder->OrderHeader.Common.rcsDst.right = rcClipped.right - 1; pLastOrder->OrderHeader.Common.rcsDst.bottom = rcClipped.bottom - 1;
OTRACE(("Clipped order %08lx at {%d, %d, %d, %d}", pLastOrder, pLastOrder->OrderHeader.Common.rcsDst.left, pLastOrder->OrderHeader.Common.rcsDst.top, pLastOrder->OrderHeader.Common.rcsDst.right, pLastOrder->OrderHeader.Common.rcsDst.bottom));
OA_DDAddOrder(pLastOrder, lpExtraInfo); } else { OTRACE(("Order clipped completely")); OA_DDFreeOrderMem(pOrder); }
DC_EXIT_POINT: g_oaPurgeAllowed = TRUE;
DebugExitVOID(OEClipAndAddOrder); }
//
// DDI PATCHES
//
//
// DrvArc()
//
BOOL WINAPI DrvArc ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom, int xStartArc, int yStartArc, int xEndArc, int yEndArc ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPARC_ORDER pArc; POINT ptStart; POINT ptEnd;
DebugEntry(DrvArc);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_ARC, hdcDst, 0);
fOutput = Arc(hdcDst, xLeft, yTop, xRight, yBottom, xStartArc, yStartArc, xEndArc, yEndArc);
if (OEAfterDDI(DDI_ARC, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION);
//
// Get the bound rect
//
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom;
OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Can we send an ARC order?
//
pOrder = NULL;
if (OECheckOrder(ORD_ARC, OECHECK_PEN | OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(ARC_ORDER), 0); if (!pOrder) goto NoArcOrder;
pArc = (LPARC_ORDER)pOrder->abOrderData; pArc->type = LOWORD(ORD_ARC);
//
// Note that order coordinates are 32-bits, but we're 16-bits.
// So we need intermediate variables to do conversions on.
//
pArc->nLeftRect = g_oeState.rc.left; pArc->nTopRect = g_oeState.rc.top; pArc->nRightRect = g_oeState.rc.right; pArc->nBottomRect = g_oeState.rc.bottom;
ptStart.x = xStartArc; ptStart.y = yStartArc; OELPtoVirtual(g_oeState.hdc, &ptStart, 1); pArc->nXStart = ptStart.x; pArc->nYStart = ptStart.y;
ptEnd.x = xEndArc; ptEnd.y = yEndArc; OELPtoVirtual(g_oeState.hdc, &ptEnd, 1); pArc->nXEnd = ptEnd.x; pArc->nYEnd = ptEnd.y;
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, &pArc->BackColor, FALSE); pArc->BackMode = g_oeState.lpdc->DrawMode.bkMode; pArc->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pArc->PenStyle = g_oeState.logPen.lopnStyle; pArc->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pArc->PenColor, FALSE);
//
// Get the arc direction (counter-clockwise or clockwise)
//
if (g_oeState.lpdc->fwPath & DCPATH_CLOCKWISE) pArc->ArcDirection = ORD_ARC_CLOCKWISE; else pArc->ArcDirection = ORD_ARC_COUNTERCLOCKWISE;
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
OTRACE(("Arc: Order %08lx, Rect {%d, %d, %d, %d}, Start {%d, %d}, End {%d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y)); OEClipAndAddOrder(pOrder, NULL); }
NoArcOrder: if (!pOrder) { OTRACE(("Arc: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvArc, fOutput); return(fOutput); }
//
// DrvChord()
//
BOOL WINAPI DrvChord ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom, int xStartChord, int yStartChord, int xEndChord, int yEndChord ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPCHORD_ORDER pChord; POINT ptStart; POINT ptEnd; POINT ptBrushOrg;
DebugEntry(DrvChord);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_CHORD, hdcDst, 0);
fOutput = Chord(hdcDst, xLeft, yTop, xRight, yBottom, xStartChord, yStartChord, xEndChord, yEndChord);
if (OEAfterDDI(DDI_CHORD, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
//
// Get the bound rect
//
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom; OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Can we send a CHORD order?
//
pOrder = NULL;
if (OECheckOrder(ORD_CHORD, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(CHORD_ORDER), 0); if (!pOrder) goto NoChordOrder;
pChord = (LPCHORD_ORDER)pOrder->abOrderData; pChord->type = LOWORD(ORD_CHORD);
pChord->nLeftRect = g_oeState.rc.left; pChord->nTopRect = g_oeState.rc.top; pChord->nRightRect = g_oeState.rc.right; pChord->nBottomRect = g_oeState.rc.bottom;
ptStart.x = xStartChord; ptStart.y = yStartChord; OELPtoVirtual(g_oeState.hdc, &ptStart, 1); pChord->nXStart = ptStart.x; pChord->nYStart = ptStart.y;
ptEnd.x = xEndChord; ptEnd.y = yEndChord; OELPtoVirtual(g_oeState.hdc, &ptEnd, 1); pChord->nXEnd = ptEnd.x; pChord->nYEnd = ptEnd.y;
OEGetBrushInfo(&pChord->BackColor, &pChord->ForeColor, &pChord->BrushStyle, &pChord->BrushHatch, pChord->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pChord->BrushOrgX = (BYTE)ptBrushOrg.x; pChord->BrushOrgY = (BYTE)ptBrushOrg.y;
pChord->BackMode = g_oeState.lpdc->DrawMode.bkMode; pChord->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pChord->PenStyle = g_oeState.logPen.lopnStyle; pChord->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pChord->PenColor, FALSE);
if (g_oeState.lpdc->fwPath & DCPATH_CLOCKWISE) pChord->ArcDirection = ORD_ARC_CLOCKWISE; else pChord->ArcDirection = ORD_ARC_COUNTERCLOCKWISE;
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
OTRACE(("Chord: Order %08lx, Rect {%d, %d, %d, %d}, Start {%d, %d}, End {%d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y)); OEClipAndAddOrder(pOrder, NULL); }
NoChordOrder: if (!pOrder) { OTRACE(("Chord: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvChord, fOutput); return(fOutput); }
//
// DrvEllipse()
//
BOOL WINAPI DrvEllipse ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPELLIPSE_ORDER pEllipse; POINT ptBrushOrg;
DebugEntry(DrvEllipse);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_ELLIPSE, hdcDst, 0);
fOutput = Ellipse(hdcDst, xLeft, yTop, xRight, yBottom);
if (OEAfterDDI(DDI_ELLIPSE, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
//
// Calc bound rect
//
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom; OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Can we send ELLIPSE order?
//
pOrder = NULL;
if (OECheckOrder(ORD_ELLIPSE, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(ELLIPSE_ORDER), 0); if (!pOrder) goto NoEllipseOrder;
pEllipse = (LPELLIPSE_ORDER)pOrder->abOrderData; pEllipse->type = LOWORD(ORD_ELLIPSE);
pEllipse->nLeftRect = g_oeState.rc.left; pEllipse->nTopRect = g_oeState.rc.top; pEllipse->nRightRect = g_oeState.rc.right; pEllipse->nBottomRect = g_oeState.rc.bottom;
OEGetBrushInfo(&pEllipse->BackColor, &pEllipse->ForeColor, &pEllipse->BrushStyle, &pEllipse->BrushHatch, pEllipse->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pEllipse->BrushOrgX = (BYTE)ptBrushOrg.x; pEllipse->BrushOrgY = (BYTE)ptBrushOrg.y;
pEllipse->BackMode = g_oeState.lpdc->DrawMode.bkMode; pEllipse->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pEllipse->PenStyle = g_oeState.logPen.lopnStyle; pEllipse->PenWidth = 1;
OEConvertColor(g_oeState.logPen.lopnColor, &pEllipse->PenColor, FALSE);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
OTRACE(("Ellipse: Order %08lx, Rect {%d, %d, %d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddOrder(pOrder, NULL); }
NoEllipseOrder: if (!pOrder) { OTRACE(("Ellipse: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvEllipse, fOutput); return(fOutput); }
//
// DrvPie()
//
BOOL WINAPI DrvPie ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom, int xStartArc, int yStartArc, int xEndArc, int yEndArc ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPPIE_ORDER pPie; POINT ptStart; POINT ptEnd; POINT ptBrushOrg;
DebugEntry(DrvPie);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PIE, hdcDst, 0);
fOutput = Pie(hdcDst, xLeft, yTop, xRight, yBottom, xStartArc, yStartArc, xEndArc, yEndArc);
if (OEAfterDDI(DDI_PIE, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
//
// Get bound rect
//
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom; OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Can we send PIE order?
//
pOrder = NULL;
if (OECheckOrder(ORD_PIE, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(PIE_ORDER), 0); if (!pOrder) goto NoPieOrder;
pPie = (LPPIE_ORDER)pOrder->abOrderData; pPie->type = LOWORD(ORD_PIE);
pPie->nLeftRect = g_oeState.rc.left; pPie->nTopRect = g_oeState.rc.top; pPie->nRightRect = g_oeState.rc.right; pPie->nBottomRect = g_oeState.rc.bottom;
ptStart.x = xStartArc; ptStart.y = yStartArc; OELPtoVirtual(g_oeState.hdc, &ptStart, 1); pPie->nXStart = ptStart.x; pPie->nYStart = ptStart.y;
ptEnd.x = xEndArc; ptEnd.y = yEndArc; OELPtoVirtual(g_oeState.hdc, &ptEnd, 1); pPie->nXEnd = ptEnd.x; pPie->nYEnd = ptEnd.y;
OEGetBrushInfo(&pPie->BackColor, &pPie->ForeColor, &pPie->BrushStyle, &pPie->BrushHatch, pPie->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pPie->BrushOrgX = (BYTE)ptBrushOrg.x; pPie->BrushOrgY = (BYTE)ptBrushOrg.y;
pPie->BackMode = g_oeState.lpdc->DrawMode.bkMode; pPie->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pPie->PenStyle = g_oeState.logPen.lopnStyle; pPie->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pPie->PenColor, FALSE);
if (g_oeState.lpdc->fwPath & DCPATH_CLOCKWISE) pPie->ArcDirection = ORD_ARC_CLOCKWISE; else pPie->ArcDirection = ORD_ARC_COUNTERCLOCKWISE;
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
OTRACE(("Pie: Order %08lx, Rect {%d, %d, %d, %d}, Start {%d, %d}, End {%d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddOrder(pOrder, NULL); }
NoPieOrder: if (!pOrder) { OTRACE(("PieOrder: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPie, fOutput); return(fOutput); }
//
// DrvRoundRect()
//
BOOL WINAPI DrvRoundRect ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom, int cxEllipse, int cyEllipse ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPROUNDRECT_ORDER pRoundRect; POINT ptBrushOrg;
DebugEntry(DrvRoundRect);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_ROUNDRECT, hdcDst, 0);
fOutput = RoundRect(hdcDst, xLeft, yTop, xRight, yBottom, cxEllipse, cyEllipse);
if (OEAfterDDI(DDI_ROUNDRECT, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
//
// Get bound rect
//
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom; OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Can we send ROUNDRECT order?
//
pOrder = NULL;
if (OECheckOrder(ORD_ROUNDRECT, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING) && (GetMapMode(hdcDst) == MM_TEXT)) { pOrder = OA_DDAllocOrderMem(sizeof(ROUNDRECT_ORDER), 0); if (!pOrder) goto NoRoundRectOrder;
pRoundRect = (LPROUNDRECT_ORDER)pOrder->abOrderData; pRoundRect->type = LOWORD(ORD_ROUNDRECT);
pRoundRect->nLeftRect = g_oeState.rc.left; pRoundRect->nTopRect = g_oeState.rc.top; pRoundRect->nRightRect = g_oeState.rc.right; pRoundRect->nBottomRect = g_oeState.rc.bottom;
//
// It's too difficult to do the mapping of the ellipse
// dimensions when not MM_TEXT. Therefore we don't. If we
// are here, we just pass the sizes straight through.
//
pRoundRect->nEllipseWidth = cxEllipse; pRoundRect->nEllipseHeight = cyEllipse;
OEGetBrushInfo(&pRoundRect->BackColor, &pRoundRect->ForeColor, &pRoundRect->BrushStyle, &pRoundRect->BrushHatch, pRoundRect->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pRoundRect->BrushOrgX = ptBrushOrg.x; pRoundRect->BrushOrgY = ptBrushOrg.y;
pRoundRect->BackMode = g_oeState.lpdc->DrawMode.bkMode; pRoundRect->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pRoundRect->PenStyle = g_oeState.logPen.lopnStyle; pRoundRect->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pRoundRect->PenColor, FALSE);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE; OTRACE(("RoundRect: Order %08lx, Rect {%d, %d, %d, %d}, Curve {%d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, cxEllipse, cyEllipse)); OEClipAndAddOrder(pOrder, NULL); }
NoRoundRectOrder: if (!pOrder) { OTRACE(("RoundRect: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvRoundRect, fOutput); return(fOutput); }
//
// DrvBitBlt
//
BOOL WINAPI DrvBitBlt ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, HDC hdcSrc, int xSrc, int ySrc, DWORD dwRop ) { BOOL fWeCare; BOOL fOutput; BYTE bRop; LPDC lpdcSrc; LPINT_ORDER pOrder; LPSCRBLT_ORDER pScrBlt; POINT ptT; RECT rcT;
DebugEntry(DrvBitBlt);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_BITBLT, hdcDst, 0);
fOutput = BitBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcSrc, xSrc, ySrc, dwRop);
if (OEAfterDDI(DDI_BITBLT, fWeCare, fOutput && cxDst && cyDst)) { //
// Is this really PatBlt?
//
bRop = LOBYTE(HIWORD(dwRop));
if (((bRop & 0x33) << 2) == (bRop & 0xCC)) { TRACE_OUT(("BitBlt used for PatBlt"));
OEGetState(OESTATE_COORDS | OESTATE_BRUSH | OESTATE_REGION);
//
// Get bound rect
//
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst + cxDst; g_oeState.rc.bottom = yDst + cyDst;
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
OEAddBlt(dwRop); DC_QUIT; }
//
// SPB goop
//
if (g_oeState.lpdc->hBitmap == g_ssiLastSpbBitmap) { //
// This is an SPB operation. The source is in screen coords.
//
ASSERT(g_ssiLastSpbBitmap); ASSERT(g_oeState.lpdc->DCFlags & DC_IS_MEMORY); ASSERT(dwRop == SRCCOPY);
g_oeState.rc.left = xSrc; g_oeState.rc.top = ySrc; g_oeState.rc.right = xSrc + cxDst; g_oeState.rc.bottom = ySrc + cyDst;
SSISaveBits(g_ssiLastSpbBitmap, &g_oeState.rc); g_ssiLastSpbBitmap = NULL;
DC_QUIT; }
ASSERT(!(g_oeState.lpdc->DCFlags & DC_IS_MEMORY));
//
// Is this a memory to screen blt for SPB restoration?
//
lpdcSrc = OEValidateDC(hdcSrc, TRUE); if (SELECTOROF(lpdcSrc) && (lpdcSrc->DCFlags & DC_IS_DISPLAY) && (lpdcSrc->DCFlags & DC_IS_MEMORY) && (dwRop == SRCCOPY) && SSIRestoreBits(lpdcSrc->hBitmap)) { OTRACE(("BitBlt: SPB restored")); DC_QUIT; }
//
// Now, we accumulate orders for screen-to-screen blts
//
OEGetState(OESTATE_COORDS | OESTATE_BRUSH | OESTATE_REGION);
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst + cxDst; g_oeState.rc.bottom = yDst + cyDst;
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
pOrder = NULL;
if (hdcSrc == hdcDst) { if (!OECheckOrder(ORD_SCRBLT, OECHECK_CLIPPING) || !OESendRop3AsOrder(bRop) || !ROP3_NO_PATTERN(bRop)) { goto NoBitBltOrder; }
//
// Get source coords
//
ptT.x = xSrc; ptT.y = ySrc; OELPtoVirtual(hdcSrc, &ptT, 1);
//
// If the clipping isn't simple and the source overlaps the dest,
// send as screen data. It's too complicated for an order.
//
if (!OEClippingIsSimple()) { //
// NOTE:
// The NM 2.0 code was really messed up, the source rect
// calcs were bogus.
//
rcT.left = max(g_oeState.rc.left, ptT.x); rcT.right = min(g_oeState.rc.right, ptT.x + (g_oeState.rc.right - g_oeState.rc.left));
rcT.top = max(g_oeState.rc.top, ptT.y); rcT.bottom = min(g_oeState.rc.bottom, ptT.y + (g_oeState.rc.bottom - g_oeState.rc.top));
if ((rcT.left <= rcT.right) && (rcT.top <= rcT.bottom)) { TRACE_OUT(("No SCRBLT order; non-rect clipping and Src/Dst intersect")); goto NoBitBltOrder; } }
pOrder = OA_DDAllocOrderMem(sizeof(SCRBLT_ORDER), 0); if (!pOrder) goto NoBitBltOrder;
pScrBlt = (LPSCRBLT_ORDER)pOrder->abOrderData; pScrBlt->type = LOWORD(ORD_SCRBLT);
pScrBlt->nLeftRect = g_oeState.rc.left; pScrBlt->nTopRect = g_oeState.rc.top; pScrBlt->nWidth = g_oeState.rc.right - g_oeState.rc.left + 1; pScrBlt->nHeight = g_oeState.rc.bottom - g_oeState.rc.top + 1; pScrBlt->bRop = bRop;
pScrBlt->nXSrc = ptT.x; pScrBlt->nYSrc = ptT.y;
pOrder->OrderHeader.Common.fOrderFlags = OF_BLOCKER | OF_SPOILABLE;
OTRACE(("ScrBlt: From {%d, %d}, To {%d, %d}, Size {%d, %d}", ptT.x, ptT.y, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right - g_oeState.rc.left + 1, g_oeState.rc.bottom - g_oeState.rc.top + 1));
OEClipAndAddOrder(pOrder, NULL); }
NoBitBltOrder: if (!pOrder) { OTRACE(("BitBlt: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
DC_EXIT_POINT: OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvBitBlt, fOutput); return(fOutput); }
//
// DrvExtTextOutA()
//
BOOL WINAPI DrvExtTextOutA ( HDC hdcDst, int xDst, int yDst, UINT uOptions, LPRECT lprcClip, LPSTR lpszText, UINT cchText, LPINT lpdxCharSpacing ) { BOOL fWeCare; BOOL fOutput; UINT uFlags;
DebugEntry(DrvExtTextOutA);
OE_SHM_START_WRITING;
//
// Is this really just opaquing?
//
if ((cchText == 0) && SELECTOROF(lprcClip) && !IsBadReadPtr(lprcClip, sizeof(RECT)) && (uOptions & ETO_OPAQUE)) { uFlags = 0; } else { uFlags = OESTATE_SDA_FONTCOMPLEX | OESTATE_CURPOS; }
fWeCare = OEBeforeDDI(DDI_EXTTEXTOUTA, hdcDst, uFlags);
fOutput = ExtTextOut(hdcDst, xDst, yDst, uOptions, lprcClip, lpszText, cchText, lpdxCharSpacing);
if (OEAfterDDI(DDI_EXTTEXTOUTA, fWeCare, fOutput)) { //
// Is this a simple OPAQUE rect, or a textout call?
// NOTE that OEAfterDDI() returns FALSE if fOutput is TRUE but
// we used DCBs to add it as screen data.
//
if (uFlags & OESTATE_SDA_FONTCOMPLEX) { if (cchText) { POINT ptStart = {xDst, yDst};
OEAddText(ptStart, uOptions, lprcClip, lpszText, cchText, lpdxCharSpacing); } } else { OEAddOpaqueRect(lprcClip); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvExtTextOutA, fOutput); return(fOutput); }
#pragma optimize("gle", off)
//
// DrvPatBlt()
//
BOOL WINAPI DrvPatBlt ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, DWORD rop ) { UINT cxSave; BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder;
// Save CX
_asm mov cxSave, cx
DebugEntry(DrvPatBlt);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PATBLT, hdcDst, 0);
// Restore CX for RealPatBlt
_asm mov cx, cxSave fOutput = g_lpfnRealPatBlt(hdcDst, xDst, yDst, cxDst, cyDst, rop);
if (OEAfterDDI(DDI_PATBLT, fWeCare, fOutput && (cxSave != 0))) { OEGetState(OESTATE_COORDS | OESTATE_BRUSH | OESTATE_REGION);
//
// Get bound rect
//
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst + cxDst; g_oeState.rc.bottom = yDst + cyDst;
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
OEAddBlt(rop); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPatBlt, fOutput); return(fOutput); } #pragma optimize("", on)
//
// OEAddBlt()
// Used for simple destination ROP blts
//
void OEAddBlt ( DWORD dwRop ) { LPINT_ORDER pOrder; DWORD type; POINT ptBrushOrg; BYTE bRop;
DebugEntry(OEAddBlt);
pOrder = NULL;
//
// Is this a full PATBLT_ORDER or a simple DSTBLT_ORDER? If the top
// nibble of the ROP is equal to the bottom nibble, no pattern is
// required. WHITENESS for example.
//
bRop = LOBYTE(HIWORD(dwRop)); if ((bRop >> 4) == (bRop & 0x0F)) { type = ORD_DSTBLT; } else { type = ORD_PATBLT;
if (!OECheckBrushIsSimple()) { DC_QUIT; }
if ((dwRop == PATCOPY) && (g_oeState.logBrush.lbStyle == BS_NULL)) { // No output happens in this scenario at all, no screen data even
goto NothingAtAll; } }
if (OE_SendAsOrder(type) && OESendRop3AsOrder(bRop) && !OEClippingIsComplex()) { if (type == ORD_PATBLT) { LPPATBLT_ORDER pPatBlt;
pOrder = OA_DDAllocOrderMem(sizeof(PATBLT_ORDER), 0); if (!pOrder) DC_QUIT;
pPatBlt = (LPPATBLT_ORDER)pOrder->abOrderData; pPatBlt->type = LOWORD(ORD_PATBLT);
pPatBlt->nLeftRect = g_oeState.rc.left; pPatBlt->nTopRect = g_oeState.rc.top; pPatBlt->nWidth = g_oeState.rc.right - g_oeState.rc.left + 1; pPatBlt->nHeight = g_oeState.rc.bottom - g_oeState.rc.top + 1;
pPatBlt->bRop = bRop;
OEGetBrushInfo(&pPatBlt->BackColor, &pPatBlt->ForeColor, &pPatBlt->BrushStyle, &pPatBlt->BrushHatch, pPatBlt->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pPatBlt->BrushOrgX = (BYTE)ptBrushOrg.x; pPatBlt->BrushOrgY = (BYTE)ptBrushOrg.y;
OTRACE(("PatBlt: Order %08lx, Rect {%d, %d, %d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.right)); } else { LPDSTBLT_ORDER pDstBlt;
ASSERT(type == ORD_DSTBLT);
pOrder = OA_DDAllocOrderMem(sizeof(DSTBLT_ORDER), 0); if (!pOrder) DC_QUIT; pDstBlt = (LPDSTBLT_ORDER)pOrder->abOrderData; pDstBlt->type = LOWORD(ORD_DSTBLT);
pDstBlt->nLeftRect = g_oeState.rc.left; pDstBlt->nTopRect = g_oeState.rc.top; pDstBlt->nWidth = g_oeState.rc.right - g_oeState.rc.left + 1; pDstBlt->nHeight = g_oeState.rc.bottom - g_oeState.rc.top + 1;
pDstBlt->bRop = bRop;
OTRACE(("DstBlt: Order %08lx, Rect {%d, %d, %d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); }
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE; if (ROP3_IS_OPAQUE(bRop)) pOrder->OrderHeader.Common.fOrderFlags |= OF_SPOILER;
OEClipAndAddOrder(pOrder, NULL); }
DC_EXIT_POINT: if (!pOrder) { OTRACE(("PatBlt: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } NothingAtAll: DebugExitVOID(OEAddBlt); }
//
// DrvStretchBlt()
//
BOOL WINAPI DrvStretchBlt ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, HDC hdcSrc, int xSrc, int ySrc, int cxSrc, int cySrc, DWORD rop ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvStretchBlt);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_STRETCHBLT, hdcDst, 0);
fOutput = StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcSrc, xSrc, ySrc, cxSrc, cySrc, rop);
if (OEAfterDDI(DDI_STRETCHBLT, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_REGION);
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst + cxDst; g_oeState.rc.bottom = yDst + cyDst; OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
OTRACE(("StretchBlt: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom));
OEClipAndAddScreenData(&g_oeState.rc); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvStretchBlt, fOutput); return(fOutput); }
//
// TextOutA()
//
BOOL WINAPI DrvTextOutA ( HDC hdcDst, int xDst, int yDst, LPSTR lpszText, int cchText ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvTextOutA);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_TEXTOUTA, hdcDst, OESTATE_SDA_FONTCOMPLEX | OESTATE_CURPOS);
fOutput = TextOut(hdcDst, xDst, yDst, lpszText, cchText);
if (OEAfterDDI(DDI_TEXTOUTA, fWeCare, fOutput && cchText)) { POINT ptStart = {xDst, yDst}; OEAddText(ptStart, 0, NULL, lpszText, cchText, NULL); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvTextOutA, fOutput); return(fOutput); }
//
// DrvExtFloodFill()
//
// This just gets added as screen data. Too darned complicated to
// calculate the result.
//
BOOL WINAPI DrvExtFloodFill ( HDC hdcDst, int xDst, int yDst, COLORREF clrFill, UINT uFillType ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvExtFloodFill);
OE_SHM_START_WRITING;
//
// GDI's draw bounds has an off-by-one bug in ExtFloodFill and FloodFill
//
fWeCare = OEBeforeDDI(DDI_EXTFLOODFILL, hdcDst, OESTATE_SDA_DCB | OESTATE_OFFBYONEHACK);
fOutput = ExtFloodFill(hdcDst, xDst, yDst, clrFill, uFillType);
OEAfterDDI(DDI_EXTFLOODFILL, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvExtFloodFill, fOutput); return(fOutput); }
//
// DrvFloodFill()
//
BOOL WINAPI DrvFloodFill ( HDC hdcDst, int xDst, int yDst, COLORREF clrFill ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvFloodFill);
OE_SHM_START_WRITING;
//
// GDI's draw bounds has an off-by-one bug in ExtFloodFill and FloodFill
//
fWeCare = OEBeforeDDI(DDI_FLOODFILL, hdcDst, OESTATE_SDA_DCB | OESTATE_OFFBYONEHACK);
fOutput = FloodFill(hdcDst, xDst, yDst, clrFill);
OEAfterDDI(DDI_FLOODFILL, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvFloodFill, fOutput); return(fOutput); }
//
// DrvExtTextOut()
//
BOOL WINAPI DrvExtTextOutW ( HDC hdcDst, int xDst, int yDst, UINT uOptions, LPRECT lprcClip, LPWSTR lpwszText, UINT cchText, LPINT lpdxCharSpacing ) { BOOL fWeCare; BOOL fOutput; UINT uFlags;
//
// NOTE:
// ExtTextOutW and TextOutW are only called on 32-bit app threads. So
// chewing up stack space isn't a problem.
//
UINT cchAnsi = 0; char szAnsi[ORD_MAX_STRING_LEN_WITHOUT_DELTAS+1];
DebugEntry(DrvExtTextOutW);
OE_SHM_START_WRITING;
if ((cchText == 0) && SELECTOROF(lprcClip) && !IsBadReadPtr(lprcClip, sizeof(RECT)) && (uOptions & ETO_OPAQUE)) { uFlags = 0; } else { //
// Is this order-able? It is if we can convert the unicode string
// to ansi then back to unicode, and end up where we started.
//
uFlags = OESTATE_SDA_DCB;
if (cchText && (cchText <= ORD_MAX_STRING_LEN_WITHOUT_DELTAS) && !IsBadReadPtr(lpwszText, cchText*sizeof(WCHAR))) { int cchUni;
//
// NOTE:
// UniToAnsi() returns ONE LESS than the # of chars converted
//
cchAnsi = UniToAnsi(lpwszText, szAnsi, cchText) + 1; cchUni = AnsiToUni(szAnsi, cchAnsi, g_oeTempString, ORD_MAX_STRING_LEN_WITHOUT_DELTAS);
if (cchUni == cchText) { //
// Verify these strings are the same
//
UINT ich;
for (ich = 0; ich < cchText; ich++) { if (lpwszText[ich] != g_oeTempString[ich]) break; }
if (ich == cchText) { //
// We made it to the end; everything matched.
//
uFlags = OESTATE_SDA_FONTCOMPLEX | OESTATE_CURPOS; } }
#ifdef DEBUG
if (uFlags == OESTATE_SDA_DCB) { WARNING_OUT(("Can't encode ExtTextOutW")); } #endif // DEBUG
} }
fWeCare = OEBeforeDDI(DDI_EXTTEXTOUTW, hdcDst, uFlags);
fOutput = g_lpfnExtTextOutW(hdcDst, xDst, yDst, uOptions, lprcClip, lpwszText, cchText, lpdxCharSpacing);
if (OEAfterDDI(DDI_EXTTEXTOUTW, fWeCare, fOutput)) { //
// Is this a simple OPAQUE rect, or a textout call we can order?
// NOTE that OEAfterDDI() returns FALSE even if fOutput but we
// used DCBs to add as screen data.
//
if (uFlags & OESTATE_SDA_FONTCOMPLEX) { POINT ptStart = {xDst, yDst};
ASSERT(cchAnsi); OEAddText(ptStart, uOptions, lprcClip, szAnsi, cchAnsi, lpdxCharSpacing); } else { OEAddOpaqueRect(lprcClip); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvExtTextOutW, fOutput); return(fOutput); }
//
// DrvTextOutW()
//
BOOL WINAPI DrvTextOutW ( HDC hdcDst, int xDst, int yDst, LPWSTR lpwszText, int cchText ) { BOOL fWeCare; BOOL fOutput; UINT uFlags;
//
// NOTE:
// ExtTextOutW and TextOutW are only called on 32-bit app threads. So
// chewing up stack space isn't a problem.
//
UINT cchAnsi = 0; char szAnsi[ORD_MAX_STRING_LEN_WITHOUT_DELTAS+1];
DebugEntry(DrvTextOutW);
OE_SHM_START_WRITING;
//
// Is this order-able? It is if we can convert the unicode string to
// ansi then back to unicode, and end up where we started.
//
uFlags = OESTATE_SDA_DCB;
if (cchText && (cchText <= ORD_MAX_STRING_LEN_WITHOUT_DELTAS) && !IsBadReadPtr(lpwszText, cchText*sizeof(WCHAR))) { int cchUni;
//
// NOTE:
// UniToAnsi() returns one LESS than the # of chars converted
//
cchAnsi = UniToAnsi(lpwszText, szAnsi, cchText) + 1; cchUni = AnsiToUni(szAnsi, cchAnsi, g_oeTempString, cchText);
if (cchUni == cchText) { //
// Verify these strings are the same
//
UINT ich;
for (ich = 0; ich < cchText; ich++) { if (lpwszText[ich] != g_oeTempString[ich]) break; }
if (ich == cchText) { //
// We made it to the end; everything matched.
//
uFlags = OESTATE_SDA_FONTCOMPLEX | OESTATE_CURPOS; }
#ifdef DEBUG
if (uFlags == OESTATE_SDA_DCB) { WARNING_OUT(("Can't encode TextOutW")); } #endif // DEBUG
} }
fWeCare = OEBeforeDDI(DDI_TEXTOUTW, hdcDst, uFlags);
fOutput = g_lpfnTextOutW(hdcDst, xDst, yDst, lpwszText, cchText);
if (OEAfterDDI(DDI_TEXTOUTW, fWeCare, fOutput && cchText)) { POINT ptStart = {xDst, yDst}; OEAddText(ptStart, 0, NULL, szAnsi, cchAnsi, NULL); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvTextOutW, fOutput); return(fOutput); }
//
// OEAddOpaqueRect()
// Adds a simple opaque rect order, used for "erasing" ExtTextOutA/W
// calls. The most common examples are in Office.
//
void OEAddOpaqueRect(LPRECT lprcOpaque) { LPINT_ORDER pOrder; LPOPAQUERECT_ORDER pOpaqueRect;
DebugEntry(OEAddOpaqueRect);
OEGetState(OESTATE_COORDS | OESTATE_REGION);
g_oeState.rc = *lprcOpaque; OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
pOrder = NULL;
if (OECheckOrder(ORD_OPAQUERECT, OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(OPAQUERECT_ORDER), 0); if (!pOrder) DC_QUIT;
pOpaqueRect = (LPOPAQUERECT_ORDER)pOrder->abOrderData; pOpaqueRect->type = LOWORD(ORD_OPAQUERECT);
pOpaqueRect->nLeftRect = g_oeState.rc.left; pOpaqueRect->nTopRect = g_oeState.rc.top; pOpaqueRect->nWidth = g_oeState.rc.right - g_oeState.rc.left + 1; pOpaqueRect->nHeight = g_oeState.rc.bottom - g_oeState.rc.top + 1;
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, &pOpaqueRect->Color, FALSE);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILER | OF_SPOILABLE;
OTRACE(("OpaqueRect: Order %08lx, Rect {%d, %d, %d, %d}, Color %08lx", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, pOpaqueRect->Color));
OEClipAndAddOrder(pOrder, NULL); }
DC_EXIT_POINT: if (!pOrder) { OTRACE(("OpaqueRect: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
DebugExitVOID(OEAddOpaqueRect); }
//
// OEAddText()
// Big monster routine that handles TextOutA/ExtTextOutA
//
// In general, we care about:
// * Clip rect--if none, and no text, it's an OpaqueRect instead
// * The font
// * Whether it's too complicated to send as an order
// * If it needs a deltaX array
//
void OEAddText ( POINT ptStart, UINT uOptions, LPRECT lprcClip, LPSTR lpszText, UINT cchText, LPINT lpdxCharSpacing ) { RECT rcT; int overhang; int width; UINT fOrderFlags; int cchMax; DWORD order; LPINT_ORDER pOrder; LPEXTTEXTOUT_ORDER pExtTextOut; LPTEXTOUT_ORDER pTextOut; LPCOMMON_TEXTORDER pCommon; UINT fontHeight; UINT fontWidth; UINT fontWeight; UINT fontFlags; UINT fontIndex; BOOL fSendDeltaX; POINT ptT; DebugEntry(OEAddText);
//
// NOTE:
// Do NOT convert ptStart. It is needed in logical form for several
// different things.
//
OEGetState(OESTATE_COORDS | OESTATE_FONT | OESTATE_REGION);
//
// We need to apply the same validation to the flags that GDI does.
// This bit massaging is for various app compatibility things.
//
if (uOptions & ~(ETO_CLIPPED | ETO_OPAQUE | ETO_GLYPH_INDEX | ETO_RTLREADING)) { uOptions &= (ETO_CLIPPED | ETO_OPAQUE); } if (!(uOptions & (ETO_CLIPPED | ETO_OPAQUE))) { // No opaquing/clipping, no clip rect
lprcClip = NULL; } if (!SELECTOROF(lprcClip)) { // No clip rect, no opaquing/clipping
uOptions &= ~(ETO_CLIPPED | ETO_OPAQUE); }
pOrder = NULL;
fOrderFlags = OF_SPOILABLE;
//
// Calculate the real starting position of the text
//
if (g_oeState.tmAlign & TA_UPDATECP) { ASSERT(g_oeState.uFlags & OESTATE_CURPOS); ptStart = g_oeState.ptCurPos; }
overhang = OEGetStringExtent(lpszText, cchText, lpdxCharSpacing, &rcT);
width = rcT.right - overhang - rcT.left; switch (g_oeState.tmAlign & (TA_CENTER | TA_LEFT | TA_RIGHT)) { case TA_CENTER: // The original x coord is the MIDPOINT
TRACE_OUT(("TextOut HORZ center")); ptStart.x -= (width * g_oeState.ptPolarity.x / 2); break;
case TA_RIGHT: // The original x coord is the RIGHT SIDE
TRACE_OUT(("TextOut HORZ right")); ptStart.x -= (width * g_oeState.ptPolarity.x); break;
case TA_LEFT: break; }
switch (g_oeState.tmAlign & (TA_BASELINE | TA_BOTTOM | TA_TOP)) { case TA_BASELINE: // The original y coord is the BASELINE
TRACE_OUT(("TextOut VERT baseline")); ptStart.y -= (g_oeState.tmFont.tmAscent * g_oeState.ptPolarity.y); break;
case TA_BOTTOM: // The original y coord is the BOTTOM SIDE
TRACE_OUT(("TextOut VERT bottom")); ptStart.y -= ((rcT.bottom - rcT.top) * g_oeState.ptPolarity.y); break;
case TA_TOP: break; }
//
// Calculate extent rect for order
//
if (uOptions & ETO_CLIPPED) { // Because of CopyRect() validation layer bug, do this directly
g_oeState.rc = *lprcClip;
if (uOptions & ETO_OPAQUE) fOrderFlags |= OF_SPOILER; } else { g_oeState.rc.left = ptStart.x + (g_oeState.ptPolarity.x * rcT.left); g_oeState.rc.top = ptStart.y + (g_oeState.ptPolarity.y * rcT.top); g_oeState.rc.right = ptStart.x + (g_oeState.ptPolarity.x * rcT.right); g_oeState.rc.bottom = ptStart.y + (g_oeState.ptPolarity.y * rcT.bottom);
if (uOptions & ETO_OPAQUE) { //
// Set the SPOILER flag in the order header. However, if the
// text extends outside the opaque rect, then the order isn't
// really opaque, and we have to clear this flag.
//
fOrderFlags |= OF_SPOILER;
if (g_oeState.ptPolarity.x == 1) { if ((g_oeState.rc.left < lprcClip->left) || (g_oeState.rc.right > lprcClip->right)) { fOrderFlags &= ~OF_SPOILER; }
g_oeState.rc.left = min(g_oeState.rc.left, lprcClip->left); g_oeState.rc.right = max(g_oeState.rc.right, lprcClip->right); } else { if ((g_oeState.rc.left > lprcClip->left) || (g_oeState.rc.right < lprcClip->right)) { fOrderFlags &= ~OF_SPOILER; }
g_oeState.rc.left = max(g_oeState.rc.left, lprcClip->left); g_oeState.rc.right = min(g_oeState.rc.right, lprcClip->right); }
if (g_oeState.ptPolarity.y == 1) { if ((g_oeState.rc.top < lprcClip->top) || (g_oeState.rc.bottom > lprcClip->bottom)) { fOrderFlags &= ~OF_SPOILER; }
g_oeState.rc.top = min(g_oeState.rc.top, lprcClip->top); g_oeState.rc.bottom = max(g_oeState.rc.bottom, lprcClip->bottom); } else { if ((g_oeState.rc.top > lprcClip->top) || (g_oeState.rc.bottom < lprcClip->bottom)) { fOrderFlags &= ~OF_SPOILER; }
g_oeState.rc.top = max(g_oeState.rc.top, lprcClip->top); g_oeState.rc.bottom = min(g_oeState.rc.bottom, lprcClip->bottom); }
//
// After all this, if the text is OPAQUE, then it is a spoiler
//
if (g_oeState.lpdc->DrawMode.bkMode == OPAQUE) fOrderFlags |= OF_SPOILER; } }
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// Is the font supported?
//
if (!OECheckFontIsSupported(lpszText, cchText, &fontHeight, &fontWidth, &fontWeight, &fontFlags, &fontIndex, &fSendDeltaX)) DC_QUIT;
//
// What type of order are we sending? And therefore what is the max
// # of chars we can encode?
//
if (fSendDeltaX || SELECTOROF(lpdxCharSpacing) || uOptions) { order = ORD_EXTTEXTOUT; cchMax = ORD_MAX_STRING_LEN_WITH_DELTAS; } else { order = ORD_TEXTOUT; cchMax = ORD_MAX_STRING_LEN_WITHOUT_DELTAS; }
if (OECheckOrder(order, OECHECK_CLIPPING) && (cchText <= cchMax)) { if (order == ORD_TEXTOUT) { pOrder = OA_DDAllocOrderMem((sizeof(TEXTOUT_ORDER) - ORD_MAX_STRING_LEN_WITHOUT_DELTAS + cchText), 0); if (!pOrder) DC_QUIT;
pTextOut = (LPTEXTOUT_ORDER)pOrder->abOrderData; pTextOut->type = LOWORD(order);
pCommon = &pTextOut->common; } else { //
// BOGUS LAURABU
// This allocates space for a deltax array whether or not one is
// needed.
//
pOrder = OA_DDAllocOrderMem((sizeof(EXTTEXTOUT_ORDER) - ORD_MAX_STRING_LEN_WITHOUT_DELTAS - (ORD_MAX_STRING_LEN_WITH_DELTAS * sizeof(TSHR_INT32)) + cchText + (cchText * sizeof(TSHR_INT32)) + 4), 0); // 4 is for dword alignment padding
if (!pOrder) DC_QUIT;
pExtTextOut = (LPEXTTEXTOUT_ORDER)pOrder->abOrderData; pExtTextOut->type = LOWORD(order);
pCommon = &pExtTextOut->common; }
//
// The order coords are TSHR_INT32s
//
ptT = ptStart; OELPtoVirtual(g_oeState.hdc, &ptT, 1); pCommon->nXStart = ptT.x; pCommon->nYStart = ptT.y;
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, &pCommon->BackColor, FALSE); OEConvertColor(g_oeState.lpdc->DrawMode.txColorL, &pCommon->ForeColor, FALSE);
pCommon->BackMode = g_oeState.lpdc->DrawMode.bkMode; pCommon->CharExtra = g_oeState.lpdc->DrawMode.CharExtra; pCommon->BreakExtra = g_oeState.lpdc->DrawMode.TBreakExtra; pCommon->BreakCount = g_oeState.lpdc->DrawMode.BreakCount;
//
// Font details
//
pCommon->FontHeight = fontHeight; pCommon->FontWidth = fontWidth; pCommon->FontWeight = fontWeight; pCommon->FontFlags = fontFlags; pCommon->FontIndex = fontIndex;
if (order == ORD_TEXTOUT) { //
// Copy the string
//
pTextOut->variableString.len = cchText; hmemcpy(pTextOut->variableString.string, lpszText, cchText); } else { pExtTextOut->fuOptions = uOptions & (ETO_OPAQUE | ETO_CLIPPED);
//
// If there is a clipping rect, set it up. Otherwise use the
// last ETO's clip rect. This makes OE2 encoding more efficient.
//
// NOTE that this is not the same as the drawing bounds--the
// text may extend outside the clip area.
//
if (SELECTOROF(lprcClip)) { ASSERT(uOptions & (ETO_OPAQUE | ETO_CLIPPED));
rcT = *lprcClip; OELRtoVirtual(g_oeState.hdc, &rcT, 1);
//
// This is a TSHR_RECT32, so we can't just copy
//
pExtTextOut->rectangle.left = rcT.left; pExtTextOut->rectangle.top = rcT.top; pExtTextOut->rectangle.right = rcT.right; pExtTextOut->rectangle.bottom = rcT.bottom;
g_oeLastETORect = pExtTextOut->rectangle; } else { pExtTextOut->rectangle = g_oeLastETORect; }
//
// Copy the string
//
pExtTextOut->variableString.len = cchText; hmemcpy(pExtTextOut->variableString.string, lpszText, cchText);
//
// Copy the deltax array
//
// Although we have a defined fixed length structure for
// storing ExtTextOut orders, we don't send the full structure
// over the network as the text will only be, say, 10 chars while
// the structure contains room for 127.
//
// Hence we pack the structure now to remove all the blank data
// BUT we must maintain the natural alignment of the variables.
//
// So we know the length of the string which we can use to
// start the new delta structure at the next 4-byte boundary.
//
if (!OEAddDeltaX(pExtTextOut, lpszText, cchText, lpdxCharSpacing, fSendDeltaX, ptStart)) { WARNING_OUT(("Couldn't add delta-x array to EXTTEXTOUT order")); OA_DDFreeOrderMem(pOrder); pOrder = NULL; } } }
DC_EXIT_POINT: if (pOrder) { //
// Call OEMaybeSimulateDeltaX to add a deltax array to the order
// if needed to correctly position the text. This happens when
// the font in use doesn't exist on other machines.
//
pOrder->OrderHeader.Common.fOrderFlags = fOrderFlags;
OTRACE(("TextOut: Type %08lx, Order %08lx, Rect {%d, %d, %d, %d}, Length %d", pOrder, order, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, cchText)); OEClipAndAddOrder(pOrder, NULL); } else { OTRACE(("OEAddText: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } DebugExitVOID(OEAddText); }
//
// OECheckFontIsSupported()
//
// We check if we can send this font. If we haven't received the negotiated
// packet caps yet, forget it.
//
// It returns:
// font height in points
// font ascender in points
// average font width in points
// font weight
// font style flags
// font handle
// do we need to send delta x
//
BOOL OECheckFontIsSupported ( LPSTR lpszText, UINT cchText, LPUINT pFontHeight, LPUINT pFontWidth, LPUINT pFontWeight, LPUINT pFontFlags, LPUINT pFontIndex, LPBOOL pSendDeltaX ) { BOOL fFontSupported; UINT codePage; UINT i; UINT iLocal; TSHR_UINT32 matchQuality; UINT charWidthAdjustment; int fontNameLen; int compareResult; POINT xformSize[2];
DebugEntry(OECheckFontIsSupported);
ASSERT(g_oeState.uFlags & OESTATE_FONT);
//
// Set up defaults
//
fFontSupported = FALSE; *pSendDeltaX = FALSE;
//
// Do we have our list yet?
//
if (!g_oeTextEnabled) DC_QUIT;
//
// Get the font facename
//
GetTextFace(g_oeState.hdc, LF_FACESIZE, g_oeState.logFont.lfFaceName); //
// Search our Font Alias Table for the font name. If we find it,
// replace it with the aliased name.
//
charWidthAdjustment = 0; for (i = 0; i < NUM_ALIAS_FONTS; i++) { if (!lstrcmp(g_oeState.logFont.lfFaceName, g_oeFontAliasTable[i].pszOriginalFontName)) { TRACE_OUT(("Alias name: %s -> %s", g_oeState.logFont.lfFaceName, g_oeFontAliasTable[i].pszAliasFontName)); lstrcpy(g_oeState.logFont.lfFaceName, g_oeFontAliasTable[i].pszAliasFontName); charWidthAdjustment = g_oeFontAliasTable[i].charWidthAdjustment; break; } }
//
// Get the current font code page
//
switch (g_oeState.tmFont.tmCharSet) { case ANSI_CHARSET: codePage = NF_CP_WIN_ANSI; break;
case OEM_CHARSET: codePage = NF_CP_WIN_OEM; break;
//
// LAURABU BUGBUG
// This wasn't in NM 2.0 -- does this cause problems in int'l?
//
case SYMBOL_CHARSET: codePage = NF_CP_WIN_SYMBOL; break;
default: codePage = NF_CP_UNKNOWN; break; }
//
// We have a font name to match with those we know to be available
// remotely. Try to jump straight to the first entry in the local font
// table starting with the same char as this font. If this index slot
// is empty (has 0xFFFF in it), then bail out immediately.
//
for (iLocal = g_oeLocalFontIndex[(BYTE)g_oeState.logFont.lfFaceName[0]]; iLocal < g_oeNumFonts; iLocal++) { //
// If this font isn't supported remotely, skip it.
//
matchQuality = g_poeLocalFonts[iLocal].SupportCode; if (matchQuality == FH_SC_NO_MATCH) { continue; }
//
// If this facename is different than ours, skip it. WE MUST
// CALL STRCMP(), because lstrcmp and strcmp() do different things
// for case. lstrcmp is lexi, and strcmp is alphi.
//
compareResult = MyStrcmp(g_poeLocalFonts[iLocal].Details.nfFaceName, g_oeState.logFont.lfFaceName);
//
// If this font is alphabetically before the one we're searching for,
// skip it and continue looking.
//
if (compareResult < 0) { continue; }
//
// If this font is alphabetically after the one we're searching for,
// then an entry for ours doesn't exist since the table is sorted
// alphabetically. Bail out.
//
if (compareResult > 0) { break; }
//
// This looks promising, a font with the right name is supported on
// the remote system. Let's look at the metrics.
//
*pFontFlags = 0; *pFontIndex = iLocal; *pFontWeight = g_oeState.tmFont.tmWeight;
//
// Check for a fixed pitch font (NOT present means fixed)
//
if (!(g_oeState.tmFont.tmPitchAndFamily & FIXED_PITCH)) { *pFontFlags |= NF_FIXED_PITCH; }
//
// Check for a truetype font
//
if (g_oeState.tmFont.tmPitchAndFamily & TMPF_TRUETYPE) { *pFontFlags |= NF_TRUE_TYPE; }
//
// Convert the font dimensions into pixel values. We use the
// average font width and the character height
//
xformSize[0].x = 0; xformSize[0].y = 0; xformSize[1].x = g_oeState.tmFont.tmAveCharWidth; xformSize[1].y = g_oeState.tmFont.tmHeight - g_oeState.tmFont.tmInternalLeading;
//
// For non-truetype simulated bold/italic fonts only:
//
// If the font is bold, the overhang field indicates the extra
// space a char takes up. Since our internal table contains the
// size of normal (non-bold) chars for simulated bold, we adjust
// for that here.
//
// If the font is italic, the overhang field indicates the number
// of pixels the char is skewed. We don't want to make adjustments
// in this case.
//
if (!(g_oeState.tmFont.tmPitchAndFamily & TMPF_TRUETYPE) && !g_oeState.tmFont.tmItalic) { xformSize[1].x -= g_oeState.tmFont.tmOverhang; }
//
// LAURABU BOGUS
// For baseline text orders
//
// xformSize[2].x = 0;
// xformSize[2].y = g_oeState.tmFont.tmAscent;
//
LPtoDP(g_oeState.hdc, xformSize, 2);
//
// Calculate the font width & height
//
*pFontHeight = abs(xformSize[1].y - xformSize[0].y); *pFontWidth = abs(xformSize[1].x - xformSize[0].x) - charWidthAdjustment;
//
// LAURABU BOGUS
// For baseline text orders
//
// Get the offset to the start of the text cell
//
// *pFontAscender = abs(xformSize[2].y - xformSize[0].y);
//
//
// Check that we have a matching pair -- where we require that the
// fonts (i.e., the one being used by the app and the one we've
// matched with the remot system) are the same pitch and use the
// same technology.
//
if ((g_poeLocalFonts[iLocal].Details.nfFontFlags & NF_FIXED_PITCH) != (*pFontFlags & NF_FIXED_PITCH)) { OTRACE(("Fixed pitch mismatch")); continue; } if ((g_poeLocalFonts[iLocal].Details.nfFontFlags & NF_TRUE_TYPE) != (*pFontFlags & NF_TRUE_TYPE)) { OTRACE(("True type mismatch")); continue; }
//
// We have a pair of fonts with the same attributes, both fixed or
// variable pitch, and using the same font technology.
//
// If the font is fixed pitch, then we need to check that the size
// matches also.
//
// If not, assume it's always matchable.
//
if (g_poeLocalFonts[iLocal].Details.nfFontFlags & NF_FIXED_SIZE) { //
// The font is fixed size, so we must check that this
// particular size is matchable.
//
if ( (*pFontHeight != g_poeLocalFonts[iLocal].Details.nfAveHeight) || (*pFontWidth != g_poeLocalFonts[iLocal].Details.nfAveWidth) ) { //
// The sizes differ, so we must fail this match.
//
TRACE_OUT(("Font size mismatch: want {%d, %d}, found {%d, %d}", *pFontHeight, *pFontWidth, g_poeLocalFonts[iLocal].Details.nfAveHeight, g_poeLocalFonts[iLocal].Details.nfAveWidth)); continue; } }
//
// Finally, we've got a matched pair.
//
fFontSupported = TRUE; break; }
if (!fFontSupported) { TRACE_OUT(("Couldn't find matching font for %s in table", g_oeState.logFont.lfFaceName)); DC_QUIT; }
//
// Build up the rest of the font flags. We've got pitch already.
//
if (g_oeState.tmFont.tmItalic) { *pFontFlags |= NF_ITALIC; } if (g_oeState.tmFont.tmUnderlined) { *pFontFlags |= NF_UNDERLINE; } if (g_oeState.tmFont.tmStruckOut) { *pFontFlags |= NF_STRIKEOUT; }
//
// LAURABU BOGUS
// On NT, here's where simulated bold fonts are handled. Note that we,
// like NM 2.0, handle it above with the overhang.
//
#if 0
//
// It is possible to have a font made bold by Windows, i.e. the
// standard font definition is not bold, but windows manipulates the
// font data to create a bold effect. This is marked by the
// FO_SIM_BOLD flag.
//
// In this case we need to ensure that the font flags are marked as
// bold according to the weight.
//
if ( ((pfo->flFontType & FO_SIM_BOLD) != 0) && ( pFontMetrics->usWinWeight < FW_BOLD) ) { TRACE_OUT(( "Upgrading weight for a bold font")); *pFontWeight = FW_BOLD; } #endif
//
// Should we check the chars in the string itself? Use matchQuality
// to decide.
//
// If the font is an exact match, or if it's an approx match for its
// entire range (0x00 to 0xFF), then send it happily. If not, only
// send chars within the range 0x20-0x7F (real ASCII)
//
if (codePage != g_poeLocalFonts[iLocal].Details.nfCodePage) { TRACE_OUT(( "Using different CP: downgrade to APPROX_ASC")); matchQuality = FH_SC_APPROX_ASCII_MATCH; }
//
// If we don't have an exact match, check the individual characters.
//
if ( (matchQuality != FH_SC_EXACT_MATCH ) && (matchQuality != FH_SC_APPROX_MATCH) ) { //
// LAURABU BOGUS!
// NT does approximate matching only if the font supports the
// ANSI charset. NM 2.0 never did this, so we won't either.
//
//
// This font is not a good match across its entire range. Check
// that all chars are within the desired range.
//
for (i = 0; i < cchText; i++) { if ( (lpszText[i] == 0) || ( (lpszText[i] >= NF_ASCII_FIRST) && (lpszText[i] <= NF_ASCII_LAST) ) ) { continue; }
//
// Can only get here by finding a char outside our acceptable
// range.
//
OTRACE(("Found non ASCII char %c", lpszText[i])); fFontSupported = FALSE; DC_QUIT; }
if (fFontSupported) { //
// We still have to check that this is ANSI text. Consider a
// string written in symbol font where all the chars in
// the string are in the range 0x20-0x7F, but none of them
// are ASCII.
//
OemToAnsiBuff(lpszText, g_oeAnsiString, cchText);
//
// BOGUS LAURABU
// This is our own inline MEMCMP to avoid pulling in the CRT.
// If any other place needs it, we should make this a function
//
for (i = 0; i < cchText; i++) { if (lpszText[i] != g_oeAnsiString[i]) { OTRACE(("Found non ANSI char %c", lpszText[i])); fFontSupported = FALSE; DC_QUIT; } } } }
//
// We have a valid font. Now sort out deltaX issues
//
if (!(g_oeFontCaps & CAPS_FONT_NEED_X_ALWAYS)) { if (!(g_oeFontCaps & CAPS_FONT_NEED_X_SOMETIMES)) { //
// CAPS_FONT_NEED_X_SOMETIMES and CAPS_FONT_NEED_X_ALWAYS are
// both not set so we can exit now. (We do not need a delta X
// array).
//
TRACE_OUT(( "Capabilities eliminated delta X")); DC_QUIT; }
//
// CAPS_FONT_NEED_X_SOMETIMES is set and CAPS_FONT_NEED_X_ALWAYS is
// not set. In this case whether we need a delta X is determined
// by whether the font is an exact match or an approximate match
// (because of either approximation of name, signature, or aspect
// ratio). We can only find this out after we have extracted the
// font handle from the existing order.
//
}
//
// If the string is a single character (or less) then we can just
// return.
//
if (cchText <= 1) { TRACE_OUT(( "String only %u long", cchText)); DC_QUIT; }
//
// Capabilities allow us to ignore delta X position if we have an exact
// match.
//
if (matchQuality & FH_SC_EXACT) { //
// Exit immediately, providing that there is no override to always
// send increments.
//
if (!(g_oeFontCaps & CAPS_FONT_NEED_X_ALWAYS)) { TRACE_OUT(( "Font has exact match")); DC_QUIT; } }
//
// We must send a deltaX array
//
*pSendDeltaX = TRUE;
DC_EXIT_POINT: DebugExitDWORD(OECheckFontIsSupported, fFontSupported); return(fFontSupported); }
//
// OEAddDeltaX()
//
// This fills in the allocated deltaX array if one is needed, either because
// the app passed one in ExtTextOut, or we need to simulate a font that
// isn't available remotely.
//
BOOL OEAddDeltaX ( LPEXTTEXTOUT_ORDER pExtTextOut, LPSTR lpszText, UINT cchText, LPINT lpdxCharSpacing, BOOL fDeltaX, POINT ptStart ) { BOOL fSuccess; LPBYTE lpVariable; LPVARIABLE_DELTAX lpDeltaPos; UINT i; int charWidth; int xLastLP; int xLastDP;
DebugEntry(OEAddDeltaX);
lpVariable = ((LPBYTE)&pExtTextOut->variableString) + sizeof(pExtTextOut->variableString.len) + cchText; lpDeltaPos = (LPVARIABLE_DELTAX)DC_ROUND_UP_4((DWORD)lpVariable);
fSuccess = FALSE;
if (SELECTOROF(lpdxCharSpacing)) { //
// We must translate the LPDX increments into device units.
// We have to do this a single point at a time to preserve
// accuracy and because the order field isn't the same size.
//
// We preserve accuracy by calculating the position of the
// point in the current coords, and converting this before
// subtracting the original point to get the delta.
// Otherwise, we'd hit rounding errors very often. 4 chars
// is the limit in TWIPs e.g.
//
lpDeltaPos->len = cchText * sizeof(TSHR_INT32);
xLastLP = ptStart.x; ptStart.y = 0; LPtoDP(g_oeState.hdc, &ptStart, 1); xLastDP = ptStart.x;
for (i = 0; i < cchText; i++) { xLastLP += lpdxCharSpacing[i];
ptStart.x = xLastLP; ptStart.y = 0; LPtoDP(g_oeState.hdc, &ptStart, 1);
lpDeltaPos->deltaX[i] = ptStart.x - xLastDP; xLastDP = ptStart.x; }
//
// Remember we have a deltax array
//
pExtTextOut->fuOptions |= ETO_LPDX; fSuccess = TRUE; } else if (fDeltaX) { //
// Simulate deltax.
//
lpDeltaPos->len = cchText * sizeof(TSHR_INT32);
//
// Is this the same font as last time? If so, we have the
// generated character width table cached.
//
// NOTE that when the capabilities chage, we clear the cache to
// avoid matching a font based on a stale index. And when starting
// to share.
//
if ((g_oeFhLast.fontIndex != pExtTextOut->common.FontIndex) || (g_oeFhLast.fontHeight != pExtTextOut->common.FontHeight) || (g_oeFhLast.fontWidth != pExtTextOut->common.FontWidth) || (g_oeFhLast.fontWeight != pExtTextOut->common.FontWeight) || (g_oeFhLast.fontFlags != pExtTextOut->common.FontFlags)) { LPLOCALFONT lpFont; HFONT hFontSim; HFONT hFontOld; TEXTMETRIC tmNew; int width; ABC abc; BYTE italic; BYTE underline; BYTE strikeout; BYTE pitch; BYTE charset; BYTE precis; TSHR_UINT32 FontFlags;
//
// Generate a new table and cache the info
//
// We can not use the ACTUAL font selected in. We must
// create a new logical font from our table info.
//
ASSERT(g_poeLocalFonts); lpFont = g_poeLocalFonts + pExtTextOut->common.FontIndex; FontFlags = pExtTextOut->common.FontFlags;
//
// What are the logical attributes of this desired font?
//
italic = (BYTE)(FontFlags & NF_ITALIC); underline = (BYTE)(FontFlags & NF_UNDERLINE); strikeout = (BYTE)(FontFlags & NF_STRIKEOUT);
if (FontFlags & NF_FIXED_PITCH) { pitch = FF_DONTCARE | FIXED_PITCH; } else { pitch = FF_DONTCARE | VARIABLE_PITCH; }
//
// Is this a TrueType font? The windows Font Mapper biases
// towards non-TrueType fonts.
//
if (FontFlags & NF_TRUE_TYPE) { pitch |= TMPF_TRUETYPE; precis = OUT_TT_ONLY_PRECIS; } else { precis = OUT_RASTER_PRECIS; }
//
// The given height is the char height, not the cell height.
// So pass it as a negative value below...
//
//
// Use the codepage (misleadingly named) to figure out the
// charset to ask for.
//
if (lpFont->Details.nfCodePage == NF_CP_WIN_ANSI) { charset = ANSI_CHARSET; } else if (lpFont->Details.nfCodePage == NF_CP_WIN_OEM) { charset = OEM_CHARSET; } else if (lpFont->Details.nfCodePage == NF_CP_WIN_SYMBOL) { charset = SYMBOL_CHARSET; } else { charset = DEFAULT_CHARSET; }
hFontSim = CreateFont(-(int)pExtTextOut->common.FontHeight, (int)pExtTextOut->common.FontWidth, 0, 0, (int)pExtTextOut->common.FontWeight, italic, underline, strikeout, charset, precis, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, pitch, (LPSTR)lpFont->Details.nfFaceName); if (!hFontSim) { ERROR_OUT(("Couldn't create simulated font for metrics")); DC_QUIT; } hFontOld = SelectFont(g_osiScreenDC, hFontSim); if (!hFontOld) { ERROR_OUT(("Couldn't select simulated font for metrics")); DeleteFont(hFontSim); DC_QUIT; }
//
// Get the character dimensions
//
GetTextMetrics(g_osiScreenDC, &tmNew);
for (i = 0; i < 256; i++) { if (tmNew.tmPitchAndFamily & TMPF_TRUETYPE) { //
// Use ABC spacing for truetype
//
GetCharABCWidths(g_osiScreenDC, i, i, &abc); width = abc.abcA + abc.abcB + abc.abcC; } else if (!(tmNew.tmPitchAndFamily & FIXED_PITCH)) { //
// Note that the name of FIXED_PITCH is not what you'd
// expect, its ABSENCE means it's fixed.
//
// In any case, for fixed pitch fonts, each char is the
// same size.
//
width = tmNew.tmAveCharWidth - tmNew.tmOverhang; } else { //
// Query the width of the char
//
GetCharWidth(g_osiScreenDC, i, i, &width); width -= tmNew.tmOverhang; }
g_oeFhLast.charWidths[i] = width; }
//
// We've successfully generated the width info for this font,
// update our cache.
//
g_oeFhLast.fontIndex = pExtTextOut->common.FontIndex; g_oeFhLast.fontHeight = pExtTextOut->common.FontHeight; g_oeFhLast.fontWidth = pExtTextOut->common.FontWidth; g_oeFhLast.fontWeight = pExtTextOut->common.FontWeight; g_oeFhLast.fontFlags = pExtTextOut->common.FontFlags;
//
// Select back in old font and delete new one
//
SelectFont(g_osiScreenDC, hFontOld); DeleteFont(hFontSim); }
//
// Now calculate the width of each character in the string.
// This includes the last char because it is needed to correctly
// define the extent of the string.
//
for (i = 0; i < cchText; i++) { //
// The width is that in the width table for the current char.
//
lpDeltaPos->deltaX[i] = g_oeFhLast.charWidths[lpszText[i]]; }
//
// Remember we have a deltax array
//
pExtTextOut->fuOptions |= ETO_LPDX; fSuccess = TRUE; } else { //
// No deltax array
//
lpDeltaPos->len = 0; fSuccess = TRUE; }
DC_EXIT_POINT: DebugExitBOOL(OEAddDeltaX, fSuccess); return(fSuccess); }
//
// OEGetStringExtent()
//
int OEGetStringExtent ( LPSTR lpszText, UINT cchText, LPINT lpdxCharSpacing, LPRECT lprcExtent ) { DWORD textExtent; UINT i; int thisX; int minX; int maxX; ABC abcSpace; int overhang = 0;
DebugEntry(OEGetStringExtent);
ASSERT(g_oeState.uFlags & OESTATE_FONT); ASSERT(g_oeState.uFlags & OESTATE_COORDS);
//
// With no characters, return a NULL rect
//
if (cchText == 0) { lprcExtent->left = 1; lprcExtent->top = 0; lprcExtent->right = 0; lprcExtent->bottom = 0; } else if (!SELECTOROF(lpdxCharSpacing)) { //
// Get the simple text extent from GDI
//
textExtent = GetTextExtent(g_oeState.hdc, lpszText, cchText);
lprcExtent->left = 0; lprcExtent->top = 0; lprcExtent->right = LOWORD(textExtent); lprcExtent->bottom = HIWORD(textExtent);
//
// We now have the the advance distance for the string. However,
// some fonts like TrueType with C widths, or Italic, may extend
// beyond this. Add in extra space here if necessary
//
if (g_oeState.tmFont.tmPitchAndFamily & TMPF_TRUETYPE) { //
// Get the A-B-C widths of the last character
//
GetCharABCWidths(g_oeState.hdc, lpszText[cchText-1], lpszText[cchText-1], &abcSpace);
//
// Add on the C width (the right side extra) of the last char
//
overhang = abcSpace.abcC; } else { //
// Use global overhang, this is an old font (like simulated Italic)
//
overhang = g_oeState.tmFont.tmOverhang; }
lprcExtent->right += overhang; } else { //
// Delta positions were given. In this case, the text extent is
// the sum of the delta values + the width of the last char
//
// Get the dimensions of the chars one by one, starting with 1st char
textExtent = GetTextExtent(g_oeState.hdc, lpszText, 1);
thisX = 0; minX = 0; maxX = LOWORD(textExtent);
for (i = 1; i < cchText; i++) { thisX += g_oeState.ptPolarity.x * lpdxCharSpacing[i-1]; textExtent = GetTextExtent(g_oeState.hdc, lpszText+i, 1);
minX = min(minX, thisX); maxX = max(maxX, thisX + (int)LOWORD(textExtent)); }
thisX += g_oeState.ptPolarity.x * lpdxCharSpacing[cchText-1]; maxX = max(maxX, thisX);
lprcExtent->left = minX; lprcExtent->top = 0; lprcExtent->right = maxX; lprcExtent->bottom = HIWORD(textExtent); }
DebugExitDWORD(OEGetStringExtent, (DWORD)(LONG)overhang); return(overhang); }
//
// DrvFillPath()
//
BOOL WINAPI DrvFillPath ( HDC hdcDst ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvFillPath);
OE_SHM_START_WRITING;
//
// The Path() apis don't set the drawing bounds. We assume the whole
// screen (device coords) instead.
//
// NOTE that NM 2.0 had a bug--it didn't account for the virtual
// screen origin when setting up the rect to accum as screen data.
// It just passed (0, 0, 32765, 32765) in.
//
fWeCare = OEBeforeDDI(DDI_FILLPATH, hdcDst, OESTATE_SDA_SCREEN);
fOutput = FillPath(hdcDst);
OEAfterDDI(DDI_FILLPATH, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvFillPath, fOutput); return(fOutput); }
//
// DrvStrokeAndFillPath()
//
BOOL WINAPI DrvStrokeAndFillPath ( HDC hdcDst ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvStrokeAndFillPath);
OE_SHM_START_WRITING;
//
// The Path() apis don't set the drawing bounds. We assume the whole
// screen (device coords) instead.
//
// NOTE that NM 2.0 had a bug--it didn't account for the virtual
// screen origin when setting up the rect to accum as screen data.
// It just passed (0, 0, 32765, 32765) in.
//
fWeCare = OEBeforeDDI(DDI_STROKEANDFILLPATH, hdcDst, OESTATE_SDA_SCREEN);
fOutput = StrokeAndFillPath(hdcDst);
OEAfterDDI(DDI_STROKEANDFILLPATH, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvStrokeAndFillPath, fOutput); return(fOutput); }
//
// DrvStrokePath()
//
BOOL WINAPI DrvStrokePath ( HDC hdcDst ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvStrokePath);
OE_SHM_START_WRITING;
//
// The Path() apis don't set the drawing bounds. We assume the whole
// screen (device coords) instead.
//
// NOTE that NM 2.0 had a bug--it didn't account for the virtual
// screen origin when setting up the rect to accum as screen data.
// It just passed (0, 0, 32765, 32765) in.
//
fWeCare = OEBeforeDDI(DDI_STROKEPATH, hdcDst, OESTATE_SDA_SCREEN);
fOutput = StrokePath(hdcDst);
OEAfterDDI(DDI_STROKEPATH, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvStrokePath, fOutput); return(fOutput); }
//
// DrvFillRgn()
//
BOOL WINAPI DrvFillRgn ( HDC hdcDst, HRGN hrgnFill, HBRUSH hbrFill ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvFillRgn);
OE_SHM_START_WRITING;
//
// We can't use Rgn apis if the map mode isn't MM_TEXT. So we use DCBs
// instead.
//
fWeCare = OEBeforeDDI(DDI_FILLRGN, hdcDst, 0);
fOutput = FillRgn(hdcDst, hrgnFill, hbrFill);
if (OEAfterDDI(DDI_FILLRGN, fWeCare, fOutput)) { //
// NOTE that OEAfterDDI() returns FALSE even if fOutput if we used
// DCBs to send as screen data. In other words, OEAfterDDI() returns
// TRUE IFF output happened into a DC we care about and it needs
// processing still.
//
OEAddRgnPaint(hrgnFill, hbrFill, g_oeState.lpdc->DrawMode.Rop2); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvFillRgn, fOutput); return(fOutput); }
//
// OETwoWayRopToThree()
// Gets the 3-way ROP equivalent of a 2-way ROP.
//
BOOL OETwoWayRopToThree ( int rop2, LPDWORD lpdwRop3 ) { BOOL fConverted = TRUE;
DebugEntry(OETwoWayRopToThree);
switch (rop2) { case R2_BLACK: *lpdwRop3 = BLACKNESS; break;
case R2_NOT: *lpdwRop3 = DSTINVERT; break;
case R2_XORPEN: *lpdwRop3 = PATINVERT; break;
case R2_COPYPEN: *lpdwRop3 = PATCOPY; break;
case R2_WHITE: *lpdwRop3 = WHITENESS; break;
default: fConverted = FALSE; break; }
DebugExitBOOL(OETwoWayRopToThree, fConverted); return(fConverted); }
//
// OEAddRgnPaint()
// This will set up a modified region (vis intersect param) and brush, and
// if possible will fake a PatBlt. If not, screen data.
//
// NOTE:
// (1) hrgnPaint is in DC coords
// (2) GetClipRgn() returns a region in screen coords
// (3) SelectClipRgn() takes a region in DC coords
//
void OEAddRgnPaint ( HRGN hrgnPaint, HBRUSH hbrPaint, UINT rop2 ) { BOOL fScreenData = TRUE; HRGN hrgnClip; HRGN hrgnNewClip; HRGN hrgnOldClip; POINT ptXlation; DWORD dwRop3;
DebugEntry(OEAddRgnPaint);
//
// Get the original visrgn.
//
OEGetState(OESTATE_COORDS | OESTATE_REGION);
//
// Get the bounding box and convert the bounding box to our coords.
//
if (GetRgnBox(hrgnPaint, &g_oeState.rc) <= NULLREGION) { // Nothing to do.
TRACE_OUT(("OEAddRgnPaint: empty region")); goto DC_EMPTY_REGION; } OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// We can't continue if we aren't MM_TEXT--clip rgn APIs only work
// in that mode. So send as screen data instead.
//
if (GetMapMode(g_oeState.hdc) != MM_TEXT) { TRACE_OUT(("OEAddRgnPaint: map mode not MM_TEXT, send as screen data")); DC_QUIT; }
//
// Save a copy of the current cliprgn
//
hrgnNewClip = CreateRectRgn(0, 0, 0, 0); if (!hrgnNewClip) DC_QUIT;
//
// Get app LP xlation factor; SelectClipRgn() expects DP units
//
ptXlation.x = 0; ptXlation.y = 0; DPtoLP(g_oeState.hdc, &ptXlation, 1);
hrgnOldClip = NULL; if (hrgnClip = GetClipRgn(g_oeState.hdc)) { hrgnOldClip = CreateRectRgn(0, 0, 0, 0); if (!hrgnOldClip) { DeleteRgn(hrgnNewClip); DC_QUIT; }
//
// This is in screen coords. Convert to DC coords
// * Subtract the DC origin
// * Get the DP-LP xlation and subtract
//
CopyRgn(hrgnOldClip, hrgnClip); OffsetRgn(hrgnOldClip, -g_oeState.ptDCOrg.x + ptXlation.x, -g_oeState.ptDCOrg.y + ptXlation.y);
//
// Intersect the current clip with the paint region (already in
// DC coords)
//
IntersectRgn(hrgnNewClip, hrgnOldClip, hrgnPaint);
//
// Convert the old LP region back to DP units to select back in
// when done.
//
OffsetRgn(hrgnOldClip, -ptXlation.x, -ptXlation.y); } else { CopyRgn(hrgnNewClip, hrgnPaint); }
//
// Convert LP paint region to DP clip region
//
OffsetRgn(hrgnNewClip, -ptXlation.x, -ptXlation.y);
//
// Select in new clip region (expected to be in device coords).
//
SelectClipRgn(g_oeState.hdc, hrgnNewClip); DeleteRgn(hrgnNewClip);
//
// Reget the RAO (intersect of vis/clip)
//
OEGetState(OESTATE_REGION);
//
// Get brush info
//
if (hbrPaint) { if (GetObject(hbrPaint, sizeof(g_oeState.logBrush), &g_oeState.logBrush)) { g_oeState.uFlags |= OESTATE_BRUSH; } else { g_oeState.logBrush.lbStyle = BS_NULL; } }
//
// Fake a patblt
//
if (OETwoWayRopToThree(rop2, &dwRop3)) { fScreenData = FALSE; OEAddBlt(dwRop3); }
//
// Select back in the previous clip rgn
//
SelectClipRgn(g_oeState.hdc, hrgnOldClip); if (hrgnOldClip) DeleteRgn(hrgnOldClip);
DC_EXIT_POINT: if (fScreenData) { OTRACE(("OEAddRgnPaint: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
DC_EMPTY_REGION: DebugExitVOID(OEAddRgnPaint); }
//
// DrvFrameRgn()
//
BOOL WINAPI DrvFrameRgn ( HDC hdcDst, HRGN hrgnFrameArea, HBRUSH hbrFramePattern, int cxFrame, int cyFrame ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvFrameRgn);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_FRAMERGN, hdcDst, 0);
fOutput = FrameRgn(hdcDst, hrgnFrameArea, hbrFramePattern, cxFrame, cyFrame);
if (OEAfterDDI(DDI_FRAMERGN, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_REGION);
if (GetRgnBox(hrgnFrameArea, &g_oeState.rc) > NULLREGION) { InflateRect(&g_oeState.rc, g_oeState.ptPolarity.x * cxFrame, g_oeState.ptPolarity.y * cyFrame); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
OTRACE(("FrameRgn: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvFrameRgn, fOutput); return(fOutput); }
//
// DrvInvertRgn()
//
BOOL WINAPI DrvInvertRgn ( HDC hdcDst, HRGN hrgnInvert ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvInvertRgn);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_INVERTRGN, hdcDst, 0);
fOutput = InvertRgn(hdcDst, hrgnInvert);
if (OEAfterDDI(DDI_INVERTRGN, fWeCare, fOutput)) { OEAddRgnPaint(hrgnInvert, NULL, R2_NOT); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvInvertRgn, fOutput); return(fOutput); }
//
// DrvPaintRgn()
//
BOOL WINAPI DrvPaintRgn ( HDC hdcDst, HRGN hrgnPaint ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPaintRgn);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PAINTRGN, hdcDst, 0);
fOutput = PaintRgn(hdcDst, hrgnPaint);
if (OEAfterDDI(DDI_PAINTRGN, fWeCare, fOutput)) { OEAddRgnPaint(hrgnPaint, g_oeState.lpdc->hBrush, g_oeState.lpdc->DrawMode.Rop2); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPaintRgn, fOutput); return(fOutput); }
//
// DrvLineTo()
//
BOOL WINAPI DrvLineTo ( HDC hdcDst, int xTo, int yTo ) { POINT ptEnd; BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvLineTo);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_LINETO, hdcDst, OESTATE_CURPOS);
fOutput = LineTo(hdcDst, xTo, yTo);
//
// OEAfterDDI returns TRUE if the DC is a screen DC and output happened
// and we aren't skipping due to reentrancy.
//
if (OEAfterDDI(DDI_LINETO, fWeCare, fOutput)) { //
// OEAddLine() will calculate extents, and if an order can't be sent,
// OEDoneDDI will add the bounds as screen data.
//
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION); ptEnd.x = xTo; ptEnd.y = yTo;
ASSERT(g_oeState.uFlags & OESTATE_CURPOS); OEAddLine(g_oeState.ptCurPos, ptEnd); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvLineTo, fOutput); return(fOutput); }
//
// DrvPolyline()
//
// NOTE:
// The differences between Polyline() and PolylineTo() are
// (1) PolylineTo moves the current position to the end coords of the
// last point; Polyline preserves the current position
// (2) Polyline uses the first point in the array as the starting coord
// of the first point; PolylineTo() uses the current position.
//
BOOL WINAPI DrvPolyline ( HDC hdcDst, LPPOINT aPoints, int cPoints ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPolyline);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYLINE, hdcDst, 0);
fOutput = Polyline(hdcDst, aPoints, cPoints);
if (OEAfterDDI(DDI_POLYLINE, fWeCare, fOutput && cPoints > 1)) { //
// GDI should NEVER return success if the aPoints parameter is
// bogus.
//
// NOTE LAURABU:
// This implementation is better than NM 2.0. That one would turn
// this GDI call actually into separate MoveTo/LineTo calls, which
// whacks out metafiles etc. Instead, we call through to the org
// Polyline, then add LineTo orders.
//
ASSERT(!IsBadReadPtr(aPoints, cPoints*sizeof(POINT)));
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION);
OEAddPolyline(aPoints[0], aPoints+1, cPoints-1); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolyline, fOutput); return(fOutput); }
//
// DrvPolylineTo()
//
BOOL WINAPI DrvPolylineTo ( HDC hdcDst, LPPOINT aPoints, int cPoints ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPolylineTo);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYLINETO, hdcDst, OESTATE_CURPOS);
fOutput = g_lpfnPolylineTo(hdcDst, aPoints, cPoints);
if (OEAfterDDI(DDI_POLYLINETO, fWeCare, fOutput && cPoints)) { //
// GDI should NEVER return success if the aPoints parameter is
// bogus.
//
// NOTE LAURABU:
// This implementation is better than NM 2.0. That one would turn
// this GDI call actually into separate LineTo calls, which whacks
// out metafiles etc. Instead, we call through to the original
// PolylineTo, then add LineTo orders.
//
ASSERT(!IsBadReadPtr(aPoints, cPoints*sizeof(POINT)));
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION); ASSERT(g_oeState.uFlags & OESTATE_CURPOS);
OEAddPolyline(g_oeState.ptCurPos, aPoints, cPoints); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolylineTo, fOutput); return(fOutput); }
//
// OEAddPolyline
// Used by Polyline(), PolylineTo(), and PolyPolyline()
//
void OEAddPolyline ( POINT ptStart, LPPOINT aPoints, UINT cPoints ) { DebugEntry(OEAddPolyline);
ASSERT(g_oeState.uFlags & OESTATE_COORDS); ASSERT(g_oeState.uFlags & OESTATE_REGION);
while (cPoints-- > 0) { OEAddLine(ptStart, *aPoints);
//
// The start point of the next line is the end point of the
// current one.
//
ptStart = *aPoints;
aPoints++; }
DebugExitVOID(OEAddPolyline); }
//
// DrvPlayEnhMetaFileRecord()
//
BOOL WINAPI DrvPlayEnhMetaFileRecord ( HDC hdcDst, LPHANDLETABLE lpEMFHandles, LPENHMETARECORD lpEMFRecord, DWORD cEMFHandles ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPlayEnhMetaFileRecord);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PLAYENHMETAFILERECORD, hdcDst, OESTATE_SDA_DCB);
fOutput = PlayEnhMetaFileRecord(hdcDst, lpEMFHandles, lpEMFRecord, cEMFHandles);
OEAfterDDI(DDI_PLAYENHMETAFILERECORD, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPlayEnhMetaFileRecord, fOutput); return(fOutput); }
//
// DrvPlayMetaFile()
//
BOOL WINAPI DrvPlayMetaFile ( HDC hdcDst, HMETAFILE hmf ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPlayMetaFile);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PLAYMETAFILE, hdcDst, OESTATE_SDA_DCB); fOutput = PlayMetaFile(hdcDst, hmf);
OEAfterDDI(DDI_PLAYMETAFILE, fWeCare, fOutput);
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPlayMetaFile, fOutput); return(fOutput); }
//
// DrvPlayMetaFileRecord()
//
void WINAPI DrvPlayMetaFileRecord ( HDC hdcDst, LPHANDLETABLE lpMFHandles, LPMETARECORD lpMFRecord, UINT cMFHandles ) { BOOL fWeCare;
DebugEntry(DrvPlayMetaFileRecord);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_PLAYMETAFILERECORD, hdcDst, OESTATE_SDA_DCB);
PlayMetaFileRecord(hdcDst, lpMFHandles, lpMFRecord, cMFHandles);
OEAfterDDI(DDI_PLAYMETAFILERECORD, fWeCare, TRUE);
OE_SHM_STOP_WRITING;
DebugExitVOID(DrvPlayMetaFileRecord); }
//
// DrvPolyBezier()
//
BOOL WINAPI DrvPolyBezier ( HDC hdcDst, LPPOINT aPoints, UINT cPoints ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPolyBezier);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYBEZIER, hdcDst, 0);
fOutput = PolyBezier(hdcDst, aPoints, cPoints);
if (OEAfterDDI(DDI_POLYBEZIER, fWeCare, fOutput && (cPoints > 1))) { ASSERT(!IsBadReadPtr(aPoints, cPoints*sizeof(POINT)));
OEAddPolyBezier(aPoints[0], aPoints+1, cPoints-1); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolyBezier, fOutput); return(fOutput); }
//
// DrvPolyBezierTo()
//
BOOL WINAPI DrvPolyBezierTo ( HDC hdcDst, LPPOINT aPoints, UINT cPoints ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvPolyBezierTo);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYBEZIERTO, hdcDst, OESTATE_CURPOS);
fOutput = PolyBezierTo(hdcDst, aPoints, cPoints);
if (OEAfterDDI(DDI_POLYBEZIERTO, fWeCare, fOutput && cPoints)) { ASSERT(!IsBadReadPtr(aPoints, cPoints*sizeof(POINT))); ASSERT(g_oeState.uFlags & OESTATE_CURPOS);
OEAddPolyBezier(g_oeState.ptCurPos, aPoints, cPoints); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolyBezierTo, fOutput); return(fOutput); }
//
// OEAddPolyBezier()
//
// Adds poly bezier order for both PolyBezier() and PolyBezierTo().
//
void OEAddPolyBezier ( POINT ptStart, LPPOINT aPoints, UINT cPoints ) { UINT iPoint; LPINT_ORDER pOrder; LPPOLYBEZIER_ORDER pPolyBezier;
DebugEntry(OEAddPolyBezier);
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION);
//
// Calculate the bounds
//
g_oeState.rc.left = ptStart.x; g_oeState.rc.top = ptStart.y; g_oeState.rc.right = ptStart.x; g_oeState.rc.bottom = ptStart.y;
for (iPoint = 0; iPoint < cPoints; iPoint++) { g_oeState.rc.left = min(g_oeState.rc.left, aPoints[iPoint].x); g_oeState.rc.right = max(g_oeState.rc.right, aPoints[iPoint].x); g_oeState.rc.top = min(g_oeState.rc.top, aPoints[iPoint].y); g_oeState.rc.bottom = max(g_oeState.rc.bottom, aPoints[iPoint].y); }
OEPolarityAdjust(&g_oeState.rc, 1); OEPenWidthAdjust(&g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// OELRtoVirtual takes an exclusive rect and returns an inclusive one.
// But we passed it an inclusive already rect, so we need to account
// for that.
//
g_oeState.rc.right++; g_oeState.rc.bottom++;
pOrder = NULL;
// Account for starting point also
if (OECheckOrder(ORD_POLYBEZIER, OECHECK_PEN | OECHECK_CLIPPING) && (cPoints < ORD_MAX_POLYBEZIER_POINTS)) { pOrder = OA_DDAllocOrderMem(sizeof(POLYBEZIER_ORDER) - ((ORD_MAX_POLYBEZIER_POINTS - cPoints - 1) * sizeof(pPolyBezier->variablePoints.aPoints[0])), 0); if (!pOrder) DC_QUIT;
pPolyBezier = (LPPOLYBEZIER_ORDER)pOrder->abOrderData; pPolyBezier->type = LOWORD(ORD_POLYBEZIER);
//
// Copy them into the order array
//
pPolyBezier->variablePoints.len = ((cPoints+1) * sizeof(pPolyBezier->variablePoints.aPoints[0]));
pPolyBezier->variablePoints.aPoints[0].x = ptStart.x; pPolyBezier->variablePoints.aPoints[0].y = ptStart.y; hmemcpy(pPolyBezier->variablePoints.aPoints+1, aPoints, cPoints*sizeof(pPolyBezier->variablePoints.aPoints[0]));
//
// Convert points to virtual
//
// NOTE that this works because aPoints[] holds TSHR_POINT16s, which
// are natively the same size as POINT structures.
//
OELPtoVirtual(g_oeState.hdc, (LPPOINT)pPolyBezier->variablePoints.aPoints, cPoints+1);
OEConvertColor(g_oeState.lpdc->DrawMode.bkColorL, &pPolyBezier->BackColor, FALSE); OEConvertColor(g_oeState.lpdc->DrawMode.txColorL, &pPolyBezier->ForeColor, FALSE); pPolyBezier->BackMode = g_oeState.lpdc->DrawMode.bkMode; pPolyBezier->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pPolyBezier->PenStyle = g_oeState.logPen.lopnStyle; pPolyBezier->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pPolyBezier->PenColor, FALSE);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
OTRACE(("PolyBezier: Order %08lx, Rect {%d, %d, %d, %d} with %d points", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, cPoints+1)); OEClipAndAddOrder(pOrder, NULL); }
DC_EXIT_POINT: if (!pOrder) { OTRACE(("PolyBezier: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
DebugExitVOID(OEAddPolyBezier); }
//
// DrvPolygon()
//
BOOL WINAPI DrvPolygon ( HDC hdcDst, LPPOINT aPoints, int cPoints ) { BOOL fWeCare; BOOL fOutput; LPINT_ORDER pOrder; LPPOLYGON_ORDER pPolygon; int iPoint; POINT ptBrushOrg;
DebugEntry(DrvPolygon);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYGON, hdcDst, 0);
fOutput = Polygon(hdcDst, aPoints, cPoints);
if (OEAfterDDI(DDI_POLYGON, fWeCare, fOutput && (cPoints > 1))) { ASSERT(!IsBadReadPtr(aPoints, cPoints*sizeof(POINT)));
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
//
// Compute the bounds
//
g_oeState.rc.left = aPoints[0].x; g_oeState.rc.top = aPoints[0].y; g_oeState.rc.right = aPoints[0].x; g_oeState.rc.bottom = aPoints[0].y;
for (iPoint = 1; iPoint < cPoints; iPoint++) { g_oeState.rc.left = min(g_oeState.rc.left, aPoints[iPoint].x); g_oeState.rc.top = min(g_oeState.rc.top, aPoints[iPoint].y); g_oeState.rc.right = max(g_oeState.rc.right, aPoints[iPoint].x); g_oeState.rc.bottom = max(g_oeState.rc.bottom, aPoints[iPoint].y); }
OEPolarityAdjust(&g_oeState.rc, 1); OEPenWidthAdjust(&g_oeState.rc, 1);
//
// The rect is in inclusive coords already, OELRtoVirtual thinks
// it's exclusive. So we need to add one back on to the right
// and bottom to end up with the real inclusive rect.
//
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1); g_oeState.rc.right++; g_oeState.rc.bottom++;
pOrder = NULL;
if (OECheckOrder(ORD_POLYGON, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING) && (cPoints <= ORD_MAX_POLYGON_POINTS)) { pOrder = OA_DDAllocOrderMem(sizeof(POLYGON_ORDER) - ((ORD_MAX_POLYGON_POINTS - cPoints) * sizeof(pPolygon->variablePoints.aPoints[0])), 0); if (!pOrder) goto NoPolygonOrder;
pPolygon = (LPPOLYGON_ORDER)pOrder->abOrderData; pPolygon->type = LOWORD(ORD_POLYGON);
pPolygon->variablePoints.len = cPoints * sizeof(pPolygon->variablePoints.aPoints[0]); hmemcpy(pPolygon->variablePoints.aPoints, aPoints, pPolygon->variablePoints.len);
//
// Convert all the points to virtual
//
// NOTE that this works because aPoints[] hols TSHR_POINT16s,
// which are natively the same size as POINT structures.
//
OELPtoVirtual(g_oeState.hdc, (LPPOINT)pPolygon->variablePoints.aPoints, cPoints);
OEGetBrushInfo(&pPolygon->BackColor, &pPolygon->ForeColor, &pPolygon->BrushStyle, &pPolygon->BrushHatch, pPolygon->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pPolygon->BrushOrgX = (BYTE)ptBrushOrg.x; pPolygon->BrushOrgY = (BYTE)ptBrushOrg.y;
pPolygon->BackMode = g_oeState.lpdc->DrawMode.bkMode; pPolygon->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
//
// Pen info
//
pPolygon->PenStyle = g_oeState.logPen.lopnStyle; pPolygon->PenWidth = 1; OEConvertColor(g_oeState.logPen.lopnColor, &pPolygon->PenColor, FALSE); pPolygon->FillMode = GetPolyFillMode(g_oeState.hdc);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE; OTRACE(("Polygon: Order %08lx, Rect {%d, %d, %d, %d} with %d points", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom, cPoints)); OEClipAndAddOrder(pOrder, NULL);
}
NoPolygonOrder: if (!pOrder) { OTRACE(("Polygon: Sending %d points as screen data {%d, %d, %d, %d}", cPoints, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolygon, fOutput); return(fOutput); }
//
// DrvPolyPolygon()
//
BOOL WINAPI DrvPolyPolygon ( HDC hdcDst, LPPOINT aPoints, LPINT aPolygonPoints, int cPolygons ) { BOOL fWeCare; BOOL fOutput; int iPolygon; int iPoint;
DebugEntry(DrvPolyPolygon);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_POLYPOLYGON, hdcDst, 0);
fOutput = PolyPolygon(hdcDst, aPoints, aPolygonPoints, cPolygons);
if (OEAfterDDI(DDI_POLYPOLYGON, fWeCare, fOutput && cPolygons)) { ASSERT(!IsBadReadPtr(aPolygonPoints, cPolygons*sizeof(int)));
#ifdef DEBUG
//
// How many points total are there?
//
iPoint = 0; for (iPolygon = 0; iPolygon < cPolygons; iPolygon++) { iPoint += aPolygonPoints[iPolygon]; }
ASSERT(!IsBadReadPtr(aPoints, iPoint*sizeof(POINT))); #endif
//
// Like LineTo, we need to juggle the coords for polarity.
//
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION);
for (iPolygon = 0; iPolygon < cPolygons; iPolygon++, aPolygonPoints++) { //
// No points for this polygon, nothing to do.
//
if (*aPolygonPoints < 2) { aPoints += *aPolygonPoints; continue; }
g_oeState.rc.left = aPoints[0].x; g_oeState.rc.top = aPoints[0].y; g_oeState.rc.right = aPoints[0].x; g_oeState.rc.bottom = aPoints[0].y;
aPoints++;
for (iPoint = 1; iPoint < *aPolygonPoints; iPoint++, aPoints++) { g_oeState.rc.left = min(g_oeState.rc.left, aPoints[0].x); g_oeState.rc.top = min(g_oeState.rc.top, aPoints[0].y); g_oeState.rc.right = max(g_oeState.rc.right, aPoints[0].x); g_oeState.rc.bottom = max(g_oeState.rc.bottom, aPoints[0].y); }
OEPolarityAdjust(&g_oeState.rc, 1); OEPenWidthAdjust(&g_oeState.rc, 1);
//
// Our rectangle is already inclusive, and OELRtoVirtual() will
// treat it like it's exclusive. So after we return add one back
// to the right & bottom to end up with the real inclusive
// rectangle.
//
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1); g_oeState.rc.right++; g_oeState.rc.bottom++;
OTRACE(("PolyPolygon: Sending piece %d as screen data {%d, %d, %d, %d}", iPolygon, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolyPolygon, fOutput); return(fOutput); }
//
// PolyPolyline()
//
BOOL WINAPI DrvPolyPolyline ( DWORD cPtTotal, HDC hdcDst, LPPOINT aPoints, LPINT acPolylinePoints, int cPolylines ) { BOOL fWeCare; BOOL fOutput; UINT cPoints;
DebugEntry(DrvPolyPolyline);
OE_SHM_START_WRITING;
//
// LAURABU NOTE:
// This code is better than 2.0. 2.0 would simulate the actual GDI
// call by repeated Polyline calls. We accumulate orders the same way
// that would have happened, but let GDI do the drawing, which is much
// more metafile friendly, among other things.
//
fWeCare = OEBeforeDDI(DDI_POLYPOLYLINE, hdcDst, 0);
fOutput = g_lpfnPolyPolyline(cPtTotal, hdcDst, aPoints, acPolylinePoints, cPolylines);
if (OEAfterDDI(DDI_POLYPOLYLINE, fWeCare, fOutput && cPolylines)) { ASSERT(!IsBadReadPtr(acPolylinePoints, cPolylines*sizeof(int))); ASSERT(!IsBadReadPtr(aPoints, (UINT)cPtTotal*sizeof(POINT)));
OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_REGION);
while (cPolylines-- > 0) { cPoints = *(acPolylinePoints++);
if (cPoints > 1) { OEAddPolyline(aPoints[0], aPoints+1, cPoints-1); }
aPoints += cPoints; } }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvPolyPolyline, fOutput); return(fOutput); }
//
// DrvRectangle()
//
BOOL WINAPI DrvRectangle ( HDC hdcDst, int xLeft, int yTop, int xRight, int yBottom ) { BOOL fWeCare; BOOL fOutput; RECT rcAdjusted; LPINT_ORDER pOrder; LPRECTANGLE_ORDER pRectangle; POINT ptBrushOrg; LPRECT pRect; int sideWidth;
DebugEntry(DrvRectangle);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_RECTANGLE, hdcDst, 0);
fOutput = Rectangle(hdcDst, xLeft, yTop, xRight, yBottom);
if (OEAfterDDI(DDI_RECTANGLE, fWeCare, fOutput && (xLeft != xRight) && (yTop != yBottom))) { OEGetState(OESTATE_COORDS | OESTATE_PEN | OESTATE_BRUSH | OESTATE_REGION);
g_oeState.rc.left = xLeft; g_oeState.rc.top = yTop; g_oeState.rc.right = xRight; g_oeState.rc.bottom = yBottom;
CopyRect(&rcAdjusted, &g_oeState.rc);
if ((g_oeState.logPen.lopnStyle == PS_SOLID) || (g_oeState.logPen.lopnStyle == PS_INSIDEFRAME)) { OEPenWidthAdjust(&rcAdjusted, 2); }
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1); OELRtoVirtual(g_oeState.hdc, &rcAdjusted, 1);
rcAdjusted.right--; rcAdjusted.bottom--;
pOrder = NULL;
if (OECheckOrder(ORD_RECTANGLE, OECHECK_PEN | OECHECK_BRUSH | OECHECK_CLIPPING)) { pOrder = OA_DDAllocOrderMem(sizeof(RECTANGLE_ORDER), 0); if (!pOrder) goto NoRectOrder;
pRectangle = (LPRECTANGLE_ORDER)pOrder->abOrderData; pRectangle->type = LOWORD(ORD_RECTANGLE);
pRectangle->nLeftRect = g_oeState.rc.left; pRectangle->nTopRect = g_oeState.rc.top; pRectangle->nRightRect = g_oeState.rc.right; pRectangle->nBottomRect = g_oeState.rc.bottom;
OEGetBrushInfo(&pRectangle->BackColor, &pRectangle->ForeColor, &pRectangle->BrushStyle, &pRectangle->BrushHatch, pRectangle->BrushExtra);
GetBrushOrgEx(g_oeState.hdc, &ptBrushOrg); pRectangle->BrushOrgX = (BYTE)ptBrushOrg.x; pRectangle->BrushOrgY = (BYTE)ptBrushOrg.y;
pRectangle->BackMode = g_oeState.lpdc->DrawMode.bkMode; pRectangle->ROP2 = g_oeState.lpdc->DrawMode.Rop2;
pRectangle->PenStyle = g_oeState.logPen.lopnStyle; pRectangle->PenWidth = 1;
OEConvertColor(g_oeState.logPen.lopnColor, &pRectangle->PenColor, FALSE);
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE; if ((g_oeState.logBrush.lbStyle == BS_SOLID) || ((pRectangle->BackMode == OPAQUE) && (g_oeState.logBrush.lbStyle != BS_NULL))) { pOrder->OrderHeader.Common.fOrderFlags |= OF_SPOILER; }
//
// Since we only encode orders of width 1, the bounding rect
// stuff is simple.
//
OTRACE(("Rectangle: Order %08lx, pOrder, Rect {%d, %d, %d, %d}", pOrder, g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddOrder(pOrder, NULL); } NoRectOrder: if (!pOrder) { //
// This is more complicated. We accumulate screen data for
// pens of different sizes.
//
//
// If the interior is drawn, then we need to send all the screen
// area enclosed by the rect. Otherwise, we can just send the
// four rectangles describing the border.
//
if (g_oeState.logBrush.lbStyle == BS_NULL) { pRect = NULL;
//
// Use the pen width to determine the width of each rect
// to add as screen data
//
switch (g_oeState.logPen.lopnStyle) { case PS_NULL: // Nothing to do.
break;
case PS_SOLID: //
// The difference between the adjusted and normal
// rects is half the pen width, so double this up
// to get the width of each piece to send.
//
pRect = &rcAdjusted; sideWidth = 2*(g_oeState.rc.left - rcAdjusted.left) - 1; break;
case PS_INSIDEFRAME: //
// The pen is contained entirely within the corner
// pts passed to this function.
//
pRect = &g_oeState.rc; sideWidth = 2*(g_oeState.rc.left - rcAdjusted.left) - 1; break;
default: //
// All other pens have width of 1 and are inside the
// frame.
//
pRect = &g_oeState.rc; sideWidth = 0; break; }
if (pRect) { RECT rcT;
//
// Left
//
CopyRect(&rcT, pRect); rcT.right = rcT.left + sideWidth; rcT.bottom -= sideWidth + 1;
OTRACE(("Rectangle left: Sending screen data {%d, %d, %d, %d}", rcT.left, rcT.top, rcT.right, rcT.bottom)); OEClipAndAddScreenData(&rcT);
//
// Top
//
CopyRect(&rcT, pRect); rcT.left += sideWidth + 1; rcT.bottom = rcT.top + sideWidth;
OTRACE(("Rectangle top: Sending screen data {%d, %d, %d, %d}", rcT.left, rcT.top, rcT.right, rcT.bottom)); OEClipAndAddScreenData(&rcT);
//
// Right
//
CopyRect(&rcT, pRect); rcT.left = rcT.right - sideWidth; rcT.top += sideWidth + 1;
OTRACE(("Rectangle right: Sending screen data {%d, %d, %d, %d}", rcT.left, rcT.top, rcT.right, rcT.bottom)); OEClipAndAddScreenData(&rcT);
//
// Bottom
//
CopyRect(&rcT, pRect); rcT.right -= sideWidth + 1; rcT.top = rcT.bottom - sideWidth;
OTRACE(("Rectangle bottom: Sending screen data {%d, %d, %d, %d}", rcT.left, rcT.top, rcT.right, rcT.bottom)); OEClipAndAddScreenData(&rcT); } } else { if (g_oeState.logPen.lopnStyle == PS_SOLID) pRect = &rcAdjusted; else pRect = &g_oeState.rc;
OTRACE(("Rectangle: Sending as screen data {%d, %d, %d, %d}", pRect->left, pRect->top, pRect->right, pRect->bottom)); OEClipAndAddScreenData(pRect); } }
}
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvRectangle, fOutput); return(fOutput); }
//
// DrvSetDIBitsToDevice()
//
int WINAPI DrvSetDIBitsToDevice ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT fuColorUse ) { BOOL fWeCare; BOOL fOutput;
DebugEntry(DrvSetDIBitsToDevice);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_SETDIBITSTODEVICE, hdcDst, 0);
fOutput = SetDIBitsToDevice(hdcDst, xDst, yDst, cxDst, cyDst, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse);
if (OEAfterDDI(DDI_SETDIBITSTODEVICE, fWeCare, fOutput)) { OEGetState(OESTATE_COORDS | OESTATE_REGION);
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; OELPtoVirtual(g_oeState.hdc, (LPPOINT)&g_oeState.rc.left, 1); g_oeState.rc.right = g_oeState.rc.left + cxDst; g_oeState.rc.bottom = g_oeState.rc.top + cyDst;
OTRACE(("SetDIBitsToDevice: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvSetDIBitsToDevice, fOutput); return(fOutput); }
//
// DrvSetPixel()
//
COLORREF WINAPI DrvSetPixel ( HDC hdcDst, int xDst, int yDst, COLORREF crPixel ) { BOOL fWeCare; COLORREF rgbOld;
DebugEntry(DrvSetPixel);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_SETPIXEL, hdcDst, 0);
rgbOld = SetPixel(hdcDst, xDst, yDst, crPixel); if (OEAfterDDI(DDI_SETPIXEL, fWeCare, (rgbOld != (COLORREF)-1))) { OEGetState(OESTATE_COORDS | OESTATE_REGION);
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst; g_oeState.rc.bottom = yDst; OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
g_oeState.rc.right++; g_oeState.rc.bottom++;
OTRACE(("SetPixel: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
OE_SHM_STOP_WRITING;
DebugExitDWORD(DrvSetPxel, rgbOld); return(rgbOld); }
//
// DrvStretchDIBits()
//
int WINAPI DrvStretchDIBits ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, int xSrc, int ySrc, int cxSrc, int cySrc, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT fuColorUse, DWORD dwRop ) { BOOL fWeCare; BOOL fOutput; BYTE bRop;
DebugEntry(DrvStretchDIBits);
OE_SHM_START_WRITING;
fWeCare = OEBeforeDDI(DDI_STRETCHDIBITS, hdcDst, 0);
fOutput = StretchDIBits(hdcDst, xDst, yDst, cxDst, cyDst, xSrc, ySrc, cxSrc, cySrc, lpvBits, lpbmi, fuColorUse, dwRop);
if (OEAfterDDI(DDI_STRETCHDIBITS, fWeCare, fOutput && cxDst && cyDst)) { OEGetState(OESTATE_COORDS | OESTATE_BRUSH | OESTATE_REGION);
g_oeState.rc.left = xDst; g_oeState.rc.top = yDst; g_oeState.rc.right = xDst + cxDst; g_oeState.rc.bottom = yDst + cyDst;
OELRtoVirtual(g_oeState.hdc, &g_oeState.rc, 1);
//
// If this is a PatBlt really, do that instead.
//
bRop = LOBYTE(HIWORD(dwRop)); if (((bRop & 0x33) << 2) == (bRop & 0xCC)) { OEAddBlt(dwRop); DC_QUIT; }
//
// Do tile bitblt order stuff...
//
OTRACE(("StretchDIBits: Sending as screen data {%d, %d, %d, %d}", g_oeState.rc.left, g_oeState.rc.top, g_oeState.rc.right, g_oeState.rc.bottom)); OEClipAndAddScreenData(&g_oeState.rc); }
DC_EXIT_POINT: OE_SHM_STOP_WRITING;
DebugExitBOOL(DrvStretchDIBits, fOutput); return(fOutput); }
//
// DrvUpdateColors()
//
int WINAPI DrvUpdateColors ( HDC hdcDst ) { BOOL fWeCare; int ret;
DebugEntry(DrvUpdateColors);
OE_SHM_START_WRITING;
//
// This doesn't reset the drawing bounds. So we just assume the whole
// DC changed. And the return value is meaningless. We can't assume
// that zero means failure.
//
fWeCare = OEBeforeDDI(DDI_UPDATECOLORS, hdcDst, OESTATE_SDA_SCREEN);
ret = UpdateColors(hdcDst);
OEAfterDDI(DDI_UPDATECOLORS, fWeCare, TRUE);
OE_SHM_STOP_WRITING;
DebugExitDWORD(DrvUpdateColors, (DWORD)(UINT)ret); return(ret); }
//
// SETTINGS/MODE FUNCTIONS
// For full screen dos boxes, resolution/color depth changes
//
//
// DrvGDIRealizePalette()
//
// The WM_PALETTE* messages in Win95 are unreliable. So, like NM 2.0, we
// patch two GDI APIs instead and update a shared variable
//
DWORD WINAPI DrvGDIRealizePalette(HDC hdc) { DWORD dwRet;
DebugEntry(DrvGDIRealizePalette);
EnableFnPatch(&g_oeDDPatches[DDI_GDIREALIZEPALETTE], PATCH_DISABLE); dwRet = GDIRealizePalette(hdc); EnableFnPatch(&g_oeDDPatches[DDI_GDIREALIZEPALETTE], PATCH_ENABLE);
ASSERT(g_asSharedMemory); g_asSharedMemory->pmPaletteChanged = TRUE;
DebugExitDWORD(DrvGDIRealizePalette, dwRet); return(dwRet); }
//
// DrvRealizeDefaultPalette()
//
// The WM_PALETTE* messages in Win95 are unreliable. So, like NM 2.0, we
// patch two GDI APIs instead and update a shared variable
//
void WINAPI DrvRealizeDefaultPalette(HDC hdc) { DebugEntry(DrvRealizeDefaultPalette);
EnableFnPatch(&g_oeDDPatches[DDI_REALIZEDEFAULTPALETTE], PATCH_DISABLE); RealizeDefaultPalette(hdc); EnableFnPatch(&g_oeDDPatches[DDI_REALIZEDEFAULTPALETTE], PATCH_ENABLE);
ASSERT(g_asSharedMemory); g_asSharedMemory->pmPaletteChanged = TRUE;
DebugExitVOID(DrvRealizeDefaultPalette); }
//
// This is called when a blue screen fault is coming up, or an app calls
// Disable() in USER.
//
UINT WINAPI DrvDeath ( HDC hdc ) { UINT uResult;
g_asSharedMemory->fullScreen = TRUE;
EnableFnPatch(&g_oeDDPatches[DDI_DEATH], PATCH_DISABLE); uResult = Death(hdc); EnableFnPatch(&g_oeDDPatches[DDI_DEATH], PATCH_ENABLE);
return(uResult); }
//
// This is called when a blue screen fault is going away, or an app calls
// Enable() in USER.
//
UINT WINAPI DrvResurrection ( HDC hdc, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { UINT uResult;
g_asSharedMemory->fullScreen = FALSE;
EnableFnPatch(&g_oeDDPatches[DDI_RESURRECTION], PATCH_DISABLE); uResult = Resurrection(hdc, dwParam1, dwParam2, dwParam3); EnableFnPatch(&g_oeDDPatches[DDI_RESURRECTION], PATCH_ENABLE);
return(uResult); }
//
// This is called by a dosbox when going to or coming out of full screen
// mode. DirectX calls it also.
//
LONG WINAPI DrvWinOldAppHackoMatic ( LONG lFlags ) { LONG lResult;
if (lFlags == WOAHACK_LOSINGDISPLAYFOCUS) { //
// DOS box is going to full screen from windowed
//
g_asSharedMemory->fullScreen = TRUE; } else if (lFlags == WOAHACK_GAININGDISPLAYFOCUS) { //
// DOS box is going from windowed to full screen
//
g_asSharedMemory->fullScreen = FALSE; }
EnableFnPatch(&g_oeDDPatches[DDI_WINOLDAPPHACKOMATIC], PATCH_DISABLE); lResult = WinOldAppHackoMatic(lFlags); EnableFnPatch(&g_oeDDPatches[DDI_WINOLDAPPHACKOMATIC], PATCH_ENABLE);
return(lResult); }
//
// ChangeDisplaySettings() WIN95
// ChangeDisplaySettingsEx() MEMPHIS
//
// This is called in 3 circumstances:
// * By the control to change your screen
// * By the shell when warm-docking
// * By 3rd party games to change the settings silently.
//
// Easiest thing to do is just to fail this completely.
//
LONG WINAPI DrvChangeDisplaySettings ( LPDEVMODE lpDevMode, DWORD flags ) { return(DISP_CHANGE_FAILED); }
LONG WINAPI DrvChangeDisplaySettingsEx ( LPCSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD flags, LPVOID lParam ) { return(DISP_CHANGE_FAILED); }
//
// OBJECT FUNCTIONS
// For bitmaps (SPBs and cache) and brushes
//
//
// DrvCreateSpb()
//
// This watches for SPB bitmaps being created.
//
UINT WINAPI DrvCreateSpb ( HDC hdcCompat, int cxWidth, int cyHeight ) { HBITMAP hbmpRet;
DebugEntry(DrvCreateSpb);
EnableFnPatch(&g_oeDDPatches[DDI_CREATESPB], PATCH_DISABLE); hbmpRet = (HBITMAP)CreateSpb(hdcCompat, cxWidth, cyHeight); EnableFnPatch(&g_oeDDPatches[DDI_CREATESPB], PATCH_ENABLE);
if (hbmpRet) { //
// Save in our "next SPB" bitmap list
//
g_ssiLastSpbBitmap = hbmpRet; }
DebugExitDWORD(DrvCreateSpb, (DWORD)(UINT)hbmpRet); return((UINT)hbmpRet); }
//
// DrvDeleteObject()
//
// This and DrvSysDeleteObject() watch for bitmaps being destroyed.
//
BOOL WINAPI DrvDeleteObject ( HGDIOBJ hobj ) { BOOL fReturn; int gdiType;
DebugEntry(DrvDeleteObject);
gdiType = IsGDIObject(hobj); if (gdiType == GDIOBJ_BITMAP) { OE_SHM_START_WRITING;
//
// If SPB, toss it. Else if cached bitmap, kill cache entry.
//
if ((HBITMAP)hobj == g_ssiLastSpbBitmap) { g_ssiLastSpbBitmap = NULL; } else if (!SSIDiscardBits((HBITMAP)hobj)) { }
OE_SHM_STOP_WRITING; }
EnableFnPatch(&g_oeDDPatches[DDI_DELETEOBJECT], PATCH_DISABLE); fReturn = DeleteObject(hobj); EnableFnPatch(&g_oeDDPatches[DDI_DELETEOBJECT], PATCH_ENABLE);
DebugExitBOOL(DrvDeleteObject, fReturn); return(fReturn); }
//
// OE_RectIntersectsSDA()
//
// Used by SSI and BLT orders
//
BOOL OE_RectIntersectsSDA(LPRECT pRect) { RECT rectVD; BOOL fIntersection = FALSE; UINT i;
DebugEntry(OE_RectIntersectsSDA);
//
// Copy the supplied rectangle, converting to inclusive Virtual
// Desktop coords.
//
rectVD.left = pRect->left; rectVD.top = pRect->top; rectVD.right = pRect->right - 1; rectVD.bottom = pRect->bottom - 1;
//
// Loop through each of the bounding rectangles checking for
// an intersection with the supplied rectangle.
//
for (i = 0; i <= BA_NUM_RECTS; i++) { if ( (g_baBounds[i].InUse) && (g_baBounds[i].Coord.left <= rectVD.right) && (g_baBounds[i].Coord.top <= rectVD.bottom) && (g_baBounds[i].Coord.right >= rectVD.left) && (g_baBounds[i].Coord.bottom >= rectVD.top) ) { OTRACE(("Rect {%d, %d, %d, %d} intersects SDA {%d, %d, %d, %d}", rectVD.left, rectVD.top, rectVD.right, rectVD.bottom, g_baBounds[i].Coord.left, g_baBounds[i].Coord.top, g_baBounds[i].Coord.right, g_baBounds[i].Coord.bottom)); fIntersection = TRUE; break; } }
DebugExitBOOL(OE_RectIntersectsSDA, fIntersection); return(fIntersection); }
//
// MyStrcmp()
// Real strcmp() algorithm.
//
int MyStrcmp(LPCSTR lp1, LPCSTR lp2) { ASSERT(lp1); ASSERT(lp2);
while (*lp1 == *lp2) { //
// The two strings are identical
//
if (!*lp1) return(0);
lp1++; lp2++; }
//
// String1 is numerically > String2, or <
//
return((*lp1 > *lp2) ? 1 : -1); }
|