|
|
#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 ������������ͻ ROP2 uses P & D only
// 1 1 1 0 � �
// 1 1 0 1 Ŀ � � ROP3 uses P, S & D
// 1 1 0 0 �ROP2-1�ROP3 �ROP4
// 1 0 1 1 �(see � � ROP4 uses M, P, S & D
// 1 0 1 0 �� note)� �
// 1 0 0 1 � �
// 1 0 0 0 �������; �
// 0 1 1 1 �
// 0 1 1 0 � NOTE: Windows defines its
// 0 1 0 1 � ROP2 codes as the bitwise
// 0 1 0 0 � value calculated here
// 0 0 1 1 � plus one. All other ROP
// 0 0 1 0 � codes are the straight
// 0 0 0 1 � bitwise value.
// 0 0 0 0 ��������������ͼ
//
// 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; POINT pt = {0,0}; ENUMRECTS clipRect; 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; }
//
// Extract a single point from the clip object
//
if (pco == NULL) { //
// No clip object - use a point from the bounding rectangle
//
pt.x = pRect->left; pt.y = pRect->top; TRACE_OUT(( "No clip object, point is %d, %d", pt.x, pt.y)); } else if (pco->iDComplexity == DC_TRIVIAL) { //
// Trivial clip object - use a point from the bounding rectangle
//
pt.x = pRect->left; pt.y = pRect->top; TRACE_OUT(( "Trivial clip object, point is %d, %d", pt.x, pt.y)); } else if (pco->iDComplexity == DC_RECT) { //
// Single clip rectangle - use a point from it
//
// It appears that the clip rectangle is frequantly the entire
// display. This is about as much use as a chocolate teapot. If
// this is the case, use a point from the bounding rectangle
// instead.
//
if ((pco->rclBounds.left == 0) && (pco->rclBounds.top == 0)) { pt.x = pRect->left; pt.y = pRect->top; TRACE_OUT(( "Meaningless clip rect, point is %d, %d", pt.x, pt.y)); } else { pt.x = pco->rclBounds.left; pt.y = pco->rclBounds.top; TRACE_OUT(( "Single clip rect, point is %d, %d", pt.x, pt.y)); } } else { //
// Complex clip object - enumerate its first rectangle and use a
// point from that.
//
TRACE_OUT(( "Complex clip rect - call cEnumStart")); CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
clipRect.c = 1; memset(clipRect.arcl, 0, sizeof(RECTL)); TRACE_OUT(( "Complex clip rect - call bEnum")); CLIPOBJ_bEnum(pco, sizeof(clipRect), (ULONG *)(&clipRect));
pt.x = clipRect.arcl[0].left; pt.y = clipRect.arcl[0].top; TRACE_OUT(( "Complex clip rect, point is %d, %d", pt.x, pt.y)); }
//
// Check if we are accumulating this window.
//
rc = HET_DDOutputIsHosted(pt);
DC_EXIT_POINT: TRACE_OUT(("OEAccumulateOutput: point {%d, %d} is %sshared", pt.x, pt.y, (rc ? "" : "NOT "))); 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 = HET_DDOutputRectIsHosted(pRect);
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); }
|