Printing using EMF spool files is still missing some features and has some bugs: - ResetDC should generally work on gdi side but is ignored on playback - because of that it wasn't really tested - no support for ExtEscape / Escape yet - DC bounds are incorrect
In order to enable printing using EMF spool files it's needed to change printer print processor to wineps.
-- v2: gdi32: Add GdiIsMetaPrintDC implementation. gdi32: Implicitly call StartPage while creating spool file. gdi32: Add support for creating EMF spool files. gdi32: Factor out emf_create helper. gdi32: Factor out emf_eof helper. gdi32: Improve EMF DC cleanup when CloseEnhMetafile is not called. gdi32: Store the printer info in a structure. wineps: Reset current position on every page. localspl: Validate datatype in StartDocPrinter. localspl: Add support for PRINTER_ATTRIBUTE_RAW_ONLY printer attribute.
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index d09ac4420c3..59f2b8c8cd0 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -237,6 +237,7 @@ typedef struct { WCHAR *port; WCHAR *print_proc; WCHAR *datatype; + DWORD attributes;
CRITICAL_SECTION jobs_cs; struct list jobs; @@ -546,6 +547,17 @@ static WCHAR * reg_query_value(HKEY key, const WCHAR *name) return ret; }
+static DWORD reg_query_dword(HKEY hkey, const WCHAR *name) +{ + DWORD type, val, size = sizeof(size); + + if (RegQueryValueExW(hkey, name, 0, &type, (BYTE*)&val, &size)) + return 0; + if (type != REG_DWORD) + return 0; + return val; +} + static printer_info_t* get_printer_info(const WCHAR *name) { HKEY hkey, hprinter = NULL; @@ -582,6 +594,7 @@ static printer_info_t* get_printer_info(const WCHAR *name) info->port = reg_query_value(hprinter, L"Port"); info->print_proc = reg_query_value(hprinter, L"Print Processor"); info->datatype = reg_query_value(hprinter, L"Datatype"); + info->attributes = reg_query_dword(hprinter, L"Attributes"); RegCloseKey(hprinter);
if (!info->name || !info->port || !info->print_proc || !info->datatype) @@ -3281,6 +3294,7 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in { printer_t *printer = (printer_t *)hprinter; DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + WCHAR *datatype;
TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n", hprinter, level, doc_info, debugstr_w(info->pDocName), @@ -3318,6 +3332,21 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in return 0; }
+ if (info->pDatatype) + datatype = info->pDatatype; + else if (printer->datatype) + datatype = printer->datatype; + else + datatype = printer->info->datatype; + + if (!datatype || ((printer->info->attributes & PRINTER_ATTRIBUTE_RAW_ONLY) && + wcsicmp(datatype, L"RAW"))) + { + TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype)); + SetLastError(ERROR_INVALID_DATATYPE); + return 0; + } + printer->doc = add_job(printer, info, TRUE); return printer->doc ? printer->doc->id : 0; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 243 +++++++++++++++++++++------------------ 1 file changed, 132 insertions(+), 111 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 59f2b8c8cd0..56014461012 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3290,11 +3290,124 @@ static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size return TRUE; }
+typedef struct { + HMODULE hmod; + WCHAR *name; + BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD, + BYTE *, DWORD, DWORD *, DWORD *); + HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *); + BOOL (WINAPI *print)(HANDLE, WCHAR *); + BOOL (WINAPI *close)(HANDLE); +} printproc_t; + +static printproc_t * print_proc_load(const WCHAR *name) +{ + WCHAR *reg_path, path[2 * MAX_PATH]; + printproc_t *ret; + DWORD size, len; + LSTATUS status; + HKEY hkey; + + size = sizeof(fmt_printprocessorsW) + + (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR); + reg_path = malloc(size); + if (!reg_path) + return NULL; + swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname); + wcscat(reg_path, name); + + status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey); + free(reg_path); + if (status != ERROR_SUCCESS) + return NULL; + + if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size)) + { + RegCloseKey(hkey); + return NULL; + } + len = size / sizeof(WCHAR); + path[len - 1] = '\'; + + size = sizeof(path) - len * sizeof(WCHAR); + status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size); + RegCloseKey(hkey); + if (status != ERROR_SUCCESS) + return NULL; + + ret = malloc(sizeof(*ret)); + if (!ret) + return NULL; + + TRACE("loading print processor: %s\n", debugstr_w(path)); + + ret->hmod = LoadLibraryW(path); + if (!ret->hmod) + { + free(ret); + return NULL; + } + + ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW"); + ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor"); + ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor"); + ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor"); + if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close) + { + FreeLibrary(ret->hmod); + free(ret); + return NULL; + } + + ret->name = wcsdup(name); + return ret; +} + +static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype) +{ + DATATYPES_INFO_1W *types; + DWORD size, no, i; + + if (!datatype) + return FALSE; + + pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return FALSE; + + types = malloc(size); + if (!types) + return FALSE; + + if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no)) + { + free(types); + return FALSE; + } + + for (i = 0; i < no; i++) + { + if (!wcscmp(types[i].pName, datatype)) + break; + } + free(types); + return i < no; +} + +static void print_proc_unload(printproc_t *pp) +{ + FreeLibrary(pp->hmod); + free(pp->name); + free(pp); +} + static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_info) { printer_t *printer = (printer_t *)hprinter; DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + BOOL datatype_valid; WCHAR *datatype; + printproc_t *pp;
TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n", hprinter, level, doc_info, debugstr_w(info->pDocName), @@ -3347,6 +3460,25 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in return 0; }
+ pp = print_proc_load(printer->info->print_proc); + if (!pp) + { + WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc)); + pp = print_proc_load(L"winprint"); + } + if (!pp) + return 0; + + datatype_valid = print_proc_check_datatype(pp, datatype); + print_proc_unload(pp); + if (!datatype_valid) + { + TRACE("%s datatype not supported by %s\n", debugstr_w(datatype), + debugstr_w(printer->info->print_proc)); + SetLastError(ERROR_INVALID_DATATYPE); + return 0; + } + printer->doc = add_job(printer, info, TRUE); return printer->doc ? printer->doc->id : 0; } @@ -3586,117 +3718,6 @@ static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level, return ret; }
-typedef struct { - HMODULE hmod; - WCHAR *name; - BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD, - BYTE *, DWORD, DWORD *, DWORD *); - HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *); - BOOL (WINAPI *print)(HANDLE, WCHAR *); - BOOL (WINAPI *close)(HANDLE); -} printproc_t; - -static printproc_t * print_proc_load(const WCHAR *name) -{ - WCHAR *reg_path, path[2 * MAX_PATH]; - printproc_t *ret; - DWORD size, len; - LSTATUS status; - HKEY hkey; - - size = sizeof(fmt_printprocessorsW) + - (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR); - reg_path = malloc(size); - if (!reg_path) - return NULL; - swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname); - wcscat(reg_path, name); - - status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey); - free(reg_path); - if (status != ERROR_SUCCESS) - return NULL; - - if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size)) - { - RegCloseKey(hkey); - return NULL; - } - len = size / sizeof(WCHAR); - path[len - 1] = '\'; - - size = sizeof(path) - len * sizeof(WCHAR); - status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size); - RegCloseKey(hkey); - if (status != ERROR_SUCCESS) - return NULL; - - ret = malloc(sizeof(*ret)); - if (!ret) - return NULL; - - TRACE("loading print processor: %s\n", debugstr_w(path)); - - ret->hmod = LoadLibraryW(path); - if (!ret->hmod) - { - free(ret); - return NULL; - } - - ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW"); - ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor"); - ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor"); - ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor"); - if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close) - { - FreeLibrary(ret->hmod); - free(ret); - return NULL; - } - - ret->name = wcsdup(name); - return ret; -} - -static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype) -{ - DATATYPES_INFO_1W *types; - DWORD size, no, i; - - if (!datatype) - return FALSE; - - pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no); - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return FALSE; - - types = malloc(size); - if (!types) - return FALSE; - - if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no)) - { - free(types); - return FALSE; - } - - for (i = 0; i < no; i++) - { - if (!wcscmp(types[i].pName, datatype)) - break; - } - free(types); - return i < no; -} - -static void print_proc_unload(printproc_t *pp) -{ - FreeLibrary(pp->hmod); - free(pp->name); - free(pp); -} - static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) { printer_t *printer = (printer_t *)hprinter;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 914fc23f69e..9b96b2c1465 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -3040,6 +3040,7 @@ static BOOL print_metafile(struct pp_data *data, HANDLE hdata) return FALSE;
AbortPath(data->pdev->dev.hdc); + MoveToEx(data->pdev->dev.hdc, 0, 0, NULL); SetBkColor(data->pdev->dev.hdc, RGB(255, 255, 255)); SetBkMode(data->pdev->dev.hdc, OPAQUE); SetMapMode(data->pdev->dev.hdc, MM_TEXT);
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 45 ++++++++++++++++++++++++++++++++++++--------- include/ntgdi.h | 3 +-- 2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 8fa30884baf..6a5bb86d4f1 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -51,6 +51,11 @@ struct graphics_driver driver_entry_point entry_point; };
+struct print +{ + HANDLE printer; + WCHAR *output; +};
DC_ATTR *get_dc_attr( HDC hdc ) { @@ -200,6 +205,7 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, driver_entry_point entry_point = NULL; const WCHAR *display = NULL, *p; WCHAR buf[300], *port = NULL; + struct print *print = NULL; BOOL is_display = FALSE; HANDLE hspool = NULL; DC_ATTR *dc_attr; @@ -249,6 +255,11 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, ClosePrinter( hspool ); return 0; } + else if (!(print = HeapAlloc( GetProcessHeap(), 0, sizeof(*print) ))) + { + ClosePrinter( hspool ); + HeapFree( GetProcessHeap(), 0, port ); + }
if (display) { @@ -275,13 +286,15 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, memcpy( port, output, output_str.Length ); port[output_str.Length / sizeof(WCHAR)] = 0; } - dc_attr->hspool = HandleToULong( hspool ); - dc_attr->output = (ULONG_PTR)port; + print->printer = hspool; + print->output = port; + dc_attr->print = (UINT_PTR)print; } else if (hspool) { ClosePrinter( hspool ); HeapFree( GetProcessHeap(), 0, port ); + HeapFree( GetProcessHeap(), 0, print ); }
return ret; @@ -392,6 +405,21 @@ DEVMODEW *WINAPI GdiConvertToDevmodeW( const DEVMODEA *dmA ) return dmW; }
+static inline struct print *get_dc_print( DC_ATTR *dc_attr ) +{ + return (struct print *)(UINT_PTR)dc_attr->print; +} + +static void delete_print_dc( DC_ATTR *dc_attr ) +{ + struct print *print = get_dc_print( dc_attr ); + + ClosePrinter( print->printer ); + HeapFree( GetProcessHeap(), 0, print->output ); + HeapFree( GetProcessHeap(), 0, print ); + dc_attr->print = 0; +} + /*********************************************************************** * DeleteDC (GDI32.@) */ @@ -401,10 +429,7 @@ BOOL WINAPI DeleteDC( HDC hdc )
if (is_meta_dc( hdc )) return METADC_DeleteDC( hdc ); if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; - HeapFree( GetProcessHeap(), 0, (WCHAR *)(ULONG_PTR)dc_attr->output ); - dc_attr->output = 0; - if (dc_attr->hspool) ClosePrinter( ULongToHandle(dc_attr->hspool) ); - dc_attr->hspool = 0; + if (dc_attr->print) delete_print_dc( dc_attr ); if (dc_attr->emf) EMFDC_DeleteDC( dc_attr ); return NtGdiDeleteObjectApp( hdc ); } @@ -2192,6 +2217,7 @@ BOOL WINAPI CancelDC(HDC hdc) INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) { WCHAR *output = NULL; + struct print *print; DC_ATTR *dc_attr; ABORTPROC proc; DOCINFOW info; @@ -2218,10 +2244,11 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) proc = (ABORTPROC)(UINT_PTR)dc_attr->abort_proc; if (proc && !proc( hdc, 0 )) return 0;
- if (dc_attr->hspool) + print = get_dc_print( dc_attr ); + if (print) { - if (!info.lpszOutput) info.lpszOutput = (const WCHAR *)(ULONG_PTR)dc_attr->output; - output = StartDocDlgW( ULongToHandle( dc_attr->hspool ), &info ); + if (!info.lpszOutput) info.lpszOutput = print->output; + output = StartDocDlgW( print->printer, &info ); if (output) info.lpszOutput = output; }
diff --git a/include/ntgdi.h b/include/ntgdi.h index 1aa5cad468f..7d00ced2d19 100644 --- a/include/ntgdi.h +++ b/include/ntgdi.h @@ -198,8 +198,7 @@ typedef struct DC_ATTR RECTL emf_bounds; UINT64 emf; /* client EMF record pointer */ UINT64 abort_proc; /* AbortProc for printing */ - UINT64 hspool; - UINT64 output; + UINT64 print; /* client printer info pointer */ } DC_ATTR;
struct font_enum_entry
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 42330a22861..47f48bef9d3 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2384,6 +2384,9 @@ void EMFDC_DeleteDC( DC_ATTR *dc_attr ) struct emf *emf = get_dc_emf( dc_attr ); UINT index;
+ if (emf->dc_brush) DeleteObject( emf->dc_brush ); + if (emf->dc_pen) DeleteObject( emf->dc_pen ); + CloseHandle( emf->file ); HeapFree( GetProcessHeap(), 0, emf->palette ); HeapFree( GetProcessHeap(), 0, emf->emh ); for (index = 0; index < emf->handles_size; index++) @@ -2597,7 +2600,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) RestoreDC( hdc, 1 );
if (emf->dc_brush) DeleteObject( emf->dc_brush ); + emf->dc_brush = 0; if (emf->dc_pen) DeleteObject( emf->dc_pen ); + emf->dc_pen = 0;
emr->emr.iType = EMR_EOF; @@ -2630,6 +2635,7 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, NULL, NULL )) { CloseHandle( emf->file ); + emf->file = 0; return 0; } HeapFree( GetProcessHeap(), 0, emf->emh ); @@ -2642,6 +2648,7 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) }
hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 ); + emf->file = 0; emf->emh = NULL; /* So it won't be deleted */ DeleteDC( hdc ); return hmf;
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 57 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 47f48bef9d3..2e4b0a85de6 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2575,35 +2575,16 @@ HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, return ret; }
-/****************************************************************** - * CloseEnhMetaFile (GDI32.@) - */ -HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) +static BOOL emf_eof( DC_ATTR *dc_attr ) { + struct emf *emf = get_dc_emf( dc_attr ); UINT size, palette_size; - HENHMETAFILE hmf; - struct emf *emf; - DC_ATTR *dc_attr; EMREOF *emr; - HANDLE mapping = 0; - - TRACE("(%p)\n", hdc ); - - if (!(dc_attr = get_dc_attr( hdc )) || !get_dc_emf( dc_attr )) return 0; - emf = get_dc_emf( dc_attr ); + BOOL ret;
palette_size = emf->palette_used * sizeof(*emf->palette); size = sizeof(*emr) + palette_size; - if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return 0; - - if (dc_attr->save_level) - RestoreDC( hdc, 1 ); - - if (emf->dc_brush) DeleteObject( emf->dc_brush ); - emf->dc_brush = 0; - if (emf->dc_pen) DeleteObject( emf->dc_pen ); - emf->dc_pen = 0; - + if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
emr->emr.iType = EMR_EOF; emr->emr.nSize = size; @@ -2612,8 +2593,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) memcpy( (BYTE *)emr + emr->offPalEntries, emf->palette, palette_size ); /* Set nSizeLast */ ((DWORD *)((BYTE *)emr + size))[-1] = size; - emfdc_record( emf, &emr->emr ); + ret = emfdc_record( emf, &emr->emr ); HeapFree( GetProcessHeap(), 0, emr ); + if (!ret) return FALSE;
emf->emh->rclBounds = dc_attr->emf_bounds;
@@ -2629,6 +2611,33 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom * emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy; } + return TRUE; +} + +/****************************************************************** + * CloseEnhMetaFile (GDI32.@) + */ +HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) +{ + HENHMETAFILE hmf; + struct emf *emf; + DC_ATTR *dc_attr; + HANDLE mapping = 0; + + TRACE("(%p)\n", hdc ); + + if (!(dc_attr = get_dc_attr( hdc )) || !get_dc_emf( dc_attr )) return 0; + emf = get_dc_emf( dc_attr ); + + if (dc_attr->save_level) + RestoreDC( hdc, 1 ); + + if (emf->dc_brush) DeleteObject( emf->dc_brush ); + emf->dc_brush = 0; + if (emf->dc_pen) DeleteObject( emf->dc_pen ); + emf->dc_pen = 0; + + if (!emf_eof( dc_attr )) return 0;
if (emf->file) /* disk based metafile */ {
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 140 +++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 57 deletions(-)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 2e4b0a85de6..e483b6a3498 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2460,61 +2460,20 @@ HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect, return ret; }
-/********************************************************************** - * CreateEnhMetaFileW (GDI32.@) - */ -HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, - const WCHAR *description ) +static void emf_reset( DC_ATTR *dc_attr, const RECT *rect ) { - HDC ret; - struct emf *emf; - DC_ATTR *dc_attr; - HANDLE file; - DWORD size = 0, length = 0; - - TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), - debugstr_w(description) ); - - if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0; - - if (!(dc_attr = get_dc_attr( ret )) || !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) ))) - { - DeleteDC( ret ); - return 0; - } - - emf->dc_attr = dc_attr; - dc_attr->emf = (UINT_PTR)emf; - - if (description) /* App name\0Title\0\0 */ - { - length = lstrlenW( description ); - length += lstrlenW( description + length + 1 ); - length += 3; - length *= 2; - } - size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; - - if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size))) - { - DeleteDC( ret ); - return 0; - } + struct emf *emf = get_dc_emf( dc_attr ); + HDC hdc = dc_attr_handle( dc_attr );
- emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - HANDLE_LIST_INC * sizeof(emf->handles[0]) ); - emf->handles_size = HANDLE_LIST_INC; + memset( emf->handles, 0, emf->handles_size * sizeof(emf->handles[0]) ); emf->cur_handles = 1; emf->file = 0; + if (emf->dc_brush) DeleteObject( emf->dc_brush ); emf->dc_brush = 0; + if (emf->dc_pen) DeleteObject( emf->dc_pen ); emf->dc_pen = 0; emf->path = FALSE; - emf->palette_size = 0; emf->palette_used = 0; - emf->palette = NULL; - - emf->emh->iType = EMR_HEADER; - emf->emh->nSize = size;
dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0; dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1; @@ -2538,28 +2497,95 @@ HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, emf->emh->nBytes = emf->emh->nSize; emf->emh->nRecords = 1; emf->emh->nHandles = 1; - emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */ - emf->emh->nDescription = length / 2; - - emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0; - - emf->emh->nPalEntries = 0; /* I guess this should start at 0 */ + emf->emh->nPalEntries = 0;
/* Size in pixels */ - emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES ); - emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES ); + emf->emh->szlDevice.cx = GetDeviceCaps( hdc, HORZRES ); + emf->emh->szlDevice.cy = GetDeviceCaps( hdc, VERTRES );
/* Size in millimeters */ - emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE ); - emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE ); + emf->emh->szlMillimeters.cx = GetDeviceCaps( hdc, HORZSIZE ); + emf->emh->szlMillimeters.cy = GetDeviceCaps( hdc, VERTSIZE ); + + emf->emh->cbPixelFormat = 0; + emf->emh->offPixelFormat = 0; + emf->emh->bOpenGL = 0;
/* Size in micrometers */ emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000; emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000; +} + +static struct emf *emf_create( HDC hdc, const RECT *rect, const WCHAR *description ) +{ + DWORD size = 0, length = 0; + DC_ATTR *dc_attr; + struct emf *emf; + + if (!(dc_attr = get_dc_attr( hdc )) || !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) ))) + return NULL; + + if (description) /* App name\0Title\0\0 */ + { + length = lstrlenW( description ); + length += lstrlenW( description + length + 1 ); + length += 3; + length *= 2; + } + size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; + + if (!(emf->emh = HeapAlloc( GetProcessHeap(), 0, size )) || + !(emf->handles = HeapAlloc( GetProcessHeap(), 0, + HANDLE_LIST_INC * sizeof(emf->handles[0]) ))) + { + HeapFree( GetProcessHeap(), 0, emf->emh ); + HeapFree( GetProcessHeap(), 0, emf ); + return NULL; + } + + emf->dc_attr = dc_attr; + dc_attr->emf = (UINT_PTR)emf; + + emf->handles_size = HANDLE_LIST_INC; + emf->dc_brush = 0; + emf->dc_pen = 0; + emf->palette_size = 0; + emf->palette = NULL; + + emf->emh->iType = EMR_HEADER; + emf->emh->nSize = size; + emf->emh->nDescription = length / 2; + emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0;
memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length );
+ emf_reset( dc_attr, rect ); + return emf; +} + +/********************************************************************** + * CreateEnhMetaFileW (GDI32.@) + */ +HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, + const WCHAR *description ) +{ + struct emf *emf; + HANDLE file; + HDC ret; + + TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), + debugstr_w(description) ); + + if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0; + + emf = emf_create( ret, rect, description ); + if (!emf) + { + DeleteDC( ret ); + return 0; + } + if (filename) /* disk based metafile */ { if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0,
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 43 ++++++++++ dlls/gdi32/emfdc.c | 181 +++++++++++++++++++++++++++++++++++++++ dlls/gdi32/gdi_private.h | 7 ++ 3 files changed, 231 insertions(+)
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;
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 114 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 20 deletions(-)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 9690bee2a17..990ee6e8109 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -892,13 +892,16 @@ BOOL EMFDC_MoveTo( DC_ATTR *dc_attr, INT x, INT y )
BOOL EMFDC_LineTo( DC_ATTR *dc_attr, INT x, INT y ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRLINETO emr;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + emr.emr.iType = EMR_LINETO; emr.emr.nSize = sizeof(emr); emr.ptl.x = x; emr.ptl.y = y; - return emfdc_record( get_dc_emf( dc_attr ), &emr.emr ); + return emfdc_record( emf, &emr.emr ); }
BOOL EMFDC_ArcChordPie( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom, @@ -909,6 +912,7 @@ BOOL EMFDC_ArcChordPie( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bott INT temp;
if (left == right || top == bottom) return FALSE; + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) );
if (left > right) { temp = left; left = right; right = temp; } if (top > bottom) { temp = top; top = bottom; bottom = temp; } @@ -934,8 +938,11 @@ BOOL EMFDC_ArcChordPie( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bott
BOOL EMFDC_AngleArc( DC_ATTR *dc_attr, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRANGLEARC emr;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + emr.emr.iType = EMR_ANGLEARC; emr.emr.nSize = sizeof( emr ); emr.ptlCenter.x = x; @@ -943,7 +950,7 @@ BOOL EMFDC_AngleArc( DC_ATTR *dc_attr, INT x, INT y, DWORD radius, FLOAT start, emr.nRadius = radius; emr.eStartAngle = start; emr.eSweepAngle = sweep; - return emfdc_record( get_dc_emf( dc_attr ), &emr.emr ); + return emfdc_record( emf, &emr.emr ); }
BOOL EMFDC_Ellipse( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom ) @@ -952,6 +959,7 @@ BOOL EMFDC_Ellipse( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom ) EMRELLIPSE emr;
if (left == right || top == bottom) return FALSE; + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) );
emr.emr.iType = EMR_ELLIPSE; emr.emr.nSize = sizeof(emr); @@ -972,7 +980,8 @@ BOOL EMFDC_Rectangle( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom struct emf *emf = get_dc_emf( dc_attr ); EMRRECTANGLE emr;
- if(left == right || top == bottom) return FALSE; + if (left == right || top == bottom) return FALSE; + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) );
emr.emr.iType = EMR_RECTANGLE; emr.emr.nSize = sizeof(emr); @@ -995,6 +1004,7 @@ BOOL EMFDC_RoundRect( DC_ATTR *dc_attr, INT left, INT top, INT right, EMRROUNDRECT emr;
if (left == right || top == bottom) return FALSE; + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) );
emr.emr.iType = EMR_ROUNDRECT; emr.emr.nSize = sizeof(emr); @@ -1014,14 +1024,17 @@ BOOL EMFDC_RoundRect( DC_ATTR *dc_attr, INT left, INT top, INT right,
BOOL EMFDC_SetPixel( DC_ATTR *dc_attr, INT x, INT y, COLORREF color ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRSETPIXELV emr;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + emr.emr.iType = EMR_SETPIXELV; emr.emr.nSize = sizeof(emr); emr.ptlPixel.x = x; emr.ptlPixel.y = y; emr.crColor = color; - return emfdc_record( get_dc_emf( dc_attr ), &emr.emr ); + return emfdc_record( emf, &emr.emr ); }
static BOOL emfdc_polylinegon( DC_ATTR *dc_attr, const POINT *points, INT count, DWORD type ) @@ -1031,6 +1044,8 @@ static BOOL emfdc_polylinegon( DC_ATTR *dc_attr, const POINT *points, INT count, DWORD size; BOOL ret, use_small_emr = can_use_short_points( points, count );
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + size = use_small_emr ? offsetof( EMRPOLYLINE16, apts[count] ) : offsetof( EMRPOLYLINE, aptl[count] );
emr = HeapAlloc( GetProcessHeap(), 0, size ); @@ -1131,11 +1146,17 @@ static BOOL emfdc_poly_polylinegon( struct emf *emf, const POINT *pt, const INT
BOOL EMFDC_PolyPolyline( DC_ATTR *dc_attr, const POINT *pt, const DWORD *counts, DWORD polys) { + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); return emfdc_poly_polylinegon( get_dc_emf( dc_attr ), pt, (const INT *)counts, polys, EMR_POLYPOLYLINE ); }
BOOL EMFDC_PolyPolygon( DC_ATTR *dc_attr, const POINT *pt, const INT *counts, UINT polys ) { + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); return emfdc_poly_polylinegon( get_dc_emf( dc_attr ), pt, counts, polys, EMR_POLYPOLYGON ); }
@@ -1148,6 +1169,8 @@ BOOL EMFDC_PolyDraw( DC_ATTR *dc_attr, const POINT *pts, const BYTE *types, DWOR BOOL use_small_emr = can_use_short_points( pts, count ); DWORD size;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + size = use_small_emr ? offsetof( EMRPOLYDRAW16, apts[count] ) : offsetof( EMRPOLYDRAW, aptl[count] ); size += (count + 3) & ~3; @@ -1175,15 +1198,18 @@ BOOL EMFDC_PolyDraw( DC_ATTR *dc_attr, const POINT *pts, const BYTE *types, DWOR
BOOL EMFDC_ExtFloodFill( DC_ATTR *dc_attr, INT x, INT y, COLORREF color, UINT fill_type ) { + struct emf *emf = get_dc_emf( dc_attr ); EMREXTFLOODFILL emr;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + emr.emr.iType = EMR_EXTFLOODFILL; emr.emr.nSize = sizeof(emr); emr.ptlStart.x = x; emr.ptlStart.y = y; emr.crColor = color; emr.iMode = fill_type; - return emfdc_record( get_dc_emf( dc_attr ), &emr.emr ); + return emfdc_record( emf, &emr.emr ); }
BOOL EMFDC_FillRgn( DC_ATTR *dc_attr, HRGN hrgn, HBRUSH hbrush ) @@ -1193,6 +1219,8 @@ BOOL EMFDC_FillRgn( DC_ATTR *dc_attr, HRGN hrgn, HBRUSH hbrush ) DWORD size, rgnsize, index; BOOL ret;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + if (!(index = emfdc_create_brush( emf, hbrush ))) return FALSE;
rgnsize = NtGdiGetRegionData( hrgn, 0, NULL ); @@ -1223,6 +1251,8 @@ BOOL EMFDC_FrameRgn( DC_ATTR *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width, INT DWORD size, rgnsize, index; BOOL ret;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + index = emfdc_create_brush( emf, hbrush ); if(!index) return FALSE;
@@ -1277,12 +1307,18 @@ static BOOL emfdc_paint_invert_region( struct emf *emf, HRGN hrgn, DWORD iType )
BOOL EMFDC_PaintRgn( DC_ATTR *dc_attr, HRGN hrgn ) { - return emfdc_paint_invert_region( get_dc_emf( dc_attr ), hrgn, EMR_PAINTRGN ); + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdc_paint_invert_region( emf, hrgn, EMR_PAINTRGN ); }
BOOL EMFDC_InvertRgn( DC_ATTR *dc_attr, HRGN hrgn ) { - return emfdc_paint_invert_region( get_dc_emf( dc_attr ), hrgn, EMR_INVERTRGN ); + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdc_paint_invert_region( emf, hrgn, EMR_INVERTRGN ); }
BOOL EMFDC_ExtTextOut( DC_ATTR *dc_attr, INT x, INT y, UINT flags, const RECT *rect, @@ -1298,6 +1334,8 @@ BOOL EMFDC_ExtTextOut( DC_ATTR *dc_attr, INT x, INT y, UINT flags, const RECT *r DWORD size; BOOL ret;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + size = sizeof(*emr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
TRACE( "%s %s count %d size = %ld\n", debugstr_wn(str, count), @@ -1431,11 +1469,14 @@ no_bounds: BOOL EMFDC_GradientFill( DC_ATTR *dc_attr, TRIVERTEX *vert_array, ULONG nvert, void *grad_array, ULONG ngrad, ULONG mode ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRGRADIENTFILL *emr; ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); const ULONG *pts = (const ULONG *)grad_array; BOOL ret;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]);
emr = HeapAlloc( GetProcessHeap(), 0, size ); @@ -1473,25 +1514,34 @@ BOOL EMFDC_GradientFill( DC_ATTR *dc_attr, TRIVERTEX *vert_array, ULONG nvert, memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) ); memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) );
- emfdc_update_bounds( get_dc_emf( dc_attr ), &emr->rclBounds ); - ret = emfdc_record( get_dc_emf( dc_attr ), &emr->emr ); + emfdc_update_bounds( emf, &emr->rclBounds ); + ret = emfdc_record( emf, &emr->emr ); HeapFree( GetProcessHeap(), 0, emr ); return ret; }
BOOL EMFDC_FillPath( DC_ATTR *dc_attr ) { - return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr ), EMR_FILLPATH ); + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stroke_and_fill_path( emf, EMR_FILLPATH ); }
BOOL EMFDC_StrokeAndFillPath( DC_ATTR *dc_attr ) { - return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr ), EMR_STROKEANDFILLPATH ); + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stroke_and_fill_path( emf, EMR_STROKEANDFILLPATH ); }
BOOL EMFDC_StrokePath( DC_ATTR *dc_attr ) { - return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr ), EMR_STROKEPATH ); + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stroke_and_fill_path( emf, EMR_STROKEPATH ); }
/* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */ @@ -1567,7 +1617,10 @@ BOOL EMFDC_AlphaBlend( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, IN HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src, BLENDFUNCTION blend_function ) { - return emfdrv_stretchblt( get_dc_emf( dc_attr ), x_dst, y_dst, width_dst, height_dst, hdc_src, + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stretchblt( emf, x_dst, y_dst, width_dst, height_dst, hdc_src, x_src, y_src, width_src, height_src, *(DWORD *)&blend_function, EMR_ALPHABLEND ); } @@ -1578,6 +1631,8 @@ BOOL EMFDC_PatBlt( DC_ATTR *dc_attr, INT left, INT top, INT width, INT height, D EMRBITBLT emr; BOOL ret;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + emr.emr.iType = EMR_BITBLT; emr.emr.nSize = sizeof(emr); emr.rclBounds.left = left; @@ -1617,8 +1672,11 @@ static inline BOOL rop_uses_src( DWORD rop ) BOOL EMFDC_BitBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width, INT height, HDC hdc_src, INT x_src, INT y_src, DWORD rop ) { + struct emf *emf = get_dc_emf( dc_attr ); + if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width, height, rop ); - return emfdrv_stretchblt( get_dc_emf( dc_attr ), x_dst, y_dst, width, height, + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stretchblt( emf, x_dst, y_dst, width, height, hdc_src, x_src, y_src, width, height, rop, EMR_BITBLT ); }
@@ -1626,8 +1684,11 @@ BOOL EMFDC_StretchBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, IN HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src, DWORD rop ) { + struct emf *emf = get_dc_emf( dc_attr ); + if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop ); - return emfdrv_stretchblt( get_dc_emf( dc_attr ), x_dst, y_dst, width_dst, height_dst, + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stretchblt( emf, x_dst, y_dst, width_dst, height_dst, hdc_src, x_src, y_src, width_src, height_src, rop, EMR_STRETCHBLT ); } @@ -1636,7 +1697,10 @@ BOOL EMFDC_TransparentBlt( DC_ATTR *dc_attr, int x_dst, int y_dst, int width_dst HDC hdc_src, int x_src, int y_src, int width_src, int height_src, UINT color ) { - return emfdrv_stretchblt( get_dc_emf( dc_attr ), x_dst, y_dst, width_dst, height_dst, + struct emf *emf = get_dc_emf( dc_attr ); + + if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + return emfdrv_stretchblt( emf, x_dst, y_dst, width_dst, height_dst, hdc_src, x_src, y_src, width_src, height_src, color, EMR_TRANSPARENTBLT ); } @@ -1657,6 +1721,8 @@ BOOL EMFDC_MaskBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT h HDC blit_dc, mask_dc = NULL; BOOL ret = FALSE;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
@@ -1753,6 +1819,8 @@ BOOL EMFDC_PlgBlt( DC_ATTR *dc_attr, const POINT *points, HDC hdc_src, INT x_src int x_min, y_min, x_max, y_max, i; BOOL ret = FALSE;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
blit_dc = hdc_src; @@ -1844,12 +1912,15 @@ BOOL EMFDC_StretchDIBits( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT x_src, INT y_src, INT width_src, INT height_src, const void *bits, const BITMAPINFO *info, UINT usage, DWORD rop ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRSTRETCHDIBITS *emr; BOOL ret; UINT bmi_size, img_size, payload_size, emr_size; BITMAPINFOHEADER bih; BITMAPINFO *bi;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + /* calculate the size of the colour table and the image */ if (!emf_parse_user_bitmapinfo( &bih, &info->bmiHeader, usage, TRUE, &bmi_size, &img_size )) return 0; @@ -1899,8 +1970,8 @@ BOOL EMFDC_StretchDIBits( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, emr->rclBounds.bottom = y_dst + height_dst - 1;
/* save the record we just created */ - ret = emfdc_record( get_dc_emf( dc_attr ), &emr->emr ); - if (ret) emfdc_update_bounds( get_dc_emf( dc_attr ), &emr->rclBounds ); + ret = emfdc_record( emf, &emr->emr ); + if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); HeapFree( GetProcessHeap(), 0, emr ); return ret; } @@ -1909,6 +1980,7 @@ BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD widt INT x_src, INT y_src, UINT startscan, UINT lines, const void *bits, const BITMAPINFO *info, UINT usage ) { + struct emf *emf = get_dc_emf( dc_attr ); EMRSETDIBITSTODEVICE *emr; BOOL ret; UINT bmi_size, img_size, payload_size, emr_size; @@ -1916,6 +1988,8 @@ BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD widt BITMAPINFOHEADER bih; BITMAPINFO *bi;
+ if (emf->document_state == NEEDS_START_PAGE) StartPage( dc_attr_handle(dc_attr) ); + /* calculate the size of the colour table and the image */ if (!emf_parse_user_bitmapinfo( &bih, &info->bmiHeader, usage, TRUE, &bmi_size, &img_size )) return 0; @@ -1977,8 +2051,8 @@ BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD widt emr->iStartScan = startscan; emr->cScans = lines;
- if ((ret = emfdc_record( get_dc_emf( dc_attr ), (EMR*)emr ))) - emfdc_update_bounds( get_dc_emf( dc_attr ), &emr->rclBounds ); + if ((ret = emfdc_record( emf, (EMR*)emr ))) + emfdc_update_bounds( emf, &emr->rclBounds );
HeapFree( GetProcessHeap(), 0, emr ); return ret;
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 459d0dfb8c1..011bded3523 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2408,8 +2408,12 @@ INT WINAPI SetICMMode( HDC hdc, INT mode ) */ BOOL WINAPI GdiIsMetaPrintDC( HDC hdc ) { - FIXME( "%p\n", hdc ); - return FALSE; + DC_ATTR *dc_attr; + + TRACE( "%p\n", hdc ); + + if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; + return dc_attr->print && dc_attr->emf; }
/***********************************************************************
On Thu Apr 27 10:39:28 2023 +0000, Huw Davies wrote:
Is there more code to go in here or could it be simplified to:
if (!datatype || ((printer->info->attributes & PRINTER_ATTRIBUTE_RAW_ONLY) && wcsicmp(datatype, L"RAW"))) { TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype)); SetLastError(ERROR_INVALID_DATATYPE); return 0; }
No, I have changed it as suggested. Thanks.
This merge request was approved by Huw Davies.
It looks like 18961d8fe3993ee6065496b4f8d059ed0f85efe7 needs some more work - StartPage should be also called if direct printing / RAW spooling is used. I will remove this patch for now.