|
|
/*****************************************************************************
* * text - 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
__declspec(dllimport) ULONG __stdcall RtlUnicodeToMultiByteN( PCHAR MultiByteString, ULONG MaxBytesInMultiByteString, PULONG BytesInMultiByteString, PWSTR UnicodeString, ULONG BytesInUnicodeString );
ULONG __stdcall RtlUnicodeToMultiByteSize( PULONG BytesInMultiByteString, PWSTR UnicodeString, ULONG BytesInUnicodeString );
DWORD GetCodePage(HDC hdc) { DWORD FAR *lpSrc = UlongToPtr(GetTextCharsetInfo(hdc, 0, 0)); CHARSETINFO csi;
TranslateCharsetInfo(lpSrc, &csi, TCI_SRCCHARSET);
return csi.ciACP; }
/***************************************************************************
* ExtTextOut - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoExtTextOut ( PLOCALDC pLocalDC, INT x, // Initial x position
INT y, // Initial y position
DWORD flOpts, // Options
PRECTL prcl, // Clipping rectangle
PWCH pwch, // Character array
DWORD cch, // Character count
PLONG pDx, // Inter-Character spacing
DWORD iGraphicsMode, // Graphics mode
INT mrType // Either EMR_EXTTEXTOUTW (Unicode)
// or EMR_EXTTEXTOUTA (Ansi)
) { INT i; BOOL b; RECTS rcs; POINTL ptlRef; UINT fTextAlign; WORD fsOpts; PCHAR pch, pchAlloc; PPOINTL pptl; POINTL ptlAdjust; BOOL bAdjustAlignment; ULONG nANSIChars; PCHAR pDBCSBuffer = NULL;
pptl = (PPOINTL) NULL; fsOpts = (WORD) flOpts; pchAlloc = (PCHAR) NULL; bAdjustAlignment = FALSE; b = FALSE; // assume failure
ASSERTGDI(mrType == EMR_EXTTEXTOUTA || mrType == EMR_EXTTEXTOUTW, "MF3216: DoExtTextOut: bad record type");
// We do not handle the advanced graphics mode here except when
// we are in a path!
// 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.
if (pLocalDC->flags & RECORDING_PATH) { // The helper DC is in the advanced graphics mode. We need to set
// it to the compatible graphics mode temporarily if necessary.
if (iGraphicsMode != GM_ADVANCED) SetGraphicsMode(pLocalDC->hdcHelper, iGraphicsMode);
if (mrType == EMR_EXTTEXTOUTA) b = ExtTextOutA ( pLocalDC->hdcHelper, (int) x, (int) y, (UINT) flOpts, (LPRECT) prcl, (LPSTR) pwch, (int) cch, (LPINT) pDx ); else b = ExtTextOutW ( pLocalDC->hdcHelper, (int) x, (int) y, (UINT) flOpts, (LPRECT) prcl, (LPWSTR) pwch, (int) cch, (LPINT) pDx );
// Restore the graphics mode.
if (iGraphicsMode != GM_ADVANCED) SetGraphicsMode(pLocalDC->hdcHelper, GM_ADVANCED);
return(b); }
// If the string uses the current position, make sure that the metafile
// has the same current position as that of the helper DC.
fTextAlign = GetTextAlign(pLocalDC->hdcHelper);
if (fTextAlign & TA_UPDATECP) { POINT ptCP;
// Update the current position in the converted metafile if
// it is different from that of the helper DC. See notes
// in DoMoveTo().
if (!GetCurrentPositionEx(pLocalDC->hdcHelper, &ptCP)) goto exit_DoExtTextOut;
// Make sure that the converted metafile has the same CP as the
// helper DC.
if (!bValidateMetaFileCP(pLocalDC, ptCP.x, ptCP.y)) goto exit_DoExtTextOut;
// Initialize the XY start position.
x = ptCP.x; y = ptCP.y; }
// Transform the XY start position.
ptlRef.x = x; ptlRef.y = y;
if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) &ptlRef, 1)) goto exit_DoExtTextOut;
// If we have an opaque/clipping rectangle, transform it.
// If we have a strange transform, we will do the rectangle at this time.
if (fsOpts & (ETO_OPAQUE | ETO_CLIPPED)) { RECTL rcl;
rcl = *prcl ;
if (!(pLocalDC->flags & STRANGE_XFORM)) { if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) &rcl, 2)) goto exit_DoExtTextOut;
// The overflow test has been done in the xform.
rcs.left = (SHORT) rcl.left; rcs.top = (SHORT) rcl.top; rcs.right = (SHORT) rcl.right; rcs.bottom = (SHORT) rcl.bottom; } else { if (fsOpts & ETO_OPAQUE) { LONG lhpn32; LONG lhbr32; INT ihW32Br; LOGBRUSH lbBkColor;
// Remember the previous pen and brush
lhpn32 = pLocalDC->lhpn32; lhbr32 = pLocalDC->lhbr32;
if (DoSelectObject(pLocalDC, ENHMETA_STOCK_OBJECT | NULL_PEN)) { lbBkColor.lbStyle = BS_SOLID; lbBkColor.lbColor = pLocalDC->crBkColor; lbBkColor.lbHatch = 0;
// Get an unused W32 object index.
ihW32Br = pLocalDC->cW32ToW16ObjectMap - (STOCK_LAST + 1) - 1;
if (DoCreateBrushIndirect(pLocalDC, ihW32Br, &lbBkColor)) { if (DoSelectObject(pLocalDC, ihW32Br)) { if (DoRectangle(pLocalDC, rcl.left, rcl.top, rcl.right, rcl.bottom)) fsOpts &= ~ETO_OPAQUE;
// Restore the previous brush.
if (!DoSelectObject(pLocalDC, lhbr32)) ASSERTGDI(FALSE, "MF3216: DoExtTextOut, DoSelectObject failed"); } if (!DoDeleteObject(pLocalDC, ihW32Br)) ASSERTGDI(FALSE, "MF3216: DoExtTextOut, DoDeleteObject failed"); }
// Restore the previous pen.
if (!DoSelectObject(pLocalDC, lhpn32)) ASSERTGDI(FALSE, "MF3216: DoExtTextOut, DoSelectObject failed"); }
// Check if the rectangle is drawn.
if (fsOpts & ETO_OPAQUE) goto exit_DoExtTextOut; }
if (fsOpts & ETO_CLIPPED) { // Save the DC so that we can restore it when we are done
if (!DoSaveDC(pLocalDC)) goto exit_DoExtTextOut;
fsOpts &= ~ETO_CLIPPED; // need to restore dc
if (!DoClipRect(pLocalDC, rcl.left, rcl.top, rcl.right, rcl.bottom, EMR_INTERSECTCLIPRECT)) goto exit_DoExtTextOut; } } }
// Convert the Unicode to Ansi.
if (mrType == EMR_EXTTEXTOUTW) { DWORD dwCP; // RtlUnicodeToMultiByteSize(&nANSIChars, pwch, cch * sizeof(WORD));
dwCP = GetCodePage(pLocalDC->hdcHelper); nANSIChars = WideCharToMultiByte(dwCP, 0, pwch, cch, NULL, 0, NULL, NULL); if (nANSIChars == cch) { pch = pchAlloc = (PCHAR) LocalAlloc(LMEM_FIXED, cch * sizeof(BYTE)) ;
if (pch == (PCHAR) NULL) { RIP("MF3216: ExtTextOut, pch LocalAlloc failed\n") ; goto exit_DoExtTextOut; }
WideCharToMultiByte(dwCP, 0, pwch, cch, pch, cch, NULL, NULL); } else { // DBCS char string
UINT cjBufferSize;
// we want DX array on a DWORD boundary
cjBufferSize = ((nANSIChars+3)/4) * 4 * (sizeof(char) + sizeof(LONG)); pchAlloc = pDBCSBuffer = LocalAlloc(LMEM_FIXED, cjBufferSize);
if (pDBCSBuffer) { // start munging passed in parameters
mrType = EMR_EXTTEXTOUTA;
WideCharToMultiByte(dwCP, 0, pwch, cch, pDBCSBuffer, nANSIChars, NULL, NULL);
pwch = (PWCH) pDBCSBuffer; pch = (PCHAR) pwch; cch = nANSIChars;
if (pDx) { ULONG ii, jj;
PULONG pDxTmp = (PLONG) &pDBCSBuffer[((nANSIChars+3)/4)*4];
for(ii=jj=0; ii < nANSIChars; ii++, jj++) { pDxTmp[ii] = pDx[jj];
if(IsDBCSLeadByteEx(dwCP, pDBCSBuffer[ii])) { pDxTmp[++ii] = 0; } }
pDx = pDxTmp; } } else { goto exit_DoExtTextOut; } } } else { pch = (PCHAR) pwch ; }
// Transform the intercharacter spacing information.
// Allocate an array of (cch + 1) points to transform the points in,
// and copy the points to the array.
// ATTENTION: The following will not work if the current font has a vertical default
// baseline
pptl = (PPOINTL) LocalAlloc(LMEM_FIXED, (cch + 1) * sizeof(POINTL)); if (pptl == (PPOINTL) NULL) { RIP("MF3216: ExtTextOut, pptl LocalAlloc failed\n") ; goto exit_DoExtTextOut; }
pptl[0].x = x; pptl[0].y = y; for (i = 1; i < (INT) cch + 1; i++) { pptl[i].x = pptl[i-1].x + pDx[i-1]; pptl[i].y = y; }
// If there is no rotation or shear then we can
// output the characters as a string.
// On the other hand, if there is rotation or shear then we
// have to output each character independently.
if (!(pLocalDC->flags & STRANGE_XFORM)) { // Win31 does not do text alignment correctly in some transforms.
// It performs alignment in device space but win32 does it in the
// notional space. As a result, a win32 TextOut call may produce
// different output than a similar call in win31. We cannot
// convert this correctly since if we make it works on win31,
// it will not work on wow!
PSHORT pDx16;
if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) pptl, (INT) cch + 1)) goto exit_DoExtTextOut;
// Convert it to the Dx array. We do not need to compute it
// as a vector since we have a scaling transform here.
pDx16 = (PSHORT) pptl; for (i = 0; i < (INT) cch; i++) pDx16[i] = (SHORT) (pptl[i+1].x - pptl[i].x);
// Emit the Win16 ExtTextOut metafile record.
if (!bEmitWin16ExtTextOut(pLocalDC, (SHORT) ptlRef.x, (SHORT) ptlRef.y, fsOpts, &rcs, (PSTR) pch, (SHORT) cch, (PWORD) pDx16)) goto exit_DoExtTextOut; } else { // Deal with alignment in the world space. We should really
// do it in the notional space but with escapement and angles,
// things gets complicated pretty easily. We will try
// our best to make it work in the common case. We will not
// worry about escapement and angles.
ptlAdjust.x = 0; ptlAdjust.y = 0;
switch (fTextAlign & (TA_LEFT | TA_RIGHT | TA_CENTER)) { case TA_LEFT: // default, no need to adjust x's
break; case TA_RIGHT: // shift the string by the string length
bAdjustAlignment = TRUE; ptlAdjust.x = pptl[0].x - pptl[cch+1].x; break; case TA_CENTER: // shift the string to the center
bAdjustAlignment = TRUE; ptlAdjust.x = (pptl[0].x - pptl[cch+1].x) / 2; break; }
// We will not adjust for the vertical alignment in the strange
// transform case. We cannot rotate the glyphs in any case.
#if 0
switch (fTextAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE)) { case TA_TOP: // default, no need to adjust y's
break; case TA_BOTTOM: ptlAdjust.y = -logfont.height; break; case TA_BASELINE: ptlAdjust.y = -(logfont.height - logfont.baseline); break; } #endif // 0
// Adjust the character positions taking into account the alignment.
for (i = 0; i < (INT) cch + 1; i++) { pptl[i].x += ptlAdjust.x; pptl[i].y += ptlAdjust.y; }
if (!bXformRWorldToPPage(pLocalDC, (PPOINTL) pptl, (INT) cch + 1)) goto exit_DoExtTextOut;
// Reset the alignment since it has been accounted for.
if (bAdjustAlignment) if (!bEmitWin16SetTextAlign(pLocalDC, (WORD) ((fTextAlign & ~(TA_LEFT | TA_RIGHT | TA_CENTER)) | TA_LEFT))) goto exit_DoExtTextOut;
// Output the characters one at a time.
for (i = 0 ; i < (INT) cch ; i++) { ASSERTGDI(!(fsOpts & (ETO_OPAQUE | ETO_CLIPPED)), "mf3216: DoExtTextOut: rectangle not expected");
if (!bEmitWin16ExtTextOut(pLocalDC, (SHORT) pptl[i].x, (SHORT) pptl[i].y, fsOpts, (PRECTS) NULL, (PSTR) &pch[i], 1, (PWORD) NULL)) goto exit_DoExtTextOut; } }
// Everything is golden.
b = TRUE;
// Cleanup and return.
exit_DoExtTextOut:
// Restore the alignment.
if (bAdjustAlignment) (void) bEmitWin16SetTextAlign(pLocalDC, (WORD) fTextAlign);
if ((flOpts & ETO_CLIPPED) && !(fsOpts & ETO_CLIPPED)) (void) DoRestoreDC(pLocalDC, -1);
if (pchAlloc) LocalFree((HANDLE) pchAlloc);
if (pptl) LocalFree((HANDLE) pptl);
// Update the current position if the call succeeds.
if (b) { if (fTextAlign & TA_UPDATECP) { // Update the helper DC.
if (mrType == EMR_EXTTEXTOUTA) ExtTextOutA ( pLocalDC->hdcHelper, (int) x, (int) y, (UINT) flOpts, (LPRECT) prcl, (LPSTR) pwch, (int) cch, (LPINT) pDx ); else ExtTextOutW ( pLocalDC->hdcHelper, (int) x, (int) y, (UINT) flOpts, (LPRECT) prcl, (LPWSTR) pwch, (int) cch, (LPINT) pDx );
// Make the metafile CP invalid to force update
// when it is used next time
pLocalDC->ptCP.x = MAXLONG ; pLocalDC->ptCP.y = MAXLONG ; } }
return(b); }
/***************************************************************************
* SetTextAlign - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoSetTextAlign ( PLOCALDC pLocalDC, DWORD fMode ) { BOOL b ;
// Do it to the helper DC. It needs this in a path bracket
// and to update current position correctly.
SetTextAlign(pLocalDC->hdcHelper, (UINT) fMode);
// Emit the Win16 metafile drawing order.
b = bEmitWin16SetTextAlign(pLocalDC, LOWORD(fMode)) ;
return(b) ; }
/***************************************************************************
* SetTextColor - Win32 to Win16 Metafile Converter Entry Point **************************************************************************/ BOOL WINAPI DoSetTextColor ( PLOCALDC pLocalDC, COLORREF crColor ) { BOOL b ;
pLocalDC->crTextColor = crColor ; // used by ExtCreatePen
// Emit the Win16 metafile drawing order.
b = bEmitWin16SetTextColor(pLocalDC, crColor) ;
return(b) ; }
/***************************************************************************
* UnicodeToAnsi - Unicode to ANSI conversion routine. **************************************************************************/ VOID vUnicodeToAnsi ( PCHAR pAnsi, PWCH pUnicode, DWORD cch ) { (void) RtlUnicodeToMultiByteN(pAnsi, cch, NULL, pUnicode, cch * sizeof(WCHAR)); }
|