gdiplus: Add basic metafile recording support.
This commit is contained in:
parent
4e26336eae
commit
d436e51872
|
@ -13,6 +13,7 @@ C_SRCS = \
|
|||
image.c \
|
||||
imageattributes.c \
|
||||
matrix.c \
|
||||
metafile.c \
|
||||
pathiterator.c \
|
||||
pen.c \
|
||||
region.c \
|
||||
|
|
|
@ -51,6 +51,9 @@ extern REAL convert_unit(REAL logpixels, GpUnit unit) DECLSPEC_HIDDEN;
|
|||
|
||||
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
|
||||
|
||||
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
|
||||
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
|
||||
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
|
||||
extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
|
||||
|
@ -268,6 +271,13 @@ struct GpMetafile{
|
|||
GpImage image;
|
||||
GpRectF bounds;
|
||||
GpUnit unit;
|
||||
MetafileType metafile_type;
|
||||
HDC record_dc;
|
||||
GpGraphics *record_graphics;
|
||||
BYTE *comment_data;
|
||||
DWORD comment_data_size;
|
||||
DWORD comment_data_length;
|
||||
HENHMETAFILE hemf;
|
||||
};
|
||||
|
||||
struct GpBitmap{
|
||||
|
|
|
@ -206,6 +206,11 @@ static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
|
|||
|
||||
return Ok;
|
||||
}
|
||||
else if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||
{
|
||||
ERR("This should not be used for metafiles; fix caller\n");
|
||||
return NotImplemented;
|
||||
}
|
||||
else
|
||||
{
|
||||
HDC hdc;
|
||||
|
@ -1967,11 +1972,19 @@ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
|
|||
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
|
||||
{
|
||||
GraphicsContainerItem *cont, *next;
|
||||
GpStatus stat;
|
||||
TRACE("(%p)\n", graphics);
|
||||
|
||||
if(!graphics) return InvalidParameter;
|
||||
if(graphics->busy) return ObjectBusy;
|
||||
|
||||
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||
{
|
||||
stat = METAFILE_GraphicsDeleted((GpMetafile*)graphics->image);
|
||||
if (stat != Ok)
|
||||
return stat;
|
||||
}
|
||||
|
||||
if(graphics->owndc)
|
||||
ReleaseDC(graphics->hwnd, graphics->hdc);
|
||||
|
||||
|
@ -5873,23 +5886,6 @@ GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16
|
|||
return stat;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
|
||||
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
|
||||
{
|
||||
FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* GdipRecordMetafileI [GDIPLUS.@]
|
||||
*/
|
||||
GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
|
||||
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
|
||||
{
|
||||
FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
|
||||
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
|
||||
{
|
||||
|
@ -5919,15 +5915,3 @@ cleanup:
|
|||
GdipDeleteRegion(rgn);
|
||||
return stat;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
|
||||
{
|
||||
FIXME("(%p,%p): stub\n", metafile, hEmf);
|
||||
|
||||
if (!metafile || !hEmf)
|
||||
return InvalidParameter;
|
||||
|
||||
*hEmf = NULL;
|
||||
|
||||
return NotImplemented;
|
||||
}
|
||||
|
|
|
@ -2143,12 +2143,7 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
|
|||
if(!image || !graphics)
|
||||
return InvalidParameter;
|
||||
|
||||
if(image->type != ImageTypeBitmap){
|
||||
FIXME("not implemented for image type %d\n", image->type);
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
if (((GpBitmap*)image)->hbitmap)
|
||||
if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
|
||||
{
|
||||
hdc = ((GpBitmap*)image)->hdc;
|
||||
|
||||
|
@ -2163,6 +2158,8 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
|
|||
if (stat == Ok)
|
||||
(*graphics)->image = image;
|
||||
}
|
||||
else if (image->type == ImageTypeMetafile)
|
||||
stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
|
||||
else
|
||||
stat = graphics_from_image(image, graphics);
|
||||
|
||||
|
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Vincent Povirk for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include "objbase.h"
|
||||
#include "ocidl.h"
|
||||
#include "olectl.h"
|
||||
#include "ole2.h"
|
||||
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "gdiplus.h"
|
||||
#include "gdiplus_private.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/list.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
|
||||
|
||||
typedef struct EmfPlusRecordHeader
|
||||
{
|
||||
WORD Type;
|
||||
WORD Flags;
|
||||
DWORD Size;
|
||||
DWORD DataSize;
|
||||
} EmfPlusRecordHeader;
|
||||
|
||||
typedef struct EmfPlusHeader
|
||||
{
|
||||
EmfPlusRecordHeader Header;
|
||||
DWORD Version;
|
||||
DWORD EmfPlusFlags;
|
||||
DWORD LogicalDpiX;
|
||||
DWORD LogicalDpiY;
|
||||
} EmfPlusHeader;
|
||||
|
||||
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
|
||||
{
|
||||
DWORD size_needed;
|
||||
EmfPlusRecordHeader *record;
|
||||
|
||||
if (!metafile->comment_data_size)
|
||||
{
|
||||
DWORD data_size = max(256, size * 2 + 4);
|
||||
metafile->comment_data = GdipAlloc(data_size);
|
||||
|
||||
if (!metafile->comment_data)
|
||||
return OutOfMemory;
|
||||
|
||||
memcpy(metafile->comment_data, "EMF+", 4);
|
||||
|
||||
metafile->comment_data_size = data_size;
|
||||
metafile->comment_data_length = 4;
|
||||
}
|
||||
|
||||
size_needed = size + metafile->comment_data_length;
|
||||
|
||||
if (size_needed > metafile->comment_data_size)
|
||||
{
|
||||
DWORD data_size = size_needed * 2;
|
||||
BYTE *new_data = GdipAlloc(data_size);
|
||||
|
||||
if (!new_data)
|
||||
return OutOfMemory;
|
||||
|
||||
memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
|
||||
|
||||
metafile->comment_data_size = data_size;
|
||||
GdipFree(metafile->comment_data);
|
||||
metafile->comment_data = new_data;
|
||||
}
|
||||
|
||||
*result = metafile->comment_data + metafile->comment_data_length;
|
||||
metafile->comment_data_length += size;
|
||||
|
||||
record = (EmfPlusRecordHeader*)*result;
|
||||
record->Size = size;
|
||||
record->DataSize = size - sizeof(EmfPlusRecordHeader);
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static void METAFILE_WriteRecords(GpMetafile *metafile)
|
||||
{
|
||||
if (metafile->comment_data_length > 4)
|
||||
{
|
||||
GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
|
||||
metafile->comment_data_length = 4;
|
||||
}
|
||||
}
|
||||
|
||||
static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
|
||||
{
|
||||
GpStatus stat;
|
||||
|
||||
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
|
||||
{
|
||||
EmfPlusHeader *header;
|
||||
|
||||
stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
|
||||
if (stat != Ok)
|
||||
return stat;
|
||||
|
||||
header->Header.Type = EmfPlusRecordTypeHeader;
|
||||
|
||||
if (metafile->metafile_type == MetafileTypeEmfPlusDual)
|
||||
header->Header.Flags = 1;
|
||||
else
|
||||
header->Header.Flags = 0;
|
||||
|
||||
header->Version = 0xDBC01002;
|
||||
|
||||
if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
|
||||
header->EmfPlusFlags = 1;
|
||||
else
|
||||
header->EmfPlusFlags = 0;
|
||||
|
||||
header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||
|
||||
METAFILE_WriteRecords(metafile);
|
||||
}
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
|
||||
{
|
||||
GpStatus stat;
|
||||
|
||||
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
|
||||
{
|
||||
EmfPlusRecordHeader *record;
|
||||
|
||||
stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
|
||||
if (stat != Ok)
|
||||
return stat;
|
||||
|
||||
record->Type = EmfPlusRecordTypeEndOfFile;
|
||||
record->Flags = 0;
|
||||
|
||||
METAFILE_WriteRecords(metafile);
|
||||
}
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
|
||||
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
|
||||
{
|
||||
HDC record_dc;
|
||||
REAL framerect_factor_x, framerect_factor_y;
|
||||
RECT rc;
|
||||
GpStatus stat;
|
||||
|
||||
TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
|
||||
|
||||
if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
|
||||
return InvalidParameter;
|
||||
|
||||
if (!frameRect)
|
||||
{
|
||||
FIXME("not implemented for NULL rect\n");
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
switch (frameUnit)
|
||||
{
|
||||
case MetafileFrameUnitPixel:
|
||||
framerect_factor_x = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
framerect_factor_y = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSY);
|
||||
break;
|
||||
case MetafileFrameUnitPoint:
|
||||
framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
|
||||
break;
|
||||
case MetafileFrameUnitInch:
|
||||
framerect_factor_x = framerect_factor_y = 2540.0;
|
||||
break;
|
||||
case MetafileFrameUnitDocument:
|
||||
framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
|
||||
break;
|
||||
case MetafileFrameUnitMillimeter:
|
||||
framerect_factor_x = framerect_factor_y = 100.0;
|
||||
break;
|
||||
case MetafileFrameUnitGdi:
|
||||
framerect_factor_x = framerect_factor_y = 1.0;
|
||||
break;
|
||||
default:
|
||||
return InvalidParameter;
|
||||
}
|
||||
|
||||
rc.left = framerect_factor_x * frameRect->X;
|
||||
rc.top = framerect_factor_y * frameRect->Y;
|
||||
rc.right = rc.left + framerect_factor_x * frameRect->Width;
|
||||
rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
|
||||
|
||||
record_dc = CreateEnhMetaFileW(hdc, NULL, &rc, desc);
|
||||
|
||||
if (!record_dc)
|
||||
return GenericError;
|
||||
|
||||
*metafile = GdipAlloc(sizeof(GpMetafile));
|
||||
if(!*metafile)
|
||||
{
|
||||
DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
|
||||
return OutOfMemory;
|
||||
}
|
||||
|
||||
(*metafile)->image.type = ImageTypeMetafile;
|
||||
(*metafile)->image.picture = NULL;
|
||||
(*metafile)->image.flags = ImageFlagsNone;
|
||||
(*metafile)->image.palette_flags = 0;
|
||||
(*metafile)->image.palette_count = 0;
|
||||
(*metafile)->image.palette_size = 0;
|
||||
(*metafile)->image.palette_entries = NULL;
|
||||
(*metafile)->bounds = *frameRect;
|
||||
(*metafile)->unit = frameUnit;
|
||||
(*metafile)->metafile_type = type;
|
||||
(*metafile)->record_dc = record_dc;
|
||||
(*metafile)->comment_data = NULL;
|
||||
(*metafile)->comment_data_size = 0;
|
||||
(*metafile)->comment_data_length = 0;
|
||||
(*metafile)->hemf = NULL;
|
||||
|
||||
stat = METAFILE_WriteHeader(*metafile, hdc);
|
||||
|
||||
if (stat != Ok)
|
||||
{
|
||||
DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
|
||||
GdipFree(*metafile);
|
||||
*metafile = NULL;
|
||||
return OutOfMemory;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* GdipRecordMetafileI [GDIPLUS.@]
|
||||
*/
|
||||
GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
|
||||
MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
|
||||
{
|
||||
GpRectF frameRectF, *pFrameRectF;
|
||||
|
||||
TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
|
||||
|
||||
if (frameRect)
|
||||
{
|
||||
frameRectF.X = frameRect->X;
|
||||
frameRectF.Y = frameRect->Y;
|
||||
frameRectF.Width = frameRect->Width;
|
||||
frameRectF.Height = frameRect->Height;
|
||||
pFrameRectF = &frameRectF;
|
||||
}
|
||||
else
|
||||
pFrameRectF = NULL;
|
||||
|
||||
return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
|
||||
}
|
||||
|
||||
GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
|
||||
{
|
||||
GpStatus stat;
|
||||
|
||||
if (!metafile->record_dc || metafile->record_graphics)
|
||||
return InvalidParameter;
|
||||
|
||||
stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
|
||||
|
||||
if (stat == Ok)
|
||||
*result = metafile->record_graphics;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
|
||||
{
|
||||
GpStatus stat;
|
||||
|
||||
stat = METAFILE_WriteEndOfFile(metafile);
|
||||
metafile->record_graphics = NULL;
|
||||
|
||||
metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
|
||||
metafile->record_dc = NULL;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
|
||||
{
|
||||
TRACE("(%p,%p)\n", metafile, hEmf);
|
||||
|
||||
if (!metafile || !hEmf || !metafile->hemf)
|
||||
return InvalidParameter;
|
||||
|
||||
*hEmf = metafile->hemf;
|
||||
metafile->hemf = NULL;
|
||||
|
||||
return Ok;
|
||||
}
|
|
@ -161,8 +161,26 @@ static void test_empty(void)
|
|||
|
||||
hdc = CreateCompatibleDC(0);
|
||||
|
||||
stat = GdipRecordMetafile(NULL, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, MetafileTypeInvalid, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, MetafileTypeWmf, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, MetafileTypeWmfPlaceable, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, MetafileTypeEmfPlusDual+1, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, NULL);
|
||||
expect(InvalidParameter, stat);
|
||||
|
||||
stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile);
|
||||
todo_wine expect(Ok, stat);
|
||||
expect(Ok, stat);
|
||||
|
||||
DeleteDC(hdc);
|
||||
|
||||
|
|
Loading…
Reference in New Issue