+ hr = IWICImagingFactory_CreateStream(factory, &stream);
+ IWICImagingFactory_Release(factory);
+ if (hr != S_OK)
+ return GenericError;
+
+ if (IWICStream_InitializeFromMemory(stream, bitmapdata->BitmapData, data_size) == S_OK)
+ status = GdipCreateBitmapFromStream((IStream *)stream, (GpBitmap **)image);
+ else
+ status = GenericError;
+
+ IWICStream_Release(stream);
+ break;
+ }
+ default:
+ WARN("Invalid bitmap type %d.\n", bitmapdata->Type);
+ return InvalidParameter;
+ }
+ break;
+ }
+ default:
+ FIXME("image type %d not supported.\n", data->Type);
+ return NotImplemented;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath **path)
+{
+ EmfPlusPath *data = (EmfPlusPath *)record_data;
+ GpStatus status;
+ BYTE *types;
+ UINT size;
+ DWORD i;
+
+ *path = NULL;
+
+ if (data_size <= FIELD_OFFSET(EmfPlusPath, data))
+ return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusPath, data);
+
+ if (data->PathPointFlags & 0x800) /* R */
+ {
+ FIXME("RLE encoded path data is not supported.\n");
+ return NotImplemented;
+ }
+ else
+ {
+ if (data->PathPointFlags & 0x4000) /* C */
+ size = sizeof(EmfPlusPoint);
+ else
+ size = sizeof(EmfPlusPointF);
+ size += sizeof(BYTE); /* EmfPlusPathPointType */
+ size *= data->PathPointCount;
+ }
+
+ if (data_size < size)
+ return InvalidParameter;
+
+ status = GdipCreatePath(FillModeAlternate, path);
+ if (status != Ok)
+ return status;
+
+ (*path)->pathdata.Count = data->PathPointCount;
+ (*path)->pathdata.Points = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Points));
+ (*path)->pathdata.Types = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Types));
+ (*path)->datalen = (*path)->pathdata.Count;
+
+ if (!(*path)->pathdata.Points || !(*path)->pathdata.Types)
+ {
+ GdipDeletePath(*path);
+ return OutOfMemory;
+ }
+
+ if (data->PathPointFlags & 0x4000) /* C */
+ {
+ EmfPlusPoint *points = (EmfPlusPoint *)data->data;
+ for (i = 0; i < data->PathPointCount; i++)
+ {
+ (*path)->pathdata.Points[i].X = points[i].X;
+ (*path)->pathdata.Points[i].Y = points[i].Y;
+ }
+ types = (BYTE *)(points + i);
+ }
+ else
+ {
+ EmfPlusPointF *points = (EmfPlusPointF *)data->data;
+ memcpy((*path)->pathdata.Points, points, sizeof(*points) * data->PathPointCount);
+ types = (BYTE *)(points + data->PathPointCount);
+ }
+
+ memcpy((*path)->pathdata.Types, types, sizeof(*types) * data->PathPointCount);
+
+ return Ok;
+}
+
+static GpStatus metafile_read_region_node(struct memory_buffer *mbuf, GpRegion *region, region_element *node, UINT *count)
+{
+ const DWORD *type;
+ GpStatus status;
+
+ type = buffer_read(mbuf, sizeof(*type));
+ if (!type) return Ok;
+
+ node->type = *type;
+
+ switch (node->type)
+ {
+ case CombineModeReplace:
+ case CombineModeIntersect:
+ case CombineModeUnion:
+ case CombineModeXor:
+ case CombineModeExclude:
+ case CombineModeComplement:
+ {
+ region_element *left, *right;
+
+ left = heap_alloc_zero(sizeof(*left));
+ if (!left)
+ return OutOfMemory;
+
+ right = heap_alloc_zero(sizeof(*right));
+ if (!right)
+ {
+ heap_free(left);
+ return OutOfMemory;
+ }
+
+ status = metafile_read_region_node(mbuf, region, left, count);
+ if (status == Ok)
+ {
+ status = metafile_read_region_node(mbuf, region, right, count);
+ if (status == Ok)
+ {
+ node->elementdata.combine.left = left;
+ node->elementdata.combine.right = right;
+ region->num_children += 2;
+ return Ok;
+ }
+ }
+
+ heap_free(left);
+ heap_free(right);
+ return status;
+ }
+ case RegionDataRect:
+ {
+ const EmfPlusRectF *rect;
+
+ rect = buffer_read(mbuf, sizeof(*rect));
+ if (!rect)
+ return InvalidParameter;
+
+ memcpy(&node->elementdata.rect, rect, sizeof(*rect));
+ *count += 1;
+ return Ok;
+ }
+ case RegionDataPath:
+ {
+ const BYTE *path_data;
+ const UINT *data_size;
+ GpPath *path;
+
+ data_size = buffer_read(mbuf, FIELD_OFFSET(EmfPlusRegionNodePath, RegionNodePath));
+ if (!data_size)
+ return InvalidParameter;
+
+ path_data = buffer_read(mbuf, *data_size);
+ if (!path_data)
+ return InvalidParameter;
+
+ status = metafile_deserialize_path(path_data, *data_size, &path);
+ if (status == Ok)
+ {
+ node->elementdata.path = path;
+ *count += 1;
+ }
+ return Ok;
+ }
+ case RegionDataEmptyRect:
+ case RegionDataInfiniteRect:
+ *count += 1;
+ return Ok;
+ default:
+ FIXME("element type %#x is not supported\n", *type);
+ break;
+ }
+
+ return InvalidParameter;
+}
+
+static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size, GpRegion **region)
+{
+ struct memory_buffer mbuf;
+ GpStatus status;
+ UINT count;
+
+ *region = NULL;
+
+ init_memory_buffer(&mbuf, record_data, data_size);
+
+ if (!buffer_read(&mbuf, FIELD_OFFSET(EmfPlusRegion, RegionNode)))
+ return InvalidParameter;
+
+ status = GdipCreateRegion(region);
+ if (status != Ok)
+ return status;
+
+ count = 0;
+ status = metafile_read_region_node(&mbuf, *region, &(*region)->node, &count);
+ if (status == Ok && !count)
+ status = InvalidParameter;
+
+ if (status != Ok)
+ {
+ GdipDeleteRegion(*region);
+ *region = NULL;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
+{
+ static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
+ EmfPlusBrush *data = (EmfPlusBrush *)record_data;
+ EmfPlusTransformMatrix *transform = NULL;
+ DWORD brushflags;
+ GpStatus status;
+ UINT offset;
+
+ *brush = NULL;
+
+ if (data_size < header_size)
+ return InvalidParameter;
+
+ switch (data->Type)
+ {
+ case BrushTypeSolidColor:
+ if (data_size != header_size + sizeof(EmfPlusSolidBrushData))
+ return InvalidParameter;
+
+ status = GdipCreateSolidFill(data->BrushData.solid.SolidColor, (GpSolidFill **)brush);
+ break;
+ case BrushTypeHatchFill:
+ if (data_size != header_size + sizeof(EmfPlusHatchBrushData))
+ return InvalidParameter;
+
+ status = GdipCreateHatchBrush(data->BrushData.hatch.HatchStyle, data->BrushData.hatch.ForeColor,
+ data->BrushData.hatch.BackColor, (GpHatch **)brush);
+ break;
+ case BrushTypeTextureFill:
+ {
+ GpImage *image;
+
+ offset = header_size + FIELD_OFFSET(EmfPlusTextureBrushData, OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ brushflags = data->BrushData.texture.BrushDataFlags;
+ if (brushflags & BrushDataTransform)
+ {
+ if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
+ return InvalidParameter;
+ transform = (EmfPlusTransformMatrix *)(record_data + offset);
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ status = metafile_deserialize_image(record_data + offset, data_size - offset, &image);
+ if (status != Ok)
+ return status;
+
+ status = GdipCreateTexture(image, data->BrushData.texture.WrapMode, (GpTexture **)brush);
+ if (status == Ok && transform && !(brushflags & BrushDataDoNotTransform))
+ GdipSetTextureTransform((GpTexture *)*brush, (const GpMatrix *)transform);
+
+ GdipDisposeImage(image);
+ break;
+ }
+ case BrushTypeLinearGradient:
+ {
+ GpLineGradient *gradient = NULL;
+ GpPointF startpoint, endpoint;
+ UINT position_count = 0;
+
+ offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData, OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ brushflags = data->BrushData.lineargradient.BrushDataFlags;
+ if ((brushflags & BrushDataPresetColors) && (brushflags & (BrushDataBlendFactorsH | BrushDataBlendFactorsV)))
+ return InvalidParameter;
+
+ if (brushflags & BrushDataTransform)
+ {
+ if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
+ return InvalidParameter;
+ transform = (EmfPlusTransformMatrix *)(record_data + offset);
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ if (brushflags & (BrushDataPresetColors | BrushDataBlendFactorsH | BrushDataBlendFactorsV))
+ {
+ if (data_size <= offset + sizeof(DWORD)) /* Number of factors/preset colors. */
+ return InvalidParameter;
+ position_count = *(DWORD *)(record_data + offset);
+ offset += sizeof(DWORD);
+ }
+
+ if (brushflags & BrushDataPresetColors)
+ {
+ if (data_size != offset + position_count * (sizeof(float) + sizeof(EmfPlusARGB)))
+ return InvalidParameter;
+ }
+ else if (brushflags & BrushDataBlendFactorsH)
+ {
+ if (data_size != offset + position_count * 2 * sizeof(float))
+ return InvalidParameter;
+ }
+
+ startpoint.X = data->BrushData.lineargradient.RectF.X;
+ startpoint.Y = data->BrushData.lineargradient.RectF.Y;
+ endpoint.X = startpoint.X + data->BrushData.lineargradient.RectF.Width;
+ endpoint.Y = startpoint.Y + data->BrushData.lineargradient.RectF.Height;
+
+ status = GdipCreateLineBrush(&startpoint, &endpoint, data->BrushData.lineargradient.StartColor,
+ data->BrushData.lineargradient.EndColor, data->BrushData.lineargradient.WrapMode, &gradient);
+ if (status == Ok)
+ {
+ if (transform)
+ status = GdipSetLineTransform(gradient, (const GpMatrix *)transform);
+
+ if (status == Ok)
+ {
+ if (brushflags & BrushDataPresetColors)
+ status = GdipSetLinePresetBlend(gradient, (ARGB *)(record_data + offset +
+ position_count * sizeof(REAL)), (REAL *)(record_data + offset), position_count);
+ else if (brushflags & BrushDataBlendFactorsH)
+ status = GdipSetLineBlend(gradient, (REAL *)(record_data + offset + position_count * sizeof(REAL)),
+ (REAL *)(record_data + offset), position_count);
+
+ if (brushflags & BrushDataIsGammaCorrected)
+ FIXME("BrushDataIsGammaCorrected is not handled.\n");
+ }
+ }
+
+ if (status == Ok)
+ *brush = (GpBrush *)gradient;
+ else
+ GdipDeleteBrush((GpBrush *)gradient);
+
+ break;
+ }
+ default:
+ FIXME("brush type %u is not supported.\n", data->Type);
+ return NotImplemented;
+ }
+
+ return status;
+}
+
+static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size, DWORD *ret)
+{
+ EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
+ DWORD offset = FIELD_OFFSET(EmfPlusPen, data);
+
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += FIELD_OFFSET(EmfPlusPenData, OptionalData);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ if (pendata->PenDataFlags & PenDataTransform)
+ offset += sizeof(EmfPlusTransformMatrix);
+
+ if (pendata->PenDataFlags & PenDataStartCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataEndCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataJoin)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataMiterLimit)
+ offset += sizeof(REAL);
+
+ if (pendata->PenDataFlags & PenDataLineStyle)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataDashedLineCap)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataDashedLineOffset)
+ offset += sizeof(REAL);
+
+ if (pendata->PenDataFlags & PenDataDashedLine)
+ {
+ EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)data + offset);
+
+ offset += FIELD_OFFSET(EmfPlusDashedLineData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += dashedline->DashedLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataNonCenter)
+ offset += sizeof(DWORD);
+
+ if (pendata->PenDataFlags & PenDataCompoundLine)
+ {
+ EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE *)data + offset);
+
+ offset += FIELD_OFFSET(EmfPlusCompoundLineData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += compoundline->CompoundLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomStartCap)
+ {
+ EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)data + offset);
+
+ offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += startcap->CustomStartCapSize;
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomEndCap)
+ {
+ EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)data + offset);
+
+ offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data);
+ if (data_size <= offset)
+ return InvalidParameter;
+
+ offset += endcap->CustomEndCapSize;
+ }
+
+ *ret = offset;
+ return Ok;
+}
+
+static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size, const BYTE *record_data)
+{
+ BYTE type = (flags >> 8) & 0xff;
+ BYTE id = flags & 0xff;
+ void *object = NULL;
+ GpStatus status;
+
+ if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize)
+ return InvalidParameter;
+
+ switch (type)
+ {
+ case ObjectTypeBrush:
+ status = metafile_deserialize_brush(record_data, data_size, (GpBrush **)&object);
+ break;
+ case ObjectTypePen:
+ {
+ EmfPlusPen *data = (EmfPlusPen *)record_data;
+ EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
+ GpBrush *brush;
+ DWORD offset;
+ GpPen *pen;
+
+ status = metafile_get_pen_brush_data_offset(data, data_size, &offset);
+ if (status != Ok)
+ return status;
+
+ status = metafile_deserialize_brush(record_data + offset, data_size - offset, &brush);
+ if (status != Ok)
+ return status;
+
+ status = GdipCreatePen2(brush, pendata->PenWidth, pendata->PenUnit, &pen);
+ GdipDeleteBrush(brush);
+ if (status != Ok)
+ return status;
+
+ offset = FIELD_OFFSET(EmfPlusPenData, OptionalData);
+
+ if (pendata->PenDataFlags & PenDataTransform)
+ {
+ FIXME("PenDataTransform is not supported.\n");
+ offset += sizeof(EmfPlusTransformMatrix);
+ }
+
+ if (pendata->PenDataFlags & PenDataStartCap)
+ {
+ if ((status = GdipSetPenStartCap(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataEndCap)
+ {
+ if ((status = GdipSetPenEndCap(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataJoin)
+ {
+ if ((status = GdipSetPenLineJoin(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataMiterLimit)
+ {
+ if ((status = GdipSetPenMiterLimit(pen, *(REAL *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(REAL);
+ }
+
+ if (pendata->PenDataFlags & PenDataLineStyle)
+ {
+ if ((status = GdipSetPenDashStyle(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLineCap)
+ {
+ FIXME("PenDataDashedLineCap is not supported.\n");
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLineOffset)
+ {
+ if ((status = GdipSetPenDashOffset(pen, *(REAL *)((BYTE *)pendata + offset))) != Ok)
+ goto penfailed;
+ offset += sizeof(REAL);
+ }
+
+ if (pendata->PenDataFlags & PenDataDashedLine)
+ {
+ EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)pendata + offset);
+ FIXME("PenDataDashedLine is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusDashedLineData, data) + dashedline->DashedLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataNonCenter)
+ {
+ FIXME("PenDataNonCenter is not supported.\n");
+ offset += sizeof(DWORD);
+ }
+
+ if (pendata->PenDataFlags & PenDataCompoundLine)
+ {
+ EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE *)pendata + offset);
+ FIXME("PenDataCompundLine is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCompoundLineData, data) + compoundline->CompoundLineDataSize * sizeof(float);
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomStartCap)
+ {
+ EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)pendata + offset);
+ FIXME("PenDataCustomStartCap is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data) + startcap->CustomStartCapSize;
+ }
+
+ if (pendata->PenDataFlags & PenDataCustomEndCap)
+ {
+ EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata + offset);
+ FIXME("PenDataCustomEndCap is not supported.\n");
+ offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data) + endcap->CustomEndCapSize;
+ }
+
+ object = pen;
+ break;
+
+ penfailed:
+ GdipDeletePen(pen);
+ return status;
+ }
+ case ObjectTypePath:
+ status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
+ break;
+ case ObjectTypeRegion:
+ status = metafile_deserialize_region(record_data, data_size, (GpRegion **)&object);
+ break;
+ case ObjectTypeImage:
+ status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
+ break;
+ case ObjectTypeFont:
+ {
+ EmfPlusFont *data = (EmfPlusFont *)record_data;
+ GpFontFamily *family;
+ WCHAR *familyname;
+
+ if (data_size <= FIELD_OFFSET(EmfPlusFont, FamilyName))
+ return InvalidParameter;
+ data_size -= FIELD_OFFSET(EmfPlusFont, FamilyName);
+
+ if (data_size < data->Length * sizeof(WCHAR))
+ return InvalidParameter;
+
+ if (!(familyname = GdipAlloc((data->Length + 1) * sizeof(*familyname))))
+ return OutOfMemory;
+
+ memcpy(familyname, data->FamilyName, data->Length * sizeof(*familyname));
+ familyname[data->Length] = 0;
+
+ status = GdipCreateFontFamilyFromName(familyname, NULL, &family);
+ GdipFree(familyname);
+ if (status != Ok)
+ return InvalidParameter;
+
+ status = GdipCreateFont(family, data->EmSize, data->FontStyleFlags, data->SizeUnit, (GpFont **)&object);
+ GdipDeleteFontFamily(family);
+ break;
+ }
+ case ObjectTypeImageAttributes:
+ {
+ EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data;
+ GpImageAttributes *attributes = NULL;
+
+ if (data_size != sizeof(*data))
+ return InvalidParameter;
+
+ if ((status = GdipCreateImageAttributes(&attributes)) != Ok)
+ return status;
+
+ status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD *)&data->ClampColor,
+ !!data->ObjectClamp);
+ if (status == Ok)
+ object = attributes;
+ else
+ GdipDisposeImageAttributes(attributes);
+ break;
+ }
+ default:
+ FIXME("not implemented for object type %d.\n", type);
+ return NotImplemented;
+ }
+
+ if (status == Ok)
+ metafile_set_object_table_entry(metafile, id, type, object);
+
+ return status;
+}
+
+static GpStatus metafile_set_clip_region(GpMetafile *metafile, GpRegion *region, CombineMode mode)
+{
+ GpMatrix world_to_device;
+
+ get_graphics_transform(metafile->playback_graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
+
+ GdipTransformRegion(region, &world_to_device);
+ GdipCombineRegionRegion(metafile->clip, region, mode);
+
+ return METAFILE_PlaybackUpdateClip(metafile);
+}
+
+GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
+ EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
+{
+ GpStatus stat;
+ GpMetafile *real_metafile = (GpMetafile*)metafile;
+
+ TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
+
+ if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
+ return InvalidParameter;
+
+ if (recordType >= 1 && recordType <= 0x7a)
+ {
+ /* regular EMF record */
+ if (metafile->playback_dc)
+ {
+ switch (recordType)
+ {
+ case EMR_SETMAPMODE:
+ case EMR_SAVEDC:
+ case EMR_RESTOREDC:
+ case EMR_SETWINDOWORGEX:
+ case EMR_SETWINDOWEXTEX:
+ case EMR_SETVIEWPORTORGEX:
+ case EMR_SETVIEWPORTEXTEX:
+ case EMR_SCALEVIEWPORTEXTEX:
+ case EMR_SCALEWINDOWEXTEX:
+ case EMR_MODIFYWORLDTRANSFORM:
+ FIXME("not implemented for record type %x\n", recordType);
+ break;
+ case EMR_SETWORLDTRANSFORM:
+ {
+ const XFORM* xform = (void*)data;
+ real_metafile->gdiworldtransform = *xform;
+ METAFILE_PlaybackUpdateGdiTransform(real_metafile);
+ break;
+ }
+ case EMR_EXTSELECTCLIPRGN:
+ {
+ DWORD rgndatasize = *(DWORD*)data;
+ DWORD mode = *(DWORD*)(data + 4);
+ const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
+ HRGN hrgn = NULL;
+
+ if (dataSize > 8)
+ {
+ XFORM final;
+
+ METAFILE_GetFinalGdiTransform(metafile, &final);
+
+ hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
+ }
+
+ ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
+
+ DeleteObject(hrgn);
+
+ return Ok;
+ }
+ default:
+ {
+ ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
+
+ if (record)
+ {
+ record->iType = recordType;
+ record->nSize = dataSize + 8;
+ memcpy(record->dParm, data, dataSize);
+
+ if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
+ record, metafile->handle_count) == 0)
+ ERR("PlayEnhMetaFileRecord failed\n");
+
+ heap_free(record);
+ }
+ else
+ return OutOfMemory;
+
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
+
+ METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
+
+ switch(recordType)
+ {
+ case EmfPlusRecordTypeHeader:
+ case EmfPlusRecordTypeEndOfFile: