You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4083 lines
125 KiB
4083 lines
125 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: print.c
|
|
*
|
|
* Created: 10-Feb-1995 07:42:16
|
|
* Author: Gerrit van Wingerden [gerritv]
|
|
*
|
|
* Copyright (c) 1993-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "glsup.h"
|
|
|
|
#if DBG
|
|
int gerritv = 0;
|
|
#endif
|
|
|
|
#if DBG
|
|
BOOL gbDownloadFonts = FALSE;
|
|
BOOL gbForceUFIMapping = FALSE;
|
|
#endif
|
|
|
|
#if PRINT_TIMER
|
|
BOOL bPrintTimer = TRUE;
|
|
#endif
|
|
|
|
#ifdef DBGSUBSET
|
|
//Timing code
|
|
FILETIME startPageTime, midPageTime, endPageTime;
|
|
#endif
|
|
|
|
int StartDocEMF(HDC hdc, CONST DOCINFOW * pDocInfo, BOOL *pbBanding); // output.c
|
|
|
|
/****************************************************************************
|
|
* int PutDCStateInMetafile( HDC hdcMeta, HDC hdcSrc )
|
|
*
|
|
* Captures state of a DC into a metafile.
|
|
*
|
|
*
|
|
* History
|
|
*
|
|
* Clear the UFI in LDC so we can set the force mapping for the next metafile
|
|
* Feb-07-1997 Xudong Wu [tessiew]
|
|
*
|
|
* This routine captures the states of a DC into a METAFILE. This is important
|
|
* because we would like each page of the spooled metafile to be completely self
|
|
* contained. In order to do this it must complete capture the original state
|
|
* of the DC in which it was recorded.
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PutDCStateInMetafile( HDC hdcMeta )
|
|
{
|
|
PLDC pldc;
|
|
POINT ptlPos;
|
|
ULONG ul;
|
|
|
|
// DC_PLDC(hdcMeta,pldc,0);
|
|
|
|
pldc = GET_PLDC(hdcMeta);
|
|
|
|
if (!pldc)
|
|
return FALSE;
|
|
|
|
MFD1("Selecting pen into mf\n");
|
|
SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_PEN_TYPE) );
|
|
|
|
MFD1("Selecting brush into mf\n");
|
|
SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_BRUSH_TYPE) );
|
|
|
|
UFI_CLEAR_ID(&pldc->ufi);
|
|
|
|
MFD1("Selecting logfont into mf\n");
|
|
SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_FONT_TYPE) );
|
|
|
|
// DON'T TRY THIS AT HOME. We need to record the current state of the
|
|
// dc in the metafile. We have optimizations however, that keep us from
|
|
// setting the same attribute if it was just set.
|
|
|
|
if( GetBkColor( hdcMeta ) != 0xffffff )
|
|
{
|
|
MFD1("Changing backround color in mf\n");
|
|
SetBkColor( hdcMeta, GetBkColor( hdcMeta ) );
|
|
}
|
|
|
|
if( GetTextColor( hdcMeta ) != 0 )
|
|
{
|
|
MFD1("Changing text color in mf\n");
|
|
SetTextColor( hdcMeta, GetTextColor( hdcMeta ) );
|
|
}
|
|
|
|
if( GetBkMode( hdcMeta ) != OPAQUE )
|
|
{
|
|
MFD1("Changing Background Mode in mf\n");
|
|
SetBkMode( hdcMeta, GetBkMode( hdcMeta ) );
|
|
}
|
|
|
|
if( GetPolyFillMode( hdcMeta ) != ALTERNATE )
|
|
{
|
|
MFD1("Changing PolyFill mode in mf\n");
|
|
SetPolyFillMode( hdcMeta, GetPolyFillMode( hdcMeta ) );
|
|
}
|
|
|
|
if( GetROP2( hdcMeta ) != R2_COPYPEN )
|
|
{
|
|
MFD1("Changing ROP2 in mf\n");
|
|
SetROP2( hdcMeta, GetROP2( hdcMeta ) );
|
|
}
|
|
|
|
if( GetStretchBltMode( hdcMeta ) != BLACKONWHITE )
|
|
{
|
|
MFD1("Changing StrechBltMode in mf\n");
|
|
SetStretchBltMode( hdcMeta, GetStretchBltMode( hdcMeta ) );
|
|
}
|
|
|
|
if( GetTextAlign( hdcMeta ) != 0 )
|
|
{
|
|
MFD1("Changing TextAlign in mf\n");
|
|
SetTextAlign( hdcMeta, GetTextAlign( hdcMeta ) );
|
|
}
|
|
|
|
if( ( GetBreakExtra( hdcMeta ) != 0 )|| ( GetcBreak( hdcMeta ) != 0 ) )
|
|
{
|
|
MFD1("Setting Text Justification in mf\n");
|
|
SetTextJustification( hdcMeta, GetBreakExtra( hdcMeta ), GetcBreak( hdcMeta ) );
|
|
}
|
|
|
|
if( GetMapMode( hdcMeta ) != MM_TEXT )
|
|
{
|
|
INT iMapMode = GetMapMode( hdcMeta );
|
|
POINT ptlWindowOrg, ptlViewportOrg;
|
|
SIZEL WndExt, ViewExt;
|
|
|
|
// get these before we set the map mode to MM_TEXT
|
|
|
|
GetViewportExtEx( hdcMeta, &ViewExt );
|
|
GetWindowExtEx( hdcMeta, &WndExt );
|
|
|
|
GetWindowOrgEx( hdcMeta, &ptlWindowOrg );
|
|
GetViewportOrgEx( hdcMeta, &ptlViewportOrg );
|
|
|
|
// set it to MM_TEXT so it doesn't get optimized out
|
|
|
|
SetMapMode(hdcMeta,MM_TEXT);
|
|
|
|
MFD1("Setting ANISOTROPIC or ISOTROPIC mode in mf\n");
|
|
|
|
SetMapMode( hdcMeta, iMapMode );
|
|
|
|
if( iMapMode == MM_ANISOTROPIC || iMapMode == MM_ISOTROPIC )
|
|
{
|
|
SetWindowExtEx( hdcMeta, WndExt.cx, WndExt.cy, NULL );
|
|
SetViewportExtEx( hdcMeta, ViewExt.cx, ViewExt.cy, NULL );
|
|
}
|
|
|
|
SetWindowOrgEx( hdcMeta,
|
|
ptlWindowOrg.x,
|
|
ptlWindowOrg.y,
|
|
NULL );
|
|
|
|
SetViewportOrgEx( hdcMeta,
|
|
ptlViewportOrg.x,
|
|
ptlViewportOrg.y,
|
|
NULL );
|
|
}
|
|
|
|
if( GetCurrentPositionEx( hdcMeta, &ptlPos ) )
|
|
{
|
|
MFD1("Set CurPos in mf\n");
|
|
MoveToEx( hdcMeta, ptlPos.x, ptlPos.y, NULL );
|
|
}
|
|
|
|
if( GetBrushOrgEx( hdcMeta, &ptlPos ) )
|
|
{
|
|
MFD1("Set BrushOrg in mf\n");
|
|
SetBrushOrgEx( hdcMeta, ptlPos.x, ptlPos.y, &ptlPos );
|
|
}
|
|
|
|
if( SetICMMode( hdcMeta, ICM_QUERY ) )
|
|
{
|
|
MFD1("Set ICM mode in mf\n");
|
|
SetICMMode( hdcMeta, SetICMMode(hdcMeta,ICM_QUERY) );
|
|
}
|
|
|
|
if( GetColorSpace( hdcMeta ) != NULL )
|
|
{
|
|
MFD1("Set ColorSpace in mf\n");
|
|
SetColorSpace( hdcMeta, GetColorSpace(hdcMeta) );
|
|
}
|
|
|
|
if(!NtGdiAnyLinkedFonts())
|
|
{
|
|
// tell the machine to turn off linking
|
|
|
|
MF_SetLinkedUFIs(hdcMeta, NULL, 0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* int MFP_StartDocW( HDC hdc, CONST DOCINFOW * pDocInfo )
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
****************************************************************************/
|
|
|
|
//! this needs to be moved to a spooler header file
|
|
|
|
#define QSM_DOWNLOADFONTS 0x000000001
|
|
|
|
BOOL MFP_StartDocW( HDC hdc, CONST DOCINFOW * pDocInfo, BOOL bBanding )
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PWSTR pstr = NULL;
|
|
BOOL bEpsPrinting;
|
|
PLDC pldc;
|
|
UINT cjEMFSH;
|
|
FLONG flSpoolMode;
|
|
HANDLE hSpooler;
|
|
DWORD dwSessionId = 0;
|
|
|
|
EMFSPOOLHEADER *pemfsh = NULL;
|
|
|
|
MFD1("Entering StartDocW\n");
|
|
|
|
if (!IS_ALTDC_TYPE(hdc))
|
|
return(bRet);
|
|
|
|
DC_PLDC(hdc,pldc,bRet);
|
|
|
|
//
|
|
// Create a new EMFSpoolData object to use during EMF recording
|
|
//
|
|
|
|
if (!AllocEMFSpoolData(pldc, bBanding))
|
|
{
|
|
WARNING("MFP_StartDocW: AllocEMFSpoolData failed\n");
|
|
return bRet;
|
|
}
|
|
|
|
if( !bBanding )
|
|
{
|
|
hSpooler = pldc->hSpooler;
|
|
cjEMFSH = sizeof(EMFSPOOLHEADER);
|
|
|
|
if( pDocInfo->lpszDocName != NULL )
|
|
{
|
|
cjEMFSH += ( wcslen( pDocInfo->lpszDocName ) + 1 ) * sizeof(WCHAR);
|
|
}
|
|
|
|
if( pDocInfo->lpszOutput != NULL )
|
|
{
|
|
cjEMFSH += ( wcslen( pDocInfo->lpszOutput ) + 1 ) * sizeof(WCHAR);
|
|
}
|
|
|
|
cjEMFSH = ROUNDUP_DWORDALIGN(cjEMFSH);
|
|
|
|
pemfsh = (EMFSPOOLHEADER*) LocalAlloc( LMEM_FIXED, cjEMFSH );
|
|
|
|
if( pemfsh == NULL )
|
|
{
|
|
WARNING("MFP_StartDOCW: out of memory.\n");
|
|
goto FREEPORT;
|
|
}
|
|
|
|
pemfsh->cjSize = cjEMFSH;
|
|
|
|
cjEMFSH = 0;
|
|
|
|
if( ( pDocInfo->lpszDocName ) != NULL )
|
|
{
|
|
pemfsh->dpszDocName = sizeof(EMFSPOOLHEADER);
|
|
wcscpy( (WCHAR*) (pemfsh+1), pDocInfo->lpszDocName );
|
|
cjEMFSH += ( wcslen( pDocInfo->lpszDocName ) + 1 ) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
pemfsh->dpszDocName = 0;
|
|
}
|
|
|
|
if( pDocInfo->lpszOutput != NULL )
|
|
{
|
|
pemfsh->dpszOutput = sizeof(EMFSPOOLHEADER) + cjEMFSH;
|
|
wcscpy((WCHAR*)(((BYTE*) pemfsh ) + pemfsh->dpszOutput),
|
|
pDocInfo->lpszOutput);
|
|
}
|
|
else
|
|
{
|
|
pemfsh->dpszOutput = 0;
|
|
}
|
|
|
|
ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
|
|
|
|
if( !(*fpQuerySpoolMode)( hSpooler, &flSpoolMode, &(pemfsh->dwVersion)))
|
|
{
|
|
WARNING("MFP_StartDoc: QuerySpoolMode failed\n");
|
|
goto FREEPORT;
|
|
}
|
|
|
|
//
|
|
// In the scenario of a TS session or a console session that is non zero,
|
|
// (due to FastUserSwitching) the font is added using AddFontResource to the win32k.sys
|
|
// of one of the clients and the printing is done with the win32k.sys of the console.
|
|
// Those are separate win32k.sys that have their own data. The win32k.sys of the console
|
|
// cannot access the font that is in the data of a different win32k.sys. In this case
|
|
// we need to force the font to be embedded in the EMF stream.
|
|
//
|
|
if (!ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) || dwSessionId != 0)
|
|
{
|
|
flSpoolMode |= QSM_DOWNLOADFONTS;
|
|
}
|
|
|
|
ASSERTGDI((pemfsh->dwVersion == 0x00010000),
|
|
"QuerySpoolMode version doesn't equal 1.0\n");
|
|
|
|
if( !WriteEMFSpoolData(pldc, pemfsh, pemfsh->cjSize))
|
|
{
|
|
WARNING("MFP_StartDOC: WriteData failed\n");
|
|
goto FREEPORT;
|
|
}
|
|
else
|
|
{
|
|
MFD1("Wrote EMFSPOOLHEADER to the spooler\n");
|
|
}
|
|
|
|
//
|
|
// Write PostScript Injection data.
|
|
//
|
|
// ATTENTION: THIS MUST BE RIGHT AFTER EMFSPOOLHEADER RECORD
|
|
//
|
|
if (pldc->dwSizeOfPSDataToRecord)
|
|
{
|
|
BOOL bError = FALSE;
|
|
EMFITEMHEADER emfi;
|
|
PLIST_ENTRY p = pldc->PSDataList.Flink;
|
|
|
|
// Write the header to spooler.
|
|
|
|
emfi.ulID = EMRI_PS_JOB_DATA;
|
|
emfi.cjSize = pldc->dwSizeOfPSDataToRecord;
|
|
|
|
if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)))
|
|
{
|
|
WARNING("MFP_StartPage: Write printer failed for PS_JOB_DATA header\n");
|
|
goto FREEPORT;
|
|
}
|
|
else
|
|
{
|
|
MFD1("Wrote EMRI_PS_JOB_DATA header to the spooler\n");
|
|
}
|
|
|
|
// Record EMFITEMPSINJECTIONDATA
|
|
|
|
while(p != &(pldc->PSDataList))
|
|
{
|
|
PPS_INJECTION_DATA pPSData;
|
|
|
|
// get pointer to this cell.
|
|
|
|
pPSData = CONTAINING_RECORD(p,PS_INJECTION_DATA,ListEntry);
|
|
|
|
// record this escape to EMF.
|
|
|
|
if (!bError && !WriteEMFSpoolData(pldc, &(pPSData->EmfData), pPSData->EmfData.cjSize))
|
|
{
|
|
WARNING("MFP_StartPage: Write printer failed for PS_JOB_DATA escape data\n");
|
|
bError = TRUE;
|
|
}
|
|
|
|
// get pointer to next cell.
|
|
|
|
p = p->Flink;
|
|
|
|
// no longer needs this cell.
|
|
|
|
LOCALFREE(pPSData);
|
|
}
|
|
|
|
// mark as data already freed.
|
|
|
|
pldc->dwSizeOfPSDataToRecord = 0;
|
|
InitializeListHead(&(pldc->PSDataList));
|
|
|
|
if (bError)
|
|
{
|
|
goto FREEPORT;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if( gbDownloadFonts )
|
|
{
|
|
flSpoolMode |= QSM_DOWNLOADFONTS;
|
|
}
|
|
#endif
|
|
|
|
if (flSpoolMode & QSM_DOWNLOADFONTS)
|
|
{
|
|
// Now, QMS_DOWNLOADFONTS bit are on when print on remote print server,
|
|
// then I just use this bit to determine attach ICM profile to metafile
|
|
// or not. - hideyukn [May-08-1997]
|
|
|
|
pldc->fl |= LDC_DOWNLOAD_PROFILES;
|
|
|
|
// Configure to download fonts
|
|
|
|
pldc->fl |= LDC_DOWNLOAD_FONTS;
|
|
pldc->ppUFIHash = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof( PUFIHASH ) * 3 * UFI_HASH_SIZE );
|
|
|
|
if( pldc->ppUFIHash == NULL)
|
|
{
|
|
WARNING("MFP_StartDocW: unable to allocate UFI hash tables\n");
|
|
goto FREEPORT;
|
|
}
|
|
|
|
// do not want to allocate memory twice
|
|
|
|
pldc->ppDVUFIHash = &pldc->ppUFIHash[UFI_HASH_SIZE];
|
|
pldc->ppSubUFIHash = &pldc->ppDVUFIHash[UFI_HASH_SIZE];
|
|
|
|
pldc->fl |= LDC_FORCE_MAPPING;
|
|
pldc->ufi.Index = 0xFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
ULONG cEmbedFonts;
|
|
|
|
pldc->ppUFIHash = pldc->ppDVUFIHash = pldc->ppSubUFIHash = NULL;
|
|
if ((cEmbedFonts = NtGdiGetEmbedFonts()) && cEmbedFonts != 0xFFFFFFFF)
|
|
{
|
|
pldc->fl |= LDC_EMBED_FONTS;
|
|
pldc->ppUFIHash = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PUFIHASH) * UFI_HASH_SIZE);
|
|
|
|
if (pldc->ppUFIHash == NULL)
|
|
{
|
|
WARNING("MFP_StartDocW: unable to allocate UFI has table for embed fonts\n");
|
|
goto FREEPORT;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
// If gbDownloadFonts is set then force all fonts to be downloaded. Even
|
|
// ones on the remote machine.
|
|
|
|
if( (flSpoolMode & QSM_DOWNLOADFONTS) && !gbDownloadFonts )
|
|
#else
|
|
if( flSpoolMode & QSM_DOWNLOADFONTS )
|
|
#endif
|
|
{
|
|
// query the spooler to get the list of fonts is has available
|
|
|
|
INT nBufferSize = 0;
|
|
PUNIVERSAL_FONT_ID pufi;
|
|
|
|
nBufferSize = (*fpQueryRemoteFonts)( pldc->hSpooler, NULL, 0 );
|
|
|
|
if( nBufferSize != -1 )
|
|
{
|
|
pufi = LocalAlloc( LMEM_FIXED, sizeof(UNIVERSAL_FONT_ID) * nBufferSize );
|
|
|
|
if( pufi )
|
|
{
|
|
INT nNewBufferSize = (*fpQueryRemoteFonts)( pldc->hSpooler,
|
|
pufi,
|
|
nBufferSize );
|
|
|
|
//
|
|
// This fixes bug 420136. We have three cases according to the result
|
|
// of QueryRemoteFonts. If it returns -1, nBufferSize will be set to
|
|
// -1 in the if statement. If nNewBufferSize is larger than what we
|
|
// allocated, then we use the buffer that we allocated (nBufferSize)
|
|
// If nNewBufferSize is less than what we allocated, then we set
|
|
// nBufferSize to a lower value then the one previously held. This means
|
|
// we access only a part of the buffer we allocated.
|
|
//
|
|
if (nNewBufferSize < nBufferSize)
|
|
{
|
|
nBufferSize = nNewBufferSize;
|
|
}
|
|
|
|
MFD2("Found %d fonts\n", nBufferSize );
|
|
|
|
if (nBufferSize > 0)
|
|
{
|
|
// next add all these fonts to UFI has table so we don't
|
|
//include them in the spool file.
|
|
|
|
while( nBufferSize-- )
|
|
{
|
|
pufihAddUFIEntry(pldc->ppUFIHash, &pufi[nBufferSize], 0, 0, 0);
|
|
MFD2("%x\n", pufi[nBufferSize].CheckSum );
|
|
}
|
|
}
|
|
LocalFree( pufi );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("QueryRemoteFonts failed. We will be including all fonts in \
|
|
the EMF spoolfile\n");
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if( gbForceUFIMapping )
|
|
{
|
|
pldc->fl |= LDC_FORCE_MAPPING;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
// we now need to create an EMF DC for this document
|
|
|
|
if (!AssociateEnhMetaFile(hdc))
|
|
{
|
|
WARNING("Failed to create spool metafile");
|
|
goto FREEPORT;
|
|
}
|
|
|
|
if (bBanding)
|
|
{
|
|
pldc->fl |= LDC_BANDING;
|
|
|
|
// remove the LDC_PRINT_DIRECT which
|
|
// was set in StartDocW before NtGdiStartDoc call.
|
|
|
|
pldc->fl &= ~LDC_PRINT_DIRECT;
|
|
}
|
|
|
|
// set the data for this lhe to that of the meta file
|
|
|
|
pldc->fl |= (LDC_DOC_STARTED|LDC_META_PRINT|LDC_CALL_STARTPAGE|LDC_FONT_CHANGE);
|
|
|
|
// clear color page flag
|
|
|
|
CLEAR_COLOR_PAGE(pldc);
|
|
|
|
if (pldc->pfnAbort != NULL)
|
|
{
|
|
pldc->fl |= LDC_SAP_CALLBACK;
|
|
pldc->ulLastCallBack = GetTickCount();
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
FREEPORT:
|
|
|
|
if( pemfsh != NULL )
|
|
{
|
|
LOCALFREE(pemfsh);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* int WINAPI MFP_EndDoc(HDC hdc)
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int WINAPI MFP_EndDoc(HDC hdc)
|
|
{
|
|
int iRet = 1;
|
|
PLDC pldc;
|
|
HENHMETAFILE hmeta;
|
|
|
|
if (!IS_ALTDC_TYPE(hdc))
|
|
return(iRet);
|
|
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
MFD1("MFP_EndDoc\n");
|
|
|
|
if ((pldc->fl & LDC_DOC_STARTED) == 0)
|
|
return(1);
|
|
|
|
if (pldc->fl & LDC_PAGE_STARTED)
|
|
{
|
|
MFP_EndPage(hdc);
|
|
}
|
|
|
|
ASSERTGDI(pldc->fl & LDC_META_PRINT,
|
|
"DetachPrintMetafile not called on metafile D.C.\n" );
|
|
|
|
// completely detach the metafile from the original printer DC
|
|
|
|
hmeta = UnassociateEnhMetaFile( hdc, FALSE );
|
|
DeleteEnhMetaFile( hmeta );
|
|
|
|
DeleteEMFSpoolData(pldc);
|
|
|
|
// Clear the LDC_SAP_CALLBACK flag.
|
|
// Also clear the META_PRINT and DOC_STARTED flags
|
|
|
|
pldc->fl &= ~(LDC_SAP_CALLBACK | LDC_META_PRINT);
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
MFD1("Caling spooler to end doc\n");
|
|
|
|
if( pldc->fl & LDC_BANDING )
|
|
{
|
|
pldc->fl &= ~LDC_BANDING;
|
|
EndDoc( hdc );
|
|
}
|
|
else
|
|
{
|
|
pldc->fl &= ~LDC_DOC_STARTED;
|
|
(*fpEndDocPrinter)(pldc->hSpooler);
|
|
}
|
|
|
|
#if PRINT_TIMER
|
|
if( bPrintTimer )
|
|
{
|
|
DWORD tc;
|
|
|
|
tc = GetTickCount();
|
|
|
|
DbgPrint("Document took %d.%d seconds to spool\n",
|
|
(tc - pldc->msStartDoc) / 1000,
|
|
(tc - pldc->msStartDoc) % 1000 );
|
|
|
|
}
|
|
#endif
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* int WINAPI MFP_StartPage(HDC hdc)
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int MFP_StartPage( HDC hdc )
|
|
{
|
|
PLDC pldc;
|
|
int iRet = 1;
|
|
|
|
//Timing code
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_PAGETIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&startPageTime);
|
|
}
|
|
#endif
|
|
|
|
if (!IS_ALTDC_TYPE(hdc))
|
|
return(0);
|
|
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
MFD1("Entering MFP_StartPage\n");
|
|
|
|
pldc->fl &= ~LDC_CALL_STARTPAGE;
|
|
pldc->fl &= ~LDC_CALLED_ENDPAGE;
|
|
|
|
pldc->fl &= ~LDC_META_ARCDIR_CLOCKWISE;
|
|
|
|
// Do nothing if page has already been started.
|
|
|
|
if (pldc->fl & LDC_PAGE_STARTED)
|
|
return(1);
|
|
|
|
pldc->fl |= LDC_PAGE_STARTED;
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
if( pldc->fl & LDC_BANDING )
|
|
{
|
|
iRet = SP_ERROR;
|
|
|
|
// ATTENTION: maybe we can delay the call here and do it right before we start
|
|
// banding.
|
|
|
|
MakeInfoDC( hdc, FALSE );
|
|
|
|
iRet = NtGdiStartPage(hdc);
|
|
|
|
MakeInfoDC( hdc, TRUE );
|
|
}
|
|
else
|
|
{
|
|
ULONG ulCopyCount;
|
|
EMFITEMHEADER emfi;
|
|
EMFITEMPRESTARTPAGE emfiPre;
|
|
|
|
// If application calls Escape(SETCOPYCOUNT), we will over-write copy count in
|
|
// devmode and save it into metafile.
|
|
|
|
NtGdiGetAndSetDCDword(
|
|
hdc,
|
|
GASDDW_COPYCOUNT,
|
|
(DWORD) -1,
|
|
&ulCopyCount);
|
|
|
|
if (ulCopyCount != (ULONG) -1)
|
|
{
|
|
if (pldc->pDevMode)
|
|
{
|
|
// Set copy count into devmode.
|
|
// No driver call happen here, since this is EMF spooling...
|
|
|
|
pldc->pDevMode->dmFields |= DM_COPIES;
|
|
pldc->pDevMode->dmCopies = (short) ulCopyCount;
|
|
|
|
// Fill up EMF record for devmode.
|
|
|
|
emfi.ulID = EMRI_DEVMODE;
|
|
emfi.cjSize = pldc->pDevMode->dmSize + pldc->pDevMode->dmDriverExtra;
|
|
|
|
// Force devmode data to be DWORD aligned
|
|
|
|
emfi.cjSize = ROUNDUP_DWORDALIGN(emfi.cjSize);
|
|
|
|
if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)) ||
|
|
!WriteEMFSpoolData(pldc, pldc->pDevMode, emfi.cjSize))
|
|
{
|
|
WARNING("MFP_StartPage: Write printer failed for DEVMODE\n");
|
|
return(SP_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// before the start page, we need to see if the EPS mode has
|
|
// changed since the start doc.
|
|
|
|
NtGdiGetAndSetDCDword(
|
|
hdc,
|
|
GASDDW_EPSPRINTESCCALLED,
|
|
(DWORD) FALSE,
|
|
&emfiPre.bEPS);
|
|
|
|
if (emfiPre.bEPS)
|
|
{
|
|
int i;
|
|
EMFITEMHEADER emfiHeader;
|
|
|
|
// make sure it is true or false
|
|
|
|
emfiPre.bEPS = !!emfiPre.bEPS;
|
|
|
|
// This was ulCopyCount.
|
|
// Just set -1 for keep compatibility. -1 means "up to devmode".
|
|
|
|
emfiPre.ulUnused = -1;
|
|
|
|
// is there anything we will need to do? If so record the record
|
|
|
|
emfiHeader.ulID = EMRI_PRESTARTPAGE;
|
|
emfiHeader.cjSize = sizeof(emfiPre);
|
|
|
|
if (!WriteEMFSpoolData(pldc, &emfiHeader, sizeof(emfiHeader)) ||
|
|
!WriteEMFSpoolData(pldc, &emfiPre, sizeof(emfiPre)))
|
|
{
|
|
WARNING("MFP_StartPage: Write printer failed for PRESTARTPAGE\n");
|
|
return(SP_ERROR);
|
|
}
|
|
}
|
|
|
|
// Metafile the start page call. Now all the play journal code has to do is
|
|
// play back the metafile and the StartPage call will happen automatically
|
|
// at the right place in the metafile.
|
|
|
|
if( !(*fpStartPagePrinter)( pldc->hSpooler ) )
|
|
{
|
|
WARNING("MFP_StarPage: StartPagePrinter failed\n");
|
|
return(SP_ERROR);
|
|
}
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* BOOL StartBanding( HDC hdc, POINTL *pptl )
|
|
*
|
|
* Tells the printer driver to get ready for banding and asks for the origin
|
|
* of the first band.
|
|
*
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 1-7-95 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL StartBanding( HDC hdc, POINTL *pptl, SIZE *pSize )
|
|
{
|
|
return (NtGdiDoBanding(hdc, TRUE, pptl, pSize));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* BOOL NextBand( HDC hdc, POINTL *pptl )
|
|
*
|
|
* Tells the driver to realize the image accumlated in the DC and then
|
|
* asks for the origin of the next band. If the origin is (-1,-1) the
|
|
* driver is through banding.
|
|
*
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 1-7-95 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL NextBand( HDC hdc, POINTL *pptl )
|
|
{
|
|
BOOL bRet=FALSE;
|
|
SIZE szScratch;
|
|
|
|
bRet = NtGdiDoBanding(hdc, FALSE, pptl, &szScratch);
|
|
|
|
// reset the page started flag if this is the next band
|
|
|
|
if( bRet && ( pptl->x == -1 ) )
|
|
{
|
|
PLDC pldc;
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
pldc->fl &= ~LDC_PAGE_STARTED;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/****************************************************************************\
|
|
* VOID PrintBand()
|
|
*
|
|
* History:
|
|
*
|
|
* 1-05-97 Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
* 3-23-98 Ramanathan Venkatapathy [ramanv]
|
|
* Fixed Scaling bugs
|
|
* 6-26-98 Ramanathan Venkatapathy [ramanv]
|
|
* Added pClip to correct the clipping when Xforms are applied on the
|
|
* DC. ANDing Banding region with prect incorrectly clips off regions when
|
|
* prect is yet to be transformed.
|
|
* 8-24-99 Steve Kiraly [steveki]
|
|
* Add code to not play on the DC if there is no intersection with the
|
|
* clipping rectangle and the banding rectangle. Fix n-up bug when the
|
|
* imageable area of the document is larger that the physical page. The
|
|
* solution consisted of setting up the clipping region to stay within
|
|
* either the banding rectangle or the clipping rectangle. See bug 377434
|
|
* for more information.
|
|
*
|
|
* An illustration of the problem.
|
|
*
|
|
* We are printing a document that is larger than the imageable area of the page
|
|
* thus it must print on 2 pages and we are printing 2-up with banding enabled
|
|
* because this is a 24 bpp document.
|
|
*
|
|
* The printable region rectagle is (0,0) (2114,3066)
|
|
* Page one has a clipping rectangle of (216,46) (2114,1510)
|
|
* Page two has a clipping rectangle of (216,1601) (2114,3066)
|
|
*
|
|
* GDI will print using 4 bands each 784 high.
|
|
*
|
|
* Band 1 pptl = 0,0 pszlBand = 2400,784
|
|
* Band 2 pptl = 0,784 pszlBand = 2400,784
|
|
* Band 3 pptl = 0,1568 pszlBand = 2400,784
|
|
* Band 4 pptl = 0,2352 pszlBand = 2400,784
|
|
*
|
|
* 0,0
|
|
*
|
|
* 0,0 +-----------------------------------------------------------------+
|
|
* | 216,46 |
|
|
* | |
|
|
* | |
|
|
* 0,784 | |
|
|
* | |
|
|
* | [========================================] |
|
|
* | [ ] |
|
|
* | [ ] |
|
|
* | [ ] 2114,1510 |
|
|
* |-----------------------------------------------------------------|
|
|
* | 216,1601 [ ] |
|
|
* 0,1568 | [ ] |
|
|
* | [ ] |
|
|
* | [ ] |
|
|
* 0,2352 | [ ] |
|
|
* | [ ] |
|
|
* | [========================================] |
|
|
* | |
|
|
* | 2114,3066 |
|
|
* +-----------------------------------------------------------------+
|
|
*
|
|
* 2114,3066
|
|
*
|
|
* Band 1 clipping region is (216,0) (2401,785)
|
|
* Band 2 clipping region is (216,784) (2114,726)
|
|
* Band 3 clipping region is (216,33) (2114,785)
|
|
* Band 4 clipping region is (216,0) (2114,714)
|
|
*
|
|
* Band 2 and 3 are the most interesting cases. Band 2 the clipping
|
|
* bottom right corner is the size of the clipping rectangle rather than the
|
|
* band size as the code orignally was. Band 3 on the other hand has the
|
|
* top left corner of the region adjusted to the clipping rectangle.
|
|
*
|
|
****************************************************************************/
|
|
|
|
VOID
|
|
PrintBand(
|
|
HDC hdc,
|
|
HENHMETAFILE hmeta,
|
|
POINTL *pptl, // Offsets from top of page for this band.
|
|
RECT *prect, // Rectangle for printable reagion of this page.
|
|
SIZEL *pszlBand, // Size of band.
|
|
RECT *pClip // Clipping rectangle, non null when n-up.
|
|
)
|
|
{
|
|
ULONG ulRet;
|
|
PERBANDINFO pbi;
|
|
|
|
MFD3("gdi32:PrintBand Print offset x,y = %d,%d\n", pptl->x, pptl->y);
|
|
MFD3("gdi32:PrintBand Printable region top = %d, bottom = %d\n", prect->top, prect->bottom);
|
|
MFD3("gdi32:PrintBand Printable region left = %d, right = %d\n", prect->left, prect->right);
|
|
MFD3("gdi32:PrintBand Band size x,y = %d,%d\n",pszlBand->cx, pszlBand->cy);
|
|
|
|
do
|
|
{
|
|
RECT rectPage = *prect;
|
|
HRGN hRgnBand = NULL;
|
|
HRGN hRgnCurrent = NULL;
|
|
BOOL bSaveDC = FALSE;
|
|
ULONG ulXRes, ulYRes;
|
|
BOOL bUsePerBandInfo = FALSE;
|
|
|
|
// Updates view origin in specified coords.
|
|
|
|
SetViewportOrgEx( hdc, -(pptl->x), -(pptl->y), NULL );
|
|
|
|
// Initialize with current resolution.
|
|
|
|
ulXRes = (ULONG) prect->right - prect->left;
|
|
ulYRes = (ULONG) prect->bottom - prect->top;
|
|
|
|
pbi.bRepeatThisBand = FALSE;
|
|
pbi.ulHorzRes = ulXRes;
|
|
pbi.ulVertRes = ulYRes;
|
|
pbi.szlBand.cx = pszlBand->cx;
|
|
pbi.szlBand.cy = pszlBand->cy;
|
|
|
|
MFD1("GDI32:PrintBand() querying band information\n");
|
|
|
|
// Query band information.
|
|
|
|
ulRet = NtGdiGetPerBandInfo(hdc,&pbi);
|
|
|
|
if (ulRet != GDI_ERROR)
|
|
{
|
|
SIZEL szlClip;
|
|
POINTL pptlMove;
|
|
|
|
bUsePerBandInfo = (ulRet != 0);
|
|
|
|
// If return value is 0, we will draw without scaling.
|
|
|
|
if (bUsePerBandInfo &&
|
|
((ulXRes != pbi.ulHorzRes) ||
|
|
(ulYRes != pbi.ulVertRes)))
|
|
{
|
|
FLOAT sx,sy;
|
|
|
|
MFD1("GDI PlayEMF band information was specified\n");
|
|
|
|
// Compute scaling ratio.
|
|
|
|
//
|
|
// This code has rounding errors due to
|
|
// float to long truncation. The correct code
|
|
// should use a LONGLONG to store the numerator and do
|
|
// all of the computation in integer math.
|
|
//
|
|
// See StretchDIBits
|
|
//
|
|
// The fix is coded below in comments because we can't check it
|
|
// in till someone figures out how to break the original version.
|
|
//
|
|
|
|
sx = (FLOAT) ulXRes / (FLOAT) pbi.ulHorzRes;
|
|
sy = (FLOAT) ulYRes / (FLOAT) pbi.ulVertRes;
|
|
|
|
// Shrink/Stretch drawing frame.
|
|
|
|
//rectPage.left = (LONG) ((LONGLONG)rectPage.left*pbi.ulHorizRes)/ulXRes;
|
|
//rectPage.top = (LONG) ((LONGLONG)rectPage.top*pbi.ulVertRes)/ulYRes;
|
|
//rectPage.right = (LONG) ((LONGLONG)rectPage.right*pbi.ulHorizRes)/ulXRes;
|
|
//rectPage.bottom = (LONG) ((LONGLONG)rectPage.bottom*pbi.ulVertRes)/ulYRes;
|
|
|
|
rectPage.left = (LONG) ((FLOAT) rectPage.left / sx);
|
|
rectPage.top = (LONG) ((FLOAT) rectPage.top / sy);
|
|
rectPage.right = (LONG) ((FLOAT) rectPage.right / sx);
|
|
rectPage.bottom = (LONG) ((FLOAT) rectPage.bottom / sy);
|
|
|
|
// Compute view origin.
|
|
|
|
//pptlMove.x = (LONG) ((LONGLONG)pptl->x*pbi.ulHorizRes)/ulXRes;
|
|
//pptlMove.y = (LONG) ((LONGLONG)pptl->y*pbi.ulVertRes)/ulYRes;
|
|
|
|
pptlMove.x = (LONG) ((FLOAT) pptl->x / sx);
|
|
pptlMove.y = (LONG) ((FLOAT) pptl->y / sy);
|
|
|
|
// Updates view origin in specified coords.
|
|
|
|
SetViewportOrgEx( hdc, -pptlMove.x, -pptlMove.y, NULL );
|
|
|
|
// Set clip region size.
|
|
|
|
|
|
//szlClip.cx = (ULONG) ((LONGLONG)pbi.szlBand.cx*pbi.ulHorizRes)/ulXRes;
|
|
//szlClip.cy = (ULONG) ((LONGLONG)pbi.szlBand.cy*pbi.ulVertRes)/ulYRes;
|
|
|
|
szlClip.cx = (ULONG) ((FLOAT) pbi.szlBand.cx / sx);
|
|
szlClip.cy = (ULONG) ((FLOAT) pbi.szlBand.cy / sy);
|
|
|
|
// Create clip region for banding.
|
|
|
|
hRgnBand = CreateRectRgn(0,0,szlClip.cx,szlClip.cy);
|
|
}
|
|
else
|
|
{
|
|
SIZEL szlPage = {0,0};
|
|
SIZEL szlAdjust = {0,0};
|
|
|
|
if(!bUsePerBandInfo)
|
|
{
|
|
// Set back to default values in case driver mucked with them
|
|
|
|
pbi.bRepeatThisBand = FALSE;
|
|
pbi.ulHorzRes = ulXRes;
|
|
pbi.ulVertRes = ulYRes;
|
|
pbi.szlBand.cx = pszlBand->cx;
|
|
pbi.szlBand.cy = pszlBand->cy;
|
|
}
|
|
|
|
pptlMove.x = pptl->x;
|
|
pptlMove.y = pptl->y;
|
|
|
|
MFD1("gdi32:PrintBand(): GetPerBandInfo NO SCALING is requested\n");
|
|
|
|
// Page size
|
|
if (pClip) {
|
|
|
|
RECT rcBand;
|
|
RECT rcIntersect;
|
|
|
|
MFD3("gdi32:PrintBand(): Clipping Rectangle top = %d, bottom = %d\n", pClip->top, pClip->bottom);
|
|
MFD3("gdi32:PrintBand(): Clipping Rectangle left = %d, right = %d\n", pClip->left, pClip->right);
|
|
|
|
rcBand.left = pptlMove.x;
|
|
rcBand.top = pptlMove.y;
|
|
rcBand.right = pptlMove.x + pbi.szlBand.cx;
|
|
rcBand.bottom = pptlMove.y + pbi.szlBand.cy;
|
|
|
|
//
|
|
// If the banding rect does not instersect the clip rect
|
|
// not much to do, just continue.
|
|
//
|
|
if (!IntersectRect(&rcIntersect, pClip, &rcBand))
|
|
{
|
|
MFD1("gdi32:PrintBand(): No intersection with band rect and pClip\n");
|
|
continue;
|
|
}
|
|
|
|
szlPage.cx = pClip->right;
|
|
szlPage.cy = pClip->bottom;
|
|
|
|
//
|
|
// The adjust point it neccessary to move the clipping
|
|
// region's upper or left edge. The szlClip is used to
|
|
// move the clipping region's height and width.
|
|
//
|
|
if (pClip->left > pptlMove.x)
|
|
{
|
|
szlAdjust.cx = pClip->left - pptlMove.x;
|
|
}
|
|
|
|
if (pClip->top > pptlMove.y)
|
|
{
|
|
szlAdjust.cy = pClip->top - pptlMove.y;
|
|
}
|
|
|
|
} else {
|
|
|
|
szlPage.cx = prect->right;
|
|
szlPage.cy = prect->bottom;
|
|
}
|
|
|
|
//
|
|
// Set clip region size (clip by band size)
|
|
//
|
|
// if band rect over page rect, adjust it.
|
|
//
|
|
|
|
if ((pptlMove.x + pbi.szlBand.cx) > szlPage.cx)
|
|
{
|
|
szlClip.cx = szlPage.cx - pptlMove.x;
|
|
}
|
|
else
|
|
{
|
|
szlClip.cx = pbi.szlBand.cx;
|
|
}
|
|
|
|
if ((pptlMove.y + pbi.szlBand.cy) > szlPage.cy)
|
|
{
|
|
szlClip.cy = szlPage.cy - pptlMove.y;
|
|
}
|
|
else
|
|
{
|
|
szlClip.cy = pbi.szlBand.cy;
|
|
}
|
|
|
|
MFD3("Print offset x,y = %d,%d\n",pptlMove.x,pptlMove.y);
|
|
MFD3("Page size x,y = %d,%d\n",szlPage.cx,szlPage.cy);
|
|
MFD3("Band size x,y = %d,%d\n",pbi.szlBand.cx,pbi.szlBand.cy);
|
|
MFD3("Clip size x,y = %d,%d\n",szlClip.cx,szlClip.cy);
|
|
MFD3("Adjust size x,y = %d,%d\n",szlAdjust.cx,szlAdjust.cy);
|
|
|
|
// Create clip region for banding.
|
|
|
|
hRgnBand = CreateRectRgn(szlAdjust.cx,szlAdjust.cy,szlClip.cx,szlClip.cy);
|
|
}
|
|
|
|
if (hRgnBand)
|
|
{
|
|
int iRet;
|
|
RECT rectCurrentClip;
|
|
|
|
// Get clip box currently selected in DC.
|
|
|
|
iRet = GetClipBox(hdc,&rectCurrentClip);
|
|
|
|
if ((iRet == NULLREGION) || (iRet == ERROR))
|
|
{
|
|
// Select simple band region as clip region.
|
|
|
|
SelectClipRgn(hdc, hRgnBand);
|
|
}
|
|
else
|
|
{
|
|
MFD1("GDI PrintBand: Some region already exists\n");
|
|
MFD3("Clip Box top = %d, bottom = %d\n",
|
|
rectCurrentClip.top,rectCurrentClip.bottom);
|
|
MFD3("Clip Box left = %d, right = %d\n",
|
|
rectCurrentClip.left,rectCurrentClip.right);
|
|
|
|
// Save currect DC to restore current clip region later.
|
|
|
|
SaveDC(hdc);
|
|
|
|
// Move to the clip reagion to proper place.
|
|
|
|
OffsetClipRgn(hdc,-pptlMove.x,-pptlMove.y);
|
|
|
|
// Some clip region already defined. we need to combine those.
|
|
|
|
ExtSelectClipRgn(hdc, hRgnBand, RGN_AND);
|
|
|
|
// Mark as we saved DC.
|
|
|
|
bSaveDC = TRUE;
|
|
}
|
|
}
|
|
|
|
// Play metafile.
|
|
|
|
PlayEnhMetaFile( hdc, hmeta, &rectPage );
|
|
|
|
if (hRgnBand)
|
|
{
|
|
if (bSaveDC)
|
|
{
|
|
RestoreDC(hdc,-1);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Set back it to NULL region.
|
|
|
|
SelectClipRgn(hdc,NULL);
|
|
}
|
|
|
|
// Reset the clip region.
|
|
|
|
DeleteObject(hRgnBand);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MFD1("GDI PrintBand: Got error from kernel/driver, this band will be skipped\n");
|
|
|
|
// There is something error, Terminate printing for this band.
|
|
|
|
return;
|
|
}
|
|
|
|
// Repeat this until the driver says "no".
|
|
|
|
} while (pbi.bRepeatThisBand);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* int MFP_InternalEndPage(HDC hdc, DWORD dwEMFITEMID)
|
|
*
|
|
* Closes the EMF attached to the DC and writes it to the spooler. Then
|
|
* it creates a new metafile and binds it to the DC.
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int MFP_InternalEndPage(HDC hdc,
|
|
DWORD dwEMFITEMID)
|
|
{
|
|
PLDC pldc;
|
|
HENHMETAFILE hmeta;
|
|
BOOL bOk;
|
|
int iRet = SP_ERROR;
|
|
|
|
MFD1("Entering MFP_EndPage\n");
|
|
|
|
if (!IS_ALTDC_TYPE(hdc))
|
|
return(0);
|
|
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
if ((pldc->fl & LDC_DOC_CANCELLED) ||
|
|
((pldc->fl & LDC_PAGE_STARTED) == 0))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(SP_ERROR);
|
|
}
|
|
// Need to change the dwEMFITEMID here if mono page
|
|
if (!(pldc->fl & LDC_COLOR_PAGE)) {
|
|
dwEMFITEMID = (dwEMFITEMID == EMRI_METAFILE) ? EMRI_BW_METAFILE
|
|
: EMRI_BW_FORM_METAFILE;
|
|
}
|
|
DESIGNATE_COLOR_PAGE(pldc);
|
|
|
|
if (pldc->fl & LDC_SAP_CALLBACK)
|
|
vSAPCallback(pldc);
|
|
|
|
pldc->fl &= ~LDC_PAGE_STARTED;
|
|
|
|
//tessiew
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_PAGETIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&midPageTime);
|
|
DbgPrint("\t%ld", (midPageTime.dwLowDateTime-startPageTime.dwLowDateTime) / 10000);
|
|
}
|
|
#endif
|
|
|
|
// We need to write the subset font into the spool
|
|
// file first for remote printing
|
|
|
|
if ((pldc->fl & (LDC_DOWNLOAD_FONTS | LDC_FORCE_MAPPING)) && (pldc->fl & LDC_FONT_SUBSET))
|
|
{
|
|
PUFIHASH pBucket, pBucketNext;
|
|
PUCHAR puchDestBuff;
|
|
ULONG index, ulDestSize, ulBytesWritten;
|
|
|
|
for (index=0; index < UFI_HASH_SIZE; index++)
|
|
{
|
|
pBucketNext = pldc->ppSubUFIHash[index];
|
|
|
|
while(pBucketNext)
|
|
{
|
|
// We might fail on bDoFontSubset() thus pBucket would be deleted from the hash table
|
|
// in function WriteSubFontToSpoolFile(). Need to update pBucketNext first.
|
|
|
|
pBucket = pBucketNext;
|
|
pBucketNext = pBucket->pNext;
|
|
|
|
if ((pBucket->fs1 & FLUFI_DELTA) && (pBucket->u.ssi.cDeltaGlyphs == 0))
|
|
{
|
|
// No delta, skip
|
|
if (pBucket->u.ssi.pjDelta)
|
|
{
|
|
LocalFree(pBucket->u.ssi.pjDelta);
|
|
pBucket->u.ssi.pjDelta = NULL;
|
|
}
|
|
}
|
|
else // first page or page with nonzero delta
|
|
{
|
|
// pBucket->fs1 will change for the first page after bDoFontSubset() call,
|
|
// thus we can't use pBucket->fs1 & FLUFI_DELTA in WriteSubFontToSpoolFile() call.
|
|
BOOL bDelta = pBucket->fs1 & FLUFI_DELTA;
|
|
|
|
if
|
|
(
|
|
!bDoFontSubset(pBucket, &puchDestBuff, &ulDestSize, &ulBytesWritten) ||
|
|
!WriteSubFontToSpoolFile(pldc, puchDestBuff, ulBytesWritten, &pBucket->ufi, bDelta)
|
|
)
|
|
{
|
|
// if font subsetting failed, we need to write the whole font file to the spool file
|
|
// and clean up the UFI entry in the ldc
|
|
|
|
if (!bAddUFIandWriteSpool(hdc, &pBucket->ufi, TRUE, pBucket->fs2))
|
|
{
|
|
WARNING("bAddUFIandWriteSpool failed\n");
|
|
return SP_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Metafile the EndPage call.
|
|
|
|
MFD1("MFP_EndPage: Closing metafile\n");
|
|
|
|
hmeta = UnassociateEnhMetaFile(hdc, TRUE);
|
|
|
|
if( hmeta == NULL )
|
|
{
|
|
WARNING("MFP_InternalEndPage() Closing the Enhanced Metafile Failed\n");
|
|
return(SP_ERROR);
|
|
}
|
|
|
|
// now write the metafile to the spooler
|
|
|
|
if( pldc->fl & LDC_BANDING )
|
|
{
|
|
// play back the metafile in bands
|
|
|
|
RECT rect;
|
|
POINTL ptlOrigin;
|
|
POINT ptlKeep;
|
|
POINT ptlWindowOrg;
|
|
SIZE szWindowExt;
|
|
SIZE szViewportExt;
|
|
SIZE szSurface; // for open gl printing optimization
|
|
XFORM xf;
|
|
ULONG ulMapMode;
|
|
|
|
// get bounding rectangle
|
|
|
|
rect.left = rect.top = 0;
|
|
rect.right = GetDeviceCaps(hdc, DESKTOPHORZRES);
|
|
rect.bottom = GetDeviceCaps(hdc, DESKTOPVERTRES);
|
|
|
|
#if DBG
|
|
DbgPrint("Playing banding metafile\n");
|
|
#endif
|
|
|
|
// temporarily reset LDC_META_PRINT flag so we don't try to record
|
|
// during playback
|
|
|
|
pldc->fl &= ~LDC_META_PRINT;
|
|
|
|
bOk = StartBanding( hdc, &ptlOrigin, &szSurface );
|
|
|
|
// we need to clear the transform during this operation
|
|
|
|
GetViewportOrgEx(hdc, &ptlKeep);
|
|
GetWindowOrgEx(hdc,&ptlWindowOrg);
|
|
GetWindowExtEx(hdc,&szWindowExt);
|
|
GetViewportExtEx(hdc,&szViewportExt);
|
|
GetWorldTransform(hdc,&xf);
|
|
|
|
ulMapMode = SetMapMode(hdc,MM_TEXT);
|
|
SetWindowOrgEx(hdc,0,0,NULL);
|
|
ModifyWorldTransform(hdc,NULL,MWT_IDENTITY);
|
|
|
|
if( bOk )
|
|
{
|
|
do
|
|
{
|
|
// Print this band.
|
|
|
|
PrintBand( hdc, hmeta, &ptlOrigin, &rect, &szSurface, NULL );
|
|
|
|
// Move down to next band.
|
|
|
|
bOk = NextBand( hdc, &ptlOrigin );
|
|
} while( ptlOrigin.x != -1 && bOk );
|
|
}
|
|
|
|
if (pldc->pUMPD && bOk && (ptlOrigin.x == -1))
|
|
{
|
|
//
|
|
// if UMPD and last band
|
|
//
|
|
if( !(*fpEndPagePrinter)( pldc->hSpooler ) )
|
|
{
|
|
WARNING("MFP_StarPage: EndPagePrinter failed\n");
|
|
iRet = SP_ERROR;
|
|
}
|
|
}
|
|
|
|
SetMapMode(hdc,ulMapMode);
|
|
|
|
SetWorldTransform(hdc,&xf);
|
|
SetWindowOrgEx(hdc,ptlWindowOrg.x,ptlWindowOrg.y,NULL);
|
|
SetWindowExtEx(hdc,szWindowExt.cx,szWindowExt.cy,NULL);
|
|
SetViewportExtEx(hdc,szViewportExt.cx,szViewportExt.cy,NULL);
|
|
SetViewportOrgEx(hdc,ptlKeep.x, ptlKeep.y, NULL);
|
|
|
|
// reset the flag for the next page
|
|
|
|
pldc->fl |= LDC_META_PRINT;
|
|
|
|
if( !bOk )
|
|
{
|
|
WARNING("MFP_EndPage: Error doing banding\n");
|
|
}
|
|
else
|
|
{
|
|
// if we got here we suceeded
|
|
iRet = 1;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("Done playing banding metafile\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// if ResetDC was called record the devmode in the metafile stream
|
|
|
|
bOk = TRUE;
|
|
|
|
if( pldc->fl & LDC_RESETDC_CALLED )
|
|
{
|
|
EMFITEMHEADER emfi;
|
|
|
|
emfi.ulID = EMRI_DEVMODE;
|
|
emfi.cjSize = ( pldc->pDevMode ) ?
|
|
pldc->pDevMode->dmSize + pldc->pDevMode->dmDriverExtra : 0 ;
|
|
|
|
// Force devmode data to be DWORD aligned
|
|
|
|
emfi.cjSize = ROUNDUP_DWORDALIGN(emfi.cjSize);
|
|
|
|
if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)) ||
|
|
!WriteEMFSpoolData(pldc, pldc->pDevMode, emfi.cjSize))
|
|
{
|
|
WARNING("Writing DEVMODE to spooler failed.\n");
|
|
bOk = FALSE;
|
|
}
|
|
|
|
pldc->fl &= ~(LDC_RESETDC_CALLED);
|
|
}
|
|
|
|
if (bOk)
|
|
iRet = 1;
|
|
}
|
|
|
|
// At this point if we suceede iRet should be 1 otherwise it should be SP_ERROR
|
|
// even if we encountered an error we still want to try to associate a new
|
|
// metafile with this DC. That whether the app calls EndPage, AbortDoc, or
|
|
// EndDoc next, things will happend more smoothly.
|
|
|
|
DeleteEnhMetaFile(hmeta);
|
|
|
|
//
|
|
// flush the content of the current page to spooler
|
|
// and write out a new EndPage record
|
|
//
|
|
|
|
// next create a new metafile for the next page
|
|
|
|
if (!FlushEMFSpoolData(pldc, dwEMFITEMID) || !AssociateEnhMetaFile(hdc))
|
|
{
|
|
WARNING("StartPage: error creating metafile\n");
|
|
iRet = SP_ERROR;
|
|
}
|
|
|
|
// reset user's poll count so it counts this as output
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
if( !(pldc->fl & LDC_BANDING ) )
|
|
{
|
|
if( !(*fpEndPagePrinter)( pldc->hSpooler ) )
|
|
{
|
|
WARNING("MFP_StarPage: EndPagePrinter failed\n");
|
|
iRet = SP_ERROR;
|
|
}
|
|
}
|
|
|
|
pldc->fl |= LDC_CALL_STARTPAGE;
|
|
|
|
#if PRINT_TIMER
|
|
if( bPrintTimer )
|
|
{
|
|
DWORD tc;
|
|
tc = GetTickCount();
|
|
DbgPrint("Page took %d.%d seconds to print\n",
|
|
(tc - pldc->msStartPage) / 1000,
|
|
(tc - pldc->msStartPage) % 1000 );
|
|
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_PAGETIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&endPageTime);
|
|
DbgPrint("\t%ld\n", (endPageTime.dwLowDateTime-startPageTime.dwLowDateTime) / 10000);
|
|
}
|
|
#endif
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* int WINAPI MFP_EndPage(HDC hdc)
|
|
*
|
|
* Closes the EMF attached to the DC and writes it to the spooler. Then
|
|
* it creates a new metafile and binds it to the DC.
|
|
*
|
|
* Gerrit van Wingerden [gerritv]
|
|
*
|
|
* 11-7-94 10:00:00
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int WINAPI MFP_EndPage(HDC hdc) {
|
|
|
|
// Call MFP_InternalEndPage with EMRI_METAFILE
|
|
return MFP_InternalEndPage(hdc, EMRI_METAFILE);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* int WINAPI MFP_EndFormPage(HDC hdc)
|
|
*
|
|
* Closes the EMF attached to the DC and writes it to the spooler. Then
|
|
* it creates a new metafile and binds it to the DC. Saves the EMF Item as a
|
|
* watermark file which is played on each physical page.
|
|
*
|
|
* Ramanathan Venkatapathy [RamanV]
|
|
*
|
|
* 7/1/97
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int WINAPI MFP_EndFormPage(HDC hdc) {
|
|
|
|
// Call MFP_InternalEndPage with EMRI_FORM_METAFILE
|
|
return MFP_InternalEndPage(hdc, EMRI_FORM_METAFILE);
|
|
|
|
}
|
|
|
|
BOOL MFP_ResetDCW( HDC hdc, DEVMODEW *pdmw )
|
|
{
|
|
PLDC pldc;
|
|
HENHMETAFILE hmeta;
|
|
ULONG cjDevMode;
|
|
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
MFD1("MFP_ResetDCW Called\n");
|
|
|
|
pldc->fl |= LDC_RESETDC_CALLED;
|
|
|
|
// finally associate a new metafile since call to ResetDC could have changed
|
|
// the dimensions of the DC
|
|
|
|
hmeta = UnassociateEnhMetaFile( hdc, FALSE );
|
|
DeleteEnhMetaFile( hmeta );
|
|
|
|
if( !AssociateEnhMetaFile( hdc ) )
|
|
{
|
|
WARNING("MFP_ResetDCW is unable to associate a new metafile\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL MFP_ResetBanding( HDC hdc, BOOL bBanding )
|
|
{
|
|
PLDC pldc;
|
|
HENHMETAFILE hmeta;
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
if( pldc->fl & LDC_BANDING )
|
|
{
|
|
// we were banding before so we must remove the old metafile from the DC
|
|
// since we might not be banding any more or the surface dimenstions could
|
|
// have changed requiring us to have a new metafile
|
|
|
|
hmeta = UnassociateEnhMetaFile( hdc, FALSE );
|
|
DeleteEnhMetaFile( hmeta );
|
|
|
|
pldc->fl &= ~(LDC_BANDING|LDC_META_PRINT);
|
|
|
|
MFD1("Remove old banding metafile\n");
|
|
|
|
}
|
|
|
|
if( bBanding )
|
|
{
|
|
// if we are banding after the ResetDC then we must attach a new metafile
|
|
|
|
if( !AssociateEnhMetaFile(hdc) )
|
|
{
|
|
WARNING("MFP_ResetBanding: Failed to attach banding metafile spool metafile");
|
|
return(FALSE);
|
|
}
|
|
|
|
pldc->fl |= LDC_BANDING|LDC_META_PRINT;
|
|
|
|
MFD1("Adding new banding metafile\n");
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
|
|
*
|
|
* Read a requested number of bytes from the spooler.
|
|
*
|
|
* History:
|
|
* 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
*
|
|
* 5/1/1997 by Ramanathan N Venkatapathy [ramanv]
|
|
* Modified to synchronously wait during Print while spooling.
|
|
* SeekPrinter sets last error when spool file isn't big enough.
|
|
*****************************************************************************/
|
|
|
|
BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
|
|
{
|
|
ULONG cjRead;
|
|
LARGE_INTEGER liOffset;
|
|
|
|
ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
|
|
|
|
// Wait till enough bytes have been written.
|
|
liOffset.QuadPart = cjBuf;
|
|
if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Seek back to the original position in the spoolfile.
|
|
liOffset.QuadPart = -liOffset.QuadPart;
|
|
if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
while( cjBuf )
|
|
{
|
|
if(!(*fpReadPrinter)( hPrinter, pjBuf, cjBuf, &cjRead ) )
|
|
{
|
|
WARNING("MyReadPrinter: Read printer failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if( cjRead == 0 )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pjBuf += cjRead;
|
|
cjBuf -= cjRead;
|
|
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL MemMapReadPrinter(
|
|
HANDLE hPrinter,
|
|
LPBYTE *pBuf,
|
|
ULONG cbBuf
|
|
)
|
|
{
|
|
LARGE_INTEGER liOffset;
|
|
|
|
ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
|
|
|
|
// Memory mapped ReadPrinter not exported.
|
|
if (!fpSplReadPrinter) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Wait till enough bytes have been written.
|
|
liOffset.QuadPart = cbBuf;
|
|
if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Seek back to the original position in the spoolfile.
|
|
liOffset.QuadPart = -liOffset.QuadPart;
|
|
if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(*fpSplReadPrinter) (hPrinter, pBuf, (DWORD) cbBuf)) {
|
|
WARNING("MemMapReadPrinter: Read printer failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI GdiPlayEMF(
|
|
LPWSTR pwszPrinterName,
|
|
LPDEVMODEW pDevmode,
|
|
LPWSTR pwszDocName,
|
|
EMFPLAYPROC pfnEMFPlayFn,
|
|
HANDLE hPageQuery
|
|
)
|
|
/*++
|
|
Function Description:
|
|
GdiPlayEMF is the old playback function. It has been replaced by a
|
|
bunch of new GDI interfaces which give more flexibility to the print
|
|
processor on placing and reordering the pages of the print job. This
|
|
function has been rewritten to use these new interfaces (for backward
|
|
compatibility and maintainance)
|
|
|
|
Parameters:
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
8/15/1997 by Ramanathan N Venkatapathy [ramanv]
|
|
|
|
--*/
|
|
{
|
|
HANDLE hSpoolHandle, hEMF;
|
|
HDC hPrinterDC;
|
|
BOOL bReturn = FALSE;
|
|
DOCINFOW DocInfo;
|
|
DWORD dwPageType, dwPageNumber = 1;
|
|
RECT rectDocument;
|
|
LPDEVMODEW pCurrDM, pLastDM;
|
|
|
|
if (!(hSpoolHandle = GdiGetSpoolFileHandle(pwszPrinterName,
|
|
pDevmode,
|
|
pwszDocName)) ||
|
|
!(hPrinterDC = GdiGetDC(hSpoolHandle))) {
|
|
|
|
goto CleanUp;
|
|
}
|
|
|
|
DocInfo.cbSize = sizeof(DOCINFOW);
|
|
DocInfo.lpszDocName = pwszDocName;
|
|
DocInfo.lpszOutput = NULL;
|
|
DocInfo.lpszDatatype = NULL;
|
|
|
|
rectDocument.left = rectDocument.top = 0;
|
|
rectDocument.right = GetDeviceCaps(hPrinterDC, DESKTOPHORZRES);
|
|
rectDocument.bottom = GetDeviceCaps(hPrinterDC, DESKTOPVERTRES);
|
|
|
|
if (!GdiStartDocEMF(hSpoolHandle, &DocInfo)) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
while (1) {
|
|
|
|
hEMF = GdiGetPageHandle(hSpoolHandle,
|
|
dwPageNumber,
|
|
&dwPageType);
|
|
|
|
if (!hEMF) {
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
|
|
break;
|
|
} else {
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
if (!GdiGetDevmodeForPage(hSpoolHandle, dwPageNumber,
|
|
&pCurrDM, &pLastDM)) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
if ((pCurrDM != pLastDM) && !GdiResetDCEMF(hSpoolHandle,
|
|
pCurrDM)) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (!SetGraphicsMode(hPrinterDC, GM_ADVANCED)) {
|
|
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (!GdiStartPageEMF(hSpoolHandle) ||
|
|
!GdiPlayPageEMF(hSpoolHandle, hEMF, &rectDocument, NULL, NULL) ||
|
|
!GdiEndPageEMF(hSpoolHandle, 0)) {
|
|
|
|
goto CleanUp;
|
|
}
|
|
|
|
++dwPageNumber;
|
|
}
|
|
|
|
GdiEndDocEMF(hSpoolHandle);
|
|
|
|
bReturn = TRUE;
|
|
|
|
CleanUp:
|
|
|
|
if (hSpoolHandle) {
|
|
GdiDeleteSpoolFileHandle(hSpoolHandle);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL WINAPI GdiDeleteSpoolFileHandle(
|
|
HANDLE SpoolFileHandle)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiDeleteSpoolFileHandle frees all the resources allocated by GDI for printing
|
|
the corresponding job. This function should be called by the print processor just
|
|
before it returns.
|
|
|
|
Parameters:
|
|
SpoolFileHandle - Handle returned by GdiGetSpoolFileHandle.
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
|
|
Freed more resources associated with the SpoolFileHandle
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
LPDEVMODEW pLastDevmode;
|
|
UINT PageCount;
|
|
PRECORD_INFO_STRUCT pRecordInfo = NULL, pRecordInfoFree = NULL;
|
|
DWORD dwIndex;
|
|
PEMF_HANDLE pTemp;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiDeleteSpoolFileHandle: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiDeleteSpoolFileHandle: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Loop through all the page records, find the last page on which each DEVMODE is used
|
|
// and free it. The first DEVMODE is always allocated along with the memory for
|
|
// the spool file handle so never free that one. All DEVMODEs different than the original one
|
|
// must be non-NULL since they appear in the spool file.
|
|
|
|
for(PageCount = 0, pLastDevmode = pSpoolFileHandle->pOriginalDevmode;
|
|
PageCount < pSpoolFileHandle->MaxPageProcessed;
|
|
PageCount += 1 )
|
|
{
|
|
if(pSpoolFileHandle->pPageInfo[PageCount].pDevmode != pLastDevmode)
|
|
{
|
|
if(pLastDevmode != pSpoolFileHandle->pOriginalDevmode)
|
|
{
|
|
LocalFree(pLastDevmode);
|
|
}
|
|
|
|
pLastDevmode = pSpoolFileHandle->pPageInfo[PageCount].pDevmode;
|
|
}
|
|
}
|
|
|
|
// free the last DEVMODE used if it is not the original DEVMODE
|
|
|
|
if(pLastDevmode != pSpoolFileHandle->pOriginalDevmode)
|
|
{
|
|
LocalFree(pLastDevmode);
|
|
}
|
|
|
|
// free the PAGE_INFO_STRUCT array and lists held in them
|
|
|
|
if (pSpoolFileHandle->pPageInfo) {
|
|
|
|
for (dwIndex = pSpoolFileHandle->MaxPageProcessed; dwIndex; --dwIndex) {
|
|
|
|
pRecordInfo = pSpoolFileHandle->pPageInfo[dwIndex-1].pRecordInfo;
|
|
|
|
while (pRecordInfoFree = pRecordInfo) {
|
|
pRecordInfo = pRecordInfo->pNext;
|
|
LocalFree(pRecordInfoFree);
|
|
}
|
|
|
|
}
|
|
LocalFree(pSpoolFileHandle->pPageInfo);
|
|
}
|
|
|
|
// free the list of EMF_HANDLEs returned to the print processor
|
|
|
|
while (pTemp = pSpoolFileHandle->pEMFHandle) {
|
|
pSpoolFileHandle->pEMFHandle = (pSpoolFileHandle->pEMFHandle)->pNext;
|
|
if (pTemp->hemf) {
|
|
InternalDeleteEnhMetaFile(pTemp->hemf, pTemp->bAllocBuffer);
|
|
}
|
|
LocalFree(pTemp);
|
|
}
|
|
|
|
// free the DC
|
|
|
|
DeleteDC(pSpoolFileHandle->hdc);
|
|
|
|
// then the spooler's spool handle
|
|
|
|
(*fpClosePrinter)(pSpoolFileHandle->hSpooler);
|
|
|
|
// finally free the data associated with this handle
|
|
|
|
LocalFree(pSpoolFileHandle);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
HANDLE WINAPI GdiGetSpoolFileHandle(
|
|
LPWSTR pwszPrinterName,
|
|
LPDEVMODEW pDevmode,
|
|
LPWSTR pwszDocName)
|
|
/*
|
|
Function Description:
|
|
GdiGetSpoolFileHandle is the first function that should be called by the
|
|
print processor. It returns a handle that will be needed for all the
|
|
subsequent calls. The function performs initializations of opening the
|
|
printer, creating a device context and allocating memory for the handle.
|
|
|
|
Parameters:
|
|
pwszPrinterName - Identifies the printer on which the job is to printed.
|
|
pDevmode - Pointer to a DEVMODE structure.
|
|
pwszDocName - Identifies the document name of job.
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is a valid HANDLE;
|
|
otherwise the result is NULL.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
|
|
Handled NULL devmode case.
|
|
*/
|
|
{
|
|
SPOOL_FILE_HANDLE *pHandle;
|
|
|
|
if( !BLOADSPOOLER )
|
|
{
|
|
WARNING("GdiGetSpoolFileHandle: Unable to load spooler\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if(pHandle = LOCALALLOC(sizeof(SPOOL_FILE_HANDLE) +
|
|
((pDevmode != NULL) ? pDevmode->dmSize+pDevmode->dmDriverExtra
|
|
: 0 )))
|
|
{
|
|
// Zero out the SPOOL_FILE_HANDLE
|
|
RtlZeroMemory(pHandle , sizeof(SPOOL_FILE_HANDLE) +
|
|
((pDevmode != NULL) ? pDevmode->dmSize+pDevmode->dmDriverExtra
|
|
: 0));
|
|
|
|
if((*fpOpenPrinterW)(pwszDocName, &pHandle->hSpooler,
|
|
(LPPRINTER_DEFAULTSW) NULL ) &&
|
|
pHandle->hSpooler)
|
|
{
|
|
if(pHandle->hdc = CreateDCW(L"", pwszPrinterName, L"", pDevmode))
|
|
{
|
|
pHandle->PageInfoBufferSize = 20;
|
|
|
|
if(pHandle->pPageInfo = LOCALALLOC(sizeof(PAGE_INFO_STRUCT) *
|
|
pHandle->PageInfoBufferSize))
|
|
{
|
|
pHandle->tag = SPOOL_FILE_HANDLE_TAG;
|
|
|
|
if (pDevmode) {
|
|
pHandle->pOriginalDevmode = (LPDEVMODEW) (pHandle + 1);
|
|
memcpy(pHandle->pOriginalDevmode, pDevmode,pDevmode->dmSize+pDevmode->dmDriverExtra);
|
|
} else {
|
|
pHandle->pOriginalDevmode = NULL;
|
|
}
|
|
|
|
pHandle->pLastDevmode = pHandle->pOriginalDevmode;
|
|
pHandle->MaxPageProcessed = 0;
|
|
pHandle->pEMFHandle = NULL;
|
|
RtlZeroMemory(pHandle->pPageInfo,
|
|
sizeof(PAGE_INFO_STRUCT) * pHandle->PageInfoBufferSize);
|
|
|
|
pHandle->dwPlayBackStatus = EMF_PLAY_FORCE_MONOCHROME;
|
|
if (pHandle->pLastDevmode &&
|
|
(pHandle->pLastDevmode->dmFields & DM_COLOR) &&
|
|
(pHandle->pLastDevmode->dmColor == DMCOLOR_COLOR)) {
|
|
|
|
pHandle->dwPlayBackStatus = EMF_PLAY_COLOR;
|
|
}
|
|
pHandle->bUseMemMap = TRUE;
|
|
|
|
return((HANDLE) pHandle);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GdiGetSpoolFileHandle: OutOfMemory\n");
|
|
}
|
|
|
|
DeleteDC(pHandle->hdc);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GdiGetSpoolHandle: CreateDCW failed\n");
|
|
}
|
|
|
|
(*fpClosePrinter)(pHandle->hSpooler);
|
|
}
|
|
|
|
LocalFree(pHandle);
|
|
}
|
|
|
|
return((HANDLE) NULL);
|
|
}
|
|
|
|
BOOL ProcessJob(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle
|
|
)
|
|
{
|
|
LARGE_INTEGER LargeInt;
|
|
EMFSPOOLHEADER emsh;
|
|
EMFITEMHEADER emfi;
|
|
|
|
// Seek to offset 0.
|
|
|
|
LargeInt.QuadPart = 0;
|
|
if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
|
|
{
|
|
WARNING("GDI32 ProcessJob: seek printer to 0 failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Read EMFSPOOLHEADER
|
|
|
|
if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emsh, sizeof(emsh)))
|
|
{
|
|
WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Move Offset to next record.
|
|
|
|
LargeInt.QuadPart = emsh.cjSize;
|
|
if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
|
|
{
|
|
WARNING("GDI32 ProcessPages: seek printer failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Read next EMFITEMHEADER
|
|
|
|
if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfi, sizeof(emfi)))
|
|
{
|
|
WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// If this is EMRI_PS_JOB_DATA, process this record.
|
|
|
|
if (emfi.ulID == EMRI_PS_JOB_DATA)
|
|
{
|
|
PBYTE pPSBuffer = LOCALALLOC(emfi.cjSize);
|
|
|
|
if (pPSBuffer)
|
|
{
|
|
if (MyReadPrinter(pSpoolFileHandle->hSpooler, pPSBuffer, emfi.cjSize))
|
|
{
|
|
DWORD cjSizeProcessed = 0;
|
|
PEMFITEMPSINJECTIONDATA pPSData = (PEMFITEMPSINJECTIONDATA) pPSBuffer;
|
|
|
|
while (cjSizeProcessed < emfi.cjSize)
|
|
{
|
|
ExtEscape(pSpoolFileHandle->hdc,
|
|
pPSData->nEscape,
|
|
pPSData->cjInput,
|
|
(PVOID)&(pPSData->EscapeData),
|
|
0, NULL);
|
|
|
|
cjSizeProcessed += pPSData->cjSize;
|
|
|
|
// Move to next record.
|
|
|
|
pPSData = (PEMFITEMPSINJECTIONDATA) ((PBYTE)pPSData + pPSData->cjSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
|
|
LOCALFREE(pPSBuffer);
|
|
return(FALSE);
|
|
}
|
|
|
|
LOCALFREE(pPSBuffer);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GDI32 ProcessJob: failed on LOCALALLOC\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// Seek back to offset 0.
|
|
|
|
LargeInt.QuadPart = 0;
|
|
(*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
BOOL ProcessPages(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle,
|
|
UINT LastPage
|
|
)
|
|
/*
|
|
Function Description:
|
|
ProcessPages parses the spool file and processes the EMF records until the
|
|
required page.
|
|
|
|
Parameters:
|
|
SpoolFileHandle - Handle returned by GdiGetSpoolFileHandle.
|
|
LastPage - Page number to process.
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
|
|
Added code to handle DELTA_FONT, SUBSET_FONT, DESIGN_VECTOR
|
|
and PRESTARTPAGE.
|
|
|
|
1/28/1998 by Ramanathan N Venkatapathy [ramanv] -
|
|
Process EXT records
|
|
*/
|
|
{
|
|
LARGE_INTEGER LargeInt;
|
|
LONGLONG CurrentOffset, EMFOffset;
|
|
ULONG CurrentPage;
|
|
LPDEVMODEW pLastDevmode = NULL;
|
|
EMFITEMHEADER emfi, emfiExt;
|
|
BYTE *pTmpBuffer = NULL;
|
|
UNIVERSAL_FONT_ID ufi;
|
|
ULONG ulBytesWritten;
|
|
PVOID pvMergeBuf;
|
|
PRECORD_INFO_STRUCT pRecordInfo;
|
|
BOOL bReadPrinter = FALSE;
|
|
INT64 iOffset;
|
|
DWORD dwSize;
|
|
BOOL bLastDevmodeAllocated = FALSE;
|
|
|
|
// early exit if we've already processed the requested number of pages
|
|
|
|
if(pSpoolFileHandle->MaxPageProcessed >= LastPage)
|
|
{
|
|
//When a document is being printed back-to-front and is restarted in
|
|
//the middle of the job, we won't detect the error in the normal way.
|
|
//So we call SeekPrinter with NOOP arguments to check for the
|
|
//ERROR_PRINT_CANCELLED return value.
|
|
|
|
BOOL fSeekResult;
|
|
LargeInt.QuadPart = 0;
|
|
fSeekResult = ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt,
|
|
NULL, FILE_CURRENT, FALSE));
|
|
return fSeekResult || GetLastError() != ERROR_PRINT_CANCELLED;
|
|
}
|
|
|
|
// allocate memory to store info for all pages if the existing buffer isn't large
|
|
// enough
|
|
|
|
if(LastPage > pSpoolFileHandle->PageInfoBufferSize)
|
|
{
|
|
PAGE_INFO_STRUCT *pTemp;
|
|
|
|
if(pTemp = LOCALALLOC(sizeof(PAGE_INFO_STRUCT) * LastPage))
|
|
{
|
|
RtlZeroMemory(pTemp, sizeof(PAGE_INFO_STRUCT) * LastPage);
|
|
memcpy(pTemp,
|
|
pSpoolFileHandle->pPageInfo,
|
|
sizeof(PAGE_INFO_STRUCT) * pSpoolFileHandle->MaxPageProcessed);
|
|
|
|
pSpoolFileHandle->PageInfoBufferSize = LastPage;
|
|
LocalFree(pSpoolFileHandle->pPageInfo);
|
|
pSpoolFileHandle->pPageInfo = pTemp;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
WARNING("GDI32 ProcessPages: out of memory\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// if we've already processed some pages then start with the last page processed
|
|
|
|
if(pSpoolFileHandle->MaxPageProcessed)
|
|
{
|
|
CurrentOffset =
|
|
pSpoolFileHandle->pPageInfo[pSpoolFileHandle->MaxPageProcessed-1].SeekOffset;
|
|
|
|
pLastDevmode =
|
|
pSpoolFileHandle->pPageInfo[pSpoolFileHandle->MaxPageProcessed-1].pDevmode;
|
|
}
|
|
else
|
|
{
|
|
EMFSPOOLHEADER emsh;
|
|
|
|
LargeInt.QuadPart = 0;
|
|
if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
|
|
{
|
|
WARNING("GDI32 ProcessPages: seek printer to 0 failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emsh, sizeof(emsh)))
|
|
{
|
|
WARNING("GDI32 ProcessPages: MyReadPrinter failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
CurrentOffset = emsh.cjSize;
|
|
pLastDevmode = pSpoolFileHandle->pOriginalDevmode;
|
|
}
|
|
|
|
LargeInt.QuadPart = CurrentOffset;
|
|
|
|
if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
|
|
LargeInt, NULL,
|
|
0,FALSE)))
|
|
{
|
|
WARNING("GDI32 ProcessPages: seek printer failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
CurrentPage = pSpoolFileHandle->MaxPageProcessed;
|
|
|
|
while ((CurrentPage < LastPage) &&
|
|
MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfi, sizeof(emfi))) {
|
|
|
|
CurrentOffset += sizeof(emfi);
|
|
|
|
if (emfi.cjSize == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bReadPrinter = FALSE;
|
|
|
|
// For records to be processed now, read into a buffer
|
|
|
|
if ((emfi.ulID == EMRI_DEVMODE) ||
|
|
(emfi.ulID == EMRI_ENGINE_FONT) ||
|
|
(emfi.ulID == EMRI_TYPE1_FONT) ||
|
|
(emfi.ulID == EMRI_SUBSET_FONT) ||
|
|
(emfi.ulID == EMRI_DELTA_FONT) ||
|
|
(emfi.ulID == EMRI_DESIGNVECTOR)) {
|
|
|
|
if (pTmpBuffer = (BYTE*) LOCALALLOC(emfi.cjSize)) {
|
|
|
|
if(MyReadPrinter(pSpoolFileHandle->hSpooler,
|
|
pTmpBuffer, emfi.cjSize)) {
|
|
|
|
bReadPrinter = TRUE;
|
|
dwSize = emfi.cjSize;
|
|
|
|
} else {
|
|
|
|
WARNING("Gdi32: Process Pages error reading font or devmode\n");
|
|
goto exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
WARNING("Out of memory in ProcessPages\n");
|
|
goto exit;
|
|
}
|
|
|
|
} else if ((emfi.ulID == EMRI_ENGINE_FONT_EXT) ||
|
|
(emfi.ulID == EMRI_TYPE1_FONT_EXT) ||
|
|
(emfi.ulID == EMRI_SUBSET_FONT_EXT) ||
|
|
(emfi.ulID == EMRI_DELTA_FONT_EXT) ||
|
|
(emfi.ulID == EMRI_DESIGNVECTOR_EXT) ||
|
|
(emfi.ulID == EMRI_EMBED_FONT_EXT)) {
|
|
|
|
// For EXT records get the buffer from an offset
|
|
|
|
if (emfi.cjSize < sizeof(INT64)) {
|
|
WARNING("Ext Record bad size\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (MyReadPrinter(pSpoolFileHandle->hSpooler, (PBYTE) &iOffset, sizeof(INT64)) &&
|
|
(iOffset > 0)) {
|
|
|
|
LargeInt.QuadPart = -1 * (iOffset + sizeof(emfi) + sizeof(INT64));
|
|
|
|
if ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
|
|
LargeInt, NULL, FILE_CURRENT, FALSE) &&
|
|
MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfiExt,
|
|
sizeof(emfiExt))) {
|
|
|
|
if (pTmpBuffer = (BYTE*) LOCALALLOC(emfiExt.cjSize)) {
|
|
|
|
if (!MyReadPrinter(pSpoolFileHandle->hSpooler,
|
|
pTmpBuffer, emfiExt.cjSize)) {
|
|
|
|
WARNING("Gdi32: Process Pages error reading font or devmode\n");
|
|
goto exit;
|
|
}
|
|
|
|
dwSize = emfiExt.cjSize;
|
|
|
|
} else {
|
|
|
|
WARNING("Out of memory in ProcessPages\n");
|
|
goto exit;
|
|
}
|
|
|
|
// We will seek back to the correct position after the switch
|
|
} else {
|
|
WARNING("SeekPrinter or MyReadPrinter fail in ProcessPages\n");
|
|
goto exit;
|
|
}
|
|
} else {
|
|
WARNING("MyReadPrinter fails in ProcessPages\n");
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
switch (emfi.ulID)
|
|
{
|
|
case EMRI_METAFILE:
|
|
case EMRI_FORM_METAFILE:
|
|
case EMRI_BW_METAFILE:
|
|
case EMRI_BW_FORM_METAFILE:
|
|
|
|
// it's a metafile so setup an entry for it
|
|
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].pDevmode = pLastDevmode;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].EMFOffset = CurrentOffset;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].SeekOffset = CurrentOffset + emfi.cjSize;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].EMFSize = emfi.cjSize;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].ulID = emfi.ulID;
|
|
pSpoolFileHandle->MaxPageProcessed += 1;
|
|
bLastDevmodeAllocated = FALSE;
|
|
|
|
CurrentPage += 1;
|
|
break;
|
|
|
|
case EMRI_METAFILE_EXT:
|
|
case EMRI_BW_METAFILE_EXT:
|
|
|
|
// it's a metafile at an offset
|
|
|
|
if (emfi.cjSize < sizeof(INT64)) {
|
|
WARNING("Ext Record bad size\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (MyReadPrinter(pSpoolFileHandle->hSpooler, (PBYTE) &iOffset, sizeof(INT64)) &&
|
|
(iOffset > 0)) {
|
|
|
|
LargeInt.QuadPart = -1 * (iOffset + sizeof(emfi) + sizeof(INT64));
|
|
|
|
if ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
|
|
LargeInt, NULL, FILE_CURRENT, FALSE) &&
|
|
MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfiExt,
|
|
sizeof(emfiExt))) {
|
|
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].pDevmode = pLastDevmode;
|
|
bLastDevmodeAllocated = FALSE;
|
|
|
|
EMFOffset = CurrentOffset - (LONGLONG) iOffset;
|
|
if (EMFOffset) {
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].EMFOffset = EMFOffset;
|
|
} else {
|
|
WARNING("Bad Ext Record\n");
|
|
goto exit;
|
|
}
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].SeekOffset =
|
|
CurrentOffset + emfi.cjSize;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].EMFSize = emfiExt.cjSize;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].ulID =
|
|
(emfi.ulID == EMRI_METAFILE_EXT) ? EMRI_METAFILE
|
|
: EMRI_BW_METAFILE;
|
|
pSpoolFileHandle->MaxPageProcessed += 1;
|
|
|
|
CurrentPage += 1;
|
|
break;
|
|
|
|
// We will seek back to the correct position after the switch
|
|
}
|
|
}
|
|
|
|
WARNING("ReadPrinter or SeekPrinter failed\n");
|
|
goto exit;
|
|
|
|
case EMRI_DEVMODE:
|
|
|
|
if (!(*fpIsValidDevmodeW)((LPDEVMODEW) pTmpBuffer, dwSize))
|
|
{
|
|
EMFVALFAIL(("ProcessPages: fpIsValidDevmodeW failed\n"));
|
|
goto exit;
|
|
}
|
|
|
|
pLastDevmode = (LPDEVMODEW) pTmpBuffer;
|
|
pTmpBuffer = NULL;
|
|
bLastDevmodeAllocated = TRUE;
|
|
break;
|
|
|
|
case EMRI_METAFILE_DATA:
|
|
|
|
// Start of EMF data. Wait till EMRI_(BW_)METAFILE_EXT so that fonts can
|
|
// be correctly processed
|
|
break;
|
|
|
|
case EMRI_ENGINE_FONT:
|
|
case EMRI_ENGINE_FONT_EXT:
|
|
case EMRI_TYPE1_FONT:
|
|
case EMRI_TYPE1_FONT_EXT:
|
|
|
|
if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc,
|
|
pTmpBuffer, dwSize , NULL))
|
|
{
|
|
WARNING("Error adding remote font\n");
|
|
goto exit;
|
|
}
|
|
|
|
if ((emfi.ulID == EMRI_TYPE1_FONT) ||
|
|
(emfi.ulID == EMRI_TYPE1_FONT_EXT))
|
|
{
|
|
// force ResetDC so Type1 fonts get loaded
|
|
pSpoolFileHandle->pLastDevmode = NULL;
|
|
}
|
|
|
|
break;
|
|
|
|
case EMRI_SUBSET_FONT:
|
|
case EMRI_SUBSET_FONT_EXT:
|
|
|
|
if (bMergeSubsetFont(pSpoolFileHandle->hdc, pTmpBuffer, dwSize,
|
|
&pvMergeBuf, &ulBytesWritten, FALSE, &ufi)) {
|
|
|
|
if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc, pvMergeBuf,
|
|
ulBytesWritten, &ufi)) {
|
|
WARNING("Error adding subsetted font\n");
|
|
}
|
|
|
|
} else {
|
|
|
|
WARNING("Error merging subsetted fonts\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case EMRI_DELTA_FONT:
|
|
case EMRI_DELTA_FONT_EXT:
|
|
|
|
if (bMergeSubsetFont(pSpoolFileHandle->hdc, pTmpBuffer, dwSize,
|
|
&pvMergeBuf, &ulBytesWritten, TRUE, &ufi)) {
|
|
|
|
if (NtGdiRemoveMergeFont(pSpoolFileHandle->hdc, &ufi)) {
|
|
|
|
if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc, pvMergeBuf,
|
|
ulBytesWritten, &ufi)) {
|
|
|
|
WARNING("Error adding subsetted font\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
WARNING("Error removing merged font\n");
|
|
}
|
|
|
|
} else {
|
|
|
|
WARNING("Error merging subsetted fonts\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case EMRI_DESIGNVECTOR:
|
|
case EMRI_DESIGNVECTOR_EXT:
|
|
|
|
MFD1("Unpackaging designvector \n");
|
|
|
|
if (!NtGdiAddRemoteMMInstanceToDC(pSpoolFileHandle->hdc,
|
|
(DOWNLOADDESIGNVECTOR *) pTmpBuffer,
|
|
dwSize)) {
|
|
|
|
WARNING("Error adding remote mm instance font\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EMRI_EMBED_FONT_EXT:
|
|
|
|
MFD1("Unpackaging embed fonts\n");
|
|
|
|
if (!NtGdiAddEmbFontToDC(pSpoolFileHandle->hdc,(VOID **) pTmpBuffer))
|
|
{
|
|
WARNING("Error adding embed font to DC\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case EMRI_PRESTARTPAGE:
|
|
|
|
if (!(pRecordInfo =
|
|
(PRECORD_INFO_STRUCT) LOCALALLOC(sizeof(RECORD_INFO_STRUCT)))) {
|
|
|
|
WARNING("Out of memory in ProcessPages\n");
|
|
goto exit;
|
|
}
|
|
|
|
pRecordInfo->pNext = pSpoolFileHandle->pPageInfo[CurrentPage].pRecordInfo;
|
|
pSpoolFileHandle->pPageInfo[CurrentPage].pRecordInfo = pRecordInfo;
|
|
|
|
pRecordInfo->RecordID = emfi.ulID;
|
|
pRecordInfo->RecordSize = emfi.cjSize;
|
|
pRecordInfo->RecordOffset = CurrentOffset;
|
|
|
|
break;
|
|
|
|
case EMRI_PS_JOB_DATA:
|
|
|
|
// Already processed at GdiStartDocEMF().
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARNING("GDI32: ProcessPages: Unknown ITEM record\n");
|
|
goto exit;
|
|
break;
|
|
}
|
|
|
|
if (emfi.ulID == EMRI_METAFILE || emfi.ulID == EMRI_FORM_METAFILE)
|
|
{
|
|
ENHMETAHEADER *pemrh = ( ENHMETAHEADER *)&emfi;
|
|
CurrentOffset += pemrh->nBytes - sizeof(emfi);
|
|
}
|
|
else
|
|
{
|
|
CurrentOffset += emfi.cjSize;
|
|
}
|
|
LargeInt.QuadPart = CurrentOffset;
|
|
|
|
if(!bReadPrinter && !(*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
|
|
LargeInt, NULL, 0, FALSE))
|
|
{
|
|
WARNING("GDI32 Process Pages: seekprinter failed\n");
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Release temp buffer each time through the loop.
|
|
//
|
|
if(pTmpBuffer)
|
|
{
|
|
LocalFree(pTmpBuffer);
|
|
pTmpBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
//
|
|
// Release the temp buffer, it is a temp so it should not
|
|
// live beyond this subroutine.
|
|
//
|
|
if(pTmpBuffer)
|
|
{
|
|
LocalFree(pTmpBuffer);
|
|
}
|
|
|
|
//
|
|
// Only release the last devmode pointer if one was allocated.
|
|
//
|
|
if(pLastDevmode && bLastDevmodeAllocated)
|
|
{
|
|
LocalFree(pLastDevmode);
|
|
}
|
|
|
|
return(CurrentPage >= LastPage);
|
|
}
|
|
|
|
HDC WINAPI GdiGetDC(
|
|
HANDLE SpoolFileHandle)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiGetDC returns a handle to the device context of the printer.
|
|
This handle can be used to apply transformations (translation, rotation, scaling etc)
|
|
before playing any page at the printer
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is a valid HANDLE;
|
|
otherwise the result is NULL.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiGetDC: invalid handle\n");
|
|
return(NULL);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiGetDC: exception accessing handle\n");
|
|
return(NULL);
|
|
}
|
|
|
|
return(pSpoolFileHandle->hdc);
|
|
}
|
|
|
|
|
|
DWORD WINAPI GdiGetPageCount(
|
|
HANDLE SpoolFileHandle)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiGetPageCount returns the number of pages in the print job. If print
|
|
while spooling option is used, GdiGetPageCount synchronously waits till
|
|
the job is completely spooled and then returns the page count.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is the page count
|
|
otherwise the result is 0.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
*/
|
|
|
|
{
|
|
UINT Page = 10;
|
|
LARGE_INTEGER LargeInt;
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiGetPageCount: invalid handle\n");
|
|
return 0;
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiGetPageCount: exception accessing handle\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
while(ProcessPages(pSpoolFileHandle, Page))
|
|
{
|
|
Page += 10;
|
|
}
|
|
|
|
LargeInt.QuadPart = 0;
|
|
|
|
if(!(*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,
|
|
FALSE))
|
|
{
|
|
WARNING("GDI32 GdiGetPageCount: seek failed\n");
|
|
return 0;
|
|
}
|
|
|
|
return ((DWORD) pSpoolFileHandle->MaxPageProcessed);
|
|
}
|
|
|
|
|
|
HANDLE WINAPI GdiGetPageHandle(
|
|
HANDLE SpoolFileHandle,
|
|
DWORD Page,
|
|
LPDWORD pdwPageType)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiGetPageHandle returns a handle to contents of the required page.
|
|
This handle should be used while playing the page at the printer. If the
|
|
spool file is not sufficiently large, the last error is set to ERROR_NO_MORE_ITEMS.
|
|
If print while spooling is supported, the print processor will have to examine
|
|
for this error code to determine the end of the print job. Using GdiGetPageCount
|
|
will stall the processing till the entire print job is spooled.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
Page -- number of the page required
|
|
pdwPageType -- pointer to store the type of the page (Normal/Watermark)
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is a valid HANDLE;
|
|
otherwise the result is NULL.
|
|
|
|
History:
|
|
5/12/1995 by Gerrit van Wingerden [gerritv] - Author
|
|
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
|
|
Changed the return value to a HANDLE that contains the page number along
|
|
with the handle to the EMF file
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
PEMF_HANDLE pEMF = NULL;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiGetPageHandle: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiGetPageHandle: exception accessing handle\n");
|
|
return(NULL);
|
|
}
|
|
|
|
if(!ProcessPages(pSpoolFileHandle, (UINT) Page))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if (pEMF = (PEMF_HANDLE) LOCALALLOC(sizeof(EMF_HANDLE))) {
|
|
|
|
pEMF->tag = EMF_HANDLE_TAG;
|
|
pEMF->hemf = NULL;
|
|
pEMF->bAllocBuffer = FALSE;
|
|
pEMF->dwPageNumber = Page;
|
|
|
|
if (pdwPageType) {
|
|
switch (pSpoolFileHandle->pPageInfo[Page-1].ulID) {
|
|
|
|
case EMRI_METAFILE:
|
|
case EMRI_BW_METAFILE:
|
|
|
|
*pdwPageType = EMF_PP_NORMAL;
|
|
break;
|
|
|
|
case EMRI_FORM_METAFILE:
|
|
case EMRI_BW_FORM_METAFILE:
|
|
|
|
*pdwPageType = EMF_PP_FORM;
|
|
break;
|
|
|
|
default:
|
|
// should not occur
|
|
*pdwPageType = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Save the handle in spoolfilehandle to be freed later
|
|
pEMF->pNext = pSpoolFileHandle->pEMFHandle;
|
|
pSpoolFileHandle->pEMFHandle = pEMF;
|
|
|
|
} else {
|
|
WARNING("GDI32 GdiGetPageHandle: out of memory\n");
|
|
}
|
|
|
|
return ((HANDLE) pEMF);
|
|
}
|
|
|
|
BOOL WINAPI GdiStartDocEMF(
|
|
HANDLE SpoolFileHandle,
|
|
DOCINFOW *pDocInfo)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiStartDocEMF performs the initializations required for before printing
|
|
a document. It calls StartDoc and allocates memory to store data about the
|
|
page layout. It also sets up the banding field in the SpoolFileHandle.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
pDocInfo -- pointer to DOCINFOW struct containing information of
|
|
the job. This struct is required for StartDoc.
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiStartDocEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiStartDocEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Process Job data (before StartDoc)
|
|
if (!ProcessJob(pSpoolFileHandle))
|
|
{
|
|
WARNING("StartDocW failed at ProcessJob\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// StartDoc and get banding information
|
|
if (StartDocEMF(pSpoolFileHandle->hdc,
|
|
pDocInfo,
|
|
&(pSpoolFileHandle->bBanding)) == SP_ERROR) {
|
|
WARNING("StartDocW failed at StartDocEMF\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pSpoolFileHandle->dwNumberOfPagesInCurrSide = 0;
|
|
pSpoolFileHandle->dwNumberOfPagesAllocated = SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE;
|
|
|
|
// Allocate memory for page layout
|
|
if (!(pSpoolFileHandle->pPageLayout = LOCALALLOC(sizeof(PAGE_LAYOUT_STRUCT) *
|
|
pSpoolFileHandle->dwNumberOfPagesAllocated))) {
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
WARNING("GDI32 GdiStartDocEMF: out of memory\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL WINAPI GdiStartPageEMF(
|
|
HANDLE SpoolFileHandle)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiStartPageEMF performs the initializations required before printing
|
|
a page.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiStartPageEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiStartPageEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL WINAPI GdiPlayPageEMF(
|
|
HANDLE SpoolFileHandle,
|
|
HANDLE hEMF,
|
|
RECT *prectDocument,
|
|
RECT *prectBorder,
|
|
RECT *prectClip)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiPlayPageEMF allows the print processor to play any EMF page inside a
|
|
specified rectangle. It also draws a border around the page, if one is specified.
|
|
GdiPlayPageEMF saves all the information required for playing the page in the
|
|
SpoolFileHandle. When GdiEndPageEMF is called to eject the current physical page,
|
|
all the logical pages are played in the correct positions and the page is ejected.
|
|
This delayed printing operation is used to enable n-up printing with banding.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
hEMF -- handle returned by GdiGetEMFFromSpoolHandle
|
|
prectDocument -- pointer to the RECT containing coordinates where
|
|
the page is to be played
|
|
prectBorder -- pointer to the RECT containing coordinates where
|
|
the border (if any) is to be drawn
|
|
prectClip -- pointer to the RECT containing coordinates where
|
|
the page is to clipped
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
PAGE_LAYOUT_STRUCT *pPageLayout;
|
|
PEMF_HANDLE pEMF;
|
|
LPBYTE pBuffer = NULL;
|
|
HANDLE hFile = NULL;
|
|
BOOL bAllocBuffer = FALSE;
|
|
ULONG Size;
|
|
LARGE_INTEGER Offset;
|
|
HENHMETAFILE hEMFPage = NULL;
|
|
DWORD dwPageNumber;
|
|
|
|
pEMF = (PEMF_HANDLE) hEMF;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if ((pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG) ||
|
|
(pEMF->tag != EMF_HANDLE_TAG))
|
|
{
|
|
WARNING("GdiPlayPageEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiPlayPageEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
dwPageNumber = pEMF->dwPageNumber;
|
|
|
|
if (pEMF->hemf == NULL) {
|
|
|
|
// Allocate the EMF handle
|
|
Size = pSpoolFileHandle->pPageInfo[dwPageNumber-1].EMFSize;
|
|
Offset.QuadPart = pSpoolFileHandle->pPageInfo[dwPageNumber-1].EMFOffset;
|
|
|
|
// Use memory mapped read first and buffered next
|
|
if (pSpoolFileHandle->bUseMemMap) {
|
|
|
|
if ((*fpSeekPrinter) (pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE) &&
|
|
MemMapReadPrinter(pSpoolFileHandle->hSpooler, &pBuffer, Size)) {
|
|
|
|
hEMFPage = SetEnhMetaFileBitsAlt((HLOCAL)pBuffer, NULL, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed to get memory map pointer to EMF\n");
|
|
}
|
|
}
|
|
|
|
#define kTempSpoolFileThreshold 0x100000
|
|
#define kScratchBufferSize 0x10000
|
|
|
|
if (hEMFPage == NULL && Size > kTempSpoolFileThreshold) {
|
|
|
|
// if larger then a meg, attempt create a temporary spool file
|
|
// and copy the page to the spool file
|
|
|
|
WARNING("GdiPlayPageEMF() Page size is large using temporary spool file\n");
|
|
|
|
// If memory mapped read didnt work, dont try it again
|
|
|
|
pSpoolFileHandle->bUseMemMap = FALSE;
|
|
|
|
hFile = CreateTempSpoolFile();
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if(fpSeekPrinter(pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE))
|
|
{
|
|
PVOID pvScratch = LocalAlloc(LMEM_FIXED, kScratchBufferSize);
|
|
|
|
if(pvScratch)
|
|
{
|
|
ULONG dwOffset = 0;
|
|
|
|
while(dwOffset < Size)
|
|
{
|
|
ULONG dwSize = MIN(kScratchBufferSize, (Size - dwOffset));
|
|
ULONG dwBytesWritten;
|
|
|
|
if(!MyReadPrinter(pSpoolFileHandle->hSpooler, pvScratch, dwSize))
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed reading from spooler\n");
|
|
break;
|
|
}
|
|
|
|
if(!WriteFile(hFile, pvScratch, dwSize, &dwBytesWritten, NULL))
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed writing to temp spool file\n");
|
|
break;
|
|
}
|
|
|
|
if(dwBytesWritten != dwSize)
|
|
{
|
|
WARNING("GdiPlayPageEMF() Unexpected mismatch between attempted write size and actual\n");
|
|
break;
|
|
}
|
|
|
|
dwOffset += dwBytesWritten;
|
|
}
|
|
|
|
if(dwOffset == Size)
|
|
{
|
|
hEMFPage = SetEnhMetaFileBitsAlt(NULL, NULL, hFile, 0);
|
|
|
|
if(!hEMFPage)
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed creating EMF handle\n");
|
|
}
|
|
}
|
|
|
|
LocalFree(pvScratch);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed creating scratch buffer\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed seeking spooler\n");
|
|
}
|
|
|
|
pBuffer = NULL;
|
|
bAllocBuffer = TRUE;
|
|
|
|
if (hEMFPage == NULL)
|
|
{
|
|
if (!CloseHandle(hFile))
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed closing temp spool file handle\n");
|
|
}
|
|
else
|
|
{
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hEMFPage == NULL) {
|
|
// If memory mapped read didnt work, dont try it again
|
|
|
|
pSpoolFileHandle->bUseMemMap = FALSE;
|
|
|
|
if ((pBuffer = (BYTE*) LocalAlloc(LMEM_FIXED, Size)) &&
|
|
(*fpSeekPrinter)(pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE) &&
|
|
MyReadPrinter(pSpoolFileHandle->hSpooler, pBuffer, Size)) {
|
|
|
|
hEMFPage = SetEnhMetaFileBitsAlt((HLOCAL)pBuffer, NULL, NULL, 0);
|
|
}
|
|
|
|
bAllocBuffer = TRUE;
|
|
}
|
|
|
|
// Check if the handle was created
|
|
if (hEMFPage == NULL) {
|
|
|
|
// Free resources and quit
|
|
if (pBuffer && bAllocBuffer) {
|
|
LocalFree(pBuffer);
|
|
}
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if(!CloseHandle(hFile))
|
|
{
|
|
WARNING("GdiPlayPageEMF() Failed closing temp spool file handle\n");
|
|
}
|
|
}
|
|
|
|
WARNING("GdiPlayPageEMF: Failed to Create EMF Handle\n");
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
// Save hEMFPage in pEMF struct for future calls to GdiPlayPageEMF
|
|
pEMF->hemf = hEMFPage;
|
|
pEMF->bAllocBuffer = bAllocBuffer;
|
|
}
|
|
}
|
|
|
|
if (pSpoolFileHandle->dwNumberOfPagesInCurrSide >=
|
|
pSpoolFileHandle->dwNumberOfPagesAllocated) {
|
|
|
|
PAGE_LAYOUT_STRUCT *pTemp;
|
|
|
|
if (pTemp = LOCALALLOC(sizeof(PAGE_LAYOUT_STRUCT) *
|
|
(pSpoolFileHandle->dwNumberOfPagesAllocated +
|
|
SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE))) {
|
|
|
|
memcpy(pTemp,
|
|
pSpoolFileHandle->pPageLayout,
|
|
sizeof(PAGE_LAYOUT_STRUCT) * pSpoolFileHandle->dwNumberOfPagesAllocated);
|
|
LocalFree(pSpoolFileHandle->pPageLayout);
|
|
pSpoolFileHandle->pPageLayout = pTemp;
|
|
pSpoolFileHandle->dwNumberOfPagesAllocated += SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE;
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
WARNING("GdiPlayPageEMF: out of memory\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// update the fields
|
|
pPageLayout = &(pSpoolFileHandle->pPageLayout[pSpoolFileHandle->dwNumberOfPagesInCurrSide]);
|
|
pPageLayout->hemf = pEMF->hemf;
|
|
pPageLayout->bAllocBuffer = pEMF->bAllocBuffer;
|
|
pPageLayout->dwPageNumber = pEMF->dwPageNumber;
|
|
|
|
pPageLayout->rectDocument.top = prectDocument->top;
|
|
pPageLayout->rectDocument.bottom = prectDocument->bottom;
|
|
pPageLayout->rectDocument.left = prectDocument->left;
|
|
pPageLayout->rectDocument.right = prectDocument->right;
|
|
|
|
// Set the border
|
|
if (prectBorder) {
|
|
pPageLayout->rectBorder.top = prectBorder->top;
|
|
pPageLayout->rectBorder.bottom = prectBorder->bottom;
|
|
pPageLayout->rectBorder.left = prectBorder->left;
|
|
pPageLayout->rectBorder.right = prectBorder->right;
|
|
} else {
|
|
pPageLayout->rectBorder.top = -1; //invalid coordinates
|
|
pPageLayout->rectBorder.bottom = -1; //invalid coordinates
|
|
pPageLayout->rectBorder.left = -1; //invalid coordinates
|
|
pPageLayout->rectBorder.right = -1; //invalid coordinates
|
|
}
|
|
|
|
// Set the clipping rectangle
|
|
if (prectClip) {
|
|
pPageLayout->rectClip.top = prectClip->top;
|
|
pPageLayout->rectClip.bottom = prectClip->bottom;
|
|
pPageLayout->rectClip.left = prectClip->left;
|
|
pPageLayout->rectClip.right = prectClip->right;
|
|
} else {
|
|
pPageLayout->rectClip.top = -1; //invalid coordinates
|
|
pPageLayout->rectClip.bottom = -1; //invalid coordinates
|
|
pPageLayout->rectClip.left = -1; //invalid coordinates
|
|
pPageLayout->rectClip.right = -1; //invalid coordinates
|
|
}
|
|
|
|
// Save the current transformation at the DC
|
|
if (!GetWorldTransform(pSpoolFileHandle->hdc, &(pPageLayout->XFormDC))) {
|
|
WARNING("GdiPlayPageEMF: GetWorldTransform failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// increment the number of pages
|
|
pSpoolFileHandle->dwNumberOfPagesInCurrSide += 1;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL WINAPI GdiPlayPrivatePageEMF(
|
|
HANDLE SpoolFileHandle,
|
|
HENHMETAFILE hEnhMetaFile,
|
|
RECT *prectDocument)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiPlayPrivatePageEMF allows the print processor to play EMF pages other than the
|
|
ones present in the spool file (like watermarks) inside a specified rectangle.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
hEnhMetaFile -- handle to an EMF which is to be played on the current physical
|
|
page
|
|
prectDocument -- pointer to the RECT containing coordinates where
|
|
the page is to be played
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
6/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
EMF_HANDLE hRecord;
|
|
|
|
hRecord.tag = EMF_HANDLE_TAG;
|
|
hRecord.hemf = hEnhMetaFile;
|
|
hRecord.dwPageNumber = 0; // Invalid value
|
|
hRecord.bAllocBuffer = FALSE;
|
|
|
|
return GdiPlayPageEMF(SpoolFileHandle,
|
|
(HANDLE) &hRecord,
|
|
prectDocument,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
BOOL InternalProcessEMFRecord(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle,
|
|
DWORD dwPageNumber)
|
|
|
|
/*
|
|
Function Description:
|
|
InternalProcessEMFRecord processes any EMF records that appear before the given
|
|
EMF page which should be processed immediately before playing the page.
|
|
|
|
Parameters:
|
|
pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE struct for the job.
|
|
dwPageNumber -- number of the page being played
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
PRECORD_INFO_STRUCT pRecordInfo;
|
|
BYTE *pTmpBuffer = NULL;
|
|
LARGE_INTEGER liOffset;
|
|
BOOL bReturn = FALSE;
|
|
PEMFITEMPRESTARTPAGE pemfiPre;
|
|
|
|
|
|
pRecordInfo = pSpoolFileHandle->pPageInfo[dwPageNumber-1].pRecordInfo;
|
|
|
|
// loop thru all the records seen before the page
|
|
while (pRecordInfo) {
|
|
|
|
liOffset.QuadPart = pRecordInfo->RecordOffset;
|
|
|
|
if (pTmpBuffer = (BYTE*) LOCALALLOC(pRecordInfo->RecordSize)) {
|
|
|
|
if (!(*fpSeekPrinter) (pSpoolFileHandle->hSpooler,
|
|
liOffset,
|
|
NULL,
|
|
FILE_BEGIN,
|
|
FALSE) ||
|
|
!MyReadPrinter(pSpoolFileHandle->hSpooler,
|
|
pTmpBuffer,
|
|
pRecordInfo->RecordSize)) {
|
|
|
|
WARNING("Gdi32: error reading record\n");
|
|
goto exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
WARNING("Out of memory in InternalProcessEMFRecord\n");
|
|
goto exit;
|
|
}
|
|
|
|
switch (pRecordInfo->RecordID) {
|
|
|
|
case EMRI_PRESTARTPAGE:
|
|
|
|
MFD1("pre start page commands\n");
|
|
|
|
pemfiPre = (PEMFITEMPRESTARTPAGE) pTmpBuffer;
|
|
|
|
if (pemfiPre->bEPS & 1) {
|
|
|
|
SHORT b = 1;
|
|
|
|
MFD1("MFP_StartDocW calling bEpsPrinting\n");
|
|
ExtEscape(pSpoolFileHandle->hdc, EPSPRINTING, sizeof(b),
|
|
(LPCSTR) &b, 0 , NULL );
|
|
}
|
|
|
|
break;
|
|
|
|
// add cases for new records that must be processed before the page is played
|
|
|
|
default:
|
|
|
|
WARNING("unknown ITEM record\n");
|
|
break;
|
|
}
|
|
|
|
LocalFree(pTmpBuffer);
|
|
pTmpBuffer = NULL;
|
|
pRecordInfo = pRecordInfo->pNext;
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
exit:
|
|
|
|
if (pTmpBuffer) {
|
|
LocalFree(pTmpBuffer);
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL InternalGdiPlayPageEMF(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle,
|
|
PAGE_LAYOUT_STRUCT *pPageLayout,
|
|
POINTL *pptlOrigin,
|
|
SIZE *pszSurface,
|
|
BOOL bBanding)
|
|
|
|
/*
|
|
Function Description:
|
|
InternalGdiPlayPageEMF plays the EMF file on the page and draws borders, if
|
|
specified. It also performs initialization for GL records that may present in
|
|
EMF file.
|
|
|
|
Parameters:
|
|
pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE struct for the job
|
|
pPageLayout -- pointer to PAGE_LAYOUT_STRUCT which contains information
|
|
about playing the page
|
|
pptlOrigin -- pointer to a POINTL structure used for banding
|
|
pszSurface -- pointer to a SIZE structure used for banding
|
|
bBanding -- flag to indicate if banding is being used
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
|
|
*/
|
|
|
|
{
|
|
BOOL bPrintGl, bReturn = FALSE;
|
|
XFORM OldXForm;
|
|
POINTL ptlOrigin;
|
|
SIZE szSurface;
|
|
GLPRINTSTATE gps;
|
|
HDC hPrinterDC = pSpoolFileHandle->hdc;
|
|
RECT *rectBorder = &(pPageLayout->rectBorder);
|
|
RECT *rectClip = &(pPageLayout->rectClip);
|
|
RECT *rectBand = NULL;
|
|
HRGN hClipRgn = NULL;
|
|
INT indexDC = 0;
|
|
|
|
if (bBanding) {
|
|
// New structs created so that each page is played for the same band
|
|
ptlOrigin.x = pptlOrigin->x;
|
|
ptlOrigin.y = pptlOrigin->y;
|
|
szSurface.cx = pszSurface->cx;
|
|
szSurface.cy = pszSurface->cy;
|
|
|
|
// Print only on the correct band
|
|
SetViewportOrgEx(hPrinterDC, -ptlOrigin.x, -ptlOrigin.y, NULL);
|
|
}
|
|
|
|
// Process any PRESTARTPAGE records that appear immediately before this page
|
|
if (pPageLayout->dwPageNumber > 0) {
|
|
InternalProcessEMFRecord(pSpoolFileHandle, pPageLayout->dwPageNumber);
|
|
}
|
|
|
|
// Draw Page borders (if any)
|
|
if (!((rectBorder->top == -1) &&
|
|
(rectBorder->bottom == -1) &&
|
|
(rectBorder->right == -1) &&
|
|
(rectBorder->left == -1)) &&
|
|
ModifyWorldTransform(hPrinterDC, NULL, MWT_IDENTITY)) {
|
|
HRGN hBandRgn = NULL;
|
|
if (bBanding && !IsMetafileWithGl(pPageLayout->hemf))
|
|
{
|
|
ULONG ulRet,ulXRes,ulYRes;
|
|
PERBANDINFO pbi;
|
|
RECT *prect = &(pPageLayout->rectDocument);
|
|
ulXRes = (ULONG) prect->right - prect->left;
|
|
ulYRes = (ULONG) prect->bottom - prect->top;
|
|
|
|
pbi.bRepeatThisBand = FALSE;
|
|
pbi.ulHorzRes = ulXRes;
|
|
pbi.ulVertRes = ulYRes;
|
|
pbi.szlBand.cx = szSurface.cx;
|
|
pbi.szlBand.cy = szSurface.cy;
|
|
|
|
ulRet = NtGdiGetPerBandInfo(hPrinterDC,&pbi);
|
|
|
|
if (ulRet && ulRet != GDI_ERROR &&
|
|
pbi.ulHorzRes == ulXRes && pbi.ulVertRes == ulYRes)
|
|
{
|
|
hBandRgn = CreateRectRgn(0,0,pbi.szlBand.cx,pbi.szlBand.cy);
|
|
if (hBandRgn)
|
|
SelectClipRgn(hPrinterDC, hBandRgn);
|
|
}
|
|
}
|
|
|
|
MoveToEx(hPrinterDC, rectBorder->left, rectBorder->top, NULL);
|
|
LineTo(hPrinterDC, rectBorder->right, rectBorder->top);
|
|
MoveToEx(hPrinterDC, rectBorder->right, rectBorder->top, NULL);
|
|
LineTo(hPrinterDC, rectBorder->right, rectBorder->bottom);
|
|
MoveToEx(hPrinterDC, rectBorder->right, rectBorder->bottom, NULL);
|
|
LineTo(hPrinterDC, rectBorder->left, rectBorder->bottom);
|
|
MoveToEx(hPrinterDC, rectBorder->left, rectBorder->bottom, NULL);
|
|
LineTo(hPrinterDC, rectBorder->left, rectBorder->top);
|
|
if (hBandRgn)
|
|
{
|
|
SelectClipRgn(hPrinterDC,NULL);
|
|
DeleteObject(hBandRgn);
|
|
}
|
|
}
|
|
|
|
// Save the old transformation
|
|
if (!GetWorldTransform(hPrinterDC, &OldXForm)) {
|
|
WARNING("InternalGdiPlayEMFPage: GetWorldTransform failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Set the new transformation
|
|
if (!SetWorldTransform(hPrinterDC, &(pPageLayout->XFormDC))) {
|
|
WARNING("InternalGdiPlayEMFPage: SetWorldTransform failed\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (!((rectClip->top == -1) &&
|
|
(rectClip->bottom == -1) &&
|
|
(rectClip->right == -1) &&
|
|
(rectClip->left == -1))) {
|
|
|
|
rectBand = rectClip;
|
|
|
|
if (!bBanding) {
|
|
|
|
// Set the clipping rectangle
|
|
hClipRgn = CreateRectRgn(rectClip->left, rectClip->top,
|
|
rectClip->right, rectClip->bottom);
|
|
|
|
indexDC = SaveDC(hPrinterDC);
|
|
|
|
if (!hClipRgn || !indexDC ||
|
|
(SelectClipRgn(hPrinterDC, hClipRgn) == ERROR)) {
|
|
|
|
WARNING("InternalGdiPlayEMFPage: SelectClipRgn failed\n");
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Perform GL initialization if necessary
|
|
bPrintGl = IsMetafileWithGl(pPageLayout->hemf);
|
|
if (bPrintGl) {
|
|
if (!InitGlPrinting(pPageLayout->hemf,
|
|
hPrinterDC,
|
|
&(pPageLayout->rectDocument),
|
|
pSpoolFileHandle->pLastDevmode,
|
|
&gps)) {
|
|
|
|
WARNING("InternalGdiPlayEMFPage: InitGlPrinting failed\n");
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
if (bBanding) {
|
|
// call printing functions for banding case
|
|
if (bPrintGl) {
|
|
|
|
SetViewportOrgEx(hPrinterDC, -ptlOrigin.x, -ptlOrigin.y, NULL);
|
|
PrintMfWithGl(pPageLayout->hemf, &gps, &ptlOrigin, &szSurface);
|
|
EndGlPrinting(&gps);
|
|
|
|
} else {
|
|
|
|
|
|
PrintBand( hPrinterDC,
|
|
pPageLayout->hemf,
|
|
&ptlOrigin,
|
|
&(pPageLayout->rectDocument),
|
|
&szSurface,
|
|
rectBand );
|
|
}
|
|
|
|
} else {
|
|
|
|
// call priting functions for non-banding case
|
|
if (bPrintGl) {
|
|
PrintMfWithGl(pPageLayout->hemf, &gps, NULL, NULL);
|
|
EndGlPrinting(&gps);
|
|
} else {
|
|
PlayEnhMetaFile( hPrinterDC, pPageLayout->hemf, &(pPageLayout->rectDocument) );
|
|
}
|
|
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CleanUp:
|
|
|
|
// Restore the old clipping region
|
|
if (indexDC) {
|
|
RestoreDC(hPrinterDC, indexDC);
|
|
}
|
|
|
|
// Reset the world transformation
|
|
if (!SetWorldTransform(hPrinterDC, &OldXForm)) {
|
|
WARNING("InternalGdiPlayEMFPage: SetWorldTransform failed\n");
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// Delete the clipping region
|
|
if (hClipRgn) {
|
|
DeleteObject(hClipRgn);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL AddTempNode(
|
|
PEMF_LIST *ppHead,
|
|
HENHMETAFILE hemf,
|
|
BOOL bAllocBuffer)
|
|
|
|
/*
|
|
Function Description:
|
|
AddTempNode adds a EMF handle to a list that does not contain duplicates.
|
|
This list is used for deleting the handles later.
|
|
|
|
Parameters:
|
|
ppHead - pointer to the start of the list
|
|
hemf - handle to EMF to be added to the list
|
|
bAllocBuffer - flag indicating if buffer was allocated for hemf
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
7/7/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
PEMF_LIST pTemp;
|
|
|
|
for (pTemp = *ppHead; pTemp; ppHead = &(pTemp->pNext), pTemp = *ppHead) {
|
|
if (pTemp->hemf == hemf) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(pTemp = (PEMF_LIST) LOCALALLOC(sizeof(EMF_LIST)))) {
|
|
return FALSE;
|
|
}
|
|
|
|
pTemp->hemf = hemf;
|
|
pTemp->bAllocBuffer = bAllocBuffer;
|
|
pTemp->pNext = NULL;
|
|
*ppHead = pTemp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID RemoveFromSpoolFileHandle(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle,
|
|
HENHMETAFILE hemf)
|
|
|
|
/*
|
|
Function Description:
|
|
The EMF handles that are played get deleted at the end of the page (GdiEndPageEMF).
|
|
The rest of the handles are deleted in the cleanup routine (GdiDeleteSpoolFileHandle).
|
|
These are handles are listed in pSpoolFileHandle->pEMFHandle. RemoveFromSpoolFileHandle
|
|
removes deleted handles from this list, to avoid freeing the handles twice.
|
|
|
|
Parameters:
|
|
pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE
|
|
hemf -- Handle to EMF that is going to be deleted
|
|
|
|
Return Values:
|
|
NONE
|
|
|
|
History:
|
|
9/18/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
{
|
|
PEMF_HANDLE pTemp;
|
|
|
|
for (pTemp = pSpoolFileHandle->pEMFHandle; pTemp; pTemp = pTemp->pNext) {
|
|
if (pTemp->hemf == hemf) {
|
|
pTemp->hemf = NULL;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL SetColorOptimization(
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle,
|
|
DWORD dwOptimization)
|
|
|
|
/*
|
|
Function Description:
|
|
SetColorOptimization examines the page types on the next physical page and
|
|
sets the device context to take advantage of monochrome pages.
|
|
|
|
Parameters:
|
|
pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE
|
|
dwOptimization -- flag indicating optimizations to be performed
|
|
|
|
Return Values:
|
|
TRUE if successful; FALSE otherwise
|
|
|
|
History:
|
|
9/23/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
BOOL bReturn = TRUE, bFoundColor = FALSE, bReset;
|
|
short dmColor;
|
|
DWORD dmFields, dwIndex, dwPageNumber, dwRecordID;
|
|
PAGE_LAYOUT_STRUCT *pPageLayout;
|
|
|
|
// Dont process for monochrome detection if the optimization is not
|
|
// applied
|
|
if (!(dwOptimization & EMF_PP_COLOR_OPTIMIZATION)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// Search for color in the pages on the current physical page
|
|
for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
|
|
dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
|
|
++dwIndex, ++pPageLayout)
|
|
{
|
|
dwPageNumber = pPageLayout->dwPageNumber;
|
|
dwRecordID = pSpoolFileHandle->pPageInfo[dwPageNumber-1].ulID;
|
|
|
|
if ((dwRecordID == EMRI_METAFILE) ||
|
|
(dwRecordID == EMRI_FORM_METAFILE)) {
|
|
|
|
bFoundColor = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Determine if the status has to changed
|
|
bReset = (bFoundColor && (pSpoolFileHandle->dwPlayBackStatus == EMF_PLAY_MONOCHROME)) ||
|
|
(!bFoundColor && (pSpoolFileHandle->dwPlayBackStatus == EMF_PLAY_COLOR));
|
|
|
|
if (bReset) {
|
|
// Save the old settings
|
|
dmFields = pSpoolFileHandle->pLastDevmode->dmFields;
|
|
dmColor = pSpoolFileHandle->pLastDevmode->dmColor;
|
|
|
|
pSpoolFileHandle->pLastDevmode->dmFields |= DM_COLOR;
|
|
pSpoolFileHandle->pLastDevmode->dmColor = bFoundColor ? DMCOLOR_COLOR
|
|
: DMCOLOR_MONOCHROME;
|
|
|
|
// Reset the DC and set graphics mode
|
|
bReturn = ResetDCWInternal(pSpoolFileHandle->hdc,
|
|
pSpoolFileHandle->pLastDevmode,
|
|
&(pSpoolFileHandle->bBanding)) &&
|
|
SetGraphicsMode(pSpoolFileHandle->hdc, GM_ADVANCED);
|
|
|
|
// Restore old settings and update status
|
|
pSpoolFileHandle->pLastDevmode->dmFields = dmFields;
|
|
pSpoolFileHandle->pLastDevmode->dmColor = dmColor;
|
|
pSpoolFileHandle->dwPlayBackStatus = bFoundColor ? EMF_PLAY_COLOR
|
|
: EMF_PLAY_MONOCHROME;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL WINAPI GdiEndPageEMF(
|
|
HANDLE SpoolFileHandle,
|
|
DWORD dwOptimization)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiEndPageEMF completes printing on the current page and ejects it. It
|
|
loops thru the different bands while printing the page. GdiEndPageEMF also
|
|
frees up the buffers allocated for the emf handle.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
dwOptimization -- flag color optimizations. To be extended for copies
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
DWORD dwIndex;
|
|
PAGE_LAYOUT_STRUCT *pPageLayout;
|
|
BOOL bReturn = FALSE;
|
|
PEMF_LIST pTemp, pHead = NULL;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiEndPageEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiEndPageEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!SetColorOptimization(pSpoolFileHandle, dwOptimization)) {
|
|
WARNING("GdiEndPageEMF: Color optimizations failed\n");
|
|
}
|
|
|
|
if (!StartPage(pSpoolFileHandle->hdc)) {
|
|
WARNING("GdiEndPageEMF: StartPage failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pSpoolFileHandle->bBanding) {
|
|
|
|
// for opengl optimization
|
|
POINTL ptlOrigin;
|
|
SIZE szSurface;
|
|
|
|
// initialize for banding
|
|
if (!StartBanding( pSpoolFileHandle->hdc, &ptlOrigin, &szSurface )) {
|
|
goto CleanUp;
|
|
}
|
|
|
|
// loop till all the bands are printed
|
|
do {
|
|
for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
|
|
dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
|
|
++dwIndex, ++pPageLayout) {
|
|
|
|
if (!InternalGdiPlayPageEMF(pSpoolFileHandle,
|
|
pPageLayout,
|
|
&ptlOrigin,
|
|
&szSurface,
|
|
TRUE)) {
|
|
WARNING("GdiEndPageEMF: InternalGdiPlayEMFPage failed");
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
if (!NextBand(pSpoolFileHandle->hdc, &ptlOrigin)) {
|
|
WARNING("GdiEndPageEMF: NextBand failed\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
} while (ptlOrigin.x != -1);
|
|
|
|
} else {
|
|
for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
|
|
dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
|
|
++dwIndex, ++pPageLayout) {
|
|
|
|
if (!InternalGdiPlayPageEMF(pSpoolFileHandle,
|
|
pPageLayout,
|
|
NULL,
|
|
NULL,
|
|
FALSE)) {
|
|
WARNING("GdiEndPageEMF: InternalGdiPlayEMFPage failed");
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CleanUp:
|
|
|
|
// eject the current page
|
|
if (!EndPage(pSpoolFileHandle->hdc)) {
|
|
WARNING("GdiEndPageEMF: EndPage failed\n");
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
// free the emf handles
|
|
for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
|
|
dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
|
|
++dwIndex, ++pPageLayout) {
|
|
|
|
AddTempNode(&pHead, pPageLayout->hemf, pPageLayout->bAllocBuffer);
|
|
}
|
|
|
|
while (pTemp = pHead) {
|
|
pHead = pHead->pNext;
|
|
RemoveFromSpoolFileHandle(pSpoolFileHandle, pTemp->hemf);
|
|
InternalDeleteEnhMetaFile(pTemp->hemf, pTemp->bAllocBuffer);
|
|
LocalFree(pTemp);
|
|
}
|
|
|
|
// reset the number of logical pages for the next physical page
|
|
pSpoolFileHandle->dwNumberOfPagesInCurrSide = 0;
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL WINAPI GdiEndDocEMF(
|
|
HANDLE SpoolFileHandle)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiEndDocEMF completes printing the current document. GdiEndPageEMF is called
|
|
if the last physical page was not ejected. Some of the resources associated with
|
|
printing of the document are released.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiEndDocEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiEndDocEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// call GdiEndPageEMF if the last physical page was not ejected
|
|
if (pSpoolFileHandle->dwNumberOfPagesInCurrSide) {
|
|
GdiEndPageEMF(SpoolFileHandle,0);
|
|
}
|
|
|
|
EndDoc(pSpoolFileHandle->hdc);
|
|
|
|
// free the memory used for saving the page layouts
|
|
LOCALFREE(pSpoolFileHandle->pPageLayout);
|
|
pSpoolFileHandle->pPageLayout = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI GdiGetDevmodeForPage(
|
|
HANDLE SpoolFileHandle,
|
|
DWORD dwPageNumber,
|
|
PDEVMODEW *pCurrDM,
|
|
PDEVMODEW *pLastDM)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiGetDevmodeForPage allows the print processor to retrieve the last devmode
|
|
set at the printer device context and the last devmode that appears before
|
|
any given page. If the 2 devmodes are different the print processor has to
|
|
call GdiResetDCEMF with the current devmode. However since ResetDC can be called
|
|
only at page boundaries, the print processor must end printing on the current
|
|
page before calling GdiResetDCEMF. GdiEndPageEMF allows the print processor to
|
|
complete printing on the current physical page.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
dwPageNumber -- page number for which the devmode is sought
|
|
*pCurrDM -- buffer to store the pointer to the devmode for the page
|
|
*pLastDM -- buffer to store the pointer to the last devmode used in
|
|
ResetDC
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiGetDevmodeForPage: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiGetDevmodeForPage: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// process the spool file till the required page is found
|
|
if(!ProcessPages(pSpoolFileHandle, (UINT)dwPageNumber))
|
|
{
|
|
WARNING("GdiGetDevmodeForPage: ProcessPages failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// return the pointers in the buffers
|
|
if (pCurrDM) {
|
|
*pCurrDM = pSpoolFileHandle->pPageInfo[dwPageNumber-1].pDevmode;
|
|
}
|
|
if (pLastDM) {
|
|
*pLastDM = pSpoolFileHandle->pLastDevmode;
|
|
}
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL WINAPI GdiResetDCEMF(
|
|
HANDLE SpoolFileHandle,
|
|
PDEVMODEW pCurrDM)
|
|
|
|
/*
|
|
Function Description:
|
|
GdiResetDCEMF should be use to reset the printer device context with a new
|
|
devmode. The memory for the devmode will be released by GDI.
|
|
|
|
Parameters:
|
|
SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
|
|
pCurrDM -- pointer to the devmode that was used in the last ResetDC
|
|
call by the print processor
|
|
|
|
Return Values:
|
|
If the function succeeds, the return value is TRUE;
|
|
otherwise the result is FALSE.
|
|
|
|
History:
|
|
5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
|
|
*/
|
|
|
|
{
|
|
SPOOL_FILE_HANDLE *pSpoolFileHandle;
|
|
BOOL bReturn;
|
|
|
|
pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
|
|
|
|
// first check to see if this is a valid handle by checking for the tag
|
|
try
|
|
{
|
|
if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
|
|
{
|
|
WARNING("GdiResetDCEMF: invalid handle\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GdiResetDCEMF: exception accessing handle\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pCurrDM &&
|
|
ResetDCWInternal(pSpoolFileHandle->hdc,
|
|
pCurrDM,
|
|
&(pSpoolFileHandle->bBanding)))
|
|
{
|
|
// set the last devmode in the SpoolFileHandle
|
|
pSpoolFileHandle->pLastDevmode = pCurrDM;
|
|
bReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
if (pCurrDM && (pCurrDM->dmFields & DM_COLOR)) {
|
|
|
|
if (pCurrDM->dmColor == DMCOLOR_COLOR) {
|
|
pSpoolFileHandle->dwPlayBackStatus = EMF_PLAY_COLOR;
|
|
} else {
|
|
pSpoolFileHandle->dwPlayBackStatus = EMF_PLAY_FORCE_MONOCHROME;
|
|
}
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|