diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 6a5bb86d4f1..459d0dfb8c1 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2216,6 +2216,7 @@ BOOL WINAPI CancelDC(HDC hdc) */ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) { + DOC_INFO_1W spool_info; WCHAR *output = NULL; struct print *print; DC_ATTR *dc_attr; @@ -2240,6 +2241,7 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) debugstr_w(info.lpszDatatype), info.fwType); if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if (dc_attr->print && dc_attr->emf) return SP_ERROR; proc = (ABORTPROC)(UINT_PTR)dc_attr->abort_proc; if (proc && !proc( hdc, 0 )) return 0; @@ -2250,6 +2252,23 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) if (!info.lpszOutput) info.lpszOutput = print->output; output = StartDocDlgW( print->printer, &info ); if (output) info.lpszOutput = output; + + if (!info.lpszDatatype || !wcsicmp(info.lpszDatatype, L"EMF")) + { + spool_info.pDocName = (WCHAR *)info.lpszDocName; + spool_info.pOutputFile = (WCHAR *)info.lpszOutput; + spool_info.pDatatype = (WCHAR *)L"NT EMF 1.003"; + if ((ret = StartDocPrinterW( print->printer, 1, (BYTE *)&spool_info ))) + { + if (!spool_start_doc( dc_attr, print->printer, &info )) + { + AbortDoc( hdc ); + ret = 0; + } + HeapFree( GetProcessHeap(), 0, output ); + return ret; + } + } } ret = NtGdiStartDoc( hdc, &info, NULL, 0 ); @@ -2306,6 +2325,12 @@ INT WINAPI StartDocA( HDC hdc, const DOCINFOA *doc ) */ INT WINAPI StartPage( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_start_page( dc_attr, print->printer ); return NtGdiStartPage( hdc ); } @@ -2314,6 +2339,12 @@ INT WINAPI StartPage( HDC hdc ) */ INT WINAPI EndPage( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_end_page( dc_attr, print->printer ); return NtGdiEndPage( hdc ); } @@ -2322,6 +2353,12 @@ INT WINAPI EndPage( HDC hdc ) */ INT WINAPI EndDoc( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_end_doc( dc_attr, print->printer ); return NtGdiEndDoc( hdc ); } @@ -2330,6 +2367,12 @@ INT WINAPI EndDoc( HDC hdc ) */ INT WINAPI AbortDoc( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_abort_doc( dc_attr, print->printer ); return NtGdiAbortDoc( hdc ); } diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index e483b6a3498..9690bee2a17 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -44,8 +44,39 @@ struct emf DWORD palette_size; DWORD palette_used; PALETTEENTRY *palette; + enum + { + DOCUMENT_NOT_STARTED, + NEEDS_START_PAGE, + NEEDS_END_PAGE + } document_state; }; +typedef enum +{ + EMRI_METAFILE = 1, + EMRI_ENGINE_FONT, + EMRI_DEVMODE, + EMRI_TYPE1_FONT, + EMRI_PRESTARTPAGE, + EMRI_DESIGNVECTOR, + EMRI_SUBSET_FONT, + EMRI_DELTA_FONT, + EMRI_FORM_METAFILE, + EMRI_BW_METAFILE, + EMRI_BW_FORM_METAFILE, + EMRI_METAFILE_DATA, + EMRI_METAFILE_EXT, + EMRI_BW_METAFILE_EXT, + EMRI_ENGINE_FONT_EXT, + EMRI_TYPE1_FONT_EXT, + EMRI_DESIGNVECTOR_EXT, + EMRI_SUBSET_FONT_EXT, + EMRI_DELTA_FONT_EXT, + EMRI_PS_JOB_DATA, + EMRI_EMBED_FONT_EXT, +} emfspool_record_type; + #define HANDLE_LIST_INC 20 static const RECTL empty_bounds = { 0, 0, -1, -1 }; @@ -2474,6 +2505,7 @@ static void emf_reset( DC_ATTR *dc_attr, const RECT *rect ) emf->dc_pen = 0; emf->path = FALSE; emf->palette_used = 0; + emf->document_state = DOCUMENT_NOT_STARTED; dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0; dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1; @@ -2688,3 +2720,152 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) DeleteDC( hdc ); return hmf; } + +BOOL spool_start_doc( DC_ATTR *dc_attr, HANDLE hspool, const DOCINFOW *doc_info ) +{ + struct + { + unsigned int dwVersion; + unsigned int cjSize; + unsigned int dpszDocName; + unsigned int dpszOutput; + } *header; + size_t size = sizeof(*header); + struct emf *emf; + DWORD written; + WCHAR *p; + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (doc_info->lpszDocName) + size += (wcslen( doc_info->lpszDocName ) + 1) * sizeof(WCHAR); + if (doc_info->lpszOutput) + size += (wcslen( doc_info->lpszOutput ) + 1) * sizeof(WCHAR); + header = HeapAlloc( GetProcessHeap(), 0, size ); + if (!header) return FALSE; + + header->dwVersion = 0x10000; + header->cjSize = size; + p = (WCHAR *)(header + 1); + if (doc_info->lpszDocName) + { + header->dpszDocName = (BYTE *)p - (BYTE *)header; + wcscpy( p, doc_info->lpszDocName ); + p += wcslen( doc_info->lpszDocName ) + 1; + } + else + { + header->dpszDocName = 0; + } + if (doc_info->lpszOutput) + { + header->dpszOutput = (BYTE *)p - (BYTE *)header; + wcscpy( p, doc_info->lpszOutput ); + } + else + { + header->dpszOutput = 0; + } + if (!WritePrinter( hspool, header, size, &written )) written = 0; + HeapFree( GetProcessHeap(), 0, header ); + if (written != size) return FALSE; + + emf = emf_create( dc_attr_handle(dc_attr), NULL, NULL ); + if (!emf) return FALSE; + emf->document_state = NEEDS_START_PAGE; + return TRUE; +} + +int spool_start_page( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct emf *emf = get_dc_emf( dc_attr ); + HDC hdc = dc_attr_handle( dc_attr ); + POINT pos = { 0 }; + XFORM xform; + + TRACE( "(%p)\n", dc_attr ); + + /* Save current DC state to EMF */ + /* FIXME: SetTextJustification if needed */ + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_PEN) ); + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_BRUSH) ); + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_FONT) ); + if (GetBkColor( hdc ) != 0xffffff) + EMFDC_SetBkColor( dc_attr, GetBkColor(hdc) ); + if (GetBkMode( hdc ) != OPAQUE) + EMFDC_SetBkMode( dc_attr, GetBkMode(hdc) ); + GetCurrentPositionEx( hdc, &pos ); + if (pos.x || pos.y) + EMFDC_MoveTo( dc_attr, pos.x, pos.y ); + if (GetMapMode( hdc ) != MM_TEXT) + EMFDC_SetMapMode( dc_attr, GetMapMode(hdc) ); + if (GetPolyFillMode( hdc ) != ALTERNATE) + EMFDC_SetPolyFillMode( dc_attr, GetPolyFillMode(hdc) ); + if (GetROP2( hdc ) != R2_COPYPEN) + EMFDC_SetROP2( dc_attr, GetROP2(hdc) ); + if (GetStretchBltMode( hdc ) != BLACKONWHITE) + EMFDC_SetStretchBltMode( dc_attr, GetStretchBltMode(hdc) ); + if (GetTextAlign( hdc ) != (TA_LEFT | TA_TOP)) + EMFDC_SetTextAlign( dc_attr, GetTextAlign(hdc) ); + if (GetTextColor( hdc )) + EMFDC_SetTextColor( dc_attr, GetTextColor(hdc) ); + GetWorldTransform(hdc, &xform); + if (xform.eM11 != 1 || xform.eM22 != 1 || xform.eM12 || xform.eM21 || xform.eDx || xform.eDy) + EMFDC_SetWorldTransform( dc_attr, &xform ); + + emf->document_state = NEEDS_END_PAGE; + return StartPagePrinter( hspool ); +} + +int spool_end_page( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct record_hdr + { + unsigned int ulID; + unsigned int cjSize; + } record_hdr; + struct + { + struct record_hdr hdr; + LARGE_INTEGER pos; + } metafile_ext; + struct emf *emf = get_dc_emf( dc_attr ); + DWORD written; + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (!emf_eof( dc_attr )) return 0; + + record_hdr.ulID = EMRI_METAFILE_DATA; + record_hdr.cjSize = emf->emh->nBytes; + if (!WritePrinter( hspool, &record_hdr, sizeof(record_hdr), &written )) return 0; + if (!WritePrinter( hspool, emf->emh, emf->emh->nBytes, &written )) return 0; + + metafile_ext.hdr.ulID = EMRI_METAFILE_EXT; + metafile_ext.hdr.cjSize = sizeof(metafile_ext) - sizeof(struct record_hdr); + metafile_ext.pos.QuadPart = emf->emh->nBytes + sizeof(record_hdr); + if (!WritePrinter( hspool, &metafile_ext, sizeof(metafile_ext), &written )) return 0; + + emf_reset( dc_attr, NULL ); + emf->document_state = NEEDS_START_PAGE; + return EndPagePrinter( hspool ); +} + +int spool_abort_doc( DC_ATTR *dc_attr, HANDLE hspool ) +{ + TRACE( "(%p %p)\n", dc_attr, hspool ); + + EMFDC_DeleteDC( dc_attr ); + return AbortPrinter( hspool ); +} + +int spool_end_doc( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct emf *emf = get_dc_emf( dc_attr ); + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (emf->document_state == NEEDS_END_PAGE) spool_end_page( dc_attr, hspool ); + EMFDC_DeleteDC( dc_attr ); + return EndDocPrinter( hspool ); +} diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 4a9c70dcbc3..157e438c687 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -280,6 +280,13 @@ extern BOOL EMFDC_WidenPath( DC_ATTR *dc_attr ) DECLSPEC_HIDDEN; extern HENHMETAFILE EMF_Create_HENHMETAFILE( ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) DECLSPEC_HIDDEN; +extern BOOL spool_start_doc( DC_ATTR *dc_attr, HANDLE hspool, + const DOCINFOW *doc_info ) DECLSPEC_HIDDEN; +extern int spool_start_page( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_end_page( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_end_doc( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_abort_doc( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; + static inline int get_dib_stride( int width, int bpp ) { return ((width * bpp + 31) >> 3) & ~3;