mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1776 lines
61 KiB
1776 lines
61 KiB
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// OD2.CPP
|
|
// Order Decoding Second Level
|
|
//
|
|
// Copyright(c) Microsoft 1997-
|
|
//
|
|
|
|
#define MLZ_FILE_ZONE ZONE_ORDER
|
|
|
|
|
|
|
|
//
|
|
// OD2_ViewStarting()
|
|
//
|
|
// For 3.0 nodes, we create the decoding data each time they start hosting.
|
|
// For 2.x nodes, we create the decoding data once and use it until they
|
|
// leave the share.
|
|
//
|
|
BOOL ASShare::OD2_ViewStarting(ASPerson * pasPerson)
|
|
{
|
|
PPARTYORDERDATA pThisParty;
|
|
BOOL rc = FALSE;
|
|
|
|
DebugEntry(ASShare::OD2_ViewStarting);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
if (pasPerson->od2Party != NULL)
|
|
{
|
|
ASSERT(pasPerson->cpcCaps.general.version < CAPS_VERSION_30);
|
|
|
|
TRACE_OUT(("OD2_ViewStarting: Reusing od2 data for 2.x node [%d]",
|
|
pasPerson->mcsID));
|
|
rc = TRUE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the required structure.
|
|
//
|
|
pThisParty = new PARTYORDERDATA;
|
|
pasPerson->od2Party = pThisParty;
|
|
if (!pThisParty)
|
|
{
|
|
ERROR_OUT(( "Failed to get memory for od2Party entry"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Ensure the pointers are correctly set up.
|
|
//
|
|
ZeroMemory(pThisParty, sizeof(*pThisParty));
|
|
SET_STAMP(pThisParty, PARTYORDERDATA);
|
|
|
|
pThisParty->LastOrder[OE2_DSTBLT_ORDER ] = &pThisParty->LastDstblt;
|
|
pThisParty->LastOrder[OE2_PATBLT_ORDER ] = &pThisParty->LastPatblt;
|
|
pThisParty->LastOrder[OE2_SCRBLT_ORDER ] = &pThisParty->LastScrblt;
|
|
pThisParty->LastOrder[OE2_MEMBLT_ORDER ] = &pThisParty->LastMemblt;
|
|
pThisParty->LastOrder[OE2_MEM3BLT_ORDER ] = &pThisParty->LastMem3blt;
|
|
pThisParty->LastOrder[OE2_TEXTOUT_ORDER ] = &pThisParty->LastTextOut;
|
|
pThisParty->LastOrder[OE2_EXTTEXTOUT_ORDER] = &pThisParty->LastExtTextOut;
|
|
pThisParty->LastOrder[OE2_RECTANGLE_ORDER ] = &pThisParty->LastRectangle;
|
|
pThisParty->LastOrder[OE2_LINETO_ORDER ] = &pThisParty->LastLineTo;
|
|
pThisParty->LastOrder[OE2_OPAQUERECT_ORDER] = &pThisParty->LastOpaqueRect;
|
|
pThisParty->LastOrder[OE2_SAVEBITMAP_ORDER] = &pThisParty->LastSaveBitmap;
|
|
pThisParty->LastOrder[OE2_DESKSCROLL_ORDER] = &pThisParty->LastDeskScroll;
|
|
pThisParty->LastOrder[OE2_MEMBLT_R2_ORDER ] = &pThisParty->LastMembltR2;
|
|
pThisParty->LastOrder[OE2_MEM3BLT_R2_ORDER] = &pThisParty->LastMem3bltR2;
|
|
pThisParty->LastOrder[OE2_POLYGON_ORDER ] = &pThisParty->LastPolygon;
|
|
pThisParty->LastOrder[OE2_PIE_ORDER ] = &pThisParty->LastPie;
|
|
pThisParty->LastOrder[OE2_ELLIPSE_ORDER ] = &pThisParty->LastEllipse;
|
|
pThisParty->LastOrder[OE2_ARC_ORDER ] = &pThisParty->LastArc;
|
|
pThisParty->LastOrder[OE2_CHORD_ORDER ] = &pThisParty->LastChord;
|
|
pThisParty->LastOrder[OE2_POLYBEZIER_ORDER] = &pThisParty->LastPolyBezier;
|
|
pThisParty->LastOrder[OE2_ROUNDRECT_ORDER] = &pThisParty->LastRoundRect;
|
|
|
|
OD2_SyncIncoming(pasPerson);
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASShare::OD2_ViewStarting, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// OD2_SyncIncoming()
|
|
// Called when NEW dude starts to share, a share is created, or someone new
|
|
// joins the share.
|
|
//
|
|
void ASShare::OD2_SyncIncoming(ASPerson * pasPerson)
|
|
{
|
|
PPARTYORDERDATA pThisParty;
|
|
|
|
DebugEntry(ASShare::OD2_SyncIncoming);
|
|
|
|
ValidateView(pasPerson);
|
|
|
|
pThisParty = pasPerson->od2Party;
|
|
|
|
pThisParty->LastOrderType = OE2_PATBLT_ORDER;
|
|
pThisParty->pLastOrder =
|
|
(LPCOM_ORDER)(pThisParty->LastOrder[pThisParty->LastOrderType]);
|
|
|
|
//
|
|
// Set all buffers to NULL Fill in the datalength fields and the type
|
|
// field. Note that because the type field is always the first one in
|
|
// an order we can cast each pointer to a TEXTOUT order to get the
|
|
// correct position for this field
|
|
//
|
|
#define Reset(field, ord) \
|
|
{ \
|
|
ZeroMemory(&pThisParty->field, sizeof(pThisParty->field)); \
|
|
((LPCOM_ORDER_HEADER)pThisParty->field)->cbOrderDataLength = \
|
|
sizeof(pThisParty->field) - sizeof(COM_ORDER_HEADER); \
|
|
TEXTFIELD(((LPCOM_ORDER)pThisParty->field))->type = LOWORD(ord); \
|
|
}
|
|
|
|
//
|
|
// The compiler generates a warning for our use of LOWORD here on a
|
|
// constant. We disable the warning just for now.
|
|
//
|
|
|
|
Reset(LastDstblt, ORD_DSTBLT);
|
|
Reset(LastPatblt, ORD_PATBLT);
|
|
Reset(LastScrblt, ORD_SCRBLT);
|
|
Reset(LastMemblt, ORD_MEMBLT);
|
|
Reset(LastMem3blt, ORD_MEM3BLT);
|
|
Reset(LastTextOut, ORD_TEXTOUT);
|
|
Reset(LastExtTextOut, ORD_EXTTEXTOUT);
|
|
Reset(LastRectangle, ORD_RECTANGLE);
|
|
Reset(LastLineTo, ORD_LINETO);
|
|
Reset(LastOpaqueRect, ORD_OPAQUERECT);
|
|
Reset(LastSaveBitmap, ORD_SAVEBITMAP);
|
|
Reset(LastDeskScroll, ORD_DESKSCROLL);
|
|
Reset(LastMembltR2, ORD_MEMBLT_R2);
|
|
Reset(LastMem3bltR2, ORD_MEM3BLT_R2);
|
|
Reset(LastPolygon, ORD_POLYGON);
|
|
Reset(LastPie, ORD_PIE);
|
|
Reset(LastEllipse, ORD_ELLIPSE);
|
|
Reset(LastArc, ORD_ARC);
|
|
Reset(LastChord, ORD_CHORD);
|
|
Reset(LastPolyBezier, ORD_POLYBEZIER);
|
|
Reset(LastRoundRect, ORD_ROUNDRECT);
|
|
|
|
//
|
|
// Reset the bounds rectangle
|
|
//
|
|
ZeroMemory(&pThisParty->LastBounds, sizeof(pThisParty->LastBounds));
|
|
|
|
//
|
|
// The sender and the receiver both set their structures to the same
|
|
// NULL state and the sender only ever sends differences from the
|
|
// current state. However the fontID fields in the received orders
|
|
// refer to the sender, so we must actually set our fontID fields to
|
|
// the local equivalent of the NULL entries just set.
|
|
// We cannot do this until we have actually received the font details
|
|
// so set the field to a dummy value we can recognise later.
|
|
//
|
|
TEXTFIELD(((LPCOM_ORDER)pThisParty->LastTextOut))->common.FontIndex =
|
|
DUMMY_FONT_ID;
|
|
EXTTEXTFIELD(((LPCOM_ORDER)pThisParty->LastExtTextOut))->common.
|
|
FontIndex = DUMMY_FONT_ID;
|
|
|
|
DebugExitVOID(ASShare::OD2_SyncIncoming);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// OD2_ViewEnded()
|
|
//
|
|
void ASShare::OD2_ViewEnded(ASPerson * pasPerson)
|
|
{
|
|
DebugEntry(ASShare::OD2_ViewEnded);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
//
|
|
// For 3.0 nodes, we can free the decode data; 3.0 senders clear theirs
|
|
// every time they host.
|
|
// For 2.x nodes, we must keep it around while they are in the share.
|
|
//
|
|
|
|
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
|
|
{
|
|
OD2FreeIncoming(pasPerson);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("OD2_ViewEnded: Keeping od2 data for 2.x node [%d]",
|
|
pasPerson->mcsID));
|
|
}
|
|
|
|
DebugExitVOID(ASShare::OD2_ViewEnded);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// OD2_PartyLeftShare()
|
|
// For 2.x nodes, frees the incoming OD2 data
|
|
//
|
|
void ASShare::OD2_PartyLeftShare(ASPerson * pasPerson)
|
|
{
|
|
DebugEntry(ASShare::OD2_PartyLeftShare);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
|
|
{
|
|
// This should be gone!
|
|
ASSERT(pasPerson->od2Party == NULL);
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("OD2_PartyLeftShare: Freeing od2 data for 2.x node [%d]",
|
|
pasPerson->mcsID));
|
|
OD2FreeIncoming(pasPerson);
|
|
}
|
|
|
|
DebugExitVOID(ASShare::OD2_PartyLeftShare);
|
|
}
|
|
|
|
|
|
//
|
|
// OD2FreeIncoming()
|
|
// Frees per-party incoming OD2 resources
|
|
//
|
|
void ASShare::OD2FreeIncoming(ASPerson * pasPerson)
|
|
{
|
|
DebugEntry(OD2FreeIncoming);
|
|
|
|
if (pasPerson->od2Party != NULL)
|
|
{
|
|
if (pasPerson->od2Party->LastHFONT != NULL)
|
|
{
|
|
if (pasPerson->m_pView)
|
|
{
|
|
// For 3.0 nodes, pView won't be NULL; for 2.x nodes it may.
|
|
|
|
//
|
|
// This font might be currently selected into the DC for
|
|
// this person's desktop. Select it out.
|
|
//
|
|
SelectFont(pasPerson->m_pView->m_usrDC, (HFONT)GetStockObject(SYSTEM_FONT));
|
|
}
|
|
|
|
DeleteFont(pasPerson->od2Party->LastHFONT);
|
|
pasPerson->od2Party->LastHFONT = NULL;
|
|
}
|
|
|
|
delete pasPerson->od2Party;
|
|
pasPerson->od2Party = NULL;
|
|
}
|
|
|
|
DebugExitVOID(ASShare::OD2FreeIncoming);
|
|
}
|
|
|
|
//
|
|
// OD2_DecodeOrder()
|
|
//
|
|
LPCOM_ORDER ASShare::OD2_DecodeOrder
|
|
(
|
|
void * pEOrder,
|
|
LPUINT pLengthDecoded,
|
|
ASPerson * pasPerson
|
|
)
|
|
{
|
|
POE2ETFIELD pTableEntry;
|
|
UINT FieldChangedBits;
|
|
UINT FieldsChanged;
|
|
LPBYTE pNextDataToCopy;
|
|
RECT Rect;
|
|
LPBYTE pControlFlags;
|
|
LPTSHR_UINT32_UA pEncodingFlags;
|
|
LPSTR pEncodedOrder;
|
|
UINT numEncodingFlagBytes;
|
|
UINT encodedFieldLength;
|
|
UINT unencodedFieldLength;
|
|
UINT numReps;
|
|
UINT i;
|
|
LPBYTE pDest;
|
|
|
|
DebugEntry(ASShare::OD2_DecodeOrder);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
//
|
|
// Set up some local variables to access the encoding buffer in various
|
|
// ways.
|
|
//
|
|
pControlFlags = &((PDCEO2ORDER)pEOrder)->ControlFlags;
|
|
pEncodedOrder = (LPSTR)&((PDCEO2ORDER)pEOrder)->EncodedOrder[0];
|
|
pEncodingFlags = (LPTSHR_UINT32_UA)pEncodedOrder;
|
|
|
|
if ( (*pControlFlags & OE2_CF_STANDARD_ENC) == 0)
|
|
{
|
|
ERROR_OUT(("Specially encoded order received from %d", pasPerson));
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// If the unencoded flag is set, the order has not been encoded, so
|
|
// just return a pointer to the start of the data.
|
|
//
|
|
if ( (*pControlFlags & OE2_CF_UNENCODED) != 0)
|
|
{
|
|
//
|
|
// Convert the fields of the order header from wire format. Note
|
|
// that unencoded orders are also PRIVATE, and hence do not
|
|
// actually have the rcsDst field.
|
|
//
|
|
*pLengthDecoded = sizeof(COM_ORDER_HEADER)
|
|
+ EXTRACT_TSHR_UINT16_UA(
|
|
&(((LPCOM_ORDER_UA)pEncodedOrder)->OrderHeader.cbOrderDataLength))
|
|
+ FIELD_OFFSET(DCEO2ORDER, EncodedOrder);
|
|
TRACE_OUT(("Person [%d] Returning unencoded buffer length %u",
|
|
pasPerson->mcsID, *pLengthDecoded));
|
|
return((LPCOM_ORDER)pEncodedOrder);
|
|
}
|
|
|
|
//
|
|
// If type has changed, new type will be first byte in encoded order.
|
|
// Get pointer to last order of this type. The encoding flags follow
|
|
// this byte (if it is present).
|
|
//
|
|
if ( (*pControlFlags & OE2_CF_TYPE_CHANGE) != 0)
|
|
{
|
|
TRACE_OUT(("Person [%d] change type from %d to %d", pasPerson->mcsID,
|
|
(UINT)pasPerson->od2Party->LastOrderType,
|
|
(UINT)*(LPBYTE)pEncodedOrder));
|
|
pasPerson->od2Party->LastOrderType = *(LPTSHR_UINT8)pEncodedOrder;
|
|
pasPerson->od2Party->pLastOrder =
|
|
(LPCOM_ORDER)(pasPerson->od2Party->LastOrder[pasPerson->od2Party->LastOrderType]);
|
|
pEncodingFlags = (LPTSHR_UINT32_UA)&pEncodedOrder[1];
|
|
}
|
|
else
|
|
{
|
|
pEncodingFlags = (LPTSHR_UINT32_UA)&pEncodedOrder[0];
|
|
}
|
|
|
|
TRACE_OUT(("Person [%d] type %x", pasPerson->mcsID, pasPerson->od2Party->LastOrderType));
|
|
|
|
//
|
|
// Work out how many bytes we will need to store the encoding flags in.
|
|
// (We have a flag for each field in the order structure). This code
|
|
// we have written will cope with up to a DWORD of encoding flags.
|
|
//
|
|
numEncodingFlagBytes = (s_etable.NumFields[pasPerson->od2Party->LastOrderType]+7)/8;
|
|
if (numEncodingFlagBytes > 4)
|
|
{
|
|
ERROR_OUT(( "[%#lx] Too many flag bytes (%d) for this code",
|
|
pasPerson, numEncodingFlagBytes));
|
|
}
|
|
|
|
//
|
|
// Now we know how many bytes make up the flags we can get a pointer
|
|
// to the position at which to start encoding the orders fields into.
|
|
//
|
|
pNextDataToCopy = (LPBYTE)pEncodingFlags + numEncodingFlagBytes;
|
|
|
|
//
|
|
// Reset the flags field to zero
|
|
//
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.fOrderFlags = 0;
|
|
|
|
//
|
|
// Rebuild the Order Common Header in the same order as it was
|
|
// encoded:
|
|
//
|
|
//
|
|
// If a bounding rectangle is included, copy it into the order header
|
|
//
|
|
if ( *pControlFlags & OE2_CF_BOUNDS )
|
|
{
|
|
OD2DecodeBounds((LPTSHR_UINT8*)&pNextDataToCopy,
|
|
&pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst,
|
|
pasPerson);
|
|
}
|
|
|
|
//
|
|
// locate entry in encoding table for this ORDER type and extract the
|
|
// encoded order flags from the Encoded order
|
|
//
|
|
pTableEntry = s_etable.pFields[pasPerson->od2Party->LastOrderType];
|
|
FieldChangedBits = 0;
|
|
for (i=numEncodingFlagBytes; i>0; i--)
|
|
{
|
|
FieldChangedBits = FieldChangedBits << 8;
|
|
FieldChangedBits |= (UINT)((LPBYTE)pEncodingFlags)[i-1];
|
|
}
|
|
|
|
//
|
|
// We need to keep a record of which fields we change.
|
|
//
|
|
FieldsChanged = FieldChangedBits;
|
|
|
|
//
|
|
// Now decode the order: While field changed bits are non-zero
|
|
// If rightmost bit is non-zero
|
|
// copy data from the buffer to the copy of this order type
|
|
// skip to next entry in Encoding table
|
|
// shift field changed bits right one bit
|
|
//
|
|
while (FieldChangedBits != 0)
|
|
{
|
|
//
|
|
// If this field was encoded (ie changed since the last order)...
|
|
//
|
|
if ((FieldChangedBits & 1) != 0)
|
|
{
|
|
//
|
|
// Set up a pointer to the destination (unencoded) field.
|
|
//
|
|
pDest = ((LPBYTE)pasPerson->od2Party->pLastOrder)
|
|
+ pTableEntry->FieldPos
|
|
+ sizeof(COM_ORDER_HEADER);
|
|
|
|
//
|
|
// If the field type is OE2_ETF_DATA, we just copy the number
|
|
// of bytes given by the encoded length in the table.
|
|
//
|
|
if ((pTableEntry->FieldType & OE2_ETF_DATA) != 0)
|
|
{
|
|
encodedFieldLength = 1;
|
|
unencodedFieldLength = 1;
|
|
numReps = pTableEntry->FieldEncodedLen;
|
|
|
|
TRACE_OUT(("Byte data field, len %d", numReps));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is not a straightforward data copy. The length of
|
|
// the source and destination data is given in the table in
|
|
// the FieldEncodedLen and FieldUnencodedLen elements
|
|
// respectively.
|
|
//
|
|
encodedFieldLength = pTableEntry->FieldEncodedLen;
|
|
unencodedFieldLength = pTableEntry->FieldUnencodedLen;
|
|
|
|
if ((pTableEntry->FieldType & OE2_ETF_FIXED) != 0)
|
|
{
|
|
//
|
|
// If the field type is fixed (OE2_ETF_FIXED is set),
|
|
// we just have to decode one element of the given
|
|
// size.
|
|
//
|
|
numReps = 1;
|
|
TRACE_OUT(("Fixed fld: encoded size %d, unencoded size %d",
|
|
encodedFieldLength,
|
|
unencodedFieldLength));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a variable field. The next byte to be
|
|
// decoded contains the number of BYTES of encoded data
|
|
// (not elements), so divide by the encoded field size
|
|
// to get numReps.
|
|
//
|
|
numReps = *pNextDataToCopy / encodedFieldLength;
|
|
TRACE_OUT(("Var field: encoded size %d, unencoded size " \
|
|
"%d, reps %d",
|
|
encodedFieldLength,
|
|
unencodedFieldLength,
|
|
numReps));
|
|
|
|
//
|
|
// Step past the length field in the encoded order
|
|
//
|
|
pNextDataToCopy++;
|
|
|
|
//
|
|
// For a variable length field, the unencoded version
|
|
// contains a UINT for the length (in bytes) of the
|
|
// following variable data, followed by the actual
|
|
// data. Fill in the length field in the unencoded
|
|
// order.
|
|
//
|
|
*(LPTSHR_UINT32)pDest = numReps * unencodedFieldLength;
|
|
pDest += sizeof(TSHR_UINT32);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the order was encoded using delta coordinate mode and
|
|
// this field is a coordinate then convert the coordinate from
|
|
// the single byte sized delta to a value of the size given by
|
|
// unencodedFieldLen...
|
|
//
|
|
// Note that we've already handled the leading length field of
|
|
// variable length fields above, so we don't have to worry
|
|
// about FIXED / VARIABLE issues here.
|
|
//
|
|
if ( (*pControlFlags & OE2_CF_DELTACOORDS) &&
|
|
(pTableEntry->FieldType & OE2_ETF_COORDINATES) )
|
|
{
|
|
//
|
|
// NOTE:
|
|
// numReps can be zero in the case of an EXTTEXTOUT
|
|
// order that needs the opaque rect but has no absolute
|
|
// char positioning
|
|
//
|
|
OD2CopyFromDeltaCoords((LPTSHR_INT8*)&pNextDataToCopy,
|
|
pDest,
|
|
unencodedFieldLength,
|
|
pTableEntry->FieldSigned,
|
|
numReps);
|
|
}
|
|
else
|
|
{
|
|
if ((pasPerson->od2Party->LastOrderType == OE2_POLYGON_ORDER) ||
|
|
(pasPerson->od2Party->LastOrderType == OE2_POLYBEZIER_ORDER))
|
|
{
|
|
//
|
|
// numReps can never be zero in this case
|
|
//
|
|
ASSERT(numReps);
|
|
}
|
|
OD2DecodeField(&pNextDataToCopy,
|
|
pDest,
|
|
encodedFieldLength,
|
|
unencodedFieldLength,
|
|
pTableEntry->FieldSigned,
|
|
numReps);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Move on to the next field in the order structure...
|
|
//
|
|
FieldChangedBits = FieldChangedBits >> 1;
|
|
pTableEntry++;
|
|
}
|
|
|
|
//
|
|
// Check to see if we just got a font handle.
|
|
// Because of the rather nasty test against an unnamed bit in the
|
|
// FieldsChanged bits, we have a compile time check against the number
|
|
// of fields in the TEXT orders structures.
|
|
// The requirement for this code not to break is that the font handle
|
|
// field must stay as the 13th field (hence 1 << 12).
|
|
//
|
|
|
|
#if (OE2_NUM_TEXTOUT_FIELDS != 15) || (OE2_NUM_EXTTEXTOUT_FIELDS != 22)
|
|
#error code breaks if font handle not 13th field
|
|
#endif // OE2_NUM_TEXTOUT_FIELDS is 15 or 22
|
|
|
|
if (((pasPerson->od2Party->LastOrderType == OE2_EXTTEXTOUT_ORDER) &&
|
|
((FieldsChanged & (1 << 12)) ||
|
|
(EXTTEXTFIELD(((LPCOM_ORDER)pasPerson->od2Party->LastExtTextOut))->common.
|
|
FontIndex == DUMMY_FONT_ID))) ||
|
|
((pasPerson->od2Party->LastOrderType == OE2_TEXTOUT_ORDER) &&
|
|
((FieldsChanged & (1 << 12)) ||
|
|
(TEXTFIELD(((LPCOM_ORDER)pasPerson->od2Party->LastTextOut))->common.
|
|
FontIndex == DUMMY_FONT_ID))))
|
|
{
|
|
//
|
|
// This was a text order, and the font changed for it.
|
|
//
|
|
FH_ConvertAnyFontIDToLocal(pasPerson->od2Party->pLastOrder, pasPerson);
|
|
}
|
|
|
|
//
|
|
// if the OE2_CF_BOUNDS flag is not set, we have not yet constructed
|
|
// the bounding rectangle, so call OD2ReconstructBounds to do so
|
|
//
|
|
if ( (*pControlFlags & OE2_CF_BOUNDS) == 0)
|
|
{
|
|
OD2_CalculateBounds(pasPerson->od2Party->pLastOrder,
|
|
&Rect,
|
|
TRUE,
|
|
pasPerson);
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.left
|
|
= (TSHR_INT16)Rect.left;
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.right
|
|
= (TSHR_INT16)Rect.right;
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.top
|
|
= (TSHR_INT16)Rect.top;
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.rcsDst.bottom
|
|
= (TSHR_INT16)Rect.bottom;
|
|
pasPerson->od2Party->pLastOrder->OrderHeader.fOrderFlags |= OF_NOTCLIPPED;
|
|
}
|
|
|
|
//
|
|
// Return the decoded order length and a pointer to the order.
|
|
//
|
|
*pLengthDecoded = (UINT)(pNextDataToCopy - (LPBYTE)pEOrder);
|
|
|
|
TRACE_OUT(("Person [%d] Return decoded order length %u",
|
|
pasPerson->mcsID, *pLengthDecoded));
|
|
|
|
DebugExitPVOID(ASShare::OD2_DecodeOrder, pasPerson->od2Party->pLastOrder);
|
|
return(pasPerson->od2Party->pLastOrder);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: OD2UseFont
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Selects the font described by the parameters into the person's DC.
|
|
// so that we can then query the text extent etc.
|
|
// The queried metrics are available from pasPerson->od2Party->LastFontMetrics.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// RETURNS: TRUE if successful, FALSE otherwise.
|
|
//
|
|
//
|
|
BOOL ASShare::OD2UseFont
|
|
(
|
|
ASPerson * pasPerson,
|
|
LPSTR pName,
|
|
UINT facelength,
|
|
UINT codePage,
|
|
UINT MaxHeight,
|
|
UINT Height,
|
|
UINT Width,
|
|
UINT Weight,
|
|
UINT flags
|
|
)
|
|
{
|
|
BOOL rc = TRUE;
|
|
|
|
DebugEntry(ASShare::OD2UseFont);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
if ((pasPerson->od2Party->LastFontFaceLen != facelength ) ||
|
|
(memcmp((LPSTR)(pasPerson->od2Party->LastFaceName),pName,
|
|
facelength) != 0 ) ||
|
|
(pasPerson->od2Party->LastCodePage != codePage) ||
|
|
(pasPerson->od2Party->LastFontHeight != Height ) ||
|
|
(pasPerson->od2Party->LastFontWidth != Width ) ||
|
|
(pasPerson->od2Party->LastFontWeight != Weight ) ||
|
|
(pasPerson->od2Party->LastFontFlags != flags ))
|
|
{
|
|
TRACE_OUT(("Person [%d] Font %s (CP%d,w%d,h%d,f%04X,wgt%d) to %s (CP%d,w%d,h%d,f%04X,wgt%d)",
|
|
pasPerson->mcsID, pasPerson->od2Party->LastFaceName,
|
|
pasPerson->od2Party->LastCodePage, pasPerson->od2Party->LastFontWidth,
|
|
pasPerson->od2Party->LastFontHeight,
|
|
pasPerson->od2Party->LastFontFlags,
|
|
pasPerson->od2Party->LastFontWeight,
|
|
pName,
|
|
codePage,
|
|
Width,
|
|
Height,
|
|
flags,
|
|
Weight ));
|
|
|
|
memcpy(pasPerson->od2Party->LastFaceName,pName,facelength);
|
|
pasPerson->od2Party->LastFontFaceLen = facelength;
|
|
pasPerson->od2Party->LastFaceName[facelength] = '\0';
|
|
pasPerson->od2Party->LastFontHeight = Height;
|
|
pasPerson->od2Party->LastCodePage = codePage;
|
|
pasPerson->od2Party->LastFontWidth = Width;
|
|
pasPerson->od2Party->LastFontWeight = Weight;
|
|
pasPerson->od2Party->LastFontFlags = flags;
|
|
|
|
rc = USR_UseFont(pasPerson->m_pView->m_usrDC,
|
|
&pasPerson->od2Party->LastHFONT,
|
|
&pasPerson->od2Party->LastFontMetrics,
|
|
(LPSTR)pasPerson->od2Party->LastFaceName,
|
|
codePage,
|
|
MaxHeight,
|
|
Height,
|
|
Width,
|
|
Weight,
|
|
flags);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The font hasn't changed, so LastHFONT should be the one we
|
|
// want. We must still select it in however, since several fonts
|
|
// get selected into usrDC.
|
|
//
|
|
ASSERT(pasPerson->od2Party->LastHFONT != NULL);
|
|
SelectFont(pasPerson->m_pView->m_usrDC, pasPerson->od2Party->LastHFONT);
|
|
}
|
|
|
|
DebugExitBOOL(ASShare::OD2UseFont, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// OD2_CalculateTextOutBounds()
|
|
//
|
|
void ASShare::OD2_CalculateTextOutBounds
|
|
(
|
|
LPTEXTOUT_ORDER pTextOut,
|
|
LPRECT pRect,
|
|
BOOL fDecoding,
|
|
ASPerson * pasPerson
|
|
)
|
|
{
|
|
LPSTR pString;
|
|
int cbString;
|
|
BOOL fExtTextOut;
|
|
LPEXTTEXTOUT_ORDER pExtTextOut = NULL;
|
|
LPCOMMON_TEXTORDER pCommon;
|
|
LPSTR faceName;
|
|
UINT faceNameLength;
|
|
BOOL fFontSelected;
|
|
UINT FontIndex;
|
|
UINT width;
|
|
UINT maxFontHeight;
|
|
UINT nFontFlags;
|
|
UINT nCodePage;
|
|
|
|
DebugEntry(ASShare::OD2_CalculateTextOutBounds);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
//
|
|
// Workout if this is a TextOut or ExtTextOut order.
|
|
//
|
|
if (pTextOut->type == ORD_EXTTEXTOUT_TYPE)
|
|
{
|
|
fExtTextOut = TRUE;
|
|
pExtTextOut = (LPEXTTEXTOUT_ORDER)pTextOut;
|
|
pCommon = &(pExtTextOut->common);
|
|
|
|
//
|
|
// This code does not cope with calculating the bounds of an
|
|
// ExtTextOut order with a delta X array. We return a NULL
|
|
// rectangle in this case to force the OE2 code to transmit the
|
|
// bounds explicitly. However if we are decoding then we must
|
|
// calculate the rectangle (even though it may be wrong) to
|
|
// maintain backward compatability to previous versions of the
|
|
// product (R11) which did not return a NULL rect if delta-x was
|
|
// present.
|
|
//
|
|
if ( (pExtTextOut->fuOptions & ETO_LPDX)
|
|
&& (!fDecoding) )
|
|
{
|
|
TRACE_OUT(( "Delta X so return NULL rect"));
|
|
pRect->left = 0;
|
|
pRect->right = 0;
|
|
pRect->top = 0;
|
|
pRect->bottom = 0;
|
|
return;
|
|
}
|
|
}
|
|
else if (pTextOut->type == ORD_TEXTOUT_TYPE)
|
|
{
|
|
fExtTextOut = FALSE;
|
|
pCommon = &(pTextOut->common);
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(( "{%p} Unexpected order type %x",
|
|
pasPerson, (int)pTextOut->type));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The order structures both have the variableString as their first
|
|
// variable field. If this were not the case then the code here would
|
|
// have to take into account that the encoding side packs variable
|
|
// sized fields while the decoding side does not pack them.
|
|
//
|
|
if (fExtTextOut)
|
|
{
|
|
cbString = pExtTextOut->variableString.len;
|
|
pString = (LPSTR)&pExtTextOut->variableString.string;
|
|
}
|
|
else
|
|
{
|
|
cbString = pTextOut->variableString.len;
|
|
pString = (LPSTR)&pTextOut->variableString.string;
|
|
}
|
|
FontIndex = pCommon->FontIndex;
|
|
width = pCommon->FontWidth;
|
|
|
|
//
|
|
// Get the facename from the handle, and get the various font width/
|
|
// height adjusted values.
|
|
//
|
|
faceName = FH_GetFaceNameFromLocalHandle(FontIndex,
|
|
&faceNameLength);
|
|
maxFontHeight = (UINT)FH_GetMaxHeightFromLocalHandle(FontIndex);
|
|
|
|
//
|
|
// Get the local font flags for the font, so that we can merge in any
|
|
// specific local flag information when setting up the font. The prime
|
|
// example of this is whether the local font we matched is TrueType or
|
|
// not, which information is not sent over the wire, but does need to
|
|
// be used when setting up the font - or else we may draw using a local
|
|
// fixed font of the same facename.
|
|
//
|
|
nFontFlags = FH_GetFontFlagsFromLocalHandle(FontIndex);
|
|
|
|
//
|
|
// Get the local codePage for the font.
|
|
//
|
|
nCodePage = FH_GetCodePageFromLocalHandle(FontIndex);
|
|
|
|
//
|
|
// Hosting only version does not ever decode orders.
|
|
//
|
|
|
|
//
|
|
// Select the font into the appropriate DC and query the text extent.
|
|
//
|
|
if (fDecoding)
|
|
{
|
|
fFontSelected = OD2UseFont(pasPerson,
|
|
faceName,
|
|
faceNameLength,
|
|
nCodePage,
|
|
maxFontHeight,
|
|
pCommon->FontHeight,
|
|
width,
|
|
pCommon->FontWeight,
|
|
pCommon->FontFlags
|
|
| (nFontFlags & NF_LOCAL));
|
|
if (!fFontSelected)
|
|
{
|
|
//
|
|
// We failed to select the correct font - so we cannot
|
|
// calculate the bounds correctly. However, the fact that we
|
|
// are in this routine means that on the host the text was
|
|
// unclipped. Therefore we just return a (fairly arbitrary)
|
|
// very big rect.
|
|
//
|
|
// This is far from a perfect answer (for example, it will
|
|
// force a big repaint), but allow us to keep running in a
|
|
// difficult situation (i.e. acute resource shortage).
|
|
//
|
|
pRect->left = 0;
|
|
pRect->right = 2000;
|
|
pRect->top = -2000;
|
|
pRect->bottom = 2000;
|
|
return;
|
|
}
|
|
|
|
OE_GetStringExtent(pasPerson->m_pView->m_usrDC,
|
|
&pasPerson->od2Party->LastFontMetrics,
|
|
pString, cbString, pRect );
|
|
}
|
|
else
|
|
{
|
|
ASSERT(m_pHost);
|
|
|
|
fFontSelected = m_pHost->OE2_UseFont(faceName,
|
|
(TSHR_UINT16)faceNameLength,
|
|
(TSHR_UINT16)nCodePage,
|
|
(TSHR_UINT16)maxFontHeight,
|
|
(TSHR_UINT16)pCommon->FontHeight,
|
|
(TSHR_UINT16)width,
|
|
(TSHR_UINT16)pCommon->FontWeight,
|
|
(TSHR_UINT16)(pCommon->FontFlags
|
|
| (nFontFlags & NF_LOCAL)));
|
|
|
|
if (!fFontSelected)
|
|
{
|
|
//
|
|
// We failed to select the correct font. We return a NULL
|
|
// rectangle in this case to force the OE2 code to transmit
|
|
// the bounds explicitly.
|
|
//
|
|
pRect->left = 0;
|
|
pRect->right = 0;
|
|
pRect->top = 0;
|
|
pRect->bottom = 0;
|
|
return;
|
|
}
|
|
|
|
OE_GetStringExtent(m_pHost->m_usrWorkDC, NULL, pString, cbString, pRect );
|
|
}
|
|
|
|
//
|
|
// We have a rectangle with the text extent in it relative to (0,0) so
|
|
// add in the text starting position to this to give us the bounding
|
|
// rectangle. At the same time we will convert the exclusive rect
|
|
// returned by OE_GetStringExtent to an inclusive rectangle as us
|
|
//
|
|
pRect->left += pCommon->nXStart;
|
|
pRect->right += pCommon->nXStart - 1;
|
|
pRect->top += pCommon->nYStart;
|
|
pRect->bottom += pCommon->nYStart - 1;
|
|
|
|
//
|
|
// If this is an ExtTextOut order then we must take into account the
|
|
// opaque/clipping rectangle if there is one.
|
|
//
|
|
if (fExtTextOut)
|
|
{
|
|
//
|
|
// If the rectangle is an opaque rectangle then expand the bounding
|
|
// rectangle to bound the opaque rectangle also.
|
|
//
|
|
if (pExtTextOut->fuOptions & ETO_OPAQUE)
|
|
{
|
|
pRect->left = min(pExtTextOut->rectangle.left, pRect->left);
|
|
pRect->right = max(pExtTextOut->rectangle.right,
|
|
pRect->right);
|
|
pRect->top = min(pExtTextOut->rectangle.top,
|
|
pRect->top);
|
|
pRect->bottom = max(pExtTextOut->rectangle.bottom,
|
|
pRect->bottom);
|
|
}
|
|
|
|
//
|
|
// If the rectangle is a clip rectangle then restrict the bounding
|
|
// rectangle to be within the clip rectangle.
|
|
//
|
|
if (pExtTextOut->fuOptions & ETO_CLIPPED)
|
|
{
|
|
pRect->left = max(pExtTextOut->rectangle.left,
|
|
pRect->left);
|
|
pRect->right = min(pExtTextOut->rectangle.right,
|
|
pRect->right);
|
|
pRect->top = max(pExtTextOut->rectangle.top,
|
|
pRect->top);
|
|
pRect->bottom = min(pExtTextOut->rectangle.bottom,
|
|
pRect->bottom);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(ASShare::OD2_CalculateTextOutBounds);
|
|
}
|
|
|
|
|
|
//
|
|
// OD2_CalculateBounds()
|
|
//
|
|
void ASShare::OD2_CalculateBounds
|
|
(
|
|
LPCOM_ORDER pOrder,
|
|
LPRECT pRect,
|
|
BOOL fDecoding,
|
|
ASPerson * pasPerson
|
|
)
|
|
{
|
|
UINT i;
|
|
UINT numPoints;
|
|
|
|
DebugEntry(ASShare::OD2_CalculateBounds);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
//
|
|
// Calculate the bounds according to the order type.
|
|
// All blts can be handled in the same way.
|
|
//
|
|
switch ( ((LPPATBLT_ORDER)pOrder->abOrderData)->type )
|
|
{
|
|
//
|
|
// Calculate bounds for the blts.
|
|
// This is the destination rectangle. Bounds are inclusive.
|
|
//
|
|
case ORD_DSTBLT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPDSTBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top = ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right = pRect->left
|
|
+ ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nWidth
|
|
- 1;
|
|
pRect->bottom = pRect->top
|
|
+ ((LPDSTBLT_ORDER)(pOrder->abOrderData))->nHeight
|
|
- 1;
|
|
break;
|
|
|
|
|
|
case ORD_PATBLT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPPATBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPPATBLT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPPATBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPPATBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
|
|
case ORD_SCRBLT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPSCRBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
case ORD_MEMBLT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPMEMBLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
case ORD_MEM3BLT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPMEM3BLT_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
case ORD_MEMBLT_R2_TYPE:
|
|
pRect->left =
|
|
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPMEMBLT_R2_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
case ORD_MEM3BLT_R2_TYPE:
|
|
pRect->left =
|
|
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPMEM3BLT_R2_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
//
|
|
// Calculate bounds for Rectangle.
|
|
// This is the rectangle itself. Bounds are inclusive.
|
|
//
|
|
case ORD_RECTANGLE_TYPE:
|
|
|
|
pRect->left =
|
|
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom =
|
|
((LPRECTANGLE_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
break;
|
|
|
|
|
|
case ORD_ROUNDRECT_TYPE:
|
|
|
|
pRect->left =
|
|
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom =
|
|
((LPROUNDRECT_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
break;
|
|
|
|
case ORD_POLYGON_TYPE:
|
|
//
|
|
// Calculate bounds for Polygon.
|
|
//
|
|
pRect->left = 0x7fff;
|
|
pRect->right = 0;
|
|
pRect->top = 0x7fff;
|
|
pRect->bottom = 0;
|
|
|
|
//
|
|
// BOGUS! LAURABU BUGBUG
|
|
//
|
|
// In NM 2.0, the wrong fields were being compared. x to top/
|
|
// bottom, and y to left/right.
|
|
//
|
|
// Effectively, this meant that we never matched the bounds
|
|
// in the rcsDst rect.
|
|
//
|
|
numPoints = ((LPPOLYGON_ORDER)(pOrder->abOrderData))->
|
|
variablePoints.len
|
|
/ sizeof(((LPPOLYGON_ORDER)(pOrder->abOrderData))->
|
|
variablePoints.aPoints[0]);
|
|
|
|
for (i = 0; i < numPoints; i++ )
|
|
{
|
|
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y > pRect->bottom )
|
|
{
|
|
pRect->bottom = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y;
|
|
}
|
|
|
|
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y < pRect->top )
|
|
{
|
|
pRect->top = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y;
|
|
}
|
|
|
|
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x > pRect->right )
|
|
{
|
|
pRect->right = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x;
|
|
}
|
|
|
|
if ( ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x < pRect->left )
|
|
{
|
|
pRect->left = ((LPPOLYGON_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x;
|
|
}
|
|
}
|
|
|
|
TRACE_OUT(("Poly bounds: left:%d, right:%d, top:%d, bottom:%d",
|
|
pRect->left, pRect->right, pRect->top, pRect->bottom ));
|
|
|
|
break;
|
|
|
|
case ORD_PIE_TYPE:
|
|
//
|
|
// Pull out the bounding rectangle directly from the PIE order.
|
|
//
|
|
|
|
pRect->left = ((LPPIE_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top = ((LPPIE_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right = ((LPPIE_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom = ((LPPIE_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
|
|
break;
|
|
|
|
case ORD_ELLIPSE_TYPE:
|
|
//
|
|
// Pull out the bounding rectangle directly from ELLIPSE order.
|
|
//
|
|
pRect->left = ((LPELLIPSE_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top = ((LPELLIPSE_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
((LPELLIPSE_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom =
|
|
((LPELLIPSE_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
|
|
break;
|
|
|
|
case ORD_ARC_TYPE:
|
|
//
|
|
// Pull out the bounding rectangle directly from the ARC order.
|
|
//
|
|
pRect->left = ((LPARC_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top = ((LPARC_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right = ((LPARC_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom = ((LPARC_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
|
|
break;
|
|
|
|
case ORD_CHORD_TYPE:
|
|
//
|
|
// Pull out the bounding rectangle directly from the CHORD
|
|
// order.
|
|
//
|
|
pRect->left = ((LPCHORD_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top = ((LPCHORD_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right = ((LPCHORD_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
pRect->bottom =
|
|
((LPCHORD_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
|
|
break;
|
|
|
|
|
|
case ORD_POLYBEZIER_TYPE:
|
|
//
|
|
// Calculate bounds for PolyBezier.
|
|
//
|
|
pRect->left = 0x7fff;
|
|
pRect->right = 0;
|
|
pRect->top = 0x7fff;
|
|
pRect->bottom = 0;
|
|
|
|
numPoints = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))->
|
|
variablePoints.len
|
|
/ sizeof(((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))->
|
|
variablePoints.aPoints[0]);
|
|
|
|
//
|
|
// BOGUS! LAURABU BUGBUG
|
|
//
|
|
// In NM 2.0, the wrong fields were being compared. x to top/
|
|
// bottom, and y to left/right.
|
|
//
|
|
// Effectively, this meant that we never matched the bounds
|
|
// in the rcsDst rect.
|
|
//
|
|
for (i = 0; i < numPoints; i++ )
|
|
{
|
|
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y > pRect->bottom )
|
|
{
|
|
pRect->bottom = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y;
|
|
}
|
|
|
|
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y < pRect->top )
|
|
{
|
|
pRect->top = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].y;
|
|
}
|
|
|
|
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x > pRect->right )
|
|
{
|
|
pRect->right = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x;
|
|
}
|
|
|
|
if ( ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x < pRect->left )
|
|
{
|
|
pRect->left = ((LPPOLYBEZIER_ORDER)(pOrder->abOrderData))
|
|
->variablePoints.aPoints[i].x;
|
|
}
|
|
}
|
|
|
|
TRACE_OUT((
|
|
"PolyBezier bounds: left:%d, right:%d, top:%d, bot:%d",
|
|
pRect->left, pRect->right, pRect->top, pRect->bottom));
|
|
break;
|
|
|
|
|
|
case ORD_LINETO_TYPE:
|
|
//
|
|
// Calculate bounds for LineTo. This is the rectangle with
|
|
// opposite vertices on the start and end points of the line.
|
|
// The gradient of the line determines whether the start or end
|
|
// point provides the top or bottom, left or right of the
|
|
// rectangle. Bounds are inclusive.
|
|
//
|
|
if ( ((LPLINETO_ORDER)(pOrder->abOrderData))->nXStart <
|
|
((LPLINETO_ORDER)(pOrder->abOrderData))->nXEnd )
|
|
{
|
|
pRect->left =
|
|
((LPLINETO_ORDER)(pOrder->abOrderData))->nXStart;
|
|
pRect->right =
|
|
((LPLINETO_ORDER)(pOrder->abOrderData))->nXEnd;
|
|
}
|
|
else
|
|
{
|
|
pRect->right =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nXStart;
|
|
pRect->left =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nXEnd;
|
|
}
|
|
|
|
if ( ((LPLINETO_ORDER)pOrder->abOrderData)->nYStart <
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd )
|
|
{
|
|
pRect->top =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nYStart;
|
|
pRect->bottom =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd;
|
|
}
|
|
else
|
|
{
|
|
pRect->bottom =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nYStart;
|
|
pRect->top =
|
|
((LPLINETO_ORDER)pOrder->abOrderData)->nYEnd;
|
|
}
|
|
break;
|
|
|
|
case ORD_OPAQUERECT_TYPE:
|
|
//
|
|
// Calculate bounds for OpaqueRect. This is the rectangle
|
|
// itself. Bounds are inclusive.
|
|
//
|
|
pRect->left =
|
|
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->right =
|
|
pRect->left +
|
|
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nWidth - 1;
|
|
pRect->bottom =
|
|
pRect->top +
|
|
((LPOPAQUERECT_ORDER)(pOrder->abOrderData))->nHeight - 1;
|
|
break;
|
|
|
|
case ORD_SAVEBITMAP_TYPE:
|
|
//
|
|
// Calculate bounds for SaveBitmap. This is the rectangle
|
|
// itself. Bounds are inclusive.
|
|
//
|
|
pRect->left =
|
|
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nLeftRect;
|
|
pRect->top =
|
|
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nTopRect;
|
|
pRect->bottom =
|
|
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nBottomRect;
|
|
pRect->right =
|
|
((LPSAVEBITMAP_ORDER)(pOrder->abOrderData))->nRightRect;
|
|
break;
|
|
|
|
|
|
case ORD_TEXTOUT_TYPE:
|
|
case ORD_EXTTEXTOUT_TYPE:
|
|
//
|
|
// TextOut and ExtTextOut bounds calculations are done by the
|
|
// OD2_CalculateTextOutBounds function.
|
|
//
|
|
OD2_CalculateTextOutBounds((LPTEXTOUT_ORDER)pOrder->abOrderData,
|
|
pRect,
|
|
fDecoding,
|
|
pasPerson);
|
|
break;
|
|
|
|
|
|
case ORD_DESKSCROLL_TYPE:
|
|
pRect->left = 0;
|
|
pRect->top = 0;
|
|
pRect->right = 0;
|
|
pRect->bottom = 0;
|
|
break;
|
|
|
|
|
|
default:
|
|
ERROR_OUT((
|
|
"{%p} unrecognized type passed to OD2ReconstructBounds: %d",
|
|
pasPerson,
|
|
(int)((LPPATBLT_ORDER)pOrder->abOrderData)->type));
|
|
break;
|
|
}
|
|
|
|
DebugExitVOID(ASShare::OD2_CalculateBounds);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// OD2DecodeBounds()
|
|
//
|
|
void ASShare::OD2DecodeBounds
|
|
(
|
|
LPBYTE* ppNextDataToCopy,
|
|
LPTSHR_RECT16 pRect,
|
|
ASPerson * pasPerson
|
|
)
|
|
{
|
|
LPBYTE pFlags;
|
|
|
|
DebugEntry(ASShare::OD2DecodeBounds);
|
|
|
|
ValidatePerson(pasPerson);
|
|
|
|
//
|
|
// The encoding used is a byte of flags followed by a variable number
|
|
// of 16bit coordinate values and 8bit delta coordinate values (which
|
|
// may be interleaved).
|
|
//
|
|
|
|
//
|
|
// The first byte of the encoding will contain the flags that represent
|
|
// how the coordinates of the rectangle were encoded.
|
|
//
|
|
pFlags = *ppNextDataToCopy;
|
|
(*ppNextDataToCopy)++;
|
|
|
|
//
|
|
// Initialise the rectangle with the last decoded coordinates.
|
|
//
|
|
*pRect = pasPerson->od2Party->LastBounds;
|
|
|
|
//
|
|
// If the flags indicate that none of the coordinates have changed then
|
|
// fast path and exit now.
|
|
//
|
|
if (*pFlags == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// For each of the four coordinate values in the rectangle: If the
|
|
// coordinate was encoded as an 8bit delta then add on the delta to the
|
|
// previous value. If the coordinate was encoded as a 16bit value
|
|
// then copy the value across. Otherwise the coordinate was the same
|
|
// as the previous one so leave it alone.
|
|
//
|
|
if (*pFlags & OE2_BCF_DELTA_LEFT)
|
|
{
|
|
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
|
|
&pRect->left,
|
|
sizeof(pRect->left),
|
|
TRUE, // The value is signed
|
|
1);
|
|
}
|
|
else if (*pFlags & OE2_BCF_LEFT)
|
|
{
|
|
pRect->left = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
|
|
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
|
|
}
|
|
|
|
if (*pFlags & OE2_BCF_DELTA_TOP)
|
|
{
|
|
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
|
|
&pRect->top,
|
|
sizeof(pRect->top),
|
|
TRUE, // The value is signed
|
|
1);
|
|
}
|
|
else if (*pFlags & OE2_BCF_TOP)
|
|
{
|
|
pRect->top = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
|
|
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
|
|
}
|
|
|
|
if (*pFlags & OE2_BCF_DELTA_RIGHT)
|
|
{
|
|
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
|
|
&pRect->right,
|
|
sizeof(pRect->right),
|
|
TRUE, // The value is signed
|
|
1);
|
|
}
|
|
else if (*pFlags & OE2_BCF_RIGHT)
|
|
{
|
|
pRect->right = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
|
|
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
|
|
}
|
|
|
|
if (*pFlags & OE2_BCF_DELTA_BOTTOM)
|
|
{
|
|
OD2CopyFromDeltaCoords((LPTSHR_INT8*)ppNextDataToCopy,
|
|
&pRect->bottom,
|
|
sizeof(pRect->bottom),
|
|
TRUE, // The value is signed
|
|
1);
|
|
}
|
|
else if (*pFlags & OE2_BCF_BOTTOM)
|
|
{
|
|
pRect->bottom = EXTRACT_TSHR_INT16_UA(*ppNextDataToCopy);
|
|
(*ppNextDataToCopy) += sizeof(TSHR_INT16);
|
|
}
|
|
|
|
//
|
|
// Copy the rectangle for reference with the next encoding.
|
|
//
|
|
pasPerson->od2Party->LastBounds = *pRect;
|
|
|
|
DebugExitVOID(ASShare::OD2DecodeBounds);
|
|
}
|
|
|
|
|
|
//
|
|
// Copy an array of source elements to an array of destination elements,
|
|
// converting the types as the copy takes place.
|
|
//
|
|
// DESTARRAY - The destination array
|
|
// SRCARRAY - The source array
|
|
// DESTTYPE - The type of the elements in the destination array
|
|
// NUMELEMENTS - The number of elements in the array
|
|
//
|
|
//
|
|
#define CONVERT_ARRAY(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
|
|
{ \
|
|
UINT index; \
|
|
for (index=0 ; index<(NUMELEMENTS) ; index++) \
|
|
{ \
|
|
(DESTARRAY)[index] = (DESTTYPE)(SRCARRAY)[index]; \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// Copy an array of source elements to an array of destination elements,
|
|
// converting the types as the copy takes place. This version allows for
|
|
// unaligned INT16 pointers
|
|
//
|
|
// DESTARRAY - The destination array
|
|
// SRCARRAY - The source array
|
|
// DESTTYPE - The type of the elements in the destination array
|
|
// NUMELEMENTS - The number of elements in the array
|
|
//
|
|
//
|
|
#define CONVERT_ARRAY_INT16_UA(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
|
|
{ \
|
|
UINT index; \
|
|
TSHR_INT16 value; \
|
|
for (index=0 ; index<(NUMELEMENTS) ; index++) \
|
|
{ \
|
|
value = EXTRACT_TSHR_INT16_UA((SRCARRAY)+index); \
|
|
(DESTARRAY)[index] = (DESTTYPE)value; \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// Copy an array of source elements to an array of destination elements,
|
|
// converting the types as the copy takes place. This version allows for
|
|
// unaligned TSHR_UINT16 pointers
|
|
//
|
|
// DESTARRAY - The destination array
|
|
// SRCARRAY - The source array
|
|
// DESTTYPE - The type of the elements in the destination array
|
|
// NUMELEMENTS - The number of elements in the array
|
|
//
|
|
//
|
|
#define CONVERT_ARRAY_UINT16_UA(DESTARRAY, SRCARRAY, DESTTYPE, NUMELEMENTS) \
|
|
{ \
|
|
UINT index; \
|
|
TSHR_UINT16 value; \
|
|
for (index=0 ; index<(NUMELEMENTS) ; index++) \
|
|
{ \
|
|
value = EXTRACT_TSHR_UINT16_UA((SRCARRAY)+index); \
|
|
(DESTARRAY)[index] = (DESTTYPE)((TSHR_INT16)value); \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// OD2DecodeField()
|
|
//
|
|
void ASShare::OD2DecodeField
|
|
(
|
|
LPBYTE* ppSrc,
|
|
LPVOID pDst,
|
|
UINT cbSrcField,
|
|
UINT cbDstField,
|
|
BOOL fSigned,
|
|
UINT numElements
|
|
)
|
|
{
|
|
LPTSHR_UINT8 pDst8 = (LPTSHR_UINT8)pDst;
|
|
LPTSHR_INT16 pDst16Signed = (LPTSHR_INT16)pDst;
|
|
LPTSHR_INT32 pDst32Signed = (LPTSHR_INT32)pDst;
|
|
LPTSHR_UINT16 pDst16Unsigned = (LPTSHR_UINT16)pDst;
|
|
LPTSHR_UINT32 pDst32Unsigned = (LPTSHR_UINT32)pDst;
|
|
LPTSHR_INT8 pSrc8Signed = (LPTSHR_INT8)*ppSrc;
|
|
LPTSHR_UINT8 pSrc8Unsigned = (LPTSHR_UINT8)*ppSrc;
|
|
LPTSHR_INT16_UA pSrc16Signed = (LPTSHR_INT16_UA)*ppSrc;
|
|
LPTSHR_UINT16_UA pSrc16Unsigned = (LPTSHR_UINT16_UA)*ppSrc;
|
|
|
|
//
|
|
// Note that the source fields may not be aligned correctly, so we use
|
|
// unaligned pointers. The destination is aligned correctly.
|
|
//
|
|
DebugEntry(ASShare::OD2DecodeField);
|
|
|
|
//
|
|
// Make sure that the destination field length is larger or equal to
|
|
// the source field length. If it isn't, something has gone wrong.
|
|
//
|
|
if (cbDstField < cbSrcField)
|
|
{
|
|
ERROR_OUT(( "Source field length %d is larger than destination %d",
|
|
cbSrcField,
|
|
cbDstField));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// If the source and destination field lengths are the same, we can
|
|
// just do a copy (no type conversion required).
|
|
//
|
|
if (cbSrcField == cbDstField)
|
|
{
|
|
memcpy(pDst8, *ppSrc, cbDstField * numElements);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We know that cbDstField must be greater than cbSrcField
|
|
// because of our checks above. So there are only three
|
|
// conversions to consider:
|
|
//
|
|
// 8 bit -> 16 bit
|
|
// 8 bit -> 32 bit
|
|
// 16 bit -> 32 bit
|
|
//
|
|
// We also have to get the signed / unsigned attributes correct. If
|
|
// we try to promote a signed value using unsigned pointers, we
|
|
// will get the wrong result.
|
|
//
|
|
// e.g. Consider converting the value -1 from a TSHR_INT16 to TSHR_INT32
|
|
// using unsigned pointers.
|
|
//
|
|
// -1 -> TSHR_UINT16 == 65535
|
|
// -> UINT == 65535
|
|
// -> TSHR_INT32 == 65535
|
|
//
|
|
//
|
|
if ((cbDstField == 4) && (cbSrcField == 1))
|
|
{
|
|
if (fSigned)
|
|
{
|
|
CONVERT_ARRAY(pDst32Signed,
|
|
pSrc8Signed,
|
|
TSHR_INT32,
|
|
numElements);
|
|
}
|
|
else
|
|
{
|
|
CONVERT_ARRAY(pDst32Unsigned,
|
|
pSrc8Unsigned,
|
|
TSHR_UINT32,
|
|
numElements);
|
|
}
|
|
}
|
|
else if ((cbDstField == 4) && (cbSrcField == 2))
|
|
{
|
|
if (fSigned)
|
|
{
|
|
CONVERT_ARRAY_INT16_UA(pDst32Signed,
|
|
pSrc16Signed,
|
|
TSHR_INT32,
|
|
numElements);
|
|
}
|
|
else
|
|
{
|
|
CONVERT_ARRAY_UINT16_UA(pDst32Unsigned,
|
|
pSrc16Unsigned,
|
|
TSHR_UINT32,
|
|
numElements);
|
|
}
|
|
}
|
|
else if ((cbDstField == 2) && (cbSrcField == 1))
|
|
{
|
|
if (fSigned)
|
|
{
|
|
CONVERT_ARRAY(pDst16Signed,
|
|
pSrc8Signed,
|
|
TSHR_INT16,
|
|
numElements);
|
|
}
|
|
else
|
|
{
|
|
CONVERT_ARRAY(pDst16Unsigned,
|
|
pSrc8Unsigned,
|
|
TSHR_UINT16,
|
|
numElements);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(( "Bad conversion, dest length = %d, src length = %d",
|
|
cbDstField,
|
|
cbSrcField));
|
|
}
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
*ppSrc += cbSrcField * numElements;
|
|
DebugExitVOID(ASShare::OD2DecodeField);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Given two arrays, a source array and an array of deltas, add each delta
|
|
// to the corresponding element in the source array, storing the results in
|
|
// the source array.
|
|
//
|
|
// srcArray - The array of source values
|
|
// srcArrayType - The type of the array of source values
|
|
// deltaArray - The array of deltas
|
|
// numElements - The number of elements in the arrays
|
|
//
|
|
//
|
|
#define COPY_DELTA_ARRAY(srcArray, srcArrayType, deltaArray, numElements) \
|
|
{ \
|
|
UINT index; \
|
|
for (index = 0; index < (numElements); index++) \
|
|
{ \
|
|
(srcArray)[index] = (srcArrayType) \
|
|
((srcArray)[index] + (deltaArray)[index]); \
|
|
} \
|
|
}
|
|
|
|
|
|
//
|
|
// OD2CopyFromDeltaCoords()
|
|
//
|
|
void ASShare::OD2CopyFromDeltaCoords
|
|
(
|
|
LPTSHR_INT8* ppSrc,
|
|
LPVOID pDst,
|
|
UINT cbDstField,
|
|
BOOL fSigned,
|
|
UINT numElements
|
|
)
|
|
{
|
|
LPTSHR_INT8 pDst8Signed = (LPTSHR_INT8)pDst;
|
|
LPTSHR_INT16 pDst16Signed = (LPTSHR_INT16)pDst;
|
|
LPTSHR_INT32 pDst32Signed = (LPTSHR_INT32)pDst;
|
|
LPTSHR_UINT8 pDst8Unsigned = (LPTSHR_UINT8)pDst;
|
|
LPTSHR_UINT16 pDst16Unsigned = (LPTSHR_UINT16)pDst;
|
|
LPTSHR_UINT32 pDst32Unsigned = (LPTSHR_UINT32)pDst;
|
|
|
|
DebugEntry(ASShare::OD2CopyFromDeltaCoords);
|
|
|
|
switch (cbDstField)
|
|
{
|
|
case 1:
|
|
if (fSigned)
|
|
{
|
|
COPY_DELTA_ARRAY(pDst8Signed, TSHR_INT8, *ppSrc, numElements);
|
|
}
|
|
else
|
|
{
|
|
COPY_DELTA_ARRAY(pDst8Unsigned, TSHR_UINT8, *ppSrc, numElements);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (fSigned)
|
|
{
|
|
COPY_DELTA_ARRAY(pDst16Signed, TSHR_INT16, *ppSrc, numElements);
|
|
}
|
|
else
|
|
{
|
|
COPY_DELTA_ARRAY(pDst16Unsigned, TSHR_UINT16, *ppSrc, numElements);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (fSigned)
|
|
{
|
|
COPY_DELTA_ARRAY(pDst32Signed, TSHR_INT32, *ppSrc, numElements);
|
|
}
|
|
else
|
|
{
|
|
COPY_DELTA_ARRAY(pDst32Unsigned, TSHR_UINT32, *ppSrc, numElements);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(( "Bad destination field length %d",
|
|
cbDstField));
|
|
DC_QUIT;
|
|
// break;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
*ppSrc += numElements;
|
|
DebugExitVOID(ASShare::OD2CopyFromDeltaCoords);
|
|
}
|
|
|
|
|