#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); }