/***************************************************************************** * * objects - Entry points for Win32 to Win 16 converter * * Date: 7/1/91 * Author: Jeffrey Newman (c-jeffn) * * Copyright 1991 Microsoft Corp * * * 14-Jan-1992 * Jeffrey Newman * * CR1: 14-Jan-1992 - this entire comment and the design that it * specifies. * * The Object system in mf3216. * * Overview * * The Win32 objects (represented by object handle indicies) must be * mapped to Win16 objects (also represented by object handle indices). * Win32 uses stock objects, Win16 does not. MF3216 uses a scheme * for lazy stock object creation. Through lazy stock object creation * no unused objects will be emitted into the Win16 metafile. * * Objects in a Win16 metafile are maintained in an Object Table. The * object table is not recorded in the Win16 metafile. It is created at * play-time. Each entry in the Win16-Object-Table is called a slot. * Slots are allocated one per object. If an object is deleted then the * slot becomes available for the next object created. The first object- * slot, starting from 0, in a linear search, that is available will be * used to hold the next create object request. * * Objects in either a Win32 or a Win16 metafile are represented as an * index into the Object Table. Every object created must occupy * the same slot at play-time that it would have occupied at record-time. * * Win32 objects have an object ID (index in the handle table) recorded * with them. Win16 objects do not. * * Data Structures * * There are two primary data structures used in the translation of * Win32 objects to Win16 objects. Both of them are dynamically * allocated arrays. The size of these arrays are determined by * estimating the number of objects required in the Win16 metafile from * the size of the handle table used in the Win32 metafile. The size of * the handle table is recorded in the Win32 metafile header. * * The data structure piW16ObjectHandleSlotStatus is used to represent * the status of the Win16 handle table as it would appear at any point * during the Win16 metafile playback process. A slot is either in * use or free. * * The data structure piW32ToW16ObjectMap is a translation table * from the Win32 object indicies to the Win16 object indicies. * The position in the array (aka the index into the array) is the * Win32 handle. The value in this entry is the Win16 slot number * for the handle. * * The first 16 entries in piW32ToW16ObjectMap array are used for the * stock objects. * * Support Routines * * bInitHandleTableManager * * 1] Allocate memory for pW16ObjHndlSlotStatus and * piW32ToW16ObjectMap arrays. * * 2] Initialize pW16ObjHndlSlotStatus and * piW32ToW16ObjectMap to empty and UNMAPPED respectively. * * 3] Returns a TRUE if there were no problems with the * initialization, FALSE if anything went wrong. * * 4] It is expected that this routie will be called once from * the entry level routine when translation is first started. * * iNormalizeHandle * * 1] The idea behind this routine is to isolate the handling * of stock object handles to one place. * * 2] Input will be a Win32 handle index, either stock or a * standard object. * * 3] Output will be the index of the entry in the * piW32ToW16ObjectMap table that corresponds to the W32 * handle. If an error is detected -1 is returned. * * 4] All the stock objects will be between the range of 0 * and LAST_STOCK, and all the non-stock objects will be * greater than LAST_STOCK. * * iGetW16ObjectHandleSlot * * 1] This routine searches the pW16ObjHndlSlotStatus array * looking for the first available open slot. * * 2] Mark the slot found as to its intended use. * * 3] Returns the first open slot if found, else return -1. * * 4] In essence this routine mimics the actions of the * Win16 play-time handle allocation system, in either * Win3.0 or Win3.1 * * 5] We also keep track of the max object count here. * * iAllocateW16Handle * * 1] This routine actually does the handle allocation. * * 2] It sets the entry in pW16ObjHndlSlotStatus array * for the slot allocated by iGetW16ObjectHandleSlot to * an "in-use" status (for the intended use). * * 3] It returns a ihW16 (an index handle to the Win16 handle * table, aka the Win16 handle slot number). * * iValidateHandle * * 1] This routine does a lot more than validate a Win32 handle. * It does some limited error checking on the Win32 handle, * to make sure its within a reasonable range. Then if a * Win16 handle table slot has already been allocated for * this Win32 handle it will return the Win16 handle that * was previously allocated. Alternatively, if a Win16 * handle has not been previously allocated for a Win32 * STOCK handle it will allocate a W16 handle and return the * Win16 handle. This function is called by FillRgn, FrameRgn * and SelectObject to allow lazy allocation of stock objects. * * 2] Input is a Win32 handle, either a stock or a non-stock * handle. * * 3] Output is a Win16 handle, this is the value in the * Win32-index of the piW32ToW16ObjectMap. If a stock object * does not exist, it will create one. * * 4] If there is an error a -1 is returned. * * Doer Routines * * All the Doers return a bool. TRUE if everything went OK. * FALSE if there were any problems. * * NOTE: The Doers that create an object actually must do * quite a bit of work to translate the object's prameters. * This is in addition to managing the handle table. The * work outlined below just deals with the management of the * handle table. * * DoSelectObject * * 1] For stock objects this is the workhorse routine. * * 2] For normal, non-stock, objects this routine will verify * that an object has been created for this Win32 object-index. * Then it will emit a Win16SelectObject metafile record. * * 3] For stock objects things get a little more complicated. * First this routine must make sure a Win16 object has been * created for this stock object. If a Win16 object has not * been created yet, then it will be. After a Win16 object * is created a Win16SelectObject record will be emitted for * the object. * * DoDeleteObject * * 1] The object handle is checked for reasonable limits. * We will also make sure that the Win16 slot has a handle * allocated to it. If it does not then we will return an * error. * * 2] If this is a stock object we fail and return an error. * * 3] If this is a non-stock object we emit a Win16DeleteObject * record. Then we set pW16ObjHndlSlotStatus to * indicate that this slot is available. We also set * piW32ToW16ObjectMap to -1 (UNMAPPED). * * DoCreatePen * DoExtCreatePen * DoCreateBrushIndirect * DoCreateMonoBrush * DoCreateDIBPatternBrush * DoExtCreateFont * * 1] Make sure the Win32 handle is not already being used * for something else. If it is return an error. * * 2] Validate the handle for this Object. This will return * a Win16 object table index (actually a slot number). * We really don't care what the slot number is as long * as we got one. DoDeleteObject and DoSelectObject always * refer to handles by their Win32 object indicies, and there * is no place else where used. * * 3] Emit a Win16CreateObject metafile record. * * * Special Routines * * bCommonRegionCode * Need to list the bitblt routines that use handles also * * 1] These routines just need to create objects in the Win16 * metafile. There are no corresponding objects in the Win32 * metafile. * * 2] Allocate a Win16 handle. * * 3] Use the object as needed. This includes emitting a * region or bitmap object into the Win16 metafile. * * 4] De-allocate the object. This include emitting a * DeleteObject record. * * CR1 * Paths require the current pen to selected into the helperDC. * In order to keep track of create, select, & delete of the pen * object we will add an extra field to the W16ObjectHandleSlotStatus * array entries. This new field will contain either a NULL handle * or a valid Win32 handle. Currently only pens need to be selected * into the helper DC for paths, so they are the only objects whose * W32 handle field is not NULL. * *****************************************************************************/ #include "precomp.h" #pragma hdrstop #define ABS(A) ((A) < 0 ? (-(A)) : (A)) // Stock objects Name Stock // Object // ID LOGBRUSH albStock[] = { {BS_SOLID, 0x0FFFFFF, 0}, // White Brush 0 {BS_SOLID, 0x0C0C0C0, 0}, // Ligh Grey Brush 1 {BS_SOLID, 0x0808080, 0}, // Grey Brush 2 {BS_SOLID, 0x0404040, 0}, // Dark Grey Brush 3 {BS_SOLID, 0x0000000, 0}, // Black Brush 4 {BS_HOLLOW, 0x0000000, 0} // Hollow Brush 5 } ; LOGPEN alpnStock[] = { {PS_SOLID, 0, 0, 0x0FFFFFF}, // White Pen 6 {PS_SOLID, 0, 0, 0x0000000}, // Black Pen 7 {PS_NULL, 0, 0, 0x0FFFFFF} // Null Pen 8 } ; // Internal function prototypes. BOOL bCreateStockObject(PLOCALDC pLocalDC, INT ihw32Norm) ; BOOL bCreateStockFont(PLOCALDC pLocalDC, INT ihW32) ; /*************************************************************************** * bInitHandleTableManager - Init the Handle Table Manager. * * 1] Allocate memory for pW16ObjHndlSlotStatus and * piW32ToW16ObjectMap arrays. * * 2] Initialize pW16ObjHndlSlotStatus and * piW32ToW16ObjectMap to empty and UNMAPPED respectively. * * 3] Returns a TRUE if there were no problems with the * initialization, FALSE if anything went wrong. * * 4] It is expected that this routie will be called once from * the entry level routine when translation is first started. * **************************************************************************/ BOOL bInitHandleTableManager(PLOCALDC pLocalDC, PENHMETAHEADER pmf32header) { BOOL b ; UINT i ; b = FALSE ; // The total number of handles required will be the stock handles // plus the handles used by the Win32 metafile plus one extra // for temporary brush used in opaque rectangle in textout. pLocalDC->cW32ToW16ObjectMap = pmf32header->nHandles + (STOCK_LAST + 1) + 1; // Allocate storage for the translation map. i = pLocalDC->cW32ToW16ObjectMap * sizeof(INT) ; pLocalDC->piW32ToW16ObjectMap = (PINT) LocalAlloc(LMEM_FIXED, i) ; if (pLocalDC->piW32ToW16ObjectMap == NULL) goto error_exit ; // Initialize the W32 to W16 object map to UNMAPPED (-1). // Since we never will have mapping to -1 we can test for // -1 in the map to make sure we are not double allocating a slot. for (i = 0 ; i < pLocalDC->cW32ToW16ObjectMap ; i++) pLocalDC->piW32ToW16ObjectMap[i] = UNMAPPED ; // Allocate storage for the slot status tables. // The number of Win16 object table slot may expand during conversion // due to temporary bitmaps and regions. It is my educated guess // that we will never need more than 5 extra slots, because we // only use a slot for a very short time, then free it. We are // allocating 256 extra slots in the name of robustness. // Note that the multi-format comment record may take up some // of these slots and increase the high water mark for object index. // We need to expand the table when required. pLocalDC->cW16ObjHndlSlotStatus = pLocalDC->cW32ToW16ObjectMap + 256 ; if (pLocalDC->cW16ObjHndlSlotStatus > (UINT) (WORD) MAXWORD) goto error_exit ; // w16 handle index is only 16-bit i = pLocalDC->cW16ObjHndlSlotStatus * sizeof(W16OBJHNDLSLOTSTATUS) ; pLocalDC->pW16ObjHndlSlotStatus = (PW16OBJHNDLSLOTSTATUS) LocalAlloc(LMEM_FIXED, i) ; if (pLocalDC->pW16ObjHndlSlotStatus == NULL) goto error_exit ; // Initialize the W16ObjectHandleSlotStatus to a state where every // handle is available. for (i = 0 ; i < pLocalDC->cW16ObjHndlSlotStatus ; i++) { pLocalDC->pW16ObjHndlSlotStatus[i].use = OPEN_AVAILABLE_SLOT ; pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle = 0 ; pLocalDC->pW16ObjHndlSlotStatus[i].iXORPassCreation = NOTXORPASS ; pLocalDC->pW16ObjHndlSlotStatus[i].pbCreatRec = NULL ; } // Initialize the pW32hPal palette handle table. // This table is used to store the W32 palette handles created during // the conversion. pLocalDC->cW32hPal = pmf32header->nHandles; i = pLocalDC->cW32hPal * sizeof(HPALETTE); pLocalDC->pW32hPal = (HPALETTE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, i) ; if (pLocalDC->pW32hPal == NULL) goto error_exit ; b = TRUE; error_exit: if (!b) { if (pLocalDC->piW32ToW16ObjectMap) { if (LocalFree(pLocalDC->piW32ToW16ObjectMap)) ASSERTGDI(FALSE, "MF3216: LocalFree failed"); pLocalDC->piW32ToW16ObjectMap = (PINT) NULL; } if (pLocalDC->pW16ObjHndlSlotStatus) { if (LocalFree(pLocalDC->pW16ObjHndlSlotStatus)) ASSERTGDI(FALSE, "MF3216: LocalFree failed"); pLocalDC->pW16ObjHndlSlotStatus = NULL; } } return(b) ; } /*************************************************************************** * bDeleteW16Object - Delete a W16 Object. * * This is the routine that is called to Delete a W16 Object that has * no corresponding W32 object. Region and Bitmaps are two examples. **************************************************************************/ BOOL bDeleteW16Object(PLOCALDC pLocalDC, INT ihW16) { BOOL b ; ASSERTGDI ( pLocalDC->pW16ObjHndlSlotStatus[ihW16].use != OPEN_AVAILABLE_SLOT, "MF3216: bDeleteW16Object, bad use value" ); // Mark the W16 Slot just freed as available. pLocalDC->pW16ObjHndlSlotStatus[ihW16].use = OPEN_AVAILABLE_SLOT ; // Emit a Win16 DeleteOject record for the Object b = bEmitWin16DeleteObject(pLocalDC, LOWORD(ihW16)) ; return (b) ; } /*************************************************************************** * iGetW16ObjectHandleSlot - return the first W16 open slot in the handle * table. * * 1] This routine searches the pW16ObjHndlSlotStatus array * looking for the first available open slot. * * 2] Mark the slot found as to its intended use. * * 3] Returns the first open slot if found, else return -1. * * 4] In essence this routine mimics the actions of the * Win16 play-time handle allocation system, in either * Win3.0 or Win3.1 * * 5] We also keep track of the max object count here. * **************************************************************************/ INT iGetW16ObjectHandleSlot(PLOCALDC pLocalDC, INT iIntendedUse) { BOOL b ; UINT i ; b = FALSE ; // Search for an available slot. for (i = 0 ; i < pLocalDC->cW16ObjHndlSlotStatus ; i++) { if (pLocalDC->pW16ObjHndlSlotStatus[i].use == OPEN_AVAILABLE_SLOT) { b = TRUE ; break ; } } // If a slot was found then mark its intended use. // Also set the W32 handle that may be associated with this // W16 handle to NULL. (Meaning no association at this time.) if (b) { ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle == 0, "MF3216: iGetW16ObjectHandleSlot: w32Handle is not 0"); pLocalDC->pW16ObjHndlSlotStatus[i].use = iIntendedUse ; pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle = 0 ; pLocalDC->pW16ObjHndlSlotStatus[i].iXORPassCreation = pLocalDC->iXORPass ; pLocalDC->pW16ObjHndlSlotStatus[i].pbCreatRec = pLocalDC->pbRecord ; // Update the number of object counts. This will be used // when we update the metafile header. if ((INT) i >= pLocalDC->nObjectHighWaterMark) pLocalDC->nObjectHighWaterMark = (INT) i; return((INT) i); } else { RIPS("MF3216: iGetW16ObjectHandleSlot, Slot not found\n") ; return(-1) ; } } /*************************************************************************** * iNormalizeHandle * * CR1 - this entire routine is part of the handle system redesign. * * 1] The idea behind this routine is to isolate the handling * of stock object handles to one place. * * 2] Input will be a Win32 handle index, either stock or a * standard object. * * 3] Output will be the index of the entry in the * piW32ToW16ObjectMap table that corresponds to the W32 * handle. If an error is detected -1 is returned. * * 4] All the stock objects will be between the range of 0 * and LAST_STOCK, and all the non-stock objects will be * greater than LAST_STOCK. * **************************************************************************/ INT iNormalizeHandle(PLOCALDC pLocalDC, INT ihW32) { INT ihW32Norm ; if (ihW32 & ENHMETA_STOCK_OBJECT) { ihW32Norm = ihW32 & ~ENHMETA_STOCK_OBJECT ; if ((UINT) ihW32Norm > STOCK_LAST) { RIPS("MF3216: iNormalizeHandle, bad stock object\n") ; ihW32Norm = -1 ; } } else { ihW32Norm = ihW32 + STOCK_LAST + 1 ; if ((UINT) ihW32Norm >= pLocalDC->cW32ToW16ObjectMap) { RIPS("MF3216: iNormalizeHandle, bad standard object\n") ; ihW32Norm = -1 ; } } return(ihW32Norm) ; } /*************************************************************************** * iAllocateW16Handle * * CR1 - this entire routine is part of the handle system redesign. * It is to be called from the object creation routines. * * 1] This routine actually does the handle allocation. * * 2] It sets the entry in pW16ObjHndlSlotStatus array * for the slot allocated by iGetW16ObjectHandleSlot to * an "in-use" status (for the intended use). * * 3] It returns a ihW16 (an index handle to the Win16 handle * table, aka the Win16 handle slot number). * **************************************************************************/ INT iAllocateW16Handle(PLOCALDC pLocalDC, INT ihW32, INT iIntendedUse) { INT ihW32Norm, ihW16 ; // Assume the worst, set up for a failed return code. ihW16 = -1 ; // Normalize the handle. ihW32Norm = iNormalizeHandle(pLocalDC, ihW32) ; if (ihW32Norm == -1) goto error_exit ; // Check for double allocation of a Win32 handle index. // If we find a double allocation, this would indicate an error // in the Win32 metafile. // Error out on this due to the possibility of // a brush being used for a bitmap, or some other wrong use of a handle. if (pLocalDC->piW32ToW16ObjectMap[ihW32Norm] != UNMAPPED) { RIPS("MF3216: iAllocateW16Handle, Double W32 handle allocation detected\n") ; goto error_exit ; } // Get a slot in the Win16 handle table. ihW16 = iGetW16ObjectHandleSlot(pLocalDC, iIntendedUse) ; if (ihW16 == -1) goto error_exit ; // Set the W32 to W16 slot mapping pLocalDC->piW32ToW16ObjectMap[ihW32Norm] = ihW16 ; error_exit: return(ihW16) ; } /*************************************************************************** * iValidateHandle * * CR1 - this entire routine is part of the handle system redesign. * * 1] This routine does a lot more than validate a Win32 handle. * It does some limited error checking on the Win32 handle, * to make sure its within a reasonable range. Then if a * Win16 handle table slot has already been allocated for * this Win32 handle it will return the Win16 handle that * was previously allocated. Alternatively, if a Win16 * handle has not been previously allocated for a Win32 * STOCK handle it will allocate a W16 handle and return the * Win16 handle. This function is called by FillRgn, FrameRgn * and SelectObject to allow lazy allocation of stock objects. * * 2] Input is a Win32 handle, either a stock or a non-stock * handle. * * 3] Output is a Win16 handle, this is the value in the * Win32-index of the piW32ToW16ObjectMap. If a stock object * does not exist, it will create one. * * 4] If there is an error a -1 is returned. **************************************************************************/ INT iValidateHandle(PLOCALDC pLocalDC, INT ihW32) { INT ihW32Norm, ihW16 ; // Assume the worst. ihW16 = -1 ; // NOTE: Normalizing the W32 handles takes care of checking // for a reasonable W32 handle value. ihW32Norm = iNormalizeHandle(pLocalDC, ihW32) ; if (ihW32Norm == -1) goto error_exit ; // Check the W32ToW16 map, to determine if this W32 handle has // already been allocated a W16 slot. ihW16 = pLocalDC->piW32ToW16ObjectMap[ihW32Norm] ; if (ihW16 == UNMAPPED) { // There is no mapping from W32 to W16. This implies // that the object in question does not exist. If this is // a stock object, then we will create the object at this time. // Alternatively, if this is a non-stock object then we have an // error condition. if ((DWORD) ihW32Norm <= STOCK_LAST) { if (bCreateStockObject(pLocalDC, ihW32)) ihW16 = pLocalDC->piW32ToW16ObjectMap[ihW32Norm] ; else ihW16 = -1 ; } else { RIPS("MF3216: iValidateHandle - Unmapped Standard Object\n") ; ihW16 = -1 ; } } error_exit: return (ihW16) ; } /*************************************************************************** * DoDeleteObject - Win32 to Win16 Metafile Converter Entry Point * * CR1 - Most of this routine was rewritten to conform to the new * objects management system. * * 1] The object handle is checked for reasonable limits. * We will also make sure that the Win16 slot has a handle * allocated to it. If it does not then we will return an * error. * * 2] If this is a stock object we fail and return an error. * * 3] If this is a non-stock object we emit a Win16DeleteObject * record. Then we set pW16ObjHndlSlotStatus to * indicate that this slot is available. We also set * piW32ToW16ObjectMap to -1 (UNMAPPED). * * 4] If we are in the first pass of an XOR-ClipPath rendering * then we verify if this object was created during this pass * If the object wasn't created during this pass, we will need * to recreate the object when we start the second pass so that * any call to SelectObject will return with the proper object * selected (GillesK) **************************************************************************/ BOOL WINAPI DoDeleteObject ( PLOCALDC pLocalDC, INT ihObject ) { BOOL b ; INT ihW16, ihW32Norm; // Assume the worst. b = FALSE ; // Normalize the W32 handle. ihW32Norm = iNormalizeHandle(pLocalDC, ihObject) ; if (ihW32Norm == -1) goto error_exit ; // Make sure we're not deleting a stock object. if ((DWORD) ihW32Norm <= STOCK_LAST) { PUTS("MF3216: DoDeleteObject, attempt to delete a stock object\n") ; return(TRUE); } // If this is a palette, then we do not delete the win16 object. // We do delete our local version of the palette. if (pLocalDC->pW32hPal && pLocalDC->pW32hPal[ihObject]) { b = DeleteObject(pLocalDC->pW32hPal[ihObject]); pLocalDC->pW32hPal[ihObject] = 0; if (b == FALSE) RIPS("MF3216: DoDeleteObject - DeleteObject (hPalette) failed\n") ; return (b) ; } // Map the ihW32 to a ihW16 (object handle table slot). ihW16 = pLocalDC->piW32ToW16ObjectMap[ihW32Norm] ; if (ihW16 == UNMAPPED) { RIPS("MF3216: DoDeleteObject, attempt to delete a non-existent object\n"); goto error_exit ; } // Make sure the object is one that we expect. // There is no region object or bitmap object in the enhanced metafiles. ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_BRUSH || pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_PEN || pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_FONT, "MF3216: DoDeleteObject, Invalid Object Deletion\n") ; // If there was a Win32 handle associated with this Win16 handle // then the w32Handle field of the W16ObjHndlSlotStatus[ihW16] // entry in the handle slot status array will be non-null. If // it is non-null then we should delete the Win32 handle at this time. if (pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0) { if (!DeleteObject(pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle)) { ASSERTGDI(FALSE, "MF3216: DoDeleteObject, DeleteObject failed"); } pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle = 0 ; } if( pLocalDC->iXORPass == DRAWXORPASS && pLocalDC->pW16ObjHndlSlotStatus[ihW16].iXORPassCreation != DRAWXORPASS ) { // If we delete an object that was created before this pass // the we need to save the object creation record so that // we can recreate the object once this pass is over // We create a linked list of objects that we have to recreate. PW16RECREATIONSLOT pW16RecreationSlot = (PW16RECREATIONSLOT) LocalAlloc( LMEM_FIXED, sizeof( W16RECREATIONSLOT ) ) ; if( pW16RecreationSlot == NULL ) goto error_exit ; pW16RecreationSlot->slot = ihW16 ; pW16RecreationSlot->pbCreatRec = pLocalDC->pW16ObjHndlSlotStatus[ihW16].pbCreatRec ; pW16RecreationSlot->pNext = pLocalDC->pW16RecreationSlot ; pLocalDC->pW16RecreationSlot = pW16RecreationSlot ; } // Mark the slot as available. // And set the map entry for the W32ToW16 map to unmapped. pLocalDC->pW16ObjHndlSlotStatus[ihW16].use = OPEN_AVAILABLE_SLOT ; pLocalDC->pW16ObjHndlSlotStatus[ihW16].pbCreatRec = NULL ; pLocalDC->piW32ToW16ObjectMap[ihW32Norm] = UNMAPPED ; // Emit the delete drawing order. b = bEmitWin16DeleteObject(pLocalDC, LOWORD(ihW16)) ; error_exit: return (b) ; } /*************************************************************************** * DoSelectObject - Win32 to Win16 Metafile Converter Entry Point * * CR1 - Major rewrite due to handle system redesign. * * DoSelectObject * * 1] For stock objects this is the workhorse routine. * * 2] For normal, non-stock, objects this routine will verify * that an object has been created for this Win32 object-index. * Then it will emit a Win16SelectObject metafile record. * * 3] For stock objects things get a little more complicated. * First this routine must make sure a Win16 object has been * created for this stock object. If a Win16 object has not * been created yet, then it will be. After a Win16 object * is created a Win16SelectObject record will be emitted for * the object. **************************************************************************/ BOOL WINAPI DoSelectObject ( PLOCALDC pLocalDC, LONG ihObject ) { BOOL b ; INT ihW16; // Assume the worst. b = FALSE ; // Make sure that the W16 object exists before we emit the // SelectObject record. Stock objects may not have been created // and iValidateHandle will take care of creating them. ihW16 = iValidateHandle(pLocalDC, ihObject) ; if (ihW16 == -1) goto error_exit ; // Make sure the object is one that we expect. // There is no region object or bitmap object in the enhanced metafiles. ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_BRUSH || pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_PEN || pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_FONT, "MF3216: DoSelectObject, Invalid Object Deletion\n") ; // Remember the currently selected pen. This is used in path and text. if (pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_PEN) pLocalDC->lhpn32 = ihObject; // Remember the currently selected brush. This is used in text. if (pLocalDC->pW16ObjHndlSlotStatus[ihW16].use == REALIZED_BRUSH) pLocalDC->lhbr32 = ihObject; // If there was a Win32 handle associated with this Win16 handle // then the w32Handle field of the W16ObjHndlSlotStatus[ihW16] // entry in the handle slot status array will be non-null. If // it is non-null then we should select the W32 object into the // helper DC at this time. if (pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0) SelectObject(pLocalDC->hdcHelper, pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle) ; b = bEmitWin16SelectObject(pLocalDC, LOWORD(ihW16)) ; error_exit: return(b) ; } /*************************************************************************** * bCreateStockObject **************************************************************************/ BOOL bCreateStockObject(PLOCALDC pLocalDC, INT ihW32) { BOOL b ; INT i ; ASSERTGDI((ihW32 & ENHMETA_STOCK_OBJECT) != 0, "MF3216: bCreateStockObject, invalid stock handle"); switch (ihW32 & ~ENHMETA_STOCK_OBJECT) { case WHITE_BRUSH: case LTGRAY_BRUSH: case GRAY_BRUSH: case DKGRAY_BRUSH: case BLACK_BRUSH: case NULL_BRUSH: b = DoCreateBrushIndirect(pLocalDC, ihW32, &albStock[ihW32 & ~ENHMETA_STOCK_OBJECT]) ; break ; case WHITE_PEN: case BLACK_PEN: case NULL_PEN: i = (ihW32 & ~ENHMETA_STOCK_OBJECT) - WHITE_PEN ; b = DoCreatePen(pLocalDC, ihW32, (PLOGPEN) &alpnStock[i]) ; break ; case OEM_FIXED_FONT: case ANSI_FIXED_FONT: case ANSI_VAR_FONT: case SYSTEM_FONT: case DEVICE_DEFAULT_FONT: case SYSTEM_FIXED_FONT: case DEFAULT_GUI_FONT: b = bCreateStockFont(pLocalDC, ihW32) ; break ; case DEFAULT_PALETTE: default: // Logical palettes are handled in DoSelectPalette and should // not get here. RIPS("MF3216: bCreateStockObject - Invalid Stock Object\n") ; b =FALSE ; break ; } return (b) ; } /*************************************************************************** * bCreateStockFont **************************************************************************/ BOOL bCreateStockFont(PLOCALDC pLocalDC, INT ihW32) { BOOL b ; INT i ; LOGFONTA LogFontA ; HANDLE hFont ; b = FALSE ; ASSERTGDI((ihW32 & ENHMETA_STOCK_OBJECT) != 0, "MF3216: bCreateStockObject, invalid stock handle"); // Get a handle to this logfont. hFont = GetStockObject(ihW32 & ~ENHMETA_STOCK_OBJECT) ; if (hFont == (HANDLE) 0) { RIPS("MF3216: bCreateStockFont, GetStockObject (font) failed\n") ; goto error_exit ; } // Get the logfont data. Assume we get at least one char in the // facename string. i = GetObjectA(hFont, sizeof(LOGFONTA), &LogFontA) ; if (i <= (INT) offsetof(LOGFONTA,lfFaceName[0])) { PUTS("MF3216: bCreateStockFont - GetObjectW failed\n") ; goto error_exit ; } // Zero out the remaining logfont structure. for ( ; i < sizeof(LOGFONTA); i++) ((PBYTE) &LogFontA)[i] = 0; // Create a LogFont for this stock font in the Win16 metafile. b = DoExtCreateFont(pLocalDC, ihW32, &LogFontA); error_exit: return (b) ; } /*************************************************************************** * CreateBrushIndirect - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoCreateBrushIndirect ( PLOCALDC pLocalDC, INT ihBrush, LPLOGBRUSH lpLogBrush ) { WIN16LOGBRUSH Win16LogBrush ; BOOL b ; INT ihW16 ; LOGBRUSH LogBrush ; b = FALSE ; // Only 3 brush styles are allowed. if (lpLogBrush->lbStyle != BS_SOLID && lpLogBrush->lbStyle != BS_HATCHED && lpLogBrush->lbStyle != BS_HOLLOW) goto error_exit ; // Make a copy of the logical brush. LogBrush = *lpLogBrush; // The first 6 hatched styles map directly from Win32 to Win16. // The remaining hatched brushes are simulated using DIB pattern // brushes. Note that the background color of a hatched brush // is the current background color but that of a DIB pattern brush // is given at create time! We will use the current background color // in the DIB pattern brush when it is created. As a result, the // output of these brushes may look different! if (LogBrush.lbStyle == BS_HATCHED) { switch (LogBrush.lbHatch) { case HS_HORIZONTAL: case HS_VERTICAL: case HS_FDIAGONAL: case HS_BDIAGONAL: case HS_CROSS: case HS_DIAGCROSS: break; default: RIPS("MF3216: Unknown hatched pattern\n"); LogBrush.lbStyle = BS_SOLID; break; } } // Allocate the W16 handle. ihW16 = iAllocateW16Handle(pLocalDC, ihBrush, REALIZED_BRUSH); if (ihW16 == -1) goto error_exit ; // Create the w32 brush and store it in the w16 slot table. // This brush is needed by the helper DC for BitBlt simulations. pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle = CreateBrushIndirect(lpLogBrush) ; ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0, "MF3216: CreateBrushIndirect failed"); // Assign all the Win32 brush attributes to Win16 brush attributes. Win16LogBrush.lbStyle = (WORD) LogBrush.lbStyle ; Win16LogBrush.lbColor = LogBrush.lbColor ; Win16LogBrush.lbHatch = (SHORT) LogBrush.lbHatch ; // Call the Win16 routine to emit the brush to the metafile. b = bEmitWin16CreateBrushIndirect(pLocalDC, &Win16LogBrush) ; error_exit: return(b) ; } /******************************Public*Routine******************************\ * CreateMonoDib * * This is the same as CreateBitmap except that the bits are assumed * to be DWORD aligned and that the scans start from the bottom of the bitmap. * * This routine is temporary until CreateDIBitmap supports monochrome bitmaps * * History: * Wed Jul 01 11:02:24 1992 -by- Hock San Lee [hockl] * Wrote it. \**************************************************************************/ HBITMAP CreateMonoDib ( LPBITMAPINFO pbmi, CONST BYTE * pjBits, UINT iUsage ) { HBITMAP hbm; ASSERTGDI(pbmi->bmiHeader.biPlanes == 1, "CreateMonoDib: bad biPlanes value"); ASSERTGDI(pbmi->bmiHeader.biBitCount == 1, "CreateMonoDib: bad biBitCount value"); hbm = CreateBitmap((int) pbmi->bmiHeader.biWidth, (int) pbmi->bmiHeader.biHeight, (UINT) 1, (UINT) 1, (CONST VOID *) NULL); if (!hbm) return(hbm); SetDIBits((HDC) 0, hbm, 0, (UINT) pbmi->bmiHeader.biHeight, (CONST VOID *) pjBits, pbmi, iUsage); return(hbm); } /*************************************************************************** * CreateMonoBrush - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoCreateMonoBrush ( PLOCALDC pLocalDC, DWORD ihBrush, PBITMAPINFO pBitmapInfo, DWORD cbBitmapInfo, PBYTE pBits, DWORD cbBits, DWORD iUsage ) { BOOL b ; INT ihW16; DWORD ul ; BYTE pbmi[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)]; HBITMAP hbm; b = FALSE ; // Need to make a copy of the bitmap info header, for a few reasons // 1] the memory mapped file is write protected. // 2] the iUsage may be (is) use palatte indicies, and we need // use RGB colors. ((PBITMAPINFO) pbmi)->bmiHeader = pBitmapInfo->bmiHeader; // Need to make sure the iUsage is DIB_RGB_COLORS // and the palette is initialized to Black and White. ul = 0 ; ((PBITMAPINFO) pbmi)->bmiColors[0] = (*((RGBQUAD *) &(ul))) ; ul = 0x00ffffff ; ((PBITMAPINFO) pbmi)->bmiColors[1] = (*((RGBQUAD *) &(ul))) ; // Allocate the W16 handle. ihW16 = iAllocateW16Handle(pLocalDC, ihBrush, REALIZED_BRUSH); if (ihW16 == -1) goto error_exit ; // Create the w32 brush and store it in the w16 slot table. // This brush is needed by the helper DC for BitBlt simulations. if ((hbm = CreateMonoDib ( pBitmapInfo, (CONST BYTE *) pBits, (UINT) iUsage ) ) ) { pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle = CreatePatternBrush(hbm); if (!DeleteObject(hbm)) ASSERTGDI(FALSE, "MF3216: DoCreateMonoBrush, DeleteObject failed"); } ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0, "MF3216: CreatePatternBrush failed"); // Call the Win16 routine to emit the brush to the metafile. b = bEmitWin16CreateDIBPatternBrush(pLocalDC, (PBITMAPINFO) pbmi, sizeof(pbmi), pBits, cbBits, (WORD) DIB_RGB_COLORS, (WORD) BS_PATTERN // Mono brush! ) ; error_exit: return(b) ; } /*************************************************************************** * CreateDIPatternBrush - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoCreateDIBPatternBrush ( PLOCALDC pLocalDC, DWORD ihBrush, PBITMAPINFO pBitmapInfo, DWORD cbBitmapInfo, PBYTE pBits, DWORD cbBits, DWORD iUsage ) { BOOL b; INT ihW16; HBITMAP hbm; PBYTE pBits24; DWORD cbBits24; BITMAPINFOHEADER bmih; hbm = (HBITMAP) 0; pBits24 = (PBYTE) NULL; b = FALSE ; // Allocate the W16 handle. ihW16 = iAllocateW16Handle(pLocalDC, ihBrush, REALIZED_BRUSH); if (ihW16 == -1) goto error_exit ; // Create the w32 brush and store it in the w16 slot table. // We assume that the bitmap info is followed by the bits immediately, // i.e. it is a packed dib. // This brush is needed by the helper DC for BitBlt simulations. pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle = CreateDIBPatternBrushPt((LPVOID) pBitmapInfo, (UINT) iUsage); ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0, "MF3216: CreateDIBPatternBrushPt failed"); // We need to convert new bitmap info formats to the win3 formats. if (pBitmapInfo->bmiHeader.biPlanes != 1 || pBitmapInfo->bmiHeader.biBitCount == 16 || pBitmapInfo->bmiHeader.biBitCount == 32) { if (!(hbm = CreateDIBitmap(pLocalDC->hdcHelper, (LPBITMAPINFOHEADER) pBitmapInfo, CBM_INIT | CBM_CREATEDIB, pBits, (LPBITMAPINFO) pBitmapInfo, (UINT) iUsage))) goto error_exit ; bmih = *(PBITMAPINFOHEADER) pBitmapInfo; bmih.biPlanes = 1; bmih.biBitCount = 24; bmih.biCompression = BI_RGB; bmih.biSizeImage = 0; bmih.biClrUsed = 0; bmih.biClrImportant = 0; cbBits24 = CJSCAN(bmih.biWidth,bmih.biPlanes,bmih.biBitCount) * ABS(bmih.biHeight); pBits24 = (LPBYTE) LocalAlloc(LMEM_FIXED, cbBits24); if (pBits24 == (LPBYTE) NULL) goto error_exit; // Get bitmap info and bits in 24bpp. if (!GetDIBits(pLocalDC->hdcHelper, hbm, 0, (UINT) bmih.biHeight, pBits24, (LPBITMAPINFO) &bmih, DIB_RGB_COLORS)) goto error_exit; b = bEmitWin16CreateDIBPatternBrush(pLocalDC, (PBITMAPINFO) &bmih, sizeof(bmih), pBits24, cbBits24, (WORD) DIB_RGB_COLORS, (WORD) BS_DIBPATTERN ) ; } else { // Call the Win16 routine to emit the brush to the metafile. b = bEmitWin16CreateDIBPatternBrush(pLocalDC, pBitmapInfo, cbBitmapInfo, pBits, cbBits, (WORD) iUsage, (WORD) BS_DIBPATTERN ) ; } error_exit: if (hbm) DeleteObject(hbm); if (pBits24) LocalFree((HANDLE) pBits24); return(b) ; } /*************************************************************************** * CreatePen - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoCreatePen ( PLOCALDC pLocalDC, INT ihPen, PLOGPEN pLogPen ) { EXTLOGPEN ExtLogPen ; BOOL b ; ExtLogPen.elpPenStyle = PS_GEOMETRIC | pLogPen->lopnStyle ; ExtLogPen.elpWidth = (UINT) pLogPen->lopnWidth.x ; ExtLogPen.elpBrushStyle = BS_SOLID ; ExtLogPen.elpColor = pLogPen->lopnColor ; ExtLogPen.elpNumEntries = 0 ; // ExtLogPen.elpHatch = 0 ; // ExtLogPen.elpStyleEntry[0] = 0; b = DoExtCreatePen(pLocalDC, ihPen, &ExtLogPen) ; return (b) ; } /*************************************************************************** * ExtCreatePen - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoExtCreatePen ( PLOCALDC pLocalDC, INT ihPen, PEXTLOGPEN pExtLogPen ) { BOOL b ; WORD iStyle ; POINTS ptsWidth ; INT ihW16 ; UINT iPenStyle ; POINTL ptlWidth ; COLORREF crColor ; b = FALSE; // Get pen style. iPenStyle = pExtLogPen->elpPenStyle & PS_STYLE_MASK ; switch(iPenStyle) { case PS_SOLID: case PS_DASH: case PS_DOT: case PS_DASHDOT: case PS_DASHDOTDOT: case PS_NULL: case PS_INSIDEFRAME: break ; case PS_ALTERNATE: iPenStyle = PS_DOT ; break ; case PS_USERSTYLE: default: // CR1: default to solid. iPenStyle = PS_SOLID ; break ; } // Get pen color. switch (pExtLogPen->elpBrushStyle) { case BS_SOLID: case BS_HATCHED: crColor = pExtLogPen->elpColor ; break; // If the extended pen contains a hollow brush, then // we will emit a NULL pen. case BS_NULL: // BS_HOLLOW is the same as BS_NULL iPenStyle = PS_NULL ; crColor = 0 ; break; // Win3.x does not support pens with bitmap patterns. // So we will just use solid pens here. Since we do not // know what pen color to use, we choose the text color. case BS_PATTERN: case BS_DIBPATTERN: case BS_DIBPATTERNPT: default: crColor = pLocalDC->crTextColor ; break; } // Get pen width. // If this is a cosmetic pen then the width is 0. ptlWidth.y = 0 ; if ((pExtLogPen->elpPenStyle & PS_TYPE_MASK) == PS_COSMETIC) ptlWidth.x = 0 ; else ptlWidth.x = pExtLogPen->elpWidth ; // Allocate the W16 handle. ihW16 = iAllocateW16Handle(pLocalDC, ihPen, REALIZED_PEN); if (ihW16 == -1) goto error_exit ; // This is where we need to create a pen for helper DC. // We do not select it into the helper DC at this time. pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle = CreatePen((int) iPenStyle, ptlWidth.x, crColor) ; ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[ihW16].w32Handle != 0, "MF3216: DoExtCreatePen, CreatePen failed"); // Get pen width in play time page units. ptlWidth.x = (LONG) iMagnitudeXform(pLocalDC, (INT) ptlWidth.x, CX_MAG); // Set the Win16 pen attributes iStyle = (WORD) iPenStyle ; ptsWidth.x = (WORD) ptlWidth.x ; ptsWidth.y = (WORD) ptlWidth.y ; // Call the Win16 routine to emit the pen to the metafile. b = bEmitWin16CreatePen(pLocalDC, iStyle, &ptsWidth, crColor) ; error_exit: return(b) ; } /*************************************************************************** * DoRemoveObjects - Remove the objects that were created in the first * XOR pass **************************************************************************/ BOOL WINAPI DoRemoveObjects( PLOCALDC pLocalDC ) { BOOL b = TRUE ; UINT i; INT iNorm ; INT ihW32Norm ; ASSERTGDI( pLocalDC->iXORPass == OBJECTRECREATION, "DoRemoveObject used with the wrong XOR Pass" ) ; // GillesK // We have to go through the list of 16-bit handles and delete // every single object that was created during this pass. This // is necessary to make sure that we have the exact same state // of objects when we restart the second pass so that no object // creation will fail and give wrong results. // Don't touch the stock objects for( i = STOCK_LAST + 1 ; i < pLocalDC->cW32ToW16ObjectMap ; i++ ) { iNorm = pLocalDC->piW32ToW16ObjectMap[i] ; if( iNorm != UNMAPPED && pLocalDC->pW16ObjHndlSlotStatus[iNorm].iXORPassCreation == DRAWXORPASS ) { // If there was a Win32 handle associated with this Win16 handle // then the w32Handle field of the W16ObjHndlSlotStatus[ihW16] // entry in the handle slot status array will be non-null. If // it is non-null then we should delete the Win32 handle at this time. b = DoDeleteObject( pLocalDC, i- ( STOCK_LAST + 1 ) ) ; if( !b ) break ; } } return b ; } /*************************************************************************** * DoDeleteRecreationSlots - Remove the recreation object slots because * they will not be used. **************************************************************************/ BOOL WINAPI DoDeleteRecreationSlots( PLOCALDC pLocalDC ) { BOOL b = TRUE ; while(pLocalDC->pW16RecreationSlot != NULL) { PW16RECREATIONSLOT l_pSlot = pLocalDC->pW16RecreationSlot ; pLocalDC->pW16RecreationSlot = pLocalDC->pW16RecreationSlot->pNext ; LocalFree(l_pSlot) ; } return b ; }