/***************************************************************************** * * misc - Entry points for Win32 to Win 16 converter * * Date: 7/1/91 * Author: Jeffrey Newman (c-jeffn) * * Copyright 1991 Microsoft Corp *****************************************************************************/ #include "precomp.h" #pragma hdrstop BOOL WINAPI GetTransform(HDC hdc,DWORD iXform,LPXFORM pxform); BOOL WINAPI DoGdiCommentMultiFormats ( PLOCALDC pLocalDC, PEMRGDICOMMENT_MULTIFORMATS pemr ); /*************************************************************************** * ExtFloodFill - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoExtFloodFill ( PLOCALDC pLocalDC, int x, int y, COLORREF crColor, DWORD iMode ) { POINTL ptl ; BOOL b ; ptl.x = (LONG) x ; ptl.y = (LONG) y ; b = bXformRWorldToPPage(pLocalDC, &ptl, 1) ; if (b == FALSE) goto exit1 ; b = bEmitWin16ExtFloodFill(pLocalDC, LOWORD(ptl.x), LOWORD(ptl.y), crColor, LOWORD(iMode)) ; exit1: return(b) ; } /*************************************************************************** * MoveToEx - Win32 to Win16 Metafile Converter Entry Point * * NOTE ON CURRENT POSITION * ------------------------ * There are only three Win16 functions that use and update the * current position (CP). They are: * * MoveTo * LineTo * (Ext)TextOut with TA_UPDATECP text alignment option * * In Win32, CP is used in many more functions and has two * interpretations based on the state of the current path. * As a result, it is easier and more robust to rely on the * helper DC to keep track of the CP than doing it in the * converter. To do this, we need to do the following: * * 1. The converter will update the CP in the helper DC in all * records that modify the CP. * * 2. The converter will keep track of the CP in the converted * metafile at all time. * * 3. In LineTo and (Ext)TextOut, the metafile CP is compared to * that of the helper DC. If they are different, a MoveTo record * is emitted. This is done in bValidateMetaFileCP(). * * 4. The converter should emit a MoveTo record the first time the * CP is used in the converted metafile. * * - HockL July 2, 1992 **************************************************************************/ BOOL WINAPI DoMoveTo ( PLOCALDC pLocalDC, LONG x, LONG y ) { BOOL b ; POINTL ptl ; // Whether we are recording for a path or acutally emitting // a drawing order we must pass the drawing order to the helper DC // so the helper can maintain the current positon. // If we're recording the drawing orders for a path // then just pass the drawing order to the helper DC. // Do not emit any Win16 drawing orders. b = MoveToEx(pLocalDC->hdcHelper, (INT) x, (INT) y, (LPPOINT) &ptl) ; if (pLocalDC->flags & RECORDING_PATH) return(b) ; // Update the CP in the converted metafile. b = bValidateMetaFileCP(pLocalDC, x, y) ; return(b) ; } /*************************************************************************** * bValidateMetaFiloeCP - Update the current position in the converted * metafile. * * x and y are assumed to be in the record time world coordinates. * **************************************************************************/ BOOL bValidateMetaFileCP(PLOCALDC pLocalDC, LONG x, LONG y) { BOOL b ; POINT pt ; // Compute the new current position in the play time page coord. pt.x = x ; pt.y = y ; if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) &pt, 1L)) return(FALSE); // No need to emit the record if the converted metafile has // the same CP. if (pLocalDC->ptCP.x == pt.x && pLocalDC->ptCP.y == pt.y) return(TRUE); // Call the Win16 routine to emit the move to the metafile. b = bEmitWin16MoveTo(pLocalDC, LOWORD(pt.x), LOWORD(pt.y)) ; // Update the mf16 current position. pLocalDC->ptCP = pt ; return(b) ; } /*************************************************************************** * SaveDC - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoSaveDC ( PLOCALDC pLocalDC ) { BOOL b; PLOCALDC pLocalDCNew; b = FALSE; // Save the helper DC's state first if (!SaveDC(pLocalDC->hdcHelper)) { RIP("MF3216: DoSaveDC, SaveDC failed\n"); return(b); } // Allocate some memory for the LocalDC. pLocalDCNew = (PLOCALDC) LocalAlloc(LMEM_FIXED, sizeof(LOCALDC)); if (pLocalDCNew == (PLOCALDC) NULL) { RIP("MF3216: DoSaveDC, LocalAlloc failed\n"); return(b); } // Copy the data from the current LocalDC to the new one just allocated. *pLocalDCNew = *pLocalDC; // Link in the new level. pLocalDC->pLocalDCSaved = pLocalDCNew; pLocalDC->iLevel++; // Emit Win16 drawing order. b = bEmitWin16SaveDC(pLocalDC); return(b); } /*************************************************************************** * RestoreDC - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoRestoreDC ( PLOCALDC pLocalDC, int nSavedDC ) { BOOL b; INT iLevel; PLOCALDC pLocalDCNext; PLOCALDC pLocalDCTmp; b = FALSE; // First check to make sure this is a relative save level. if (nSavedDC > 0) return(b); // Restore the helper DC's state first // If we can restore the helper DC, we know that it is a balanced restore. // Otherwise, we return an error. if (!RestoreDC(pLocalDC->hdcHelper, nSavedDC)) return(b); // Compute an absolute level. iLevel = pLocalDC->iLevel + nSavedDC; // The helper DC should have caught bogus levels. ASSERTGDI((iLevel >= 0) && ((UINT) iLevel < pLocalDC->iLevel), "MF3216: DoRestoreDC, Bogus RestoreDC"); // Restore down to the level we want. pLocalDCNext = pLocalDC->pLocalDCSaved; while ((UINT) iLevel < pLocalDCNext->iLevel) { pLocalDCTmp = pLocalDCNext; pLocalDCNext = pLocalDCNext->pLocalDCSaved; if (LocalFree(pLocalDCTmp)) ASSERTGDI(FALSE, "MF3216: DoRestoreDC, LocalFree failed"); } // Restore the state of our local DC to that level. // keep some of the attributes in the current DC pLocalDCNext->ulBytesEmitted = pLocalDC->ulBytesEmitted; pLocalDCNext->ulMaxRecord = pLocalDC->ulMaxRecord; pLocalDCNext->nObjectHighWaterMark = pLocalDC->nObjectHighWaterMark; pLocalDCNext->pbCurrent = pLocalDC->pbCurrent; pLocalDCNext->cW16ObjHndlSlotStatus = pLocalDC->cW16ObjHndlSlotStatus; pLocalDCNext->pW16ObjHndlSlotStatus = pLocalDC->pW16ObjHndlSlotStatus; // now restore the other attributes *pLocalDC = *pLocalDCNext; // Free the local copy of the DC. if (LocalFree(pLocalDCNext)) ASSERTGDI(FALSE, "MF3216: DoRestoreDC, LocalFree failed"); // Emit the record to the Win16 metafile. b = bEmitWin16RestoreDC(pLocalDC, LOWORD(nSavedDC)) ; return (b) ; } /*************************************************************************** * SetRop2 - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoSetRop2 ( PLOCALDC pLocalDC, DWORD rop ) { BOOL b ; // Emit the Win16 metafile drawing order. b = bEmitWin16SetROP2(pLocalDC, LOWORD(rop)) ; return(b) ; } /*************************************************************************** * SetBkMode - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoSetBkMode ( PLOCALDC pLocalDC, DWORD iBkMode ) { BOOL b ; // Do it to the helper DC. It needs this in a path bracket // if a text string is drawn. SetBkMode(pLocalDC->hdcHelper, (int) iBkMode); // Emit the Win16 metafile drawing order. b = bEmitWin16SetBkMode(pLocalDC, LOWORD(iBkMode)) ; return(b) ; } /*************************************************************************** * SetBkColor - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL APIENTRY DoSetBkColor ( PLOCALDC pLocalDC, COLORREF crColor ) { BOOL b ; pLocalDC->crBkColor = crColor; // used by brushes // Emit the Win16 metafile drawing order. b = bEmitWin16SetBkColor(pLocalDC, crColor) ; return(b) ; } /*************************************************************************** * GdiComment - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoGdiComment ( PLOCALDC pLocalDC, PEMR pemr ) { BOOL b; PEMRGDICOMMENT_PUBLIC pemrComment = (PEMRGDICOMMENT_PUBLIC) pemr; // If it's not a public comment, just return TRUE. if (pemrComment->emr.nSize < sizeof(EMRGDICOMMENT_PUBLIC) || pemrComment->ident != GDICOMMENT_IDENTIFIER) return(TRUE); // Handle public comments. // A public comment consists of a public comment identifier, // a comment type, plus any accompanying data. switch (pemrComment->iComment) { case GDICOMMENT_MULTIFORMATS: b = DoGdiCommentMultiFormats(pLocalDC, (PEMRGDICOMMENT_MULTIFORMATS) pemr); break; case GDICOMMENT_BEGINGROUP: case GDICOMMENT_ENDGROUP: case GDICOMMENT_WINDOWS_METAFILE: default: b = TRUE; break; } return(b) ; } BOOL WINAPI DoGdiCommentMultiFormats ( PLOCALDC pLocalDC, PEMRGDICOMMENT_MULTIFORMATS pemrcmf ) { DWORD i; DWORD cSizeOld; int iBase; XFORM xformNew, xformScale; POINTL aptlFrame[4]; RECTL rclFrame; UINT cbwmfNew; SIZEL szlDeviceNew, szlMillimetersNew; BOOL bRet = FALSE; PBYTE pbwmfNew = (PBYTE) NULL; HDC hdcemfNew = (HDC) 0; HENHMETAFILE hemf = (HENHMETAFILE) 0; HENHMETAFILE hemfNew = (HENHMETAFILE) 0; PENHMETAHEADER pemfh; WIN16LOGBRUSH Win16LogBrush; PMETARECORD pmr; #if DBG int iSWO = 0; int iSWE = 0; #endif // We will convert the enhanced metafile format only. // Find the enhanced metafile data. for (i = 0; i < pemrcmf->nFormats; i++) { if (pemrcmf->aemrformat[i].dSignature == ENHMETA_SIGNATURE && pemrcmf->aemrformat[i].nVersion <= META_FORMAT_ENHANCED) break; } // If we cannot find a recognized format, return failure. if (i >= pemrcmf->nFormats) { PUTS("MF3216: DoGdiCommentMultiFormats - no recognized format found\n"); goto dgcmf_exit; } // Get the embedded enhanced metafile. hemf = SetEnhMetaFileBits((UINT) pemrcmf->aemrformat[i].cbData, &((PBYTE) &pemrcmf->ident)[pemrcmf->aemrformat[i].offData]); if (!hemf) goto dgcmf_exit; // Now the fun begins - we have to convert the enhanced metafile to // Windows metafile. // Since the multiformats record takes a logical rectangle, we have to // set up a proper transform for the enhanced metafile. We do it by // creating a new enhanced metafile and playing the embedded metafile // into the new metafile with the proper transform setup. // In addition, the new metafile may have a different resolution than the // metafile. We need to take this into account when setting up // the transform. // Get the world to device transform for the logical rectangle. if (!GetTransform(pLocalDC->hdcHelper, XFORM_WORLD_TO_DEVICE, &xformNew)) goto dgcmf_exit; // Compute the device scales. szlDeviceNew.cx = GetDeviceCaps(pLocalDC->hdcRef, HORZRES); szlDeviceNew.cy = GetDeviceCaps(pLocalDC->hdcRef, VERTRES); szlMillimetersNew.cx = GetDeviceCaps(pLocalDC->hdcRef, HORZSIZE); szlMillimetersNew.cy = GetDeviceCaps(pLocalDC->hdcRef, VERTSIZE); pemfh = (PENHMETAHEADER) pLocalDC->pMf32Bits; xformScale.eM11 = ((FLOAT) szlDeviceNew.cx / (FLOAT) szlMillimetersNew.cx) / ((FLOAT) pemfh->szlDevice.cx / (FLOAT) pemfh->szlMillimeters.cx); xformScale.eM12 = 0.0f; xformScale.eM21 = 0.0f; xformScale.eM22 = ((FLOAT) szlDeviceNew.cy / (FLOAT) szlMillimetersNew.cy) / ((FLOAT) pemfh->szlDevice.cy / (FLOAT) pemfh->szlMillimeters.cy); xformScale.eDx = 0.0f; xformScale.eDy = 0.0f; // Compute the resulting transform to apply to the new metafile. if (!CombineTransform(&xformNew, &xformNew, &xformScale)) goto dgcmf_exit; // Create the new enhanced metafile. // Compute the new metafile frame. aptlFrame[0].x = pemrcmf->rclOutput.left; aptlFrame[0].y = pemrcmf->rclOutput.top; aptlFrame[1].x = pemrcmf->rclOutput.right; aptlFrame[1].y = pemrcmf->rclOutput.top; aptlFrame[2].x = pemrcmf->rclOutput.right; aptlFrame[2].y = pemrcmf->rclOutput.bottom; aptlFrame[3].x = pemrcmf->rclOutput.left; aptlFrame[3].y = pemrcmf->rclOutput.bottom; if (!bXformWorkhorse(aptlFrame, 4, &xformNew)) goto dgcmf_exit; rclFrame.left = MulDiv(100 * MIN4(aptlFrame[0].x, aptlFrame[1].x, aptlFrame[2].x, aptlFrame[3].x), szlMillimetersNew.cx, szlDeviceNew.cx); rclFrame.right = MulDiv(100 * MAX4(aptlFrame[0].x, aptlFrame[1].x, aptlFrame[2].x, aptlFrame[3].x), szlMillimetersNew.cx, szlDeviceNew.cx); rclFrame.top = MulDiv(100 * MIN4(aptlFrame[0].y, aptlFrame[1].y, aptlFrame[2].y, aptlFrame[3].y), szlMillimetersNew.cy, szlDeviceNew.cy); rclFrame.bottom = MulDiv(100 * MAX4(aptlFrame[0].y, aptlFrame[1].y, aptlFrame[2].y, aptlFrame[3].y), szlMillimetersNew.cy, szlDeviceNew.cy); hdcemfNew = CreateEnhMetaFile(pLocalDC->hdcRef, (LPCSTR) NULL, (CONST RECT *) &rclFrame, (LPCSTR) NULL); if (!hdcemfNew) goto dgcmf_exit; if (!SetGraphicsMode(hdcemfNew, GM_ADVANCED)) goto dgcmf_exit; // Set up the transform in the new metafile. if (!SetWorldTransform(hdcemfNew, &xformNew)) goto dgcmf_exit; // Play the embedded metafile into the new metafile. // This call ensures balanced level etc. (void) PlayEnhMetaFile(hdcemfNew, hemf, (LPRECT) &pemrcmf->rclOutput); // Close the new metafile. hemfNew = CloseEnhMetaFile(hdcemfNew); hdcemfNew = (HDC) 0; // used by clean up code below // Convert the new enhanced metafile to windows metafile. if (!(cbwmfNew = GetWinMetaFileBits(hemfNew, 0, (LPBYTE) NULL, MM_ANISOTROPIC, pLocalDC->hdcRef))) goto dgcmf_exit; if (!(pbwmfNew = (PBYTE) LocalAlloc(LMEM_FIXED, cbwmfNew))) goto dgcmf_exit; if (cbwmfNew != GetWinMetaFileBits(hemfNew, cbwmfNew, pbwmfNew, MM_ANISOTROPIC, pLocalDC->hdcRef)) goto dgcmf_exit; // We now have the converted windows metafile. We need to include it into // our current data stream. There are a few things to be aware of: // // 1. Expand the object handle slot table. The converted metafile may // contain some undeleted objects. These objects are likely // the "stock" objects in the converter. As a result, we need to // expand the slot table by the number of object handles in the // converted metafile. // 2. The object index must be changed to the current object index. // We are going to do this by the lazy method, i.e. we will elevate // the current object index base to one higher than the current max // object index in the current data stream. This is because Windows uses // some an insane scheme for object index and this is the cheapest // method. We elevate the object index base by filling up the empty // indexes with dummy objects that are freed when we are done. // 3. Remove the now useless comments. // 4. Skip header and eof. // 5. Set up the transform to place the embedded metafile into the data // stream. We know that the metafile bits returned by the converter // contains only a SetWindowOrg and a SetWindowExt record. // By implementation, we can simply remove both the SetWindowOrg and // SetWindowExt records from the data stream. The window origin and // extents have been set up when we begin converting this enhanced // metafile. // Expand the object handle slot table. if (((PMETAHEADER) pbwmfNew)->mtNoObjects) { PW16OBJHNDLSLOTSTATUS pW16ObjHndlSlotStatusTmp; cSizeOld = (DWORD) pLocalDC->cW16ObjHndlSlotStatus; if (cSizeOld + ((PMETAHEADER)pbwmfNew)->mtNoObjects > (UINT) (WORD) MAXWORD) goto dgcmf_exit; // w16 handle index is only 16-bit pLocalDC->cW16ObjHndlSlotStatus += ((PMETAHEADER)pbwmfNew)->mtNoObjects; i = pLocalDC->cW16ObjHndlSlotStatus * sizeof(W16OBJHNDLSLOTSTATUS); pW16ObjHndlSlotStatusTmp = (PW16OBJHNDLSLOTSTATUS) LocalReAlloc(pLocalDC->pW16ObjHndlSlotStatus, i, LMEM_MOVEABLE); if (pW16ObjHndlSlotStatusTmp == NULL) { pLocalDC->cW16ObjHndlSlotStatus -= ((PMETAHEADER)pbwmfNew)->mtNoObjects; goto dgcmf_exit; } pLocalDC->pW16ObjHndlSlotStatus = pW16ObjHndlSlotStatusTmp; for (i = cSizeOld; i < pLocalDC->cW16ObjHndlSlotStatus; i++) { pLocalDC->pW16ObjHndlSlotStatus[i].use = OPEN_AVAILABLE_SLOT; pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle = 0 ; } } // Find the new base for the object index. for (iBase = pLocalDC->cW16ObjHndlSlotStatus - 1; iBase >= 0; iBase--) { if (pLocalDC->pW16ObjHndlSlotStatus[iBase].use != OPEN_AVAILABLE_SLOT) break; } iBase++; // Fill up the object index table with dummy objects. Win16LogBrush.lbStyle = BS_SOLID; Win16LogBrush.lbColor = 0; Win16LogBrush.lbHatch = 0; for (i = 0; i < (DWORD) iBase; i++) { if (pLocalDC->pW16ObjHndlSlotStatus[i].use == OPEN_AVAILABLE_SLOT) { if (!bEmitWin16CreateBrushIndirect(pLocalDC, &Win16LogBrush)) goto dgcmf_exit; pLocalDC->pW16ObjHndlSlotStatus[i].use = REALIZED_DUMMY; } } // Update the high water mark. if (iBase + ((PMETAHEADER) pbwmfNew)->mtNoObjects - 1 > pLocalDC->nObjectHighWaterMark) pLocalDC->nObjectHighWaterMark = iBase + ((PMETAHEADER) pbwmfNew)->mtNoObjects - 1; // Save DC states. if (!bEmitWin16SaveDC(pLocalDC)) goto dgcmf_exit; // Enumerate the records and fix them up as necessary. for (pmr = (PMETARECORD) (pbwmfNew + sizeof(METAHEADER)); pmr->rdFunction != 0; pmr = (PMETARECORD) ((PWORD) pmr + pmr->rdSize)) { switch (pmr->rdFunction) { case META_SETWINDOWORG: ASSERTGDI(++iSWO <= 1, "MF3216: DoGdiCommentMultiFormats - unexpected SWO record\n"); break; case META_SETWINDOWEXT: ASSERTGDI(++iSWE <= 1, "MF3216: DoGdiCommentMultiFormats - unexpected SWE record\n"); break; case META_ESCAPE: if (!IS_META_ESCAPE_ENHANCED_METAFILE((PMETA_ESCAPE_ENHANCED_METAFILE) pmr)) goto default_alt; break; case META_RESTOREDC: ASSERTGDI((int)(SHORT)pmr->rdParm[0] < 0, "MF3216: DoGdiCommentMultiFormats - bogus RestoreDC record\n"); goto default_alt; case META_SELECTCLIPREGION: if (pmr->rdParm[0] != 0) // allow for default clipping! { pmr->rdParm[0] += (WORD)iBase; pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = REALIZED_OBJECT; } goto default_alt; case META_FRAMEREGION: case META_FILLREGION: pmr->rdParm[1] += (WORD)iBase; pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[1]].use = REALIZED_OBJECT; // fall through case META_PAINTREGION: case META_INVERTREGION: case META_DELETEOBJECT: case META_SELECTPALETTE: case META_SELECTOBJECT: pmr->rdParm[0] += (WORD)iBase; if (pmr->rdFunction != META_DELETEOBJECT) pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = REALIZED_OBJECT; else pLocalDC->pW16ObjHndlSlotStatus[pmr->rdParm[0]].use = OPEN_AVAILABLE_SLOT; // fall through default: default_alt: if (!bEmit(pLocalDC, (PVOID) pmr, pmr->rdSize * sizeof(WORD))) goto dgcmf_exit; vUpdateMaxRecord(pLocalDC, pmr); break; } } // Restore DC states. if (!bEmitWin16RestoreDC(pLocalDC, (WORD) -1)) goto dgcmf_exit; // Remove the dummy objects from the handle table. for (i = 0; i < (DWORD) iBase; i++) { if (pLocalDC->pW16ObjHndlSlotStatus[i].use == REALIZED_DUMMY) { if (!bEmitWin16DeleteObject(pLocalDC, (WORD) i)) goto dgcmf_exit; pLocalDC->pW16ObjHndlSlotStatus[i].use = OPEN_AVAILABLE_SLOT; } } // Shrink the object handle slot table. if (((PMETAHEADER) pbwmfNew)->mtNoObjects) { DWORD cUndel = 0; // number of objects not deleted DWORD iUndelMax = iBase - 1; // the max undeleted object index for (i = iBase; i < pLocalDC->cW16ObjHndlSlotStatus; i++) { if (pLocalDC->pW16ObjHndlSlotStatus[i].use != OPEN_AVAILABLE_SLOT) { cUndel++; iUndelMax = i; } } pLocalDC->cW16ObjHndlSlotStatus = max(cSizeOld + cUndel, iUndelMax + 1); } // Everything is golden. bRet = TRUE; dgcmf_exit: if (pbwmfNew) if (LocalFree(pbwmfNew)) ASSERTGDI(FALSE, "MF3216: DoGdiCommentMultiFormats - LocalFree failed\n"); if (hemf) DeleteEnhMetaFile(hemf); if (hdcemfNew) hemfNew = CloseEnhMetaFile(hdcemfNew); // hemfNew will be deleted next if (hemfNew) DeleteEnhMetaFile(hemfNew); return(bRet); } /*************************************************************************** * EOF - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL APIENTRY DoEOF ( PLOCALDC pLocalDC ) { BOOL b ; b = bEmitWin16EOF(pLocalDC) ; return(b) ; }