windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/as/dd/oe.c
2020-09-26 16:20:57 +08:00

5842 lines
167 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
//
// OE.C
// Order Encoder, display driver side
//
// Copyright(c) Microsoft 1997-
//
//
// Number of entries in the font alias table.
//
#define NUM_ALIAS_FONTS 3
//
// 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...
//
//
FONT_ALIAS_TABLE fontAliasTable[NUM_ALIAS_FONTS] =
{
{ "Helv", "MS Sans Serif", 0 },
{ "MS Dialog", "MS Sans Serif", 1 },
{ "MS Dialog Light", "MS Sans Serif", 0 }
};
//
// FUNCTION: OE_SendAsOrder see oe.h
//
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 %hu", order, HIWORD(order)));
}
DebugExitDWORD(OE_SendAsOrder, rc);
return(rc);
}
//
// OE_RectIntersectsSDA - see oe.h
//
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) )
{
TRACE_OUT(("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;
}
}
DebugExitDWORD(OE_RectIntersectsSDA, fIntersection);
return(fIntersection);
}
//
// DrvBitBlt - see NT DDK documentation.
//
BOOL DrvBitBlt( SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMask,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4 )
{
LPOSI_PDEV ppdev = (LPOSI_PDEV)psoDst->dhpdev;
BOOL rc = TRUE;
UINT orderType = 0;
BYTE rop3;
LPINT_ORDER pOrder = NULL;
LPDSTBLT_ORDER pDstBlt;
LPSCRBLT_ORDER pScrBlt;
LPMEMBLT_ORDER pMemBlt;
LPMEM3BLT_ORDER pMem3Blt;
BOOL fSendOrder = FALSE;
BOOL fAccumulate = FALSE;
UINT fOrderFlags = OF_SPOILABLE;
RECT bounds;
RECT intersectRect;
POINT origin;
POE_BRUSH_DATA pCurrentBrush;
MEMBLT_ORDER_EXTRA_INFO memBltExtraInfo;
DebugEntry(DrvBitBlt);
//
// DO THIS _BEFORE_ TAKING LOCKS
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get the bounding rectangle for the operation.
//
RECT_FROM_RECTL(bounds, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &bounds);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert the data to virtual coordinates.
//
OELRtoVirtual(&bounds, 1);
//
// Check if this 4-way ROP simplifies to a 3-way ROP. A 4-way ROP
// contains two 3-way ROPS, one for each setting of a mask bit - the
// high ROP3 corresponds to a value of zero in the mask bit.
//
// If the two 3-way ROPs are the same, we know the 4-way ROP is a 3-way
// ROP.
//
if (ROP3_LOW_FROM_ROP4(rop4) == ROP3_HIGH_FROM_ROP4(rop4))
{
//
// Take the high byte as the 3-way ROP.
//
rop3 = ROP3_HIGH_FROM_ROP4(rop4);
TRACE_OUT(( "4-way ROP %04x is really 3-way %02x", rop4, rop3));
}
else
{
TRACE_OUT(( "4-way ROP %08x", rop4));
DC_QUIT;
}
//
// Determine the command type. It can be one of the following.
//
// DSTBLT - A destination only BLT (no source, or pattern)
// PATBLT - a pattern BLT (no source)
// SCRBLT - a screen to screen BLT
// MEMBLT - a memory to screen BLT (no pattern)
// MEM3BLT - a memory to screen 3-way BLT
//
//
// Check for destination only BLTs (ie. independent of source bits).
//
if ((psoSrc == NULL) || ROP3_NO_SOURCE(rop3))
{
//
// Check for a pattern or true destination BLT.
//
if (ROP3_NO_PATTERN(rop3))
{
TRACE_OUT(( "DSTBLT"));
orderType = ORD_DSTBLT;
}
else
{
TRACE_OUT(( "PATBLT"));
orderType = ORD_PATBLT;
}
}
else
{
//
// We have a source BLT, check whether we have screen or memory
// BLTs.
//
if (psoSrc->hsurf != ppdev->hsurfScreen)
{
if (psoDst->hsurf != ppdev->hsurfScreen)
{
ERROR_OUT(( "MEM to MEM blt!"));
}
else
{
//
// We have a memory to screen BLT, check which type.
//
if ((ppdev->cBitsPerPel == 4) && (rop3 != 0xcc))
{
//
// No order -- the result depends on the palette
// which is dicy in VGA
//
TRACE_OUT(("No order on VGA for rop 0x%02x", rop3));
DC_QUIT;
}
if (ROP3_NO_PATTERN(rop3))
{
TRACE_OUT(( "MEMBLT"));
orderType = ORD_MEMBLT;
}
else
{
TRACE_OUT(( "MEM3BLT"));
orderType = ORD_MEM3BLT;
}
}
}
else
{
if (psoDst->hsurf != ppdev->hsurfScreen)
{
TRACE_OUT(( "SCR to MEM blt!"));
}
else
{
//
// We only support destination only screen BLTs (ie. no
// patterns allowed).
//
if (ROP3_NO_PATTERN(rop3))
{
TRACE_OUT(( "SCRBLT"));
orderType = ORD_SCRBLT;
}
else
{
TRACE_OUT(( "Unsupported screen ROP %x", rop3));
}
}
}
}
//
// Check if we have a supported order.
//
if (orderType == 0)
{
TRACE_OUT(( "Unsupported BLT"));
fAccumulate = FALSE;
DC_QUIT;
}
//
// Check if we are allowed to send this order (determined by the
// negotiated capabilities of all the machines in the conference).
//
if (!OE_SendAsOrder(orderType))
{
TRACE_OUT(( "Order %d not allowed", orderType));
DC_QUIT;
}
//
// Check if we are allowed to send the ROP.
//
if (!OESendRop3AsOrder(rop3))
{
TRACE_OUT(( "Cannot send ROP %d", rop3));
DC_QUIT;
}
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// If this is a Memblt, do an initial check on whether it is cachable
//
if ((orderType == ORD_MEMBLT) || (orderType == ORD_MEM3BLT))
{
//
// We have to fill in a structure containing extra into
// specifically for a MEM(3)BLT order.
//
memBltExtraInfo.pSource = psoSrc;
memBltExtraInfo.pDest = psoDst;
memBltExtraInfo.pXlateObj = pxlo;
if (!SBC_DDIsMemScreenBltCachable(&memBltExtraInfo))
{
TRACE_OUT(( "MemBlt is not cachable"));
DC_QUIT;
}
//
// It is cachable. Before we get SBC to do the caching, we have to
// allow it to queue a color table (if required).
//
if (!SBC_DDMaybeQueueColorTable(ppdev))
{
TRACE_OUT(( "Unable to queue color table for MemBlt"));
DC_QUIT;
}
}
//
// We have a recognised order - do the specific checks for each order.
//
switch (orderType)
{
case ORD_DSTBLT:
//
// Allocate the memory for the order.
//
pOrder = OA_DDAllocOrderMem(sizeof(DSTBLT_ORDER),0);
if (pOrder == NULL)
{
TRACE_OUT(( "Failed to alloc order"));
DC_QUIT;
}
pDstBlt = (LPDSTBLT_ORDER)pOrder->abOrderData;
//
// Set the spoiler flag if the rop is opaque.
//
if (ROP3_IS_OPAQUE(rop3))
{
fOrderFlags |= OF_SPOILER;
}
//
// Store the order type.
//
pDstBlt->type = LOWORD(orderType);
//
// Virtual desktop co-ordinates.
//
pDstBlt->nLeftRect = bounds.left;
pDstBlt->nTopRect = bounds.top;
pDstBlt->nWidth = bounds.right - bounds.left + 1;
pDstBlt->nHeight = bounds.bottom - bounds.top + 1;
pDstBlt->bRop = rop3;
TRACE_OUT(( "DstBlt X %d Y %d w %d h %d rop %02X",
pDstBlt->nLeftRect,
pDstBlt->nTopRect,
pDstBlt->nWidth,
pDstBlt->nHeight,
pDstBlt->bRop));
break;
case ORD_PATBLT:
if ( !OEEncodePatBlt(ppdev,
pbo,
pptlBrush,
rop3,
&bounds,
&pOrder) )
{
//
// Something went wrong with the encoding, so skip to the
// end to add this operation to the SDA.
//
DC_QUIT;
}
fOrderFlags = pOrder->OrderHeader.Common.fOrderFlags;
break;
case ORD_SCRBLT:
//
// Check for a SCRBLT as a result of a Desktop Scroll. We must
// ignore these as they will stuff the remote desktop.
//
// The check is simple - if the virtual position of the source
// is the same as the virual position of the target for a
// SRCCOPY type SCRBLT, we have a hit...
//
POINT_FROM_POINTL(origin, (*pptlSrc));
//
// Allocate the memory for the order.
//
pOrder = OA_DDAllocOrderMem(sizeof(SCRBLT_ORDER),0);
if (pOrder == NULL)
{
TRACE_OUT(( "Failed to alloc order"));
DC_QUIT;
}
pScrBlt = (LPSCRBLT_ORDER)pOrder->abOrderData;
//
// Store the order type.
//
pScrBlt->type = LOWORD(orderType);
//
// All data which is sent over the wire must be in virtual
// desktop co-ordinates. OELRtoVirtual has already converted
// bounds to an inclusive rectangle in virtual co-ordinates.
//
pScrBlt->nLeftRect = bounds.left;
pScrBlt->nTopRect = bounds.top;
pScrBlt->nWidth = bounds.right - bounds.left + 1;
pScrBlt->nHeight = bounds.bottom - bounds.top + 1;
pScrBlt->bRop = rop3;
//
// Source point on the screen.
//
OELPtoVirtual(&origin, 1);
pScrBlt->nXSrc = origin.x;
pScrBlt->nYSrc = origin.y;
//
// Screen to screen blts are Blocking orders (i.e. they
// prevent any previous orders from being spoilt).
//
// We do not mark Screen to Screen blts as SPOILER orders. If
// the ROP is opaque we could spoil the destination rect, but
// only the area that does not overlap with the src rectangle.
// The most common use of Screen to Screen blts is scrolling,
// where the src and dst rects almost completely overlap,
// giving only a small "spoiler" region. The spoiler region
// could also be complex (more that 1 rect).
//
// Consequently, the potential gains of trying to spoil using
// these orders are small compared to the complexity of the
// code required.
//
//
fOrderFlags |= OF_BLOCKER;
//
// If the blt is screen to screen and the source overlaps the
// destination and the clipping is not simple (> 1 rect) then
// we do not want to send this as an order.
//
// (This is because we would need some complex code to
// calculate the order in which to blt through each of the clip
// rects. As this case is pretty rare, it seems reasonable to
// just send it as Screen Data).
//
if (!OEClippingIsSimple(pco))
{
//
// Calculate the overlapping rectangle.
//
intersectRect.left = max(pScrBlt->nLeftRect, pScrBlt->nXSrc);
intersectRect.right = min(
pScrBlt->nLeftRect + pScrBlt->nWidth-1,
pScrBlt->nXSrc + pScrBlt->nWidth-1 );
intersectRect.top = max(pScrBlt->nTopRect, pScrBlt->nYSrc);
intersectRect.bottom = min(
pScrBlt->nTopRect + pScrBlt->nHeight-1,
pScrBlt->nYSrc + pScrBlt->nHeight-1 );
//
// Check for a src / dst overlap. If they overlap, the
// intersection is a well-ordered non-trivial rectangle.
//
if ( (intersectRect.left <= intersectRect.right ) &&
(intersectRect.top <= intersectRect.bottom) )
{
//
// The src & dest overlap. Free up the order memory
// and skip out now. The destination rectangle will be
// added to the Screen Data Area.
//
OA_DDFreeOrderMem(pOrder);
DC_QUIT;
}
}
TRACE_OUT(( "ScrBlt x %d y %d w %d h %d sx %d sy %d rop %02X",
pScrBlt->nLeftRect,
pScrBlt->nTopRect,
pScrBlt->nWidth,
pScrBlt->nHeight,
pScrBlt->nXSrc,
pScrBlt->nYSrc,
pScrBlt->bRop));
break;
case ORD_MEMBLT:
//
// Allocate the memory for the order - don't use OA as we are
// only going to tile this order immediately. Instead, we have
// a static buffer to receive the template order data.
//
pOrder = (LPINT_ORDER)g_oeTmpOrderBuffer;
pMemBlt = (LPMEMBLT_ORDER)pOrder->abOrderData;
pOrder->OrderHeader.Common.cbOrderDataLength
= sizeof(MEMBLT_R2_ORDER);
//
// Store the order type.
//
pMemBlt->type = LOWORD(orderType);
//
// Any data which is sent over the wire must be in virtual
// desktop co-ordinates. The bounding rectangle has already
// been converted by OELRtoScreen.
//
pMemBlt->nLeftRect = bounds.left;
pMemBlt->nTopRect = bounds.top;
pMemBlt->nWidth = bounds.right - bounds.left + 1;
pMemBlt->nHeight = bounds.bottom - bounds.top + 1;
pMemBlt->bRop = rop3;
//
// We need to store the source bitmap origin. This is a memory
// object, so screen/virtual conversions are unnecessary.
//
pMemBlt->nXSrc = pptlSrc->x;
pMemBlt->nYSrc = pptlSrc->y;
//
// Mark the order as opaque if necessary.
//
if (ROP3_IS_OPAQUE(rop3))
{
fOrderFlags |= OF_SPOILER;
}
//
// Store the src bitmap handle in the order.
//
pMemBlt->cacheId = 0;
TRACE_OUT(( "MemBlt dx %d dy %d w %d h %d sx %d sy %d rop %04X",
pMemBlt->nLeftRect,
pMemBlt->nTopRect,
pMemBlt->nWidth,
pMemBlt->nHeight,
pMemBlt->nXSrc,
pMemBlt->nYSrc,
pMemBlt->bRop));
break;
case ORD_MEM3BLT:
//
// Check that the brush pattern is simple.
//
if (!OECheckBrushIsSimple(ppdev, pbo, &pCurrentBrush))
{
TRACE_OUT(( "Brush is not simple"));
orderType = 0;
DC_QUIT;
}
//
// Allocate the memory for the order - don't use OA as we are
// only going to tile this order immediately. Instead, we have
// a static buffer to receive the template order data.
//
pOrder = (LPINT_ORDER)g_oeTmpOrderBuffer;
pMem3Blt = (LPMEM3BLT_ORDER)pOrder->abOrderData;
pOrder->OrderHeader.Common.cbOrderDataLength
= sizeof(MEM3BLT_R2_ORDER);
//
// Store the order type.
//
pMem3Blt->type = LOWORD(orderType);
//
// All data which is sent over the wire must be in virtual
// desktop co-ordinates. OELRtoVirtual has already done this
// conversion for us.
//
pMem3Blt->nLeftRect = bounds.left;
pMem3Blt->nTopRect = bounds.top;
pMem3Blt->nWidth = bounds.right - bounds.left + 1;
pMem3Blt->nHeight = bounds.bottom - bounds.top + 1;
pMem3Blt->bRop = rop3;
//
// We need to store the source bitmap origin. This is a memory
// object, so screen/virtual conversions are unnecessary.
//
pMem3Blt->nXSrc = pptlSrc->x;
pMem3Blt->nYSrc = pptlSrc->y;
//
// Mark the order as opaque if necessary.
//
if (ROP3_IS_OPAQUE(rop3))
{
fOrderFlags |= OF_SPOILER;
}
//
// Store the src bitmap handle in the order.
//
pMem3Blt->cacheId = 0;
//
// Set up the information required for the pattern.
//
pMem3Blt->BackColor = pCurrentBrush->back;
pMem3Blt->ForeColor = pCurrentBrush->fore;
//
// The protocol brush origin is the point on the screen where
// we want the brush to start being drawn from (tiling where
// necessary). This must be in virtual coordinates.
//
pMem3Blt->BrushOrgX = pptlBrush->x;
pMem3Blt->BrushOrgY = pptlBrush->y;
OELPtoVirtual((LPPOINT)&pMem3Blt->BrushOrgX, 1);
//
// Extra brush data from the data when we realised the brush.
//
pMem3Blt->BrushStyle = pCurrentBrush->style;
pMem3Blt->BrushHatch = pCurrentBrush->style;
RtlCopyMemory(pMem3Blt->BrushExtra,
pCurrentBrush->brushData,
sizeof(pMem3Blt->BrushExtra));
TRACE_OUT(( "Mem3Blt brush %02X %02X dx %d dy %d w %d h %d "
"sx %d sy %d rop %04X",
pMem3Blt->BrushStyle,
pMem3Blt->BrushHatch,
pMem3Blt->nLeftRect,
pMem3Blt->nTopRect,
pMem3Blt->nWidth,
pMem3Blt->nHeight,
pMem3Blt->nXSrc,
pMem3Blt->nYSrc,
pMem3Blt->bRop));
break;
default:
ERROR_OUT(( "New unsupported order %08lx", orderType));
orderType = 0;
break;
}
//
// We have generated an order so make sure we send it.
//
if (orderType != 0)
{
fSendOrder = TRUE;
}
DC_EXIT_POINT:
//
// If we did not send an order, we must accumulate the output in the
// Screen Data Area.
//
if (fSendOrder)
{
//
// Check if the ROP has a dependency on the destination.
//
if (!ROP3_NO_TARGET(rop3))
{
TRACE_OUT(( "ROP has a target dependency"));
fOrderFlags |= OF_DESTROP;
}
//
// Store the general order data. The bounding rectagle
// co-ordinates must be virtual desktop. OELRtoVirtual has already
// converted rect for us.
//
pOrder->OrderHeader.Common.fOrderFlags = (TSHR_UINT16)fOrderFlags;
TSHR_RECT16_FROM_RECT(&pOrder->OrderHeader.Common.rcsDst, bounds);
//
// Add the order to the cache. Note that we have the new tiled
// processing for MEMBLT and MEM3BLT orders.
//
if ((orderType == ORD_MEMBLT) || (orderType == ORD_MEM3BLT))
{
OETileBitBltOrder(pOrder, &memBltExtraInfo, pco);
}
else
{
OEClipAndAddOrder(pOrder, NULL, pco);
}
}
else
{
if (fAccumulate)
{
OEClipAndAddScreenData(&bounds, pco);
}
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvBitBlt, rc);
return(rc);
}
//
// DrvStretchBlt - see NT DDK documentation.
//
BOOL DrvStretchBlt(SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
COLORADJUSTMENT *pca,
POINTL *pptlHTOrg,
RECTL *prclDst,
RECTL *prclSrc,
POINTL *pptlMask,
ULONG iMode)
{
BOOL rc = TRUE;
RECT rectSrc;
RECT rectDst;
BOOL fAccumulate = FALSE;
POINTL ptlSrc;
BOOL usedBitBlt = FALSE;
DebugEntry(DrvStretchBlt);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get the source and destination rectangles
//
RECT_FROM_RECTL(rectSrc, (*prclSrc));
RECT_FROM_RECTL(rectDst, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Check that we have a valid ROP code. The NT DDK states that the ROP
// code for the StretchBlt is implicit in the mask specification. If a
// mask is specified, we have an implicit ROP4 of 0xCCAA, otherwise the
// code is 0xCCCC.
//
// Our BitBlt code only encodes orders for ROP3s, so we must throw any
// StretchBlts with a mask.
//
if (psoMask != NULL)
{
TRACE_OUT(( "Mask specified"));
DC_QUIT;
}
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// Rectangles are now well-ordered, check if we have a degenerate (ie.
// no stretch) case.
//
if ( (rectSrc.right - rectSrc.left == rectDst.right - rectDst.left) &&
(rectSrc.bottom - rectSrc.top == rectDst.bottom - rectDst.top ) )
{
//
// This can be passed on to the BitBlt code.
//
usedBitBlt = TRUE;
ptlSrc.x = prclSrc->left;
ptlSrc.y = prclSrc->top;
rc = DrvBitBlt(psoDst,
psoSrc,
psoMask,
pco,
pxlo,
prclDst,
&ptlSrc,
pptlMask,
NULL,
NULL,
0xCCCC);
//
// We have stored this object in the BitBlt, so don't store the
// data again.
//
fAccumulate = FALSE;
}
DC_EXIT_POINT:
if (fAccumulate)
{
//
// Convert the data to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
//
// Update the screen data area
//
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvStretchBlt, rc);
return(rc);
}
//
// DrvCopyBits - see NT DDK documentation.
//
BOOL DrvCopyBits(SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc)
{
//
// CopyBits is a fast path for the NT display drivers. In our case it
// can always be processed as a BITBLT.
//
return(DrvBitBlt( psoDst,
psoSrc,
NULL,
pco,
pxlo,
prclDst,
pptlSrc,
NULL,
NULL,
NULL,
0xCCCC));
}
//
// DrvTextOut - see NT DDK documentation.
//
BOOL DrvTextOut(SURFOBJ *pso,
STROBJ *pstro,
FONTOBJ *pfo,
CLIPOBJ *pco,
RECTL *prclExtra,
RECTL *prclOpaque,
BRUSHOBJ *pboFore,
BRUSHOBJ *pboOpaque,
POINTL *pptlOrg,
MIX mix)
{
LPOSI_PDEV ppdev = (LPOSI_PDEV)pso->dhpdev;
BOOL rc = TRUE;
RECT rectDst;
RECT rectText;
LPINT_ORDER pOrder;
LPINT_ORDER pOpaqueOrder;
LPTEXTOUT_ORDER pTextOut;
LPEXTTEXTOUT_ORDER pExtTextOut;
BOOL fSendOrder = FALSE;
BOOL fAccumulate = FALSE;
char ansiString[ORD_MAX_STRING_LEN_WITHOUT_DELTAS+2];
ULONG ansiLen;
ULONG tempLen;
UINT orderType = 0;
ULONG maxLength;
LPSTR lpVariable;
BOOL fMoreData;
ULONG count;
ULONG i;
GLYPHPOS* pGlyphData;
int currentDelta;
LPVARIABLE_DELTAX lpDeltaPos;
UINT fontFlags;
UINT fontAscender;
UINT fontHeight;
UINT fontWidth;
UINT fontWeight;
UINT fontIndex;
POINTL lastPtl;
LPCOMMON_TEXTORDER pCommon;
POINT startPoint;
BOOL sendDeltaX = FALSE;
DebugEntry(DrvTextOut);
//
// DO THIS _BEFORE_ TAKING LOCKS
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
if (prclOpaque != NULL)
{
RECT_FROM_RECTL(rectDst, (*prclOpaque));
}
else
{
RECT_FROM_RECTL(rectDst, pstro->rclBkGround);
TRACE_OUT(( "Using STROBJ bgd for size"));
}
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(pso, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates
//
OELRtoVirtual(&rectDst, 1);
//
// Determine which order we will generate
//
if ( ((pstro->flAccel & SO_FLAG_DEFAULT_PLACEMENT) != 0) &&
(prclOpaque == NULL) )
{
orderType = ORD_TEXTOUT;
maxLength = ORD_MAX_STRING_LEN_WITHOUT_DELTAS;
}
else
{
orderType = ORD_EXTTEXTOUT;
maxLength = ORD_MAX_STRING_LEN_WITH_DELTAS;
}
//
// Check if we are allowed to send this order (determined by the
// negotiated capabilities of all the machines in the conference).
//
if (!OE_SendAsOrder(orderType))
{
TRACE_OUT(( "Text order %x not allowed", orderType));
DC_QUIT;
}
//
// Check for a valid brush for the test operation.
//
if (pboFore->iSolidColor == -1)
{
TRACE_OUT(( "Bad brush for text fg"));
DC_QUIT;
}
if (pboOpaque->iSolidColor == -1)
{
TRACE_OUT(( "Bad brush for text bg"));
DC_QUIT;
}
//
// Check that we don't have any modifiers rects on the font
//
if (prclExtra != NULL)
{
TRACE_OUT(( "Unsupported extra rects"));
DC_QUIT;
}
//
// Check that text orientation is OK.
//
if (pstro->flAccel & OE_BAD_TEXT_MASK)
{
TRACE_OUT(("DrvTextOut - unsupported flAccel 0x%08x", pstro->flAccel));
DC_QUIT;
}
//
// Check we have a valid string.
//
if (pstro->pwszOrg == NULL)
{
TRACE_OUT(( "No string - opaque %x", prclOpaque));
DC_QUIT;
}
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// Convert the string to an ANSI representation.
//
RtlFillMemory(ansiString, sizeof(ansiString), 0);
EngUnicodeToMultiByteN(ansiString,
maxLength,
&ansiLen,
pstro->pwszOrg,
pstro->cGlyphs * sizeof(WCHAR));
//
// The conversion claims it never fails, but we have seen results that
// are completely different on the remote box. So we convert the ANSI
// string back to UNICODE and check that we still have what we started
// with.
//
EngMultiByteToUnicodeN(g_oeTempString,
sizeof(g_oeTempString),
&tempLen,
ansiString,
ansiLen);
//
// Check we don't have too much data, or that the translation failed to
// give the correct data. This happens when we try to translate
// UNICODE text.
//
if ( (tempLen != pstro->cGlyphs * sizeof(WCHAR)) ||
(memcmp(pstro->pwszOrg, g_oeTempString, tempLen) != 0) )
{
TRACE_OUT(( "String not translated"));
DC_QUIT;
}
//
// Check that the font is valid.
//
if (!OECheckFontIsSupported(pfo, ansiString, ansiLen,
&fontHeight,
&fontAscender,
&fontWidth,
&fontWeight,
&fontFlags,
&fontIndex,
&sendDeltaX))
{
TRACE_OUT(( "Unsupported font for '%s'", ansiString));
//
// Check if there is an opaque rectangle. If so it is worth
// splitting this out. Word can output an entire line comprising a
// single character followed by background, eg bullets, where the
// line is blanked by drawing the bullet character at the start of
// the line followed by a large - >1000 pixel - opaque rect.
// Splitting the opaque rect from the text means we can send a
// small area of SD for the unmatched font char while encoding the
// large opaque rectangle.
//
if ( (prclOpaque != NULL) &&
(pstro->cGlyphs == 1) &&
(pstro->flAccel & SO_HORIZONTAL) &&
OE_SendAsOrder(ORD_PATBLT))
{
//
// There is an opaque rectangle and a single char.
// Encode the opaque rectangle. First get a copy of the target
// rect so we can use it later (and flip it into screen
// coordinates).
//
TRACE_OUT(( "Have 1 char + opaque rect"));
rectText.left = rectDst.left;
rectText.top = rectDst.top;
rectText.right = rectDst.right + 1;
rectText.bottom = rectDst.bottom + 1;
//
// Call into the PATBLT encoding function.
//
if ( !OEEncodePatBlt(ppdev,
pboOpaque,
pptlOrg,
OE_COPYPEN_ROP,
&rectDst,
&pOpaqueOrder) )
{
//
// Something went wrong with the encoding, so skip to the
// end to add this operation to the SDA.
//
TRACE_OUT(( "Failed to encode opaque rect"));
DC_QUIT;
}
//
// Store the general order data. The bounding rectagle
// co-ordinates must be virtual desktop. OELRtoVirtual has
// already converted rect for us.
//
TSHR_RECT16_FROM_RECT(&pOpaqueOrder->OrderHeader.Common.rcsDst, rectDst);
//
// Add the order to the cache.
//
OEClipAndAddOrder(pOpaqueOrder, NULL, pco);
//
// Calculate the bounds of the text. Get the glyph positions
// for the left and right, and assume the top and bottom equate
// approximately to the opaque rectangle.
//
if ( pstro->pgp == NULL)
{
//
// The string object doesn't contain the GLYPHPOS info, so
// enumerate the glyphs.
//
TRACE_OUT(( "Enumerate glyphs"));
STROBJ_vEnumStart(pstro);
STROBJ_bEnum(pstro, &count, &pGlyphData);
}
else
{
//
// The string object already contains the GLYPHPOS info, so
// just grab the pointer to it.
//
pGlyphData = pstro->pgp;
}
rectDst = rectText;
rectDst.left = max(rectDst.left, pGlyphData[0].ptl.x);
if ( pstro->ulCharInc == 0 )
{
//
// No character increment for this string object. Just use
// the maximum glyph width to calculate the right bounding
// edge.
//
TRACE_OUT(( "no charinc glyph %d trg %d left %d maxX %d",
pGlyphData[0].ptl.x,
rectDst.right,
rectDst.left,
pfo->cxMax));
rectDst.right = min(rectDst.right, (int)(pGlyphData[0].ptl.x +
pfo->cxMax - 1));
}
else
{
//
// The string object has a character increment, so use it
// to determine the right bounding edge.
//
TRACE_OUT(( "charinc %x glyph %d trg %d left %d",
pstro->ulCharInc,
pGlyphData[0].ptl.x,
rectDst.right,
rectDst.left));
rectDst.right = min(rectDst.right, (int)(pGlyphData[0].ptl.x +
pstro->ulCharInc - 1));
}
//
// Flip the target rectangle back to virtual coordinates.
//
rectDst.right -= 1;
rectDst.bottom -= 1;
}
//
// Skip to the end to add to the SDA.
//
DC_QUIT;
}
//
// It is possible that the font matching blows our previous decision to
// generate a TextOut order and we need to generate an ExtTextOut order
// instead. We need to reverify our parameters if this is the case.
//
if ((sendDeltaX) && (orderType != ORD_EXTTEXTOUT))
{
TRACE_OUT(( "Text order must be EXTTEXTOUT"));
//
// Set up for ExtTexOut orders.
//
orderType = ORD_EXTTEXTOUT;
maxLength = ORD_MAX_STRING_LEN_WITH_DELTAS;
//
// Check if we are allowed to send this order (determined by the
// negotiated capabilities of all the machines in the conference).
//
if (!OE_SendAsOrder(orderType))
{
TRACE_OUT(( "Text order %x not allowed", orderType));
DC_QUIT;
}
//
// Make sure we haven't blown the order size.
//
if (pstro->cGlyphs > maxLength)
{
TRACE_OUT(( "Text limit blown", pstro->cGlyphs));
DC_QUIT;
}
}
//
// Get the proper start position for the text.
//
if ( pstro->pgp == NULL)
{
STROBJ_vEnumStart(pstro);
STROBJ_bEnum(pstro, &count, &pGlyphData);
if (count == 0)
{
WARNING_OUT(( "No glyphs"));
DC_QUIT;
}
}
else
{
pGlyphData = pstro->pgp;
}
startPoint.x = pGlyphData[0].ptl.x;
//
// Check if we should be using baseline alignment for the y
// coordinate. If we should be, the value in the glyph data is
// correct. If not, we the y coordinate is for the top of the
// text, and we have to calculate it.
//
if (g_oeBaselineTextEnabled)
{
startPoint.y = pGlyphData[0].ptl.y;
fontFlags |= NF_BASELINE;
}
else
{
startPoint.y = pGlyphData[0].ptl.y - fontAscender;
}
//
// Allocate memory for the order
//
switch (orderType)
{
case ORD_TEXTOUT:
{
//
// Allocate the memory
//
pOrder = OA_DDAllocOrderMem((UINT)( sizeof(TEXTOUT_ORDER)
- ORD_MAX_STRING_LEN_WITHOUT_DELTAS
+ ansiLen ),
0);
if (pOrder == NULL)
{
TRACE_OUT(( "Failed to alloc order"));
DC_QUIT;
}
pTextOut = (LPTEXTOUT_ORDER)pOrder->abOrderData;
//
// Set up the order type.
//
pTextOut->type = ORD_TEXTOUT_TYPE;
//
// Get a pointer to the fields which are common to both TextOut
// and ExtTextOut
//
pCommon = &pTextOut->common;
}
break;
case ORD_EXTTEXTOUT:
{
//
// BOGUS LAURABU
// This allocates space for a deltax array whether or not one is needed
//
//
// Allocate the memory
//
pOrder = OA_DDAllocOrderMem((UINT)( sizeof(EXTTEXTOUT_ORDER)
- ORD_MAX_STRING_LEN_WITHOUT_DELTAS
- (ORD_MAX_STRING_LEN_WITH_DELTAS
* sizeof(TSHR_INT32))
+ ansiLen * (sizeof(TSHR_INT32) + 1)
+ 4), // Allow for internal padding
0);
if (pOrder == NULL)
{
TRACE_OUT(( "Failed to alloc order"));
DC_QUIT;
}
pExtTextOut = (LPEXTTEXTOUT_ORDER)pOrder->abOrderData;
//
// Set up the order type.
//
pExtTextOut->type = ORD_EXTTEXTOUT_TYPE;
//
// Get a pointer to the fields which are common to both TextOut
// and ExtTextOut
//
pCommon = &pExtTextOut->common;
}
break;
default:
{
ERROR_OUT(( "Unknown order %x", orderType));
DC_QUIT;
}
break;
}
//
// Fill in the fields which are common to both TextOut and ExtTextOut
//
// Convert to virtual coordinates
//
OELPtoVirtual(&startPoint, 1);
//
// The x and y values are available in virtual coords from the bounds
// rectangle.
//
pCommon->nXStart = startPoint.x;
pCommon->nYStart = startPoint.y;
//
// Get the text colours.
//
OEConvertColor(ppdev,
&pCommon->BackColor,
pboOpaque->iSolidColor,
NULL);
OEConvertColor(ppdev,
&pCommon->ForeColor,
pboFore->iSolidColor,
NULL);
//
// The transparency of the operation is determined by whether we have
// an opaque rectangle or not.
//
pCommon->BackMode = (prclOpaque == NULL) ? TRANSPARENT : OPAQUE;
//
// NT has a character extra spacing, not a generic for every character
// spacing. So, we always set this value to 0.
//
pCommon->CharExtra = 0;
//
// NT does not provide a break of any sorts.
//
pCommon->BreakExtra = 0;
pCommon->BreakCount = 0;
//
// Copy the font details
//
pCommon->FontHeight = fontHeight;
pCommon->FontWidth = fontWidth;
pCommon->FontWeight = fontWeight;
pCommon->FontFlags = fontFlags;
pCommon->FontIndex = fontIndex;
//
// Now fill in the order specific data
//
switch (orderType)
{
case ORD_TEXTOUT:
//
// Copy across the text string.
//
pTextOut->variableString.len = (BYTE)ansiLen;
RtlCopyMemory(pTextOut->variableString.string,
ansiString,
ansiLen);
//
// Make sure we send the order
//
fSendOrder = TRUE;
TRACE_OUT(( "TEXTOUT: X %u Y %u bm %u FC %02X%02X%02X "
"BC %02X%02X%02X",
pTextOut->common.nXStart,
pTextOut->common.nYStart,
pTextOut->common.BackMode,
pTextOut->common.ForeColor.red,
pTextOut->common.ForeColor.green,
pTextOut->common.ForeColor.blue,
pTextOut->common.BackColor.red,
pTextOut->common.BackColor.green,
pTextOut->common.BackColor.blue));
TRACE_OUT(( "Font: fx %u fy %u fw %u ff %04x fh %u len %u",
pTextOut->common.FontWidth,
pTextOut->common.FontHeight,
pTextOut->common.FontWeight,
pTextOut->common.FontFlags,
pTextOut->common.FontIndex,
ansiLen));
TRACE_OUT(( "String '%s'", ansiString));
break;
case ORD_EXTTEXTOUT:
//
// Since our text is only ever fully contained within the
// opaque rectangle, we only set the opaque flag (and ignore
// the clipping).
//
pExtTextOut->fuOptions = (prclOpaque == NULL) ? 0 : ETO_OPAQUE;
//
// Set up the bounding rectangle for the operation.
// EXT_TEXT_OUT orders use TSHR_RECT32s, hence we can't directly
// assign rectDst to it.
//
pExtTextOut->rectangle.left = rectDst.left;
pExtTextOut->rectangle.top = rectDst.top;
pExtTextOut->rectangle.right = rectDst.right;
pExtTextOut->rectangle.bottom = rectDst.bottom;
//
// Copy across the text string.
//
pExtTextOut->variableString.len = ansiLen;
RtlCopyMemory(pExtTextOut->variableString.string,
ansiString,
ansiLen);
//
// WHOOP WHOOP WHOOP - Prepare to shut your eyes...
//
// Although we have a defined fixed length structure for
// storing ExtTextOut orders, we must not send the full
// structure over the network as the text will only be, say, 10
// characters 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.
//
lpVariable = ((LPBYTE)(&pExtTextOut->variableString))
+ ansiLen
+ sizeof(pExtTextOut->variableString.len);
lpVariable = (LPSTR)
DC_ROUND_UP_4((UINT_PTR)lpVariable);
lpDeltaPos = (LPVARIABLE_DELTAX)lpVariable;
//
// Do we need a delta array, or are the chars at their default
// positions.
//
if ( sendDeltaX ||
((pstro->flAccel & SO_FLAG_DEFAULT_PLACEMENT) == 0) )
{
//
// Store the length of the position deltas.
//
lpDeltaPos->len = ansiLen * sizeof(TSHR_INT32);
//
// Set up the position deltas.
//
STROBJ_vEnumStart(pstro);
fMoreData = TRUE;
currentDelta = 0;
while (fMoreData)
{
//
// Get the next set of glyph data
//
fMoreData = STROBJ_bEnum(pstro, &count, &pGlyphData);
for (i = 0; i < count; i++)
{
//
// The first time through we must set up the first
// glyph position.
//
if ((currentDelta == 0) && (i == 0))
{
lastPtl.x = pGlyphData[0].ptl.x;
lastPtl.y = pGlyphData[0].ptl.y;
TRACE_OUT(( "First Pos %d", lastPtl.x));
}
else
{
//
// For subsequent entries, we need to add the
// delta on the X position to the array.
//
if (pstro->ulCharInc == 0)
{
lpDeltaPos->deltaX[currentDelta]
= pGlyphData[i].ptl.x
- lastPtl.x;
//
// Check for delta Y's - which we can't
// encode
//
if (pGlyphData[i].ptl.y - lastPtl.y)
{
WARNING_OUT(( "New Y %d",
pGlyphData[i].ptl.y));
OA_DDFreeOrderMem(pOrder);
DC_QUIT;
}
//
// Store the last position for the next
// time round.
//
lastPtl.x = pGlyphData[i].ptl.x;
lastPtl.y = pGlyphData[i].ptl.y;
TRACE_OUT(( "Next Pos %d %d", i, lastPtl.x));
}
else
{
lpDeltaPos->deltaX[currentDelta]
= pstro->ulCharInc;
}
currentDelta++;
}
}
}
//
// For the last entry, we need to set up the data by hand
// (there are only n-1 deltas for n chars)
//
// This is done for compatibility with Windows 95 which
// requires the last delta to be the delta to the place
// where the next char would be if there were n+1 chars in
// the string.
//
if (pstro->ulCharInc == 0)
{
//
// No characters left - fudge a value of the width of
// the last character.
//
lpDeltaPos->deltaX[currentDelta] =
pGlyphData[count-1].pgdf->pgb->sizlBitmap.cx;
}
else
{
//
// All chars are evenly spaced, so just stick the value
// in.
//
lpDeltaPos->deltaX[currentDelta] = pstro->ulCharInc;
}
//
// WHOOP WHOOP WHOOP - You can open your eyes now...
//
//
// We must indicate the presence of this field to the
// receiver.
//
pExtTextOut->fuOptions |= ETO_LPDX;
}
else
{
//
// Mark the delta array as empty.
//
lpDeltaPos->len = 0;
}
//
// WHOOP WHOOP WHOOP - You can open your eyes now...
//
//
// Make sure we send the order
//
fSendOrder = TRUE;
TRACE_OUT(( "EXTTEXTOUT: X %u Y %u bm %u FC %02X%02X%02X "
"BC %02X%02X%02X",
pExtTextOut->common.nXStart,
pExtTextOut->common.nYStart,
pExtTextOut->common.BackMode,
pExtTextOut->common.ForeColor.red,
pExtTextOut->common.ForeColor.green,
pExtTextOut->common.ForeColor.blue,
pExtTextOut->common.BackColor.red,
pExtTextOut->common.BackColor.green,
pExtTextOut->common.BackColor.blue));
TRACE_OUT(( "Extra: Opt %x X1 %d Y1 %d X2 %d Y2 %d",
pExtTextOut->fuOptions,
pExtTextOut->rectangle.left,
pExtTextOut->rectangle.top,
pExtTextOut->rectangle.right,
pExtTextOut->rectangle.bottom));
TRACE_OUT(( "Font: fx %u fy %u fw %u ff %04x fh %u len %u",
pExtTextOut->common.FontWidth,
pExtTextOut->common.FontHeight,
pExtTextOut->common.FontWeight,
pExtTextOut->common.FontFlags,
pExtTextOut->common.FontIndex,
ansiLen));
TRACE_OUT(( "String '%s'", ansiString));
break;
default:
ERROR_OUT(( "Unknown order %x", orderType));
break;
}
DC_EXIT_POINT:
//
// If we did not send an order, we must accumulate the output in the
// Screen Data Area.
//
if (fSendOrder)
{
//
// Store the general order data. The bounding rectangle position
// must be in virtual desktop co-ordinates. OELRtoVirtual has
// already done this.
//
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
TSHR_RECT16_FROM_RECT(&pOrder->OrderHeader.Common.rcsDst, rectDst);
//
// Add the order to the cache.
//
OEClipAndAddOrder(pOrder, NULL, pco);
}
else
{
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvTextOut, rc);
return(rc);
}
//
// DrvLineTo - see NT DDK documentation.
//
BOOL DrvLineTo(SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
LONG x1,
LONG y1,
LONG x2,
LONG y2,
RECTL *prclBounds,
MIX mix)
{
LPOSI_PDEV ppdev = (LPOSI_PDEV)pso->dhpdev;
BOOL rc = TRUE;
RECT rectDst;
POINT startPoint;
POINT endPoint;
BOOL fAccumulate = FALSE;
DebugEntry(DrvLineTo);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectDst, (*prclBounds));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(pso, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert the data to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
//
// Check if we are allowed to send this order (determined by the
// negotiated capabilities of all the machines in the conference).
//
if (!OE_SendAsOrder(ORD_LINETO))
{
TRACE_OUT(( "LineTo order not allowed"));
DC_QUIT;
}
//
// Check for a valid brush for the test operation.
//
if (pbo->iSolidColor == -1)
{
TRACE_OUT(( "Bad brush for line"));
DC_QUIT;
}
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// Set up data for order
//
startPoint.x = x1;
startPoint.y = y1;
endPoint.x = x2;
endPoint.y = y2;
//
// Store that order.
//
if (!OEAddLine(ppdev,
&startPoint,
&endPoint,
&rectDst,
mix & 0x1F,
1,
pbo->iSolidColor,
pco))
{
TRACE_OUT(( "Failed to add order - use SDA"));
DC_QUIT;
}
//
// We have stored this object, so don't store the data in the SDA
// again.
//
fAccumulate = FALSE;
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvLineTo, rc);
return(rc);
}
//
// DrvStrokePath - see NT DDK documentation.
//
BOOL DrvStrokePath(SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
XFORMOBJ *pxo,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
LINEATTRS *plineattrs,
MIX mix)
{
LPOSI_PDEV ppdev = (LPOSI_PDEV)pso->dhpdev;
BOOL rc = TRUE;
RECTFX rectfxTrg;
RECT rectDst;
BOOL fMore = TRUE;
PATHDATA pathData;
POINT startPoint;
POINT nextPoint;
POINT endPoint;
BOOL fAccumulate = FALSE;
UINT i;
DebugEntry(DrvStrokePath);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
PATHOBJ_vGetBounds(ppo, &rectfxTrg);
RECT_FROM_RECTFX(rectDst, rectfxTrg);
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(pso, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Check if we are allowed to send this order (determined by the
// negotiated capabilities of all the machines in the conference).
//
if (!OE_SendAsOrder(ORD_LINETO))
{
TRACE_OUT(( "LineTo order not allowed"));
DC_QUIT;
}
//
// Check for a valid brush for the test operation.
//
if (pbo->iSolidColor == -1)
{
TRACE_OUT(( "Bad brush for line"));
DC_QUIT;
}
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// See if we can optimize the path...
//
// We cannot send:
//
// - curvy lines (i.e. beziers)
// - lines with funny end patterns (i.e. geometric lines)
// - non Windows standard patterns
//
if ( ((ppo->fl & PO_BEZIERS) == 0) &&
((plineattrs->fl & LA_GEOMETRIC) == 0) &&
(plineattrs->pstyle == NULL) )
{
//
// This is a set of solid cosmetic (i.e. no fancy end styles)
// lines. Let's send those orders.
//
// NT stores all paths as a set of independent sub-paths. Each
// sub-path can start at a new point that is NOT linked to the
// previous sub-path.
//
// Paths used for this function (as opposed to DrvFillPath or
// DrvStrokeAndFillPath) do not need to be closed.
//
PATHOBJ_vEnumStart(ppo);
while (fMore)
{
//
// Get the next set of lines
//
fMore = PATHOBJ_bEnum(ppo, &pathData);
TRACE_OUT(( "PTS: %lu FLAG: %08lx",
pathData.count,
pathData.flags));
//
// If this is the start of a path, remember the point in case
// we need to close the path at the end.
//
if (pathData.flags & PD_BEGINSUBPATH)
{
POINT_FROM_POINTFIX(startPoint, pathData.pptfx[0]);
POINT_FROM_POINTFIX(nextPoint, pathData.pptfx[0]);
}
//
// Generate orders for each line in the path.
//
for (i = 0; i < pathData.count; i++)
{
POINT_FROM_POINTFIX(endPoint, pathData.pptfx[i]);
if ( (nextPoint.x != endPoint.x) ||
(nextPoint.y != endPoint.y) )
{
if (!OEAddLine(ppdev,
&nextPoint,
&endPoint,
&rectDst,
mix & 0x1f,
plineattrs->elWidth.l,
pbo->iSolidColor,
pco))
{
DC_QUIT;
}
}
nextPoint.x = endPoint.x;
nextPoint.y = endPoint.y;
}
//
// Close the path if necessary.
//
if ((pathData.flags & PD_CLOSEFIGURE) != 0)
{
if (!OEAddLine(ppdev,
&endPoint,
&startPoint,
&rectDst,
mix & 0x1f,
plineattrs->elWidth.l,
pbo->iSolidColor,
pco))
{
DC_QUIT;
}
}
}
//
// We have processed the entire thing as orders - don't send screen
// data.
//
fAccumulate = FALSE;
}
DC_EXIT_POINT:
if (fAccumulate)
{
//
// Convert the bounds to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
TRACE_OUT(( "SDA: (%d,%d)(%d,%d)",
rectDst.left,
rectDst.top,
rectDst.right,
rectDst.bottom));
//
// Update the Screen Data Area
//
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvStrokePath, rc);
return(rc);
}
//
// DrvFillPath - see NT DDK documentation.
//
BOOL DrvFillPath(SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix,
FLONG flOptions)
{
BOOL rc = TRUE;
RECTFX rectfxTrg;
RECT rectDst;
DebugEntry(DrvFillPath);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
PATHOBJ_vGetBounds(ppo, &rectfxTrg);
RECT_FROM_RECTFX(rectDst, rectfxTrg);
//
// Check if we are accumulating data for this function
//
if (!OEAccumulateOutput(pso, pco, &rectDst))
{
DC_QUIT;
}
//
// Convert the bounds to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
TRACE_OUT(( "SDA: (%d,%d)(%d,%d)",
rectDst.left,
rectDst.top,
rectDst.right,
rectDst.bottom));
//
// Update the Screen Data Area
//
OEClipAndAddScreenData(&rectDst, pco);
DC_EXIT_POINT:
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvFillPath, rc);
return(rc);
}
//
// DrvStrokeAndFillPath - see NT DDK documentation.
//
BOOL DrvStrokeAndFillPath(SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
XFORMOBJ *pxo,
BRUSHOBJ *pboStroke,
LINEATTRS *plineattrs,
BRUSHOBJ *pboFill,
POINTL *pptlBrushOrg,
MIX mixFill,
FLONG flOptions)
{
BOOL rc = TRUE;
RECTFX rectfxTrg;
RECT rectDst;
DebugEntry(DrvStrokeAndFillPath);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
PATHOBJ_vGetBounds(ppo, &rectfxTrg);
RECT_FROM_RECTFX(rectDst, rectfxTrg);
//
// Check if we are accumulating data for this function
//
if (!OEAccumulateOutput(pso, pco, &rectDst))
{
DC_QUIT;
}
//
// Convert the bounds to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
//
// Update the Screen Data Area
//
OEClipAndAddScreenData(&rectDst, pco);
DC_EXIT_POINT:
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvStrokeAndFillPath, rc);
return(rc);
}
//
// DrvPaint - see NT DDK documentation.
//
BOOL DrvPaint(SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix)
{
BOOL rc = TRUE;
RECT rectDst;
BOOL fAccumulate = FALSE;
ROP4 rop4;
DebugEntry(DrvPaint);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectDst, pco->rclBounds);
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(pso, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
//
// Check for overcomplicated clipping.
//
if (OEClippingIsComplex(pco))
{
TRACE_OUT(( "Clipping is too complex"));
DC_QUIT;
}
//
// The low byte of the mix represents a ROP2. We need a ROP4 for
// BitBlt, so convert the mix as follows.
//
// Remember the definitions of 2, 3 & 4 way ROP codes.
//
// Msk Pat Src Dst
//
// 1 1 1 1 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͸<EFBFBD><CDB8><EFBFBD><EFBFBD><EFBFBD>ͻ ROP2 uses P & D only
// 1 1 1 0 <20> <20>
// 1 1 0 1 Ŀ <20> <20> ROP3 uses P, S & D
// 1 1 0 0 <20>ROP2-1<>ROP3 <20>ROP4
// 1 0 1 1 <20>(see <20> <20> ROP4 uses M, P, S & D
// 1 0 1 0 <20><> note)<29> <20>
// 1 0 0 1 <20> <20>
// 1 0 0 0 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>; <20>
// 0 1 1 1 <20>
// 0 1 1 0 <20> NOTE: Windows defines its
// 0 1 0 1 <20> ROP2 codes as the bitwise
// 0 1 0 0 <20> value calculated here
// 0 0 1 1 <20> plus one. All other ROP
// 0 0 1 0 <20> codes are the straight
// 0 0 0 1 <20> bitwise value.
// 0 0 0 0 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
//
// Or, algorithmically...
//
// ROP3 = (ROP2 & 0x3) | ((ROP2 & 0xC) << 4) | (ROP2 << 2)
//
// ROP4 = (ROP3 << 8) | ROP3
//
mix = (mix & 0x1F) - 1;
rop4 = (mix & 0x3) | ((mix & 0xC) << 4) | (mix << 2);
rop4 = (rop4 << 8) | rop4;
//
// This can be passed on to the BitBlt code.
//
rc = DrvBitBlt( pso,
NULL,
NULL,
pco,
NULL,
&pco->rclBounds,
NULL,
NULL,
pbo,
pptlBrushOrg,
rop4 );
//
// We have stored this object in the BitBlt, so don't store the data
// again.
//
fAccumulate = FALSE;
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitDWORD(DrvPaint, rc);
return(rc);
}
//
// OE_DDProcessRequest - see oe.h
//
ULONG OE_DDProcessRequest
(
SURFOBJ* pso,
UINT cjIn,
void * pvIn,
UINT cjOut,
void * pvOut
)
{
BOOL rc = TRUE;
LPOSI_ESCAPE_HEADER pHeader;
DebugEntry(OE_DDProcessRequest);
//
// Get the request number.
//
pHeader = pvIn;
switch (pHeader->escapeFn)
{
case OE_ESC_NEW_FONTS:
{
if ((cjIn != sizeof(OE_NEW_FONTS)) ||
(cjOut != sizeof(OE_NEW_FONTS)))
{
ERROR_OUT(("OE_DDProcessRequest: Invalid sizes %d, %d for OE_ESC_NEW_FONTS",
cjIn, cjOut));
rc = FALSE;
DC_QUIT;
}
//
// Get new local font data
//
OEDDSetNewFonts(pvIn);
}
break;
case OE_ESC_NEW_CAPABILITIES:
{
if ((cjIn != sizeof(OE_NEW_CAPABILITIES)) ||
(cjOut != sizeof(OE_NEW_CAPABILITIES)))
{
ERROR_OUT(("OE_DDProcessRequest: Invalid sizes %d, %d for OE_ESC_NEW_CAPABILITIES",
cjIn, cjOut));
rc = FALSE;
DC_QUIT;
}
//
// The capabilities have changed - take the new copy.
//
OEDDSetNewCapabilities(pvIn);
}
break;
default:
{
ERROR_OUT(("Unrecognised OE escape"));
rc = FALSE;
}
break;
}
DC_EXIT_POINT:
DebugExitDWORD(OE_DDProcessRequest, rc);
return((ULONG)rc);
}
//
// OE_DDTerm()
// This cleans up objects used
//
void OE_DDTerm(void)
{
DebugEntry(OE_DDTerm);
//
// Free font list
//
if (g_poeLocalFonts)
{
TRACE_OUT(("OE_DDLocalHosting: freeing font block since we're done sharing"));
EngFreeMem(g_poeLocalFonts);
g_poeLocalFonts = NULL;
g_oeNumFonts = 0;
}
DebugExitVOID(OE_DDTerm);
}
//
// DrvRealizeBrush - see NT DDK documentation.
//
BOOL DrvRealizeBrush(BRUSHOBJ *pbo,
SURFOBJ *psoTarget,
SURFOBJ *psoPattern,
SURFOBJ *psoMask,
XLATEOBJ *pxlo,
ULONG iHatch)
{
LPOSI_PDEV ppdev = (LPOSI_PDEV)psoTarget->dhpdev;
BOOL rc = TRUE;
LPBYTE pData;
BYTE brushBits[8];
UINT color1;
UINT color2;
int i;
int j;
BOOL monochromeBrush = TRUE;
DebugEntry(DrvRealizeBrush);
//
// This function only sets up local data, so shared memory protection
// is not required.
//
//
// Since this function is called only when we call BRUSHOBJ_pvGetRBrush
// and we don't do any processing until we are in a share we don't need
// an explicit check for hosting here ('coz that happened before the
// call to realise the brush).
//
//
// A valid brush satisfies either of the following criteria.
//
// 1) It is a standard hatch brush (as passed by DrvEnablePDEV)
// 2) It is an 8x8 monochrome bitmap
//
//
// Check for a Windows standard hatch
//
if (iHatch < HS_DDI_MAX)
{
TRACE_OUT(( "Standard hatch %lu", iHatch));
rc = OEStoreBrush(ppdev,
pbo,
BS_HATCHED,
NULL,
pxlo,
(BYTE)iHatch,
0,
1);
DC_QUIT;
}
//
// If the driver has been passed a dither color brush we can support
// this by sending a solid color brush definition
//
if ((iHatch & RB_DITHERCOLOR) != 0)
{
TRACE_OUT(( "Standard hatch %lu", iHatch));
rc = OEStoreBrush(ppdev,
pbo,
BS_SOLID,
NULL,
NULL,
(BYTE)iHatch,
iHatch & 0xFFFFFF,
0);
DC_QUIT;
}
//
// Check for a simple 8x8 brush
//
if ( (psoPattern->sizlBitmap.cx == 8) &&
(psoPattern->sizlBitmap.cy == 8) )
{
//
// Check for 2 colours only in the bitmap.
//
// NOTE: There's a flag (BMF_TOPDOWN) in psoPattern->fjBitmap
// that's supposed to indicate whether the bitmap is top-down or
// bottom-up, but it is not always set up correctly. In fact, the
// bitmaps are always the wrong way up for our protocol, so we have
// to flip them regardless of the flag. Hence the row numbers are
// reversed ('i' loops) in all the conversions below.
//
pData = psoPattern->pvScan0;
switch (psoPattern->iBitmapFormat)
{
case BMF_1BPP:
{
//
// 1 bpp MUST be 2 colours maximum.
//
color1 = 1;
color2 = 0;
for (i = 7; i >= 0; i--)
{
brushBits[i] = *pData;
pData += psoPattern->lDelta;
}
}
break;
case BMF_4BPP:
{
//
// See if it is really a 2 colour brush. Start off with
// both colours the same.
//
color1 = pData[0] & 15;
color2 = color1;
//
// Iterate through each row of the bitmap.
//
for (i = 7; (i >= 0) && (monochromeBrush); i--)
{
brushBits[i] = 0;
//
// Check each pixel in the row: 4bpp->2 pixels per byte
//
for (j = 0; (j < 4) && (monochromeBrush); j++)
{
//
// Check the 1st pixel color
//
if ( (color1 != (UINT)(pData[j] & 0x0F)) &&
(color2 != (UINT)(pData[j] & 0x0F)) )
{
if (color1 == color2)
{
color2 = (pData[j] & 0x0F);
}
else
{
monochromeBrush = FALSE;
}
}
//
// Check the 2nd pixel color
//
if ( (color1 != (UINT)((pData[j] & 0xF0) >> 4)) &&
(color2 != (UINT)((pData[j] & 0xF0) >> 4)) )
{
if (color1 == color2)
{
color2 = (pData[j] & 0xF0) >> 4;
}
else
{
monochromeBrush = FALSE;
}
}
//
// Set up the brush data. High bit is leftmost.
//
if ((UINT)(pData[j] & 0x0F) == color1)
{
brushBits[i] |= 0x40 >> (j * 2);
}
if ((UINT)(pData[j] & 0xF0) >> 4 == color1)
{
brushBits[i] |= 0x80 >> (j * 2);
}
}
//
// Get start of next row.
//
pData += psoPattern->lDelta;
}
}
break;
case BMF_8BPP:
{
//
// See if it is really a 2 colour brush. Start off with
// both colours the same.
//
color1 = pData[0];
color2 = color1;
//
// Iterate through each row of the bitmap.
//
for (i = 7; (i >= 0) && (monochromeBrush); i--)
{
brushBits[i] = 0;
//
// Check each pixel in the row: 8bpp->1 pixel per byte
//
for (j = 0; (j < 8) && (monochromeBrush); j++)
{
//
// Check each pixel.
//
if ( (color1 != pData[j]) &&
(color2 != pData[j]) )
{
if (color1 == color2)
{
color2 = pData[j];
}
else
{
monochromeBrush = FALSE;
}
}
//
// Update the brush data. High bit is leftmost.
//
if (pData[j] == color1)
{
brushBits[i] |= 0x80 >> j;
}
}
//
// Get start of next row.
//
pData += psoPattern->lDelta;
}
}
break;
default:
{
//
// Unsupported colour depth.
//
monochromeBrush = FALSE;
}
break;
}
}
else
{
//
// The brush is the wrong size or requires dithering and so cannot
// be sent over the wire.
//
monochromeBrush = FALSE;
}
//
// Store that brush.
//
if (monochromeBrush)
{
//
// Store the brush - note that we have a monochrome brush where the
// color bit is set up so that 0 = color2 and 1 = color1. This
// actually corresponds to 0 = fg and 1 = bg for the protocol
// colors.
//
TRACE_OUT(( "Storing brush: type %d bg %x fg %x",
psoPattern->iBitmapFormat,
color1,
color2));
rc = OEStoreBrush(ppdev,
pbo,
BS_PATTERN,
brushBits,
pxlo,
0,
color2,
color1);
}
else
{
TRACE_OUT(( "Rejected brush h %08lx s (%ld, %ld) fmt %lu",
iHatch,
psoPattern != NULL ? psoPattern->sizlBitmap.cx : 0,
psoPattern != NULL ? psoPattern->sizlBitmap.cy : 0,
psoPattern != NULL ? psoPattern->iBitmapFormat : 0));
rc = OEStoreBrush(ppdev, pbo, BS_NULL, NULL, pxlo, 0, 0, 0);
}
DC_EXIT_POINT:
DebugExitDWORD(DrvRealizeBrush, rc);
return(rc);
}
//
// DrvSaveScreenBits - see NT DDK documentation.
//
ULONG_PTR DrvSaveScreenBits(SURFOBJ *pso,
ULONG iMode,
ULONG_PTR ident,
RECTL *prcl)
{
BOOL rc;
UINT ourMode;
RECT rectDst;
DebugEntry(DrvSaveScreenBits);
TRACE_OUT(("DrvSaveScreenBits: %s",
((iMode == SS_SAVE) ? "SAVE" :
((iMode == SS_RESTORE) ? "RESTORE" : "DISCARD"))));
TRACE_OUT((" rect {%04ld, %04ld, %04ld, %04ld}",
prcl->left, prcl->top, prcl->right, prcl->bottom));
//
// Default is TRUE, let SaveBits happen if we don't care. Which we don't
// if we have no shared memory (NetMeeting isn't running), no window list
// (no shared apps), or the operation isn't intersecting a window we
// care about.
//
// Note that if we return TRUE on a save, and FALSE on a restore later
// (because we are now sharing that area for example), USER+GRE handle
// that. So it's ok.
//
rc = TRUE;
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
//
// If we have no shared memory (NetMeeting isn't running), this will bail
// out immediately.
//
OE_SHM_START_WRITING;
//
// Get the bounding rectangle for the operation. NOTE that this is
// meaningless for SS_FREE.
//
RECT_FROM_RECTL(rectDst, (*prcl));
if (iMode != SS_FREE)
{
//
// Check if we are accumulating data for this area, ONLY FOR
// SAVEs. We may get notified after a window is gone to
// restore or discard bits we had saved.
//
if (!OEAccumulateOutputRect(pso, &rectDst))
{
TRACE_OUT(("DrvSaveScreenBits: save/restore in area we don't care about"));
DC_QUIT;
}
}
//
// Convert the NT orders to our generic save/restore types.
//
switch (iMode)
{
case SS_SAVE:
{
ourMode = ONBOARD_SAVE;
}
break;
case SS_RESTORE:
{
ourMode = ONBOARD_RESTORE;
}
break;
case SS_FREE:
{
ourMode = ONBOARD_DISCARD;
}
break;
default:
{
ERROR_OUT(( "Unknown type %lu", iMode));
DC_QUIT;
}
}
//
// Call through to the SSI handler.
//
rc = SSI_SaveScreenBitmap(&rectDst, ourMode);
DC_EXIT_POINT:
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
TRACE_OUT(("DrvSaveScreenBits returning %d", rc));
DebugExitDWORD(DrvSaveScreenBits, rc);
return(rc);
}
//
// Function: OEUnicodeStrlen
//
// Description: Get the length of a unicode string in bytes.
//
// Parameters: pString - Unicode string to be read
//
// Returns: Length of the Unicode string in bytes
//
int OEUnicodeStrlen(PWSTR pString)
{
int i;
for (i = 0; pString[i] != 0; i++)
;
return((i + 1) * sizeof(WCHAR));
}
//
// 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,
ULONG srcColor,
ULONG mask
)
{
ULONG 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, *lpField));
DebugExitVOID(OEExpandColor);
}
//
// Function: OEConvertColor
//
// Description: Convert a color from the NT Display Driver into a TSHR_COLOR
//
// Parameters: pDCColor - (returned) color in protocol format
// osColor - color from the NT display driver
// pxlo - XLATEOBJ for the color to be converted
// (NULL if no translation is required)
//
// Returns: (none)
//
void OEConvertColor(LPOSI_PDEV ppdev, LPTSHR_COLOR pTshrColor,
ULONG osColor,
XLATEOBJ* pxlo)
{
ULONG realIndex;
DebugEntry(OEConvertColor);
//
// Make sure we have a default setting.
//
RtlFillMemory(pTshrColor, sizeof(TSHR_COLOR), 0);
//
// Check if color translation is required.
//
if ((pxlo != NULL) && (pxlo->flXlate != XO_TRIVIAL))
{
//
// Convert from BMP to device color.
//
realIndex = XLATEOBJ_iXlate(pxlo, osColor);
if (realIndex == -1)
{
ERROR_OUT(( "Failed to convert color 0x%lx", osColor));
DC_QUIT;
}
}
else
{
//
// Use the OS color without translation
//
realIndex = osColor;
}
TRACE_OUT(( "Device color 0x%lX", realIndex));
//
// We now have the device specific version of the color. Time to
// convert it into a 24-bit RGB color as used by the line protocol.
//
switch (ppdev->iBitmapFormat)
{
case BMF_1BPP:
case BMF_4BPP:
case BMF_4RLE:
case BMF_8BPP:
case BMF_8RLE:
//
// Palette type device - use the device color as an index into
// our palette array.
//
pTshrColor->red = (BYTE)ppdev->pPal[realIndex].peRed;
pTshrColor->green= (BYTE)ppdev->pPal[realIndex].peGreen;
pTshrColor->blue = (BYTE)ppdev->pPal[realIndex].peBlue;
break;
case BMF_16BPP:
case BMF_24BPP:
case BMF_32BPP:
//
// Generic colour masks (could be eg. 5-6-5 for 16 or 8-8-8
// for 24 bits per pel). We must mask off the other bits and
// shift down to bit 0.
//
OEExpandColor(&(pTshrColor->red),
realIndex,
ppdev->flRed);
OEExpandColor(&(pTshrColor->green),
realIndex,
ppdev->flGreen);
OEExpandColor(&(pTshrColor->blue),
realIndex,
ppdev->flBlue);
break;
default:
ERROR_OUT(( "Unrecognised BMP color depth %lu",
ppdev->iBitmapFormat));
break;
}
TRACE_OUT(( "Red %x green %x blue %x", pTshrColor->red,
pTshrColor->green,
pTshrColor->blue));
DC_EXIT_POINT:
DebugExitVOID(OEConvertColor);
}
//
// Function: OEStoreBrush
//
// Description: Store the brush data required for pattern realted orders.
// This function is called by DrvRealiseBrush when it has data
// to be stored about a brush.
//
// Parameters: pbo - BRUSHOBJ of the brush to be stored
// style - Style of the brush (as defined in the DC-Share
// protocol)
// pBits - Pointer to the bits which are used to define
// a BS_PATTERN brush.
// pxlo - XLATEOBJ for the brush.
// hatch - Standard Windows hatch pattern index for a
// BS_HATCHED brush.
// color1 - index into XLATEOBJ for bit set color
// OR exact 24bpp color to use (pxlo == NULL)
// color2 - index into XLATEOBJ for bit clear color
// OR exact 24bpp color to use (pxlo == NULL)
//
// Returns: (none)
//
BOOL OEStoreBrush(LPOSI_PDEV ppdev,
BRUSHOBJ* pbo,
BYTE style,
LPBYTE pBits,
XLATEOBJ* pxlo,
BYTE hatch,
UINT color1,
UINT color2)
{
BOOL rc = FALSE;
int i;
LPBYTE pData;
ULONG* pColorTable;
POE_BRUSH_DATA pBrush;
DebugEntry(OEStoreBrush);
//
// Allocate the space for the brush data.
//
pBrush = (POE_BRUSH_DATA)BRUSHOBJ_pvAllocRbrush(pbo,
sizeof(OE_BRUSH_DATA));
if (pBrush == NULL)
{
ERROR_OUT(( "No memory"));
DC_QUIT;
}
//
// Reset the brush definition
//
RtlFillMemory(pBrush, sizeof(OE_BRUSH_DATA), 0);
//
// Set the new brush data.
//
pBrush->style = style;
pBrush->hatch = hatch;
TRACE_OUT(( " Style: %d Hatch: %d", style, hatch));
//
// For pattern brushes, copy the brush specific data.
//
if (style == BS_PATTERN)
{
//
// Copy the brush bits. Since this is an 8x8 mono bitmap, we can
// copy the first byte of the brush data for each scan line.
//
// NOTE however that the brush structures sent over the wire
// re-use the hatching variable as the first byte of the brush data.
//
pData = pBits;
pBrush->hatch = *pData;
TRACE_OUT(( " Hatch: %d", *pData));
pData++;
for (i = 0; i < 7; i++)
{
pBrush->brushData[i] = pData[i];
TRACE_OUT(( " Data[%d]: %d", i, pData[i]));
}
//
// Get pointer to the bitmap color table.
//
pColorTable = pxlo->pulXlate;
if (pColorTable == NULL)
{
pColorTable = XLATEOBJ_piVector(pxlo);
}
}
//
// Store the foreground and background colours for the brush.
//
if (pxlo != NULL)
{
//
// Conversion required.
//
OEConvertColor(ppdev,
&pBrush->fore,
color1,
pxlo);
OEConvertColor(ppdev,
&pBrush->back,
color2,
pxlo);
}
else
{
//
// We have been passed an exact 24bpp color - this only happens for
// solid brushes so we don't need to convert color2.
//
pBrush->fore.red = (BYTE) (color1 & 0x0000FF);
pBrush->fore.green = (BYTE)((color1 & 0x00FF00) >> 8);
pBrush->fore.blue = (BYTE)((color1 & 0xFF0000) >> 16);
}
rc = TRUE;
DC_EXIT_POINT:
DebugExitDWORD(OEStoreBrush, rc);
return(rc);
}
//
// Function: OECheckBrushIsSimple
//
// Description: Check that the brush is a 'simple' object we can transfer
// over the DC-Share protocol.
//
// Parameters: pbo - BRUSHOBJ of the brush to be checked.
//
// Returns: TRUE - brush can be sent as DC-Share order
// FALSE - brush is too complicated.
//
BOOL OECheckBrushIsSimple(LPOSI_PDEV ppdev,
BRUSHOBJ* pbo,
POE_BRUSH_DATA* ppBrush)
{
BOOL rc = FALSE;
POE_BRUSH_DATA pBrush = NULL;
DebugEntry(OECheckBrushIsSimple);
//
// A 'simple' brush satisfies any of the following.
//
// 1) It is a solid color.
// 2) It is a valid brush as stored by DrvRealizeBrush.
//
//
// Check for a simple solid colour.
//
if (pbo->iSolidColor != -1)
{
//
// Use the reserved brush definition to set up the solid colour.
//
TRACE_OUT(( "Simple solid colour %08lx", pbo->iSolidColor));
pBrush = &g_oeBrushData;
//
// Set up the specific data for this brush.
//
OEConvertColor(ppdev, &pBrush->fore, pbo->iSolidColor, NULL);
pBrush->back.red = 0;
pBrush->back.green = 0;
pBrush->back.blue = 0;
pBrush->style = BS_SOLID;
pBrush->hatch = 0;
RtlFillMemory(pBrush->brushData, 7, 0);
//
// We have a valid brush - return true.
//
rc = TRUE;
DC_QUIT;
}
//
// Check brush definition (which was stored when we realized the
// brush).
//
pBrush = (POE_BRUSH_DATA)pbo->pvRbrush;
if (pBrush == NULL)
{
pBrush = (POE_BRUSH_DATA)BRUSHOBJ_pvGetRbrush(pbo);
if (pBrush == NULL)
{
//
// We can get NULL returned from BRUSHOBJ_pvGetRbrush when the
// brush is NULL or in low-memory situations (when the brush
// realization may fail).
//
TRACE_OUT(( "NULL returned from BRUSHOBJ_pvGetRbrush"));
DC_QUIT;
}
}
//
// Check it is an encodable brush.
//
if (pBrush->style == BS_NULL)
{
TRACE_OUT(( "Complex brush"));
DC_QUIT;
}
//
// Evrything passed - let's use this brush.
//
rc = TRUE;
DC_EXIT_POINT:
//
// Return the brush definition
//
*ppBrush = pBrush;
TRACE_OUT(( "Returning %d - 0x%08lx", rc, pBrush));
DebugExitDWORD(OECheckBrushIsSimple, rc);
return(rc);
}
//
// Function: OEClippingIsSimple
//
// Description: Check to see if the clipping on the graphics object is
// trivial
//
// Parameters: pco - CLIPOBJ of the graphics object to be checked.
//
// Returns: TRUE - Clipping is trivial
// FALSE - Clipping is complex
//
BOOL OEClippingIsSimple(CLIPOBJ* pco)
{
BOOL rc = TRUE;
DebugEntry(OEClippingIsSimple);
//
// Check for a valid clip object
//
if (pco == NULL)
{
TRACE_OUT(( "No clipobj"));
DC_QUIT;
}
//
// Check for complexity of clipping
//
switch (pco->iDComplexity)
{
case DC_TRIVIAL:
case DC_RECT:
//
// Trivial (ignore clipping) or simple (one square) clipping -
// no worries.
//
TRACE_OUT(( "Simple clipping"));
DC_QUIT;
default:
TRACE_OUT(( "Clipping is complex"));
break;
}
//
// Failed all tests - must be too complicated.
//
rc = FALSE;
DC_EXIT_POINT:
DebugExitDWORD(OEClippingIsSimple, rc);
return(rc);
}
//
// Function: OEClippingIsComplex
//
// Description: Check to see if the clipping on the graphics object is too
// complicated to be sent as an order or multiple orders.
//
// Parameters: pco - CLIPOBJ of the graphics object to be checked.
//
// Returns: TRUE - Clipping is too complicated
// FALSE - Clipping is sufficiently simple to send as orders
//
BOOL OEClippingIsComplex(CLIPOBJ* pco)
{
BOOL rc = FALSE;
BOOL fMoreRects;
OE_ENUMRECTS clip;
UINT numRects = 0;
DebugEntry(OEClippingIsComplex);
//
// If the any of the following are true, the clipping is not too
// complicated.
//
// 1) The clip object does not exist.
// 2) The clipping is trivial (the object exists, but there are no
// clipping rectangles).
// 3) The clipping is a single rectangle.
// 4) The object enumerates to less than 'n' rectangles.
//
//
// Check for a valid clip object
//
if (pco == NULL)
{
TRACE_OUT(( "No clipobj"));
DC_QUIT;
}
//
// Check for complexity of clipping
//
switch (pco->iDComplexity)
{
case DC_TRIVIAL:
case DC_RECT:
//
// Trivial or simple clipping - no worries.
//
TRACE_OUT(( "Simple clipping"));
DC_QUIT;
case DC_COMPLEX:
//
// Lots of rectangles - make sure that it is less than the
// acceptable limit.
// The documentation for this function incorrectly states that
// the returned value is the total number of rectangles
// comprising the clip region. In fact, -1 is always returned,
// even when the final parameter is non-zero. This means we
// have to enumerate to get the number of rects.
//
CLIPOBJ_cEnumStart(pco,
FALSE,
CT_RECTANGLES,
CD_ANY,
0);
//
// MSDN: It is possible for CLIPOBJ_bEnum to return TRUE with
// the number of clipping rectangles equal to zero. In such
// cases, the driver should call CLIPOBJ_bEnum again without
// taking any action. Get as many rectangles as we permit for
// order encoding - this loop should execute once only.
// If the number of rects equals COMPLEX_CLIP_RECT_COUNT the
// 1st invocation of CLIPOBJ_bEnum returns that there are more
// rects and a second call returns there are no more without
// returning any in addition to those returned on the first
// call. Our buffer has space for COMPLEX_CLIP_RECT_COUNT+1
// rects so we should never have to execute the loop more than
// once.
//
do
{
fMoreRects = CLIPOBJ_bEnum(pco,
sizeof(clip),
(ULONG *)&clip.rects);
numRects += clip.rects.c;
} while ( fMoreRects && (numRects <= COMPLEX_CLIP_RECT_COUNT) );
//
// If there are no more rectangles in the clip region then the
// clipping complexity is within our limits for order encoding.
//
if ( numRects <= COMPLEX_CLIP_RECT_COUNT )
{
TRACE_OUT(( "Acceptable clipping %u", numRects));
DC_QUIT;
}
break;
default:
ERROR_OUT(( "Unknown clipping"));
break;
}
//
// Failed all tests - must be too complicated.
//
TRACE_OUT(( "Complex clipping"));
rc = TRUE;
DC_EXIT_POINT:
DebugExitDWORD(OEClippingIsComplex, rc);
return(rc);
}
//
// Function: OEAccumulateOutput
//
// Description: Check to see if we should accumulate this output for
// sending to the remote machine.
//
// Parameters: pso - Pointer to the target surface
// pco - Pointer to the clip object (may be NULL)
// pRect - Pointer to the bounding rectangle of the operation
//
// Returns: TRUE - We should accumulate the output
// FALSE - ignore the output
//
BOOL OEAccumulateOutput(SURFOBJ* pso, CLIPOBJ *pco, LPRECT pRect)
{
BOOL rc = FALSE;
LPOSI_PDEV ppdev = ((LPOSI_PDEV)pso->dhpdev);
DebugEntry(OEAccumulateOutput);
//
// Validate we have valid parameters to access the surface.
//
if (ppdev == NULL)
{
TRACE_OUT(( "NULL PDEV"));
DC_QUIT;
}
//
// Check for the screen surface, which will be a bitmap in the hosting
// only code.
//
if (ppdev->hsurfScreen != pso->hsurf)
{
TRACE_OUT(( "Dest is not our surface"));
DC_QUIT;
}
if (pso->dhsurf == NULL)
{
ERROR_OUT(( "NULL hSurf"));
DC_QUIT;
}
rc = TRUE;
DC_EXIT_POINT:
DebugExitBOOL(OEAccumulateOutput, rc);
return(rc);
}
//
// Function: OEAccumulateOutputRect
//
// Description: Check to see if we should accumulate the given output rect
// for sending to the remote machine.
//
// Most drawing functions will use OEAccumulateOutput, which
// just checks for a single point within the hosted area.
// This function checks for any part of the given rectangle
// intersecting with the hosted area. It is currently only
// used by DrvSaveScreenBitmap - operations which may not
// lie completetely within the hosted area.
//
// Parameters: pso - Pointer to the target surface
// pRect - Pointer to the bounding rectangle of the operation
//
// Returns: TRUE - We should accumulate the output
// FALSE - ignore the output
//
BOOL OEAccumulateOutputRect( SURFOBJ* pso, LPRECT pRect)
{
BOOL rc = FALSE;
LPOSI_PDEV ppdev = ((LPOSI_PDEV)pso->dhpdev);
DebugEntry(OEAccumulateOutputRect);
//
// Validate we have valid parameters to access the surface.
//
if (ppdev == NULL)
{
TRACE_OUT(( "NULL PDEV"));
DC_QUIT;
}
//
// Check for the screen surface, which will be a bitmap in the hosting
// only code.
//
if (ppdev->hsurfScreen != pso->hsurf)
{
TRACE_OUT(( "Dest is not our surface"));
DC_QUIT;
}
if (pso->dhsurf == NULL)
{
ERROR_OUT(( "NULL hSurf"));
DC_QUIT;
}
//
// Check if we are accumulating this window.
//
rc = TRUE;
DC_EXIT_POINT:
TRACE_OUT(("OEAccumulateOutputRect: rect {%d, %d, %d, %d} is %sshared",
pRect->left, pRect->top, pRect->right, pRect->bottom,
(rc ? "" : "NOT ")));
DebugExitBOOL(OEAccumulateOutputRect, rc);
return(rc);
}
//
// Function: OESendRop3AsOrder
//
// Description: Check if we are allowed to send this 3-way ROP. A ROP may
// be disallowed if it relies on the destination data.
//
// Parameters: rop3 - the 3-way ROP to be checked.
//
// Returns: TRUE - We are allowed to send this ROP
// FALSE - We can't send this ROP
//
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)
{
TRACE_OUT(("Rop3 0x5F never encoded"));
rc = FALSE;
}
DebugExitBOOL(OESendRop3AsOrder, rc);
return(rc);
}
//
// Function: OECheckFontIsSupported
//
// Description: Check if we are allowed to send this font. Fonts are
// disallowed while they are being negotiated on a new entry
// to the share.
//
// Parameters: pfo - (IN) the font to be checked
// pFontText - (IN) text message to be sent
// textLen - (IN) length of text message
// pFontHeight - (OUT) font height in points
// pFontAscender - (OUT) font ascender in points
// pFontWidth - (OUT) ave font width in points
// pFontWeight - (OUT) font weight
// pFontFlags - (OUT) font style flags
// pFontIndex - (OUT) font table index
// pSendDeltaX - (OUT) Do we need to send delta X coords?
//
// Returns: TRUE - We are allowed to send this font
// FALSE - We can't send this font
//
BOOL OECheckFontIsSupported
(
FONTOBJ* pfo,
LPSTR pFontText,
UINT textLen,
LPUINT pFontHeight,
LPUINT pFontAscender,
LPUINT pFontWidth,
LPUINT pFontWeight,
LPUINT pFontFlags,
LPUINT pFontIndex,
LPBOOL pSendDeltaX
)
{
BOOL rc = FALSE;
PIFIMETRICS pFontMetrics;
UINT codePage;
UINT i;
UINT iLocal;
UINT matchQuality;
UINT charWidthAdjustment = 0;
char fontName[FH_FACESIZE];
ULONG fontNameLen;
PWSTR pUnicodeString;
XFORMOBJ* pxform;
POINTL xformSize[3];
int compareResult;
FLOATOBJ_XFORM xformFloatData;
DebugEntry(OECheckFontIsSupported);
//
// Set up default return values
//
*pSendDeltaX = FALSE;
//
// Check that we have a valid list of font data from the remotes.
//
if (!g_oeTextEnabled)
{
TRACE_OUT(( "Fonts unavailable"));
DC_QUIT;
}
//
// Check for valid font attributes
//
pFontMetrics = FONTOBJ_pifi(pfo);
if (pFontMetrics->fsSelection & FM_SEL_OUTLINED)
{
TRACE_OUT(( "Unsupported font style"));
DC_QUIT;
}
//
// The current protocol cannot apply a general 2-D transform to text
// orders, so we must reject any weird ones such as:
//
// - rotations
// - X or Y shears
// - X or Y reflections
// - scaling with a negative value.
//
// Or put another way, we only allow:
//
// - the identity transformation
// - scaling with a positive value.
//
pxform = FONTOBJ_pxoGetXform(pfo);
if (pxform != NULL)
{
//
// Get the details of the transformation. Note we can ignore the
// translation vector as it does not affect the font sizing /
// orientation, so we are only interested in the matrix values...
//
//
// NOTE: Do NOT use floating point explicitly!
// Can't do float ops in ring 0 with normal lib for x86.
// Use FLOATOBJs instead and corresponding Eng services.
// On alpha, these are macros and are way fast in any case.
//
if (XFORMOBJ_iGetFloatObjXform(pxform, &xformFloatData) != DDI_ERROR)
{
//
// Rotations and shears will have cross dependencies on the x
// and y components.
//
if ( (!FLOATOBJ_EqualLong(&xformFloatData.eM12, 0)) ||
(!FLOATOBJ_EqualLong(&xformFloatData.eM21, 0)) )
{
TRACE_OUT(( "Rejected rotn/shear"));
DC_QUIT;
}
//
// Reflections and scaling operations with negative scale
// factors will have negative values on the leading diagonal of
// the matrix.
//
if ( (FLOATOBJ_LessThanLong(&xformFloatData.eM11, 0)) ||
(FLOATOBJ_LessThanLong(&xformFloatData.eM22, 0)) )
{
TRACE_OUT(( "Rejected refln/-ive"));
DC_QUIT;
}
}
}
//
// Get the current font code page for font matching.
//
switch (pFontMetrics->jWinCharSet)
{
case ANSI_CHARSET:
TRACE_OUT(( "ANSI font"));
codePage = NF_CP_WIN_ANSI;
break;
case OEM_CHARSET:
TRACE_OUT(( "OEM font"));
codePage = NF_CP_WIN_OEM;
break;
case SYMBOL_CHARSET:
TRACE_OUT(("Symbol font"));
codePage = NF_CP_WIN_SYMBOL;
break;
default:
TRACE_OUT(( "Unknown CP %d", pFontMetrics->jWinCharSet));
codePage = NF_CP_UNKNOWN;
break;
}
//
// Get the name of the font.
//
pUnicodeString = (PWSTR)( (LPBYTE)pFontMetrics +
pFontMetrics->dpwszFamilyName );
EngUnicodeToMultiByteN(fontName,
sizeof(fontName),
&fontNameLen,
pUnicodeString,
OEUnicodeStrlen(pUnicodeString));
//
// Search our Font Alias Table for the current family name. If we find
// it, replace it with the alias name from the table.
//
for (i = 0; i < NUM_ALIAS_FONTS; i++)
{
if (!strcmp((LPSTR)fontName,
(LPSTR)(fontAliasTable[i].pszOriginalFontName)))
{
TRACE_OUT(( "Alias name: %s -> %s",
(LPSTR)fontName,
(LPSTR)(fontAliasTable[i].pszAliasFontName)));
strcpy((LPSTR)fontName,
(LPSTR)(fontAliasTable[i].pszAliasFontName));
charWidthAdjustment = fontAliasTable[i].charWidthAdjustment;
break;
}
}
TRACE_OUT(( "Font name: '%s'", fontName));
//
// 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 character as this font. If this index
// slot is empty (i.e. has a value of USHRT_MAX) then the loop will
// immediately exit
//
TRACE_OUT(( "Looking for matching fonts"));
for (iLocal = g_oeLocalFontIndex[(BYTE)fontName[0]];
iLocal < g_oeNumFonts;
iLocal++)
{
TRACE_OUT(( "Trying font number %hd", iLocal));
//
// If this font is not supported remotely then skip it.
//
ASSERT(g_poeLocalFonts);
matchQuality = g_poeLocalFonts[iLocal].SupportCode;
if (matchQuality == FH_SC_NO_MATCH)
{
continue;
}
//
// See if we've got a facename match
//
compareResult =
strcmp(g_poeLocalFonts[iLocal].Details.nfFaceName, fontName);
if (compareResult < 0)
{
//
// We haven't found a match yet, but we haven't gone far enough
// into this list.
//
continue;
}
else if (compareResult > 0)
{
//
// We're past the part of the local font array that's applicable.
// We didn't find a match, it must not exist.
//
break;
}
//
// The font names match. Now see if the other attributes do...
//
//
// This is looking promising - a font with the right name is
// supported on the remote system.
//
// Start building up the details in the global variables while
// making further checks...
//
*pFontFlags = 0;
*pFontIndex = iLocal;
*pFontWeight = pFontMetrics->usWinWeight;
//
// Check for a fixed pitch font.
//
if ((pFontMetrics->jWinPitchAndFamily & FIXED_PITCH) != 0)
{
*pFontFlags |= NF_FIXED_PITCH;
}
//
// Is it a TrueType font?
//
if ((pfo->flFontType & TRUETYPE_FONTTYPE) != 0)
{
*pFontFlags |= NF_TRUE_TYPE;
}
//
// Get the basic width and height.
//
xformSize[0].y = 0;
xformSize[0].x = 0;
xformSize[1].y = pFontMetrics->fwdUnitsPerEm;
xformSize[1].x = pFontMetrics->fwdAveCharWidth;
xformSize[2].y = pFontMetrics->fwdWinAscender;
xformSize[2].x = 0;
//
// We now need to convert these sizes if the GDI has provided a
// transform object.
//
if (pxform != NULL)
{
if (!XFORMOBJ_bApplyXform(pxform,
XF_LTOL,
3,
&xformSize,
&xformSize))
{
ERROR_OUT(( "Xform failed"));
continue;
}
}
//
// Calculate the font width and height.
//
*pFontHeight = (UINT)(xformSize[1].y - xformSize[0].y);
*pFontWidth = (UINT)(xformSize[1].x - xformSize[0].x
- charWidthAdjustment);
TRACE_OUT(( "Device font size %hdx%hd", *pFontWidth, *pFontHeight));
//
// Get the offset to the start of the text cell.
//
*pFontAscender = (UINT)(xformSize[2].y - xformSize[0].y);
//
// Check that we have a matching pair - where we require that the
// fonts (ie the one being used by the application and the one
// we've matched with the remote system) are the same pitch (ie
// variable or fixed) and use the same technology (ie TrueType or
// not).
//
if ((g_poeLocalFonts[iLocal].Details.nfFontFlags & NF_FIXED_PITCH) !=
((TSHR_UINT16)(*pFontFlags) & NF_FIXED_PITCH))
{
TRACE_OUT(( "Fixed pitch mismatch"));
continue;
}
if ((g_poeLocalFonts[iLocal].Details.nfFontFlags & NF_TRUE_TYPE) !=
((TSHR_UINT16)*pFontFlags & NF_TRUE_TYPE))
{
TRACE_OUT(( "True type mismatch"));
continue;
}
//
// We have a pair of fonts with the same attributes - either both
// fixed pitch or both variable pitch - and using the same font
// technology.
//
// If the font is fixed pitch then we must also check that this
// particular size matches.
//
// If the font is not fixed pitch (scalable) then we assume that it
// is 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(( "Size mismatch"));
continue;
}
}
//
// Hey! We've got a matched pair!
//
rc = TRUE;
TRACE_OUT(( "Found match at local font %hd", iLocal));
break;
}
if (rc != TRUE)
{
TRACE_OUT(( "Couldn't find matching font in table"));
DC_QUIT;
}
//
// Build up the rest of the font flags. We have already put the pitch
// flag in place.
//
if ( ((pFontMetrics->fsSelection & FM_SEL_ITALIC) != 0) ||
((pfo->flFontType & FO_SIM_ITALIC) != 0) )
{
TRACE_OUT(( "Italic"));
*pFontFlags |= NF_ITALIC;
}
if ((pFontMetrics->fsSelection & FM_SEL_UNDERSCORE) != 0)
{
TRACE_OUT(( "Underline"));
*pFontFlags |= NF_UNDERLINE;
}
if ((pFontMetrics->fsSelection & FM_SEL_STRIKEOUT) != 0)
{
TRACE_OUT(( "Strikeout"));
*pFontFlags |= NF_STRIKEOUT;
}
//
// 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;
}
//
// If the font is an exact match, or if it is an approximate match for
// its entire range (0x00 to 0xFF) then send it happily. If not...only
// send chars within the range 0x20->0x7F ("true ASCII").
//
ASSERT(g_poeLocalFonts);
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) )
{
//
// The approximate match is only valid if we use a font that
// supports the ANSI character set.
//
if ((pFontMetrics->jWinCharSet & ANSI_CHARSET) != 0)
{
TRACE_OUT(( "Cannot do match without ANSI support"));
DC_QUIT;
}
//
// This font is not a good match across its entire range. Check
// that all chars are within the desired range.
//
for (i = 0; i < textLen; i++)
{
if ( (pFontText[i] == 0) ||
( (pFontText[i] >= NF_ASCII_FIRST) &&
(pFontText[i] <= NF_ASCII_LAST) ) )
{
continue;
}
//
// Can only get here by finding a char outside our acceptable
// range.
//
TRACE_OUT(( "found non ASCII char %x", pFontText[i]));
DC_QUIT;
}
}
//
// We have a valid font. Now sort out delta X issues.
//
//
// If we do not need to send delta X arrays then exit now.
//
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 (textLen <= 1)
{
TRACE_OUT(( "String only %lu long", textLen));
DC_QUIT;
}
//
// Capabilities allow us to ignore delta X position if we have an exact
// match.
//
if ((matchQuality & FH_SC_EXACT) != 0)
{
//
// 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 have passed all the checks - we must send a delta X array.
//
TRACE_OUT(( "Must send delta X"));
*pSendDeltaX = TRUE;
DC_EXIT_POINT:
DebugExitDWORD(OECheckFontIsSupported, rc);
return(rc);
}
//
// Function: OELPtoVirtual
//
// Description: Adjusts window coordinates to virtual desktop coordinates.
// Clips the result to [+32766, -32768].
//
// Parameters: pPoints - Array of points to be converted
// cPoints - Number of points to be converted
//
// Returns: (none)
//
void OELPtoVirtual
(
LPPOINT aPts,
UINT cPts
)
{
int l;
TSHR_INT16 s;
DebugEntry(OELPtoVirtual);
//
// Convert to screen coordinates
//
while (cPts > 0)
{
//
// Look for int16 overflow in the X coordinate
//
l = aPts->x;
s = (TSHR_INT16)l;
if (l == (int)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 int16 overflow in the Y coordinate
//
l = aPts->y;
s = (TSHR_INT16)l;
if (l == (int)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);
}
//
// Function: OELRtoVirtual
//
// Description: Adjusts RECT in window coordinates to virtual coordinates.
// Clips the result to [+32766, -32768].
//
// Parameters: pRects - Array of rects to be converted
// numRects - Number of rects to be converted
//
// Returns: (none)
//
// NB. This function takes a Windows rectangle (exclusive coords) and
// returns a DC-Share rectangle (inclusive coords).
//
void OELRtoVirtual
(
LPRECT aRects,
UINT cRects
)
{
DebugEntry(OELRtoVirtual);
//
// Convert the points to screen coords, clipping to INT16s
//
OELPtoVirtual((LPPOINT)aRects, 2 * cRects);
//
// Make each rectangle inclusive
//
while (cRects > 0)
{
aRects->right--;
aRects->bottom--;
//
// Move on to the next rect
//
cRects--;
aRects++;
}
DebugExitVOID(OELRtoVirtual);
}
//
// Function: OEClipAndAddOrder
//
// Description: Adds the order to the order buffer, splitting it up into
// multiple orders if the clipping is complicated. If we fail
// to send the full order, we accumulate it in the SDA instead
//
// Parameters: pOrder - Order to be stored.
// pExtraInfo - Pointer to extra data associated with the
// order. This data depends on the order type,
// and may be NULL.
// pco - Clipping object for the area
//
// Returns: (none)
//
void OEClipAndAddOrder(LPINT_ORDER pOrder,
void * pExtraInfo,
CLIPOBJ* pco)
{
BOOL fOrderClipped;
BOOL fMoreRects;
RECT clippedRect;
RECT orderRect;
LPINT_ORDER pNewOrder;
LPINT_ORDER pLastOrder = NULL;
OE_ENUMRECTS clip;
UINT i;
UINT numRects = 0;
DebugEntry(OEClipAndAddOrder);
//
// Convert the order rectangle passed in (in virtual co-ordinates) back
// to screen co-ordinates. It is going to be clipped against clip
// rectangles returned to us in screen co-ordinates.
//
// Note that we also convert to exclusive coords here to make
// comparison with the exclusive Windows coords easier.
//
orderRect.left = pOrder->OrderHeader.Common.rcsDst.left;
orderRect.top = pOrder->OrderHeader.Common.rcsDst.top;
orderRect.right = pOrder->OrderHeader.Common.rcsDst.right + 1;
orderRect.bottom = pOrder->OrderHeader.Common.rcsDst.bottom + 1;
fOrderClipped = FALSE;
TRACE_OUT(( "orderRect: (%d,%d)(%d,%d)",
orderRect.left,
orderRect.top,
orderRect.right,
orderRect.bottom));
//
// Check if we have a clipping object at all.
//
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
//
// No clipping object - just use the bounds
//
clippedRect = orderRect;
fOrderClipped = TRUE;
pLastOrder = pOrder;
}
else if (pco->iDComplexity == DC_RECT)
{
//
// One clipping rectangle - use it directly.
//
RECT_FROM_RECTL(clippedRect, pco->rclBounds);
clippedRect.left = max(clippedRect.left, orderRect.left);
clippedRect.bottom = min(clippedRect.bottom, orderRect.bottom);
clippedRect.right = min(clippedRect.right, orderRect.right);
clippedRect.top = max(clippedRect.top, orderRect.top);
fOrderClipped = TRUE;
pLastOrder = pOrder;
}
else
{
//
// OA can only cope as long as the orders are added in the same
// order that they were allocated, so we need to do a little
// shuffling here.
//
// We always keep one order outstanding (pLastOrder) and a flag to
// indicate if it is valid (fOrderClipped). The first time we find
// a valid clipping rectangle, we set up pLastOrder and
// fOrderClipped. If we find we need to allocate a new order, we
// request the memory for the new order (pNewOrder), add pLastOrder
// and store pNewOrder in pLastOrder.
//
// Once we have finished enumerating the clipping rectangles, if
// pLastOrder is valid, we add it in.
//
// Also, while we are adding all these orders, OA must not purge
// the order heap otherwise we'll be left holding an invalid
// pointer.
//
pNewOrder = pOrder;
g_oaPurgeAllowed = FALSE;
//
// Multiple clipping rectangles - Enumerate all the rectangles
// involved in this drawing operation.
// The documentation for this function incorrectly states that
// the returned value is the total number of rectangles
// comprising the clip region. In fact, -1 is always returned,
// even when the final parameter is non-zero.
//
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
//
// Get the clip rectangles. We fetch these into the clip buffer
// which is big enough to get all the clip rectangles we expect + 1.
// If the order runs across this number of clip rects or more then
// we will already have decided to send it as screen data.
// The clip rectangle fetching is contained within a loop because,
// while we expect to call CLIPOBJ_bEnum once only, it is possible
// for this functio to return zero rects and report that there are
// more to fetch (according to MSDN).
//
do
{
fMoreRects = CLIPOBJ_bEnum(pco,
sizeof(clip),
(ULONG *)&clip.rects);
//
// The clipping object can decide that there are no more
// rectangles and that this query has returned no rectangles,
// so we must check for any valid data in the returned
// rectangle list.
//
if (clip.rects.c == 0)
{
//
// We didn't get any rects this time so go round again - if
// we're finished, the loop termination condition will take
// us out. CLIPOBJ_bEnum can return a count of zero when
// there are still more rects.
//
TRACE_OUT(( "No rects this time, more %u", fMoreRects));
continue;
}
//
// To get to here we expect to have fetched all the rects and
// no more. Do a quick check.
//
numRects += clip.rects.c;
ASSERT( (numRects <= COMPLEX_CLIP_RECT_COUNT) );
//
// Process each clip rectangle by clipping the drawing order to
// it.
//
for ( i = 0; i < clip.rects.c; i++ )
{
TRACE_OUT(( " (%d,%d)(%d,%d)",
clip.rects.arcl[i].left,
clip.rects.arcl[i].top,
clip.rects.arcl[i].right,
clip.rects.arcl[i].bottom));
//
// Check for an intersection
//
if ( (clip.rects.arcl[i].left >= orderRect.right) ||
(clip.rects.arcl[i].bottom <= orderRect.top) ||
(clip.rects.arcl[i].right <= orderRect.left) ||
(clip.rects.arcl[i].top >= orderRect.bottom) )
{
//
// No intersection, move on to next clip rect.
//
continue;
}
//
// There is an intersection, so we may need to add a new
// order to the buffer to cater for this rectangle.
//
if (fOrderClipped)
{
//
// The order has already been clipped once, so it
// actually intersects more than one clip rect, ie
// fOrderClipped is always FALSE for at least the first
// clip rectangle in the clip.rects buffer. 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(( "Order memory allocation failed" ));
goto CLIP_ORDER_FAILED;
}
//
// Copy the header & data from the original order to
// the new order (making sure that we don't overwrite
// the list information at the start of the header).
//
memcpy((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 destination (clip) rectangle (in virtual
// desktop coordinates).
//
TSHR_RECT16_FROM_RECT(
&pLastOrder->OrderHeader.Common.rcsDst,
clippedRect);
pLastOrder->OrderHeader.Common.rcsDst.right -= 1;
pLastOrder->OrderHeader.Common.rcsDst.bottom -= 1;
TRACE_OUT(( "Adding duplicate order (%d,%d) (%d,%d)",
pLastOrder->OrderHeader.Common.rcsDst.left,
pLastOrder->OrderHeader.Common.rcsDst.top,
pLastOrder->OrderHeader.Common.rcsDst.right,
pLastOrder->OrderHeader.Common.rcsDst.bottom));
//
// Add the order to the Order List.
//
OA_DDAddOrder(pLastOrder, pExtraInfo);
}
//
// Update the clipping rectangle for the order to be sent.
//
clippedRect.left = max(clip.rects.arcl[i].left,
orderRect.left);
clippedRect.bottom= min(clip.rects.arcl[i].bottom,
orderRect.bottom);
clippedRect.right = min(clip.rects.arcl[i].right,
orderRect.right);
clippedRect.top = max(clip.rects.arcl[i].top,
orderRect.top);
fOrderClipped = TRUE;
pLastOrder = pNewOrder;
}
} while (fMoreRects);
}
//
// Check whether the clipping has removed the order entirely.
//
if (fOrderClipped)
{
TSHR_RECT16_FROM_RECT(&pLastOrder->OrderHeader.Common.rcsDst,
clippedRect);
pLastOrder->OrderHeader.Common.rcsDst.right -= 1;
pLastOrder->OrderHeader.Common.rcsDst.bottom -= 1;
TRACE_OUT(( "Adding order (%d,%d) (%d,%d)",
pLastOrder->OrderHeader.Common.rcsDst.left,
pLastOrder->OrderHeader.Common.rcsDst.top,
pLastOrder->OrderHeader.Common.rcsDst.right,
pLastOrder->OrderHeader.Common.rcsDst.bottom));
//
// Add the order to the Order List.
//
OA_DDAddOrder(pLastOrder, pExtraInfo);
}
else
{
TRACE_OUT(( "Order clipped completely"));
OA_DDFreeOrderMem(pOrder);
}
DC_QUIT;
CLIP_ORDER_FAILED:
//
// Allocation of memory for a duplicate order failed. Just add the
// original order's destination rect into the SDA and free the order.
//
// The order rectangle is already in inclusive virtual coordinates.
//
TRACE_OUT(( "Order add failed, add to SDA"));
RECT_FROM_TSHR_RECT16(&orderRect,pLastOrder->OrderHeader.Common.rcsDst);
OA_DDFreeOrderMem(pLastOrder);
BA_AddScreenData(&orderRect);
DC_EXIT_POINT:
//
// Make sure that we always re-enable heap purging.
//
g_oaPurgeAllowed = TRUE;
DebugExitVOID(OEClipAndAddOrder);
}
//
// Function: OEClipAndAddScreenData
//
// Description: Determines if we need to accumulate any screen data for the
// specified area. If so, it is added to the SDA.
//
// Parameters: pRect - Bounding rectangle of area to be accumulated
// pco - Clipping object for the area
//
// Returns: (none)
//
void OEClipAndAddScreenData(LPRECT pRect, CLIPOBJ* pco)
{
RECT SDACandidate;
BOOL fMoreRects;
RECT clippedRect;
OE_ENUMRECTS clip;
UINT i;
DebugEntry(OEClipAndAddScreenData);
//
// Convert the order rectangle passed in (in virtual co-ordinates) back
// to screen co-ordinates. It is going to be clipped against clip
// rectangles returned to us in screen co-ordinates.
//
// Note that we also convert to exclusive coords here to make
// comparison with the exclusive Windows coords easier.
//
SDACandidate.left = pRect->left;
SDACandidate.top = pRect->top;
SDACandidate.right = pRect->right + 1;
SDACandidate.bottom = pRect->bottom + 1;
TRACE_OUT(( "SDACandidate: (%d,%d)(%d,%d)",
SDACandidate.left,
SDACandidate.top,
SDACandidate.right,
SDACandidate.bottom));
//
// Check if we have a clipping object at all.
//
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
//
// Convert the clipped rect into Virtual Desktop coords.
//
clippedRect = SDACandidate;
clippedRect.right -= 1;
clippedRect.bottom -= 1;
//
// Add the clipped rect into the SDA.
//
TRACE_OUT(( "Adding SDA (%d,%d)(%d,%d)", clippedRect.left,
clippedRect.top,
clippedRect.right,
clippedRect.bottom));
BA_AddScreenData(&clippedRect);
}
else if (pco->iDComplexity == DC_RECT)
{
//
// One clipping rectangle - use it directly, converting into
// Virtual Desktop coords. Make sure the rectangle is valid before
// adding to the SDA.
//
RECT_FROM_RECTL(clippedRect, pco->rclBounds);
clippedRect.left = max(clippedRect.left, SDACandidate.left);
clippedRect.right = min(clippedRect.right, SDACandidate.right) + -1;
if ( clippedRect.left <= clippedRect.right )
{
clippedRect.bottom = min(clippedRect.bottom,
SDACandidate.bottom) + -1;
clippedRect.top = max(clippedRect.top, SDACandidate.top);
if ( clippedRect.bottom >= clippedRect.top )
{
//
// Add the clipped rect into the SDA.
//
TRACE_OUT(( "Adding SDA RECT (%d,%d)(%d,%d)",
clippedRect.left,
clippedRect.top,
clippedRect.right,
clippedRect.bottom));
BA_AddScreenData(&clippedRect);
}
}
}
else
{
//
// Enumerate all the rectangles involved in this drawing operation.
// The documentation for this function incorrectly states that
// the returned value is the total number of rectangles
// comprising the clip region. In fact, -1 is always returned,
// even when the final parameter is non-zero.
//
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
//
// Get the next batch of clipping rectangles
//
fMoreRects = CLIPOBJ_bEnum(pco,
sizeof(clip),
(ULONG *)&clip.rects);
for ( i = 0; i < clip.rects.c; i++ )
{
TRACE_OUT(( " (%d,%d)(%d,%d)",
clip.rects.arcl[i].left,
clip.rects.arcl[i].top,
clip.rects.arcl[i].right,
clip.rects.arcl[i].bottom));
//
// Intersect the SDA rect with the clip rect, checking for
// no intersection.
//
clippedRect.left = max( clip.rects.arcl[i].left,
SDACandidate.left );
clippedRect.right = min( clip.rects.arcl[i].right,
SDACandidate.right );
if (clippedRect.left >= clippedRect.right)
{
//
// No horizontal intersection.
//
continue;
}
clippedRect.bottom = min( clip.rects.arcl[i].bottom,
SDACandidate.bottom );
clippedRect.top = max( clip.rects.arcl[i].top,
SDACandidate.top );
if (clippedRect.top >= clippedRect.bottom)
{
//
// No vertical intersection.
//
continue;
}
//
// Convert the clipped rect into Virtual Desktop coords.
//
clippedRect.right -= 1;
clippedRect.bottom -= 1;
//
// Add the clipped rect into the SDA.
//
TRACE_OUT(( "Adding SDA (%d,%d)(%d,%d)",
clippedRect.left,
clippedRect.top,
clippedRect.right,
clippedRect.bottom));
BA_AddScreenData(&clippedRect);
}
} while (fMoreRects);
}
DebugExitVOID(OEClipAndAddScreenData);
}
//
// FUNCTION: OEDDSetNewFonts
//
// DESCRIPTION:
//
// Set the new font handling information to be used by the display driver.
//
// RETURNS:
//
// NONE
//
//
void OEDDSetNewFonts(LPOE_NEW_FONTS pRequest)
{
UINT cbNewSize;
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.
//
g_oeNumFonts = 0;
g_oeFontCaps = pRequest->fontCaps;
//
// Free our previous font block if we had one.
//
if (g_poeLocalFonts)
{
EngFreeMem(g_poeLocalFonts);
g_poeLocalFonts = NULL;
}
//
// Alloc a new one, the size of the new font block.
//
cbNewSize = pRequest->countFonts * sizeof(LOCALFONT);
g_poeLocalFonts = EngAllocMem(0, cbNewSize, OSI_ALLOC_TAG);
if (! g_poeLocalFonts)
{
ERROR_OUT(("OEDDSetNewFonts: can't allocate space for font info"));
DC_QUIT;
}
//
// OK, if we're here, this is going to succeed. Copy the info over.
//
g_oeNumFonts = pRequest->countFonts;
memcpy(g_poeLocalFonts, pRequest->fontData, cbNewSize);
memcpy(g_oeLocalFontIndex, pRequest->fontIndex,
sizeof(g_oeLocalFontIndex[0]) * FH_LOCAL_INDEX_SIZE);
DC_EXIT_POINT:
DebugExitVOID(OEDDSetNewFonts);
}
//
// FUNCTION: OEDDSetNewCapabilities
//
// DESCRIPTION:
//
// Set the new OE related capabilities
//
// RETURNS:
//
// NONE
//
// PARAMETERS:
//
// pDataIn - pointer to the input buffer
//
//
void OEDDSetNewCapabilities(LPOE_NEW_CAPABILITIES pCapabilities)
{
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.
//
memcpy(g_oeOrderSupported,
pCapabilities->orderSupported,
sizeof(g_oeOrderSupported));
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: OETileBitBltOrder
//
// Description: Divides a single large BitBlt order into a series of small,
// "tiled" BitBlt orders, each of which is added to the order
// queue.
//
// Parameters: pOrder - Template order to be tiled
// pExtraInfo - Structure containing pointers to the source
// and destination surface objects, and a pointer
// to the color translation object for the Blt
// pco - Clipping object for the operation
//
// Returns: TRUE - Stored in orders (and possibly some SDA)
// FALSE- Stored in SDA (or contained bad data)
//
//
void OETileBitBltOrder
(
LPINT_ORDER pOrder,
LPMEMBLT_ORDER_EXTRA_INFO pExtraInfo,
CLIPOBJ* pco
)
{
UINT tileWidth;
UINT tileHeight;
int srcLeft;
int srcTop;
int srcRight;
int srcBottom;
int xFirstTile;
int yFirstTile;
int xTile;
int yTile;
UINT type;
int bmpWidth, bmpHeight;
RECT destRect;
DebugEntry(OETileBitBltOrder);
//
// Extract the src bitmap handle from the Order - if the order is not a
// memory to screen blit, we get out now.
//
type = ((LPMEMBLT_ORDER)pOrder->abOrderData)->type;
switch (type)
{
case ORD_MEMBLT_TYPE:
{
srcLeft = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nXSrc;
srcTop = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nYSrc;
srcRight = srcLeft +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nWidth;
srcBottom = srcTop +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nHeight;
destRect.left = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nLeftRect;
destRect.top = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nTopRect;
destRect.right = destRect.left +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nWidth;
destRect.bottom= destRect.top +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nHeight;
}
break;
case ORD_MEM3BLT_TYPE:
{
srcLeft = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nXSrc;
srcTop = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nYSrc;
srcRight = srcLeft +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nWidth;
srcBottom = srcTop +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nHeight;
destRect.left = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nLeftRect;
destRect.top = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nTopRect;
destRect.right= destRect.left +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nWidth;
destRect.bottom = destRect.top +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nHeight;
}
break;
default:
{
ERROR_OUT(( "Invalid order type %u", type));
}
break;
}
//
// Fetch the bitmap details.
//
bmpWidth = (int)pExtraInfo->pSource->sizlBitmap.cx;
bmpHeight = (int)pExtraInfo->pSource->sizlBitmap.cy;
if (!SBC_DDQueryBitmapTileSize(bmpWidth, bmpHeight, &tileWidth, &tileHeight))
{
//
// This could happen if some 2.x user joins the share.
//
TRACE_OUT(("Bitmap is not tileable"));
OEClipAndAddScreenData(&destRect, pco);
}
else
{
//
// Tile the order. If an individual tile fails to get queued as an
// order, OEAddTiledBitBltOrder() will add it as screen data. Hence
// no return value to be checked.
//
xFirstTile = srcLeft - (srcLeft % tileWidth);
yFirstTile = srcTop - (srcTop % tileHeight);
for (yTile = yFirstTile; yTile < srcBottom; yTile += tileHeight)
{
for (xTile = xFirstTile; xTile < srcRight; xTile += tileWidth)
{
OEAddTiledBitBltOrder(pOrder, pExtraInfo, pco, xTile, yTile,
tileWidth, tileHeight);
}
}
}
DebugExitVOID(OETileBitBltOrder);
}
//
// Function: OEAddTiledBitBltOrder
//
// Description: Takes an unmodified "large" BitBlt and a tile rectangle,
// makes a copy of the order and modifies the copied order's
// src/dest so it applies to the source tile only. The order
// is added to the order queue. If the allocation of the
// "tiled" order fails, the destination rect is added to SDA
//
// Parameters: pOrder - Template order to be added
// pExtraInfo - Pointer to the extra BitBlt info
// pco - Clipping object for the BitBlt
// xTile - X position of the tile
// yTile - Y position of the tile
// tileWidth - tile width
// tileHeight - tile height
//
// Returns: none
//
//
void OEAddTiledBitBltOrder(
LPINT_ORDER pOrder,
LPMEMBLT_ORDER_EXTRA_INFO pExtraInfo,
CLIPOBJ* pco,
int xTile,
int yTile,
UINT tileWidth,
UINT tileHeight)
{
LPINT_ORDER pTileOrder;
LPINT pXSrc = NULL;
LPINT pYSrc = NULL;
LPINT pLeft = NULL;
LPINT pTop = NULL;
LPINT pWidth = NULL;
LPINT pHeight = NULL;
RECT srcRect;
RECT destRect;
UINT type;
DebugEntry(OETileAndAddBitBltOrder);
//
// This is a trusted interface - assume the type is correct
//
type = ((LPMEMBLT_ORDER)pOrder->abOrderData)->type;
ASSERT(((type == ORD_MEMBLT_TYPE) || (type == ORD_MEM3BLT_TYPE)));
//
// Do processing which depends on the type of bit blt being tiled:
// - save existing src and dest rects
// - make a copy of the order (which will be the tile order)
// - save pointers to the fields in the tile order which we're likely
// to change.
//
if (type == ORD_MEMBLT_TYPE)
{
srcRect.left = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nXSrc;
srcRect.top = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nYSrc;
srcRect.right = srcRect.left +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nWidth;
srcRect.bottom = srcRect.top +
((LPMEMBLT_ORDER)pOrder->abOrderData)->nHeight;
destRect.left = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nLeftRect;
destRect.top = ((LPMEMBLT_ORDER)pOrder->abOrderData)->nTopRect;
//
// We must allocate enough space for the maximum size order that
// SBC may use (i.e. an R2 order). We default to filling in the
// data as an R1 order.
//
pTileOrder = OA_DDAllocOrderMem(sizeof(MEMBLT_R2_ORDER),0);
if (pTileOrder == NULL)
{
TRACE_OUT(( "No space for tile order"));
DC_QUIT;
}
//
// We must not mess up the linked list data in the orders.
//
RtlCopyMemory(((LPBYTE)pTileOrder) +
FIELD_SIZE(INT_ORDER, OrderHeader.list),
((LPBYTE)pOrder) +
FIELD_SIZE(INT_ORDER, OrderHeader.list),
sizeof(INT_ORDER_HEADER)
+ sizeof(MEMBLT_R2_ORDER)
- FIELD_SIZE(INT_ORDER, OrderHeader.list));
pXSrc = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nXSrc;
pYSrc = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nYSrc;
pWidth = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nWidth;
pHeight = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nHeight;
pLeft = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nLeftRect;
pTop = &((LPMEMBLT_ORDER)pTileOrder->abOrderData)->nTopRect;
}
else
{
srcRect.left = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nXSrc;
srcRect.top = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nYSrc;
srcRect.right = srcRect.left +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nWidth;
srcRect.bottom = srcRect.top +
((LPMEM3BLT_ORDER)pOrder->abOrderData)->nHeight;
destRect.left = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nLeftRect;
destRect.top = ((LPMEM3BLT_ORDER)pOrder->abOrderData)->nTopRect;
//
// We must allocate enough space for the maximum size order that
// SBC may use (i.e. an R2 order). We default to filling in the
// data as an R1 order.
//
pTileOrder = OA_DDAllocOrderMem(sizeof(MEM3BLT_R2_ORDER),0);
if (pTileOrder == NULL)
{
TRACE_OUT(( "No space for tile order"));
DC_QUIT;
}
//
// We must not mess up the linked list data in the orders.
//
RtlCopyMemory(((LPBYTE)pTileOrder) +
FIELD_SIZE(INT_ORDER, OrderHeader.list),
((LPBYTE)pOrder) +
FIELD_SIZE(INT_ORDER, OrderHeader.list),
sizeof(INT_ORDER_HEADER)
+ sizeof(MEM3BLT_R2_ORDER)
- FIELD_SIZE(INT_ORDER, OrderHeader.list));
pXSrc = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nXSrc;
pYSrc = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nYSrc;
pWidth = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nWidth;
pHeight = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nHeight;
pLeft = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nLeftRect;
pTop = &((LPMEM3BLT_ORDER)pTileOrder->abOrderData)->nTopRect;
}
TRACE_OUT(( "Tiling order, orig srcLeft=%hd, srcTop=%hd, srcRight=%hd, "
"srcBottom=%hd, destX=%hd, destY=%hd; "
"xTile=%hd, yTile=%hd, tileW=%hd, tileH=%hd",
srcRect.left, srcRect.top, srcRect.right, srcRect.bottom,
destRect.left, destRect.top,
xTile, yTile, tileWidth, tileHeight));
DC_EXIT_POINT:
//
// NOTE: ALL THE POINTERS MAY BE NULL AT THIS POINT - DO NOT USE THEM
// UNTIL YOU VERIFY PTILEORDER IS NON-NULL.
//
// Intersect source and tile rects, and set up destination rect
// accordingly - we need to do this even if we failed to copy the
// order, because the tiled source rect will have to be added to the
// screen data area.
//
if (xTile > srcRect.left)
{
destRect.left += (xTile - srcRect.left);
srcRect.left = xTile;
}
if (yTile > srcRect.top)
{
destRect.top += (yTile - srcRect.top);
srcRect.top = yTile;
}
srcRect.right = min((UINT)srcRect.right, xTile + tileWidth);
srcRect.bottom = min((UINT)srcRect.bottom, yTile + tileHeight);
destRect.right = destRect.left + (srcRect.right - srcRect.left);
destRect.bottom = destRect.top + (srcRect.bottom - srcRect.top);
//
// If the order was successfully copied above, then modify the order
// to contain the tiled coordinates, and add it to the order list.
// Otherwise, send the dest rect as screen data.
//
if (pTileOrder != NULL)
{
TRACE_OUT(( "Tile order originally: srcX=%hd, srcY=%hd, destX=%hd, "
"destY=%hd, w=%hd, h=%hd",
*pXSrc, *pYSrc, *pLeft, *pTop, *pWidth, *pHeight));
*pXSrc = srcRect.left;
*pYSrc = srcRect.top;
*pLeft = destRect.left;
*pTop = destRect.top;
*pWidth = srcRect.right - srcRect.left;
*pHeight = srcRect.bottom - srcRect.top;
pTileOrder->OrderHeader.Common.rcsDst.left = (TSHR_INT16)destRect.left;
pTileOrder->OrderHeader.Common.rcsDst.right = (TSHR_INT16)destRect.right;
pTileOrder->OrderHeader.Common.rcsDst.top = (TSHR_INT16)destRect.top;
pTileOrder->OrderHeader.Common.rcsDst.bottom =
(TSHR_INT16)destRect.bottom;
TRACE_OUT(( "Adding order srcX=%hd, srcY=%hd, destX=%hd, destY=%hd,"
" w=%hd, h=%hd",
*pXSrc, *pYSrc, *pLeft, *pTop, *pWidth, *pHeight));
OEClipAndAddOrder(pTileOrder, pExtraInfo, pco);
}
else
{
TRACE_OUT(( "Failed to allocate order - sending as screen data"));
OEClipAndAddScreenData(&destRect, pco);
}
DebugExitVOID(OETileAndAddBitBltOrder);
}
// NAME: OEAddLine
//
// PURPOSE:
//
// Add a LineTo order to the order heap.
//
// RETURNS:
//
// TRUE - Attempted to add to heap
// FALSE - No room left to allocate an order
//
// PARAMS:
//
// ppdev - display driver PDEV
// startPoint - start point of line
// endPoint - end point of line
// rectDst - bounding rectangle
// rop2 - ROP2 to use with line
// width - width of line to add
// color - color of line to add
// pco - clipping object for drawing operation
//
BOOL OEAddLine(LPOSI_PDEV ppdev,
LPPOINT startPoint,
LPPOINT endPoint,
LPRECT rectDst,
UINT rop2,
UINT width,
UINT color,
CLIPOBJ* pco)
{
BOOL rc = FALSE;
LPLINETO_ORDER pLineTo;
LPINT_ORDER pOrder;
DebugEntry(OEAddLine);
//
// Allocate the memory for the order.
//
pOrder = OA_DDAllocOrderMem(sizeof(LINETO_ORDER),0);
if (pOrder == NULL)
{
TRACE_OUT(( "Failed to alloc order"));
DC_QUIT;
}
pLineTo = (LPLINETO_ORDER)pOrder->abOrderData;
//
// Mark this order type.
//
pLineTo->type = ORD_LINETO_TYPE;
//
// Store the line end coordinates.
//
pLineTo->nXStart = startPoint->x;
pLineTo->nYStart = startPoint->y;
pLineTo->nXEnd = endPoint->x;
pLineTo->nYEnd = endPoint->y;
//
// We must convert these values to virtual coords.
//
OELPtoVirtual((LPPOINT)&pLineTo->nXStart, 2);
//
// Always do solid lines, so it does not matter what we specify as the
// back color.
//
RtlFillMemory(&pLineTo->BackColor,
sizeof(pLineTo->BackColor),
0);
//
// We only draw solid lines with no option as to what we do to the
// background, so this is always transparent.
//
pLineTo->BackMode = TRANSPARENT;
//
// Get the ROP value.
//
pLineTo->ROP2 = rop2;
//
// The NT Display Driver is only called to accelerate simple solid
// lines. So we only support pen styles of PS_SOLID.
//
pLineTo->PenStyle = PS_SOLID;
//
// Get the pen width.
//
pLineTo->PenWidth = width;
//
// Set up the color.
//
OEConvertColor(ppdev,
&pLineTo->PenColor,
color,
NULL);
TRACE_OUT(( "LineTo BC %02x%02x%02x BM %04X rop2 %02X "
"pen %04X %04X %02x%02x%02x x1 %d y1 %d x2 %d y2 %d",
pLineTo->BackColor.red,
pLineTo->BackColor.green,
pLineTo->BackColor.blue,
pLineTo->BackMode,
pLineTo->ROP2,
pLineTo->PenStyle,
pLineTo->PenWidth,
pLineTo->PenColor.red,
pLineTo->PenColor.green,
pLineTo->PenColor.blue,
pLineTo->nXStart,
pLineTo->nYStart,
pLineTo->nXEnd,
pLineTo->nYEnd));
//
// Store the general order data. The bounding rectangle must be in to
// virtual desktop co-ordinates. OELRtoVirtual has already done this.
//
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILABLE;
pOrder->OrderHeader.Common.rcsDst.left = (TSHR_INT16)rectDst->left;
pOrder->OrderHeader.Common.rcsDst.right = (TSHR_INT16)rectDst->right;
pOrder->OrderHeader.Common.rcsDst.top = (TSHR_INT16)rectDst->top;
pOrder->OrderHeader.Common.rcsDst.bottom = (TSHR_INT16)rectDst->bottom;
//
// Store that order!
//
OEClipAndAddOrder(pOrder, NULL, pco);
rc = TRUE;
DC_EXIT_POINT:
DebugExitDWORD(OEAddLine, rc);
return(rc);
}
// NAME: OEEncodePatBlt
//
// PURPOSE:
//
// Attempts to encode a PatBlt order. This function allocates the memory
// for the encoded order (pointer returned in ppOrder). If the function
// completes successfully, it is the caller's responsibility to free this
// memory.
//
// RETURNS:
//
// TRUE - Order encoded
// FALSE - Order not encoded (so add to SDA)
//
// PARAMS:
//
// ppdev - display driver PDEV
// pbo - brush object for the blt
// pptlBrush - brush origin
// rop3 - 3-way rop to use
// pBounds - bounding rectangle
// ppOrder - the encoded order
//
BOOL OEEncodePatBlt(LPOSI_PDEV ppdev,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
BYTE rop3,
LPRECT pBounds,
LPINT_ORDER *ppOrder)
{
BOOL rc = FALSE;
POE_BRUSH_DATA pCurrentBrush;
LPPATBLT_ORDER pPatBlt;
UINT orderFlags = OF_SPOILABLE;
DebugEntry(OEEncodePatBlt);
//
// Check for a simple brush pattern.
//
if ( OECheckBrushIsSimple(ppdev, pbo, &pCurrentBrush) )
{
//
// Allocate the memory for the order.
//
*ppOrder = OA_DDAllocOrderMem(sizeof(PATBLT_ORDER),0);
if (*ppOrder != NULL)
{
pPatBlt = (LPPATBLT_ORDER)((*ppOrder)->abOrderData);
//
// Set the opaque flag if the rop is opaque.
//
if (ROP3_IS_OPAQUE(rop3))
{
orderFlags |= OF_SPOILER;
}
//
// Set up order type.
//
pPatBlt->type = LOWORD(ORD_PATBLT);
//
// Virtual desktop co-ordinates.
//
pPatBlt->nLeftRect = pBounds->left;
pPatBlt->nTopRect = pBounds->top;
pPatBlt->nWidth = pBounds->right - pBounds->left + 1;
pPatBlt->nHeight = pBounds->bottom - pBounds->top + 1;
pPatBlt->bRop = rop3;
//
// Pattern colours.
//
pPatBlt->BackColor = pCurrentBrush->back;
pPatBlt->ForeColor = pCurrentBrush->fore;
//
// The protocol brush origin is the point on the screen where
// we want the brush to start being drawn from (tiling where
// necessary). This must be in virtual coordinates.
//
pPatBlt->BrushOrgX = pptlBrush->x;
pPatBlt->BrushOrgY = pptlBrush->y;
OELPtoVirtual((LPPOINT)&pPatBlt->BrushOrgX, 1);
//
// Extra brush data from the data when we realised the brush.
//
pPatBlt->BrushStyle = pCurrentBrush->style;
pPatBlt->BrushHatch = pCurrentBrush->hatch;
RtlCopyMemory(pPatBlt->BrushExtra,
pCurrentBrush->brushData,
sizeof(pPatBlt->BrushExtra));
TRACE_OUT(( "PatBlt BC %02x%02x%02x FC %02x%02x%02x "
"Brush %02X %02X X %d Y %d w %d h %d rop %02X",
pPatBlt->BackColor.red,
pPatBlt->BackColor.green,
pPatBlt->BackColor.blue,
pPatBlt->ForeColor.red,
pPatBlt->ForeColor.green,
pPatBlt->ForeColor.blue,
pPatBlt->BrushStyle,
pPatBlt->BrushHatch,
pPatBlt->nLeftRect,
pPatBlt->nTopRect,
pPatBlt->nWidth,
pPatBlt->nHeight,
pPatBlt->bRop));
//
// Copy any order flags into the encoded order structure.
//
(*ppOrder)->OrderHeader.Common.fOrderFlags = (TSHR_UINT16)orderFlags;
rc = TRUE;
}
else
{
TRACE_OUT(( "Failed to alloc order"));
}
}
else
{
TRACE_OUT(( "Brush is not simple"));
}
DebugExitDWORD(OEEncodePatBlt, rc);
return(rc);
}
//
// DrvTransparentBlt()
// NEW FOR NT5
//
BOOL DrvTransparentBlt
(
SURFOBJ * psoDst,
SURFOBJ * psoSrc,
CLIPOBJ * pco,
XLATEOBJ * pxlo,
RECTL * prclDst,
RECTL * prclSrc,
ULONG iTransColor,
ULONG ulReserved
)
{
BOOL rc = TRUE;
RECT rectSrc;
RECT rectDst;
BOOL fAccumulate = FALSE;
DebugEntry(DrvTransparentBlt);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectSrc, (*prclSrc));
RECT_FROM_RECTL(rectDst, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitBOOL(DrvTransparentBlt, rc);
return(rc);
}
//
// DrvAlphaBlend()
// NEW FOR NT5
//
BOOL DrvAlphaBlend
(
SURFOBJ * psoDst,
SURFOBJ * psoSrc,
CLIPOBJ * pco,
XLATEOBJ * pxlo,
RECTL * prclDst,
RECTL * prclSrc,
BLENDOBJ * pBlendObj
)
{
BOOL rc = TRUE;
RECT rectSrc;
RECT rectDst;
BOOL fAccumulate = FALSE;
DebugEntry(DrvAlphaBlend);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectSrc, (*prclSrc));
RECT_FROM_RECTL(rectDst, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitBOOL(DrvAlphaBlend, rc);
return(rc);
}
//
// DrvPlgBlt()
// NEW FOR NT5
//
BOOL DrvPlgBlt
(
SURFOBJ * psoDst,
SURFOBJ * psoSrc,
SURFOBJ * psoMsk,
CLIPOBJ * pco,
XLATEOBJ * pxlo,
COLORADJUSTMENT * pca,
POINTL * pptlBrushOrg,
POINTFIX * pptfx,
RECTL * prclDst,
POINTL * pptlSrc,
ULONG iMode
)
{
BOOL rc = TRUE;
RECT rectDst;
BOOL fAccumulate = FALSE;
DebugEntry(DrvPlgBlt);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectDst, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitBOOL(DrvPlgBlt, rc);
return(rc);
}
//
// DrvStretchBltROP()
// NEW FOR NT5
//
BOOL DrvStretchBltROP
(
SURFOBJ * psoDst,
SURFOBJ * psoSrc,
SURFOBJ * psoMask,
CLIPOBJ * pco,
XLATEOBJ * pxlo,
COLORADJUSTMENT * pca,
POINTL * pptlHTOrg,
RECTL * prclDst,
RECTL * prclSrc,
POINTL * pptlMask,
ULONG iMode,
BRUSHOBJ * pbo,
DWORD rop4
)
{
BOOL rc = TRUE;
RECT rectSrc;
RECT rectDst;
BOOL fAccumulate = FALSE;
DebugEntry(DrvStretchBltROP);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectSrc, (*prclSrc));
RECT_FROM_RECTL(rectDst, (*prclDst));
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitBOOL(DrvStretchBltROP, rc);
return(rc);
}
//
// DrvGradientFill()
// NEW FOR NT5
//
BOOL DrvGradientFill
(
SURFOBJ * psoDst,
CLIPOBJ * pco,
XLATEOBJ * pxlo,
TRIVERTEX * pVertex,
ULONG nVertex,
PVOID pMesh,
ULONG nMesh,
RECTL * prclExtents,
POINTL * pptlDitherOrg,
ULONG ulMode
)
{
BOOL rc = TRUE;
RECT rectDst;
BOOL fAccumulate = FALSE;
DebugEntry(DrvGradientFill);
//
// DO THIS _BEFORE_ TAKING LOCK
//
if (!g_oeViewers)
goto NO_LOCK_EXIT;
OE_SHM_START_WRITING;
//
// Get bounding rectangle and convert to a RECT.
//
RECT_FROM_RECTL(rectDst, pco->rclBounds);
//
// Check if we are accumulating data for this function
//
fAccumulate = OEAccumulateOutput(psoDst, pco, &rectDst);
if (!fAccumulate)
{
DC_QUIT;
}
//
// Convert to virtual coordinates.
//
OELRtoVirtual(&rectDst, 1);
DC_EXIT_POINT:
if (fAccumulate)
{
OEClipAndAddScreenData(&rectDst, pco);
}
OE_SHM_STOP_WRITING;
NO_LOCK_EXIT:
DebugExitBOOL(DrvGradientFill, rc);
return(rc);
}