* Sync with Wine 1.7.17.
CORE-8080
svn path=/trunk/; revision=62888
/******************************************************************************
* GdipCreateTextureIA [GDIPLUS.@]
- *
- * FIXME: imageattr ignored
*/
GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
imageattr->wrap = wrapmode;
stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
+ GdipDisposeImageAttributes(imageattr);
}
return stat;
/*****************************************************************************
* GdipPrivateAddFontFile [GDIPLUS.@]
*/
-GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection,
- GDIPCONST WCHAR* filename)
+GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name)
{
- FIXME("stub: %p, %s\n", fontCollection, debugstr_w(filename));
+ HANDLE file, mapping;
+ LARGE_INTEGER size;
+ void *mem;
+ GpStatus status;
+
+ TRACE("%p, %s\n", collection, debugstr_w(name));
+
+ if (!collection || !name) return InvalidParameter;
- if (!(fontCollection && filename))
+ file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE) return InvalidParameter;
+
+ if (!GetFileSizeEx(file, &size) || size.u.HighPart)
+ {
+ CloseHandle(file);
return InvalidParameter;
+ }
+
+ mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
+ CloseHandle(file);
+ if (!mapping) return InvalidParameter;
+
+ mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(mapping);
+ if (!mem) return InvalidParameter;
+
+ /* GdipPrivateAddMemoryFont creates a copy of the memory block */
+ status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart);
+ UnmapViewOfFile(mem);
- return NotImplemented;
+ return status;
}
#define TT_PLATFORM_APPLE_UNICODE 0
}
/* Calculates Bezier points from cardinal spline points. */
-void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
+void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2)
{
REAL xdiff, ydiff;
case RegionDataRect:
break;
case RegionDataPath:
- GdipDeletePath(element->elementdata.pathdata.path);
+ GdipDeletePath(element->elementdata.path);
break;
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
}
}
-const char *debugstr_rectf(CONST RectF* rc)
+const char *debugstr_rectf(const RectF* rc)
{
if (!rc) return "(null)";
return wine_dbg_sprintf("(%0.2f,%0.2f,%0.2f,%0.2f)", rc->X, rc->Y, rc->Width, rc->Height);
}
-const char *debugstr_pointf(CONST PointF* pt)
+const char *debugstr_pointf(const PointF* pt)
{
if (!pt) return "(null)";
return wine_dbg_sprintf("(%0.2f,%0.2f)", pt->X, pt->Y);
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
+ GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
+extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
-extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) DECLSPEC_HIDDEN;
-extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
+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,
REAL tension, REAL *x, REAL *y) DECLSPEC_HIDDEN;
return (a<<24)|(r<<16)|(g<<8)|b;
}
-extern const char *debugstr_rectf(CONST RectF* rc) DECLSPEC_HIDDEN;
+extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
-extern const char *debugstr_pointf(CONST PointF* pt) DECLSPEC_HIDDEN;
+extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride) DECLSPEC_HIDDEN;
GpGraphics *playback_graphics;
HDC playback_dc;
GpPointF playback_points[3];
+ GpRectF src_rect;
HANDLETABLE *handle_table;
int handle_count;
+ GpMatrix *world_transform;
+ GpUnit page_unit;
+ REAL page_scale;
};
struct GpBitmap{
union
{
GpRectF rect;
- struct
- {
- GpPath* path;
- struct
- {
- DWORD size;
- DWORD magic;
- DWORD count;
- DWORD flags;
- } pathheader;
- } pathdata;
+ GpPath *path;
struct
{
struct region_element *left; /* the original region */
};
struct GpRegion{
- struct
- {
- DWORD size;
- DWORD checksum;
- DWORD magic;
- DWORD num_children;
- } header;
+ DWORD num_children;
region_element node;
};
return (a << 24) | (r << 16) | (g << 8) | b;
}
-static int color_is_gray(ARGB color)
+static BOOL color_is_gray(ARGB color)
{
unsigned char r, g, b;
return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
}
-static INT brush_can_fill_path(GpBrush *brush)
+static BOOL brush_can_fill_path(GpBrush *brush)
{
switch (brush->bt)
{
case BrushTypeSolidColor:
- return 1;
+ return TRUE;
case BrushTypeHatchFill:
{
GpHatch *hatch = (GpHatch*)brush;
case BrushTypeTextureFill:
/* Gdi32 isn't much help with these, so we should use brush_fill_pixels instead. */
default:
- return 0;
+ return FALSE;
}
}
}
}
-static INT brush_can_fill_pixels(GpBrush *brush)
+static BOOL brush_can_fill_pixels(GpBrush *brush)
{
switch (brush->bt)
{
case BrushTypeLinearGradient:
case BrushTypeTextureFill:
case BrushTypePathGradient:
- return 1;
+ return TRUE;
default:
- return 0;
+ return FALSE;
}
}
INT min_y, max_y, min_x, max_x;
INT x, y;
ARGB outer_color;
- static int transform_fixme_once;
+ static BOOL transform_fixme_once;
if (fill->focus.X != 0.0 || fill->focus.Y != 0.0)
{
if (!is_identity)
{
FIXME("path gradient transform not implemented\n");
- transform_fixme_once = 1;
+ transform_fixme_once = TRUE;
}
}
for (i=0; i<flat_path->pathdata.Count; i++)
{
int start_center_line=0, end_center_line=0;
- int seen_start=0, seen_end=0, seen_center=0;
+ BOOL seen_start = FALSE, seen_end = FALSE, seen_center = FALSE;
REAL center_distance;
ARGB start_color, end_color;
REAL dy, dx;
if (!seen_start && yf >= start_point.Y)
{
- seen_start = 1;
+ seen_start = TRUE;
start_center_line ^= 1;
}
if (!seen_end && yf >= end_point.Y)
{
- seen_end = 1;
+ seen_end = TRUE;
end_center_line ^= 1;
}
if (!seen_center && yf >= center_point.Y)
{
- seen_center = 1;
+ seen_center = TRUE;
start_center_line ^= 1;
end_center_line ^= 1;
}
return GdipCreateFromHWND(hwnd, graphics);
}
-GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
- GpMetafile **metafile)
-{
- ENHMETAHEADER header;
- MetafileType metafile_type;
-
- TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
-
- if(!hemf || !metafile)
- return InvalidParameter;
-
- if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
- return GenericError;
-
- metafile_type = METAFILE_GetEmfType(hemf);
-
- if (metafile_type == MetafileTypeInvalid)
- return GenericError;
-
- *metafile = GdipAlloc(sizeof(GpMetafile));
- if (!*metafile)
- return OutOfMemory;
-
- (*metafile)->image.type = ImageTypeMetafile;
- (*metafile)->image.format = ImageFormatEMF;
- (*metafile)->image.frame_count = 1;
- (*metafile)->image.xres = (REAL)header.szlDevice.cx;
- (*metafile)->image.yres = (REAL)header.szlDevice.cy;
- (*metafile)->bounds.X = (REAL)header.rclBounds.left;
- (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
- (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
- (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
- (*metafile)->unit = UnitPixel;
- (*metafile)->metafile_type = metafile_type;
- (*metafile)->hemf = hemf;
- (*metafile)->preserve_hemf = !delete;
-
- TRACE("<-- %p\n", *metafile);
-
- return Ok;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
- GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
-{
- UINT read;
- BYTE *copy;
- HENHMETAFILE hemf;
- GpStatus retval = Ok;
-
- TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
-
- if(!hwmf || !metafile || !placeable)
- return InvalidParameter;
-
- *metafile = NULL;
- read = GetMetaFileBitsEx(hwmf, 0, NULL);
- if(!read)
- return GenericError;
- copy = GdipAlloc(read);
- GetMetaFileBitsEx(hwmf, read, copy);
-
- hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
- GdipFree(copy);
-
- /* FIXME: We should store and use hwmf instead of converting to hemf */
- retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
-
- if (retval == Ok)
- {
- (*metafile)->image.xres = (REAL)placeable->Inch;
- (*metafile)->image.yres = (REAL)placeable->Inch;
- (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
- (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
- (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
- placeable->BoundingBox.Left);
- (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
- placeable->BoundingBox.Top);
- (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
- (*metafile)->image.format = ImageFormatWMF;
-
- if (delete) DeleteMetaFile(hwmf);
- }
- else
- DeleteEnhMetaFile(hemf);
- return retval;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
- GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
-{
- HMETAFILE hmf = GetMetaFileW(file);
-
- TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
-
- if(!hmf) return InvalidParameter;
-
- return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
- GpMetafile **metafile)
-{
- FIXME("(%p, %p): stub\n", file, metafile);
- return NotImplemented;
-}
-
-GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
- GpMetafile **metafile)
-{
- FIXME("(%p, %p): stub\n", stream, metafile);
- return NotImplemented;
-}
-
GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
UINT access, IStream **stream)
{
}
GdipDeleteRegion(graphics->clip);
+
+ /* Native returns ObjectBusy on the second free, instead of crashing as we'd
+ * do otherwise, but we can't have that in the test suite because it means
+ * accessing freed memory. */
+ graphics->busy = TRUE;
+
GdipFree(graphics);
return Ok;
debugstr_pointf(&points[2]));
memcpy(ptf, points, 3 * sizeof(GpPointF));
+
+ /* Ensure source width/height is positive */
+ if (srcwidth < 0)
+ {
+ GpPointF tmp = ptf[1];
+ srcx = srcx + srcwidth;
+ srcwidth = -srcwidth;
+ ptf[2].X = ptf[2].X + ptf[1].X - ptf[0].X;
+ ptf[2].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
+ ptf[1] = ptf[0];
+ ptf[0] = tmp;
+ }
+
+ if (srcheight < 0)
+ {
+ GpPointF tmp = ptf[2];
+ srcy = srcy + srcheight;
+ srcheight = -srcheight;
+ ptf[1].X = ptf[1].X + ptf[2].X - ptf[0].X;
+ ptf[1].Y = ptf[1].Y + ptf[2].Y - ptf[0].Y;
+ ptf[2] = ptf[0];
+ ptf[0] = tmp;
+ }
+
ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X;
ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
- if (!srcwidth || !srcheight || ptf[3].X == ptf[0].X || ptf[3].Y == ptf[0].Y)
+ if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y))
return Ok;
transform_and_round_points(graphics, pti, ptf, 4);
else if (image->type == ImageTypeBitmap)
{
GpBitmap* bitmap = (GpBitmap*)image;
- int use_software=0;
+ BOOL use_software = FALSE;
TRACE("graphics: %.2fx%.2f dpi, fmt %#x, scale %f, image: %.2fx%.2f dpi, fmt %#x, color %08x\n",
graphics->xres, graphics->yres,
ptf[1].X - ptf[0].X != srcwidth || ptf[2].Y - ptf[0].Y != srcheight ||
srcx < 0 || srcy < 0 ||
srcx + srcwidth > bitmap->width || srcy + srcheight > bitmap->height)
- use_software = 1;
+ use_software = TRUE;
if (use_software)
{
RECT dst_area;
+ GpRectF graphics_bounds;
GpRect src_area;
int i, x, y, src_stride, dst_stride;
GpMatrix dst_to_src;
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
}
+ stat = get_graphics_bounds(graphics, &graphics_bounds);
+ if (stat != Ok) return stat;
+
+ if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
+ if (graphics_bounds.Y > dst_area.top) dst_area.top = floorf(graphics_bounds.Y);
+ if (graphics_bounds.X + graphics_bounds.Width < dst_area.right) dst_area.right = ceilf(graphics_bounds.X + graphics_bounds.Width);
+ if (graphics_bounds.Y + graphics_bounds.Height < dst_area.bottom) dst_area.bottom = ceilf(graphics_bounds.Y + graphics_bounds.Height);
+
TRACE("dst_area: %s\n", wine_dbgstr_rect(&dst_area));
+ if (IsRectEmpty(&dst_area)) return Ok;
+
m11 = (ptf[1].X - ptf[0].X) / srcwidth;
m21 = (ptf[2].X - ptf[0].X) / srcheight;
mdx = ptf[0].X - m11 * srcx - m21 * srcy;
if (stat != Ok)
{
- if (src_data != dst_data)
- GdipFree(src_data);
+ GdipFree(src_data);
GdipFree(dst_data);
return stat;
}
else
{
HDC hdc;
- int temp_hdc=0, temp_bitmap=0;
+ BOOL temp_hdc = FALSE, temp_bitmap = FALSE;
HBITMAP hbitmap, old_hbm=NULL;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
/* we can't draw a bitmap of this format directly */
hdc = CreateCompatibleDC(0);
- temp_hdc = 1;
- temp_bitmap = 1;
+ temp_hdc = TRUE;
+ temp_bitmap = TRUE;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = bitmap->width;
else
{
GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
- temp_bitmap = 1;
+ temp_bitmap = TRUE;
}
hdc = bitmap->hdc;
{
INT save_state;
GpStatus retval;
+ HRGN hrgn=NULL;
TRACE("(%p, %p, %p)\n", graphics, pen, path);
save_state = prepare_dc(graphics, pen);
+ retval = get_clip_hrgn(graphics, &hrgn);
+
+ if (retval != Ok)
+ goto end;
+
+ if (hrgn)
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
retval = draw_poly(graphics, pen, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, TRUE);
+end:
restore_dc(graphics, save_state);
+ DeleteObject(hrgn);
return retval;
}
{
INT save_state;
GpStatus retval;
+ HRGN hrgn=NULL;
if(!graphics->hdc || !brush_can_fill_path(brush))
return NotImplemented;
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
: WINDING));
+ retval = get_clip_hrgn(graphics, &hrgn);
+
+ if (retval != Ok)
+ goto end;
+
+ if (hrgn)
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
BeginPath(graphics->hdc);
retval = draw_poly(graphics, NULL, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, FALSE);
end:
RestoreDC(graphics->hdc, save_state);
+ DeleteObject(hrgn);
return retval;
}
GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
REAL x, REAL y, REAL width, REAL height)
{
- GpStatus stat;
- GpPath *path;
+ GpRectF rect;
TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
- if(!graphics || !brush)
- return InvalidParameter;
-
- if(graphics->busy)
- return ObjectBusy;
-
- stat = GdipCreatePath(FillModeAlternate, &path);
-
- if (stat == Ok)
- {
- stat = GdipAddPathRectangle(path, x, y, width, height);
-
- if (stat == Ok)
- stat = GdipFillPath(graphics, brush, path);
-
- GdipDeletePath(path);
- }
+ rect.X = x;
+ rect.Y = y;
+ rect.Width = width;
+ rect.Height = height;
- return stat;
+ return GdipFillRectangles(graphics, brush, &rect, 1);
}
GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
INT x, INT y, INT width, INT height)
{
+ GpRectF rect;
+
TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
- return GdipFillRectangle(graphics, brush, x, y, width, height);
+ rect.X = (REAL)x;
+ rect.Y = (REAL)y;
+ rect.Width = (REAL)width;
+ rect.Height = (REAL)height;
+
+ return GdipFillRectangles(graphics, brush, &rect, 1);
}
GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects,
TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
- if(!rects)
+ if(!graphics || !brush || !rects || count <= 0)
return InvalidParameter;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ status = METAFILE_FillRectangles((GpMetafile*)graphics->image, brush, rects, count);
+ /* FIXME: Add gdi32 drawing. */
+ return status;
+ }
+
status = GdipCreatePath(FillModeAlternate, &path);
if (status != Ok) return status;
INT *hotkeyprefix_offsets=NULL;
INT hotkeyprefix_count=0;
INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0;
- int seen_prefix=0;
+ BOOL seen_prefix = FALSE;
+ GpStringFormat *dyn_format=NULL;
if(length == -1) length = lstrlenW(string);
stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
if(!stringdup) return OutOfMemory;
+ if (!format)
+ {
+ stat = GdipStringFormatGetGenericDefault(&dyn_format);
+ if (stat != Ok)
+ {
+ GdipFree(stringdup);
+ return stat;
+ }
+ format = dyn_format;
+ }
+
nwidth = rect->Width;
nheight = rect->Height;
if (ignore_empty_clip)
if (!nheight) nheight = INT_MAX;
}
- if (format)
- hkprefix = format->hkprefix;
- else
- hkprefix = HotkeyPrefixNone;
+ hkprefix = format->hkprefix;
if (hkprefix == HotkeyPrefixShow)
{
hotkeyprefix_offsets[hotkeyprefix_count++] = j;
else if (!seen_prefix && hkprefix != HotkeyPrefixNone && string[i] == '&')
{
- seen_prefix = 1;
+ seen_prefix = TRUE;
continue;
}
- seen_prefix = 0;
+ seen_prefix = FALSE;
stringdup[j] = string[i];
j++;
length = j;
- if (format) halign = format->align;
- else halign = StringAlignmentNear;
+ halign = format->align;
while(sum < length){
GetTextExtentExPointW(hdc, stringdup + sum, length - sum,
bounds.Width = size.cx;
if(height + size.cy > nheight)
+ {
+ if (format->attr & StringFormatFlagsLineLimit)
+ break;
bounds.Height = nheight - (height + size.cy);
+ }
else
bounds.Height = size.cy;
break;
/* Stop if this was a linewrap (but not if it was a linebreak). */
- if ((lret == fitcpy) && format &&
- (format->attr & (StringFormatFlagsNoWrap | StringFormatFlagsLineLimit)))
+ if ((lret == fitcpy) && (format->attr & StringFormatFlagsNoWrap))
break;
}
GdipFree(stringdup);
GdipFree(hotkeyprefix_offsets);
+ GdipDeleteStringFormat(dyn_format);
return stat;
}
GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
{
+ GpStatus stat;
+
TRACE("(%p, %.2f)\n", graphics, scale);
if(!graphics || (scale <= 0.0))
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, graphics->unit, scale);
+ if (stat != Ok)
+ return stat;
+ }
+
graphics->scale = scale;
return Ok;
GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
{
+ GpStatus stat;
+
TRACE("(%p, %d)\n", graphics, unit);
if(!graphics)
if(unit == UnitWorld)
return InvalidParameter;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ stat = METAFILE_SetPageTransform((GpMetafile*)graphics->image, unit, graphics->scale);
+ if (stat != Ok)
+ return stat;
+ }
+
graphics->unit = unit;
return Ok;
return status;
}
-GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
- UINT limitDpi)
-{
- static int calls;
-
- TRACE("(%p,%u)\n", metafile, limitDpi);
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- return NotImplemented;
-}
-
GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
INT count)
{
if (glyphsize > max_glyphsize)
max_glyphsize = glyphsize;
- left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
- top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
- right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
- bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
-
- if (left < min_x) min_x = left;
- if (top < min_y) min_y = top;
- if (right > max_x) max_x = right;
- if (bottom > max_y) max_y = bottom;
+ if (glyphsize != 0)
+ {
+ left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
+ top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
+ right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX;
+ bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY;
+
+ if (left < min_x) min_x = left;
+ if (top < min_y) min_y = top;
+ if (right > max_x) max_x = right;
+ if (bottom > max_y) max_y = bottom;
+ }
if (i+1 < length && (flags & DriverStringOptionsRealizedAdvance) == DriverStringOptionsRealizedAdvance)
{
}
}
+ if (max_glyphsize == 0)
+ /* Nothing to draw. */
+ return Ok;
+
glyph_mask = GdipAlloc(max_glyphsize);
text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
text_mask_stride = max_x - min_x;
/* Generate a mask for the text */
for (i=0; i<length; i++)
{
+ DWORD ret;
int left, top, stride;
- GetGlyphOutlineW(hdc, text[i], ggo_flags,
+ ret = GetGlyphOutlineW(hdc, text[i], ggo_flags,
&glyphmetrics, max_glyphsize, glyph_mask, &identity);
+ if (ret == GDI_ERROR || ret == 0)
+ continue; /* empty glyph */
+
left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x;
top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y;
stride = (glyphmetrics.gmBlackBoxX + 3) & (~3);
for (i = index; i < length; ++i)
{
GLYPHMETRICS gm;
- TTPOLYGONHEADER *ph = NULL;
+ TTPOLYGONHEADER *ph = NULL, *origph;
char *start;
DWORD len, ofs = 0;
len = GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
status = GenericError;
break;
}
- ph = GdipAlloc(len);
+ origph = ph = GdipAlloc(len);
start = (char *)ph;
if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
{
x += gm.gmCellIncX * args->scale;
y += gm.gmCellIncY * args->scale;
- GdipFree(ph);
+ GdipFree(origph);
if (status != Ok)
break;
}
}
}
-static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
- path_list_node_t **last_point)
+static void widen_open_figure(const GpPointF *points, GpPen *pen, int start, int end,
+ GpLineCap start_cap, GpCustomLineCap *start_custom, GpLineCap end_cap,
+ GpCustomLineCap *end_custom, path_list_node_t **last_point)
{
int i;
path_list_node_t *prev_point;
prev_point = *last_point;
- widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
- pen, pen->startcap, pen->customstart, FALSE, TRUE, last_point);
+ widen_cap(&points[start], &points[start+1],
+ pen, start_cap, start_custom, FALSE, TRUE, last_point);
for (i=start+1; i<end; i++)
- widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i],
- &path->pathdata.Points[i+1], pen, last_point);
+ widen_joint(&points[i-1], &points[i],
+ &points[i+1], pen, last_point);
- widen_cap(&path->pathdata.Points[end], &path->pathdata.Points[end-1],
- pen, pen->endcap, pen->customend, TRUE, TRUE, last_point);
+ widen_cap(&points[end], &points[end-1],
+ pen, end_cap, end_custom, TRUE, TRUE, last_point);
for (i=end-1; i>start; i--)
- widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i],
- &path->pathdata.Points[i-1], pen, last_point);
+ widen_joint(&points[i+1], &points[i],
+ &points[i-1], pen, last_point);
- widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
- pen, pen->startcap, pen->customstart, TRUE, FALSE, last_point);
+ widen_cap(&points[start], &points[start+1],
+ pen, start_cap, start_custom, TRUE, FALSE, last_point);
prev_point->next->type = PathPointTypeStart;
(*last_point)->type |= PathPointTypeCloseSubpath;
(*last_point)->type |= PathPointTypeCloseSubpath;
}
+static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
+ int closed, path_list_node_t **last_point)
+{
+ int i, j;
+ REAL dash_pos=0.0;
+ int dash_index=0;
+ const REAL *dash_pattern;
+ int dash_count;
+ GpPointF *tmp_points;
+ REAL segment_dy;
+ REAL segment_dx;
+ REAL segment_length;
+ REAL segment_pos;
+ int num_tmp_points=0;
+ int draw_start_cap=0;
+ static const REAL dash_dot_dot[6] = { 3.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
+
+ if (end <= start)
+ return;
+
+ switch (pen->dash)
+ {
+ case DashStyleDash:
+ default:
+ dash_pattern = dash_dot_dot;
+ dash_count = 2;
+ break;
+ case DashStyleDot:
+ dash_pattern = &dash_dot_dot[2];
+ dash_count = 2;
+ break;
+ case DashStyleDashDot:
+ dash_pattern = dash_dot_dot;
+ dash_count = 4;
+ break;
+ case DashStyleDashDotDot:
+ dash_pattern = dash_dot_dot;
+ dash_count = 6;
+ break;
+ case DashStyleCustom:
+ dash_pattern = pen->dashes;
+ dash_count = pen->numdashes;
+ break;
+ }
+
+ tmp_points = GdipAlloc((end - start + 2) * sizeof(GpPoint));
+ if (!tmp_points) return; /* FIXME */
+
+ if (!closed)
+ draw_start_cap = 1;
+
+ for (j=start; j <= end; j++)
+ {
+ if (j == start)
+ {
+ if (closed)
+ i = end;
+ else
+ continue;
+ }
+ else
+ i = j-1;
+
+ segment_dy = path->pathdata.Points[j].Y - path->pathdata.Points[i].Y;
+ segment_dx = path->pathdata.Points[j].X - path->pathdata.Points[i].X;
+ segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
+ segment_pos = 0.0;
+
+ while (1)
+ {
+ if (dash_pos == 0.0)
+ {
+ if ((dash_index % 2) == 0)
+ {
+ /* start dash */
+ num_tmp_points = 1;
+ tmp_points[0].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
+ tmp_points[0].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
+ }
+ else
+ {
+ /* end dash */
+ tmp_points[num_tmp_points].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
+ tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
+
+ widen_open_figure(tmp_points, pen, 0, num_tmp_points,
+ draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
+ LineCapFlat, NULL, last_point);
+ draw_start_cap = 0;
+ num_tmp_points = 0;
+ }
+ }
+
+ if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
+ {
+ /* advance to next segment */
+ if ((dash_index % 2) == 0)
+ {
+ tmp_points[num_tmp_points] = path->pathdata.Points[j];
+ num_tmp_points++;
+ }
+ dash_pos += segment_length - segment_pos;
+ break;
+ }
+ else
+ {
+ /* advance to next dash in pattern */
+ segment_pos += dash_pattern[dash_index] - dash_pos;
+ dash_pos = 0.0;
+ if (++dash_index == dash_count)
+ dash_index = 0;
+ continue;
+ }
+ }
+ }
+
+ if (dash_index % 2 == 0 && num_tmp_points != 0)
+ {
+ /* last dash overflows last segment */
+ tmp_points[num_tmp_points] = path->pathdata.Points[end];
+ widen_open_figure(tmp_points, pen, 0, num_tmp_points,
+ draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
+ closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
+ }
+
+ GdipFree(tmp_points);
+}
+
GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
REAL flatness)
{
if (pen->join == LineJoinRound)
FIXME("unimplemented line join %d\n", pen->join);
- if (pen->dash != DashStyleSolid)
- FIXME("unimplemented dash style %d\n", pen->dash);
-
if (pen->align != PenAlignmentCenter)
FIXME("unimplemented pen alignment %d\n", pen->align);
if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
{
- widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
+ if (pen->dash != DashStyleSolid)
+ widen_dashed_figure(flat_path, pen, subpath_start, i, 1, &last_point);
+ else
+ widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
}
else if (i == flat_path->pathdata.Count-1 ||
(flat_path->pathdata.Types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
{
- widen_open_figure(flat_path, pen, subpath_start, i, &last_point);
+ if (pen->dash != DashStyleSolid)
+ widen_dashed_figure(flat_path, pen, subpath_start, i, 0, &last_point);
+ else
+ widen_open_figure(flat_path->pathdata.Points, pen, subpath_start, i, pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point);
}
}
if (flags & ImageLockModeRead)
{
- static int fixme=0;
+ static BOOL fixme = FALSE;
if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
{
FIXME("Cannot copy rows that don't start at a whole byte.\n");
- fixme = 1;
+ fixme = TRUE;
}
stat = convert_pixels(act_rect.Width, act_rect.Height,
BitmapData* lockeddata)
{
GpStatus stat;
- static int fixme=0;
+ static BOOL fixme = FALSE;
TRACE("(%p,%p)\n", bitmap, lockeddata);
if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
{
FIXME("Cannot copy rows that don't start at a whole byte.\n");
- fixme = 1;
+ fixme = TRUE;
}
stat = convert_pixels(lockeddata->Width, lockeddata->Height,
GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
{
- BitmapData lockeddata_src, lockeddata_dst;
- int i;
- UINT row_size;
Rect area;
GpStatus stat;
area.Width = gdip_round(width);
area.Height = gdip_round(height);
- stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
- &lockeddata_src);
- if (stat != Ok) return stat;
-
- stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
- 0, lockeddata_src.PixelFormat, NULL, dstBitmap);
+ stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
if (stat == Ok)
{
- stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
- lockeddata_src.PixelFormat, &lockeddata_dst);
+ stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
+ srcBitmap->stride,
+ srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
+ srcBitmap->format, srcBitmap->image.palette);
- if (stat == Ok)
+ if (stat == Ok && srcBitmap->image.palette)
{
- /* copy the image data */
- row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
- for (i=0; i<lockeddata_src.Height; i++)
- memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
- (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
- row_size);
-
- GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
+ ColorPalette *src_palette, *dst_palette;
+
+ src_palette = srcBitmap->image.palette;
+
+ dst_palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
+
+ if (dst_palette)
+ {
+ dst_palette->Flags = src_palette->Flags;
+ dst_palette->Count = src_palette->Count;
+ memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
+
+ GdipFree((*dstBitmap)->image.palette);
+ (*dstBitmap)->image.palette = dst_palette;
+ }
+ else
+ stat = OutOfMemory;
}
if (stat != Ok)
GdipDisposeImage((GpImage*)*dstBitmap);
}
- GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
-
if (stat != Ok)
- {
*dstBitmap = NULL;
- }
return stat;
}
}
else if (image->type == ImageTypeBitmap)
{
- GpBitmap *bitmap = (GpBitmap*)image;
- BitmapData lockeddata_src, lockeddata_dst;
- int i;
- UINT row_size;
-
- stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
- &lockeddata_src);
- if (stat != Ok) return stat;
-
- stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
- 0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
- if (stat == Ok)
- {
- stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
- lockeddata_src.PixelFormat, &lockeddata_dst);
-
- if (stat == Ok)
- {
- /* copy the image data */
- row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
- for (i=0; i<lockeddata_src.Height; i++)
- memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
- (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
- row_size);
-
- GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
- }
+ GpBitmap *bitmap = (GpBitmap *)image;
- if (stat != Ok)
- GdipDisposeImage(*cloneImage);
- }
-
- GdipBitmapUnlockBits(bitmap, &lockeddata_src);
-
- if (stat != Ok)
- {
- *cloneImage = NULL;
- }
- else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
-
- return stat;
+ return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
+ bitmap->format, bitmap, (GpBitmap **)cloneImage);
}
else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
{
return stat;
}
-GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
- GpMetafile* metafile, BOOL* succ, EmfType emfType,
- const WCHAR* description, GpMetafile** out_metafile)
-{
- static int calls;
-
- TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
- debugstr_w(description), out_metafile);
-
- if(!ref || !metafile || !out_metafile)
- return InvalidParameter;
-
- *succ = FALSE;
- *out_metafile = NULL;
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- return NotImplemented;
-}
-
GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
GpGraphics* target, GpBitmap** bitmap)
{
GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
{
- BITMAPINFO* pbmi;
HBITMAP hbitmap=NULL;
INT row_size, dib_stride;
BYTE *bits=NULL, *own_bits=NULL;
if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
{
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
- if (!pbmi)
- return OutOfMemory;
+ char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
+ BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = width;
hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
- GdipFree(pbmi);
-
if (!hbitmap) return GenericError;
stride = dib_stride;
return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
}
-GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
- LPBYTE pData16, INT iMapMode, INT eFlags)
-{
- FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
- return NotImplemented;
-}
-
/* Internal utility function: Replace the image data of dst with that of src,
* and free src. */
static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
return Ok;
}
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
- MetafileHeader * header)
-{
- static int calls;
-
- TRACE("(%p, %p)\n", metafile, header);
-
- if(!metafile || !header)
- return InvalidParameter;
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- memset(header, 0, sizeof(MetafileHeader));
-
- return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
- MetafileHeader *header)
-{
- static int calls;
-
- if(!hEmf || !header)
- return InvalidParameter;
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- memset(header, 0, sizeof(MetafileHeader));
-
- return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
- MetafileHeader *header)
-{
- static int calls;
-
- TRACE("(%s,%p)\n", debugstr_w(filename), header);
-
- if(!filename || !header)
- return InvalidParameter;
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- memset(header, 0, sizeof(MetafileHeader));
-
- return Ok;
-}
-
-GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
- MetafileHeader *header)
-{
- static int calls;
-
- TRACE("(%p,%p)\n", stream, header);
-
- if(!stream || !header)
- return InvalidParameter;
-
- if(!(calls++))
- FIXME("not implemented\n");
-
- memset(header, 0, sizeof(MetafileHeader));
-
- return Ok;
-}
-
GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
{
TRACE("(%p, %p)\n", image, num);
HRESULT hr;
UINT width, height;
PixelFormat gdipformat=0;
+ const WICPixelFormatGUID *desired_wicformat;
WICPixelFormatGUID wicformat;
GpRect rc;
BitmapData lockeddata;
{
if (pixel_formats[i].gdip_format == bitmap->format)
{
- memcpy(&wicformat, pixel_formats[i].wic_format, sizeof(GUID));
+ desired_wicformat = pixel_formats[i].wic_format;
gdipformat = bitmap->format;
break;
}
}
if (!gdipformat)
{
- memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+ desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
gdipformat = PixelFormat32bppARGB;
}
+ memcpy(&wicformat, desired_wicformat, sizeof(GUID));
hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
}
+ if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
+ {
+ /* Encoder doesn't support this bitmap's format. */
+ gdipformat = 0;
+ for (i=0; pixel_formats[i].wic_format; i++)
+ {
+ if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
+ {
+ gdipformat = pixel_formats[i].gdip_format;
+ break;
+ }
+ }
+ if (!gdipformat)
+ {
+ ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
+ hr = E_FAIL;
+ }
+ }
+
if (SUCCEEDED(hr))
{
stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
if (retval == Ok)
{
HDC hdc;
- BITMAPINFO *pbmi;
+ char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
+ BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
INT src_height;
hdc = CreateCompatibleDC(NULL);
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-
- if (pbmi)
- {
- pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pbmi->bmiHeader.biBitCount = 0;
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biBitCount = 0;
- src_height = abs(pbmi->bmiHeader.biHeight);
- pbmi->bmiHeader.biHeight = -src_height;
+ GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
- GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
+ src_height = abs(pbmi->bmiHeader.biHeight);
+ pbmi->bmiHeader.biHeight = -src_height;
- GdipFree(pbmi);
- }
- else
- retval = OutOfMemory;
+ GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
DeleteDC(hdc);
return Ok;
}
-GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
- HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
- MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
- GpMetafile **metafile)
-{
- FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
- frameUnit, debugstr_w(desc), metafile);
-
- return NotImplemented;
-}
-
-GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
- GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
- GDIPCONST WCHAR *desc, GpMetafile **metafile)
-{
- FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
- frameUnit, debugstr_w(desc), metafile);
-
- return NotImplemented;
-}
-
GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
{
TRACE("%p\n", image);
GpBitmap *new_bitmap;
GpBitmap *bitmap;
int bpp, bytesperpixel;
- int rotate_90, flip_x, flip_y;
+ BOOL rotate_90, flip_x, flip_y;
int src_x_offset, src_y_offset;
LPBYTE src_origin;
UINT x, y, width, height;
return stat;
}
-
-/*****************************************************************************
- * GdipConvertToEmfPlusToFile [GDIPLUS.@]
- */
-
-GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
- GpMetafile* metafile, BOOL* conversionSuccess,
- const WCHAR* filename, EmfType emfType,
- const WCHAR* description, GpMetafile** out_metafile)
-{
- FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
- return NotImplemented;
-}
DWORD LogicalDpiY;
} EmfPlusHeader;
+typedef struct EmfPlusFillRects
+{
+ EmfPlusRecordHeader Header;
+ DWORD BrushID;
+ DWORD Count;
+} EmfPlusFillRects;
+
+typedef struct EmfPlusSetPageTransform
+{
+ EmfPlusRecordHeader Header;
+ REAL PageScale;
+} EmfPlusSetPageTransform;
+
+typedef struct EmfPlusRect
+{
+ SHORT X;
+ SHORT Y;
+ SHORT Width;
+ SHORT Height;
+} EmfPlusRect;
+
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
{
DWORD size_needed;
(*metafile)->image.picture = NULL;
(*metafile)->image.flags = ImageFlagsNone;
(*metafile)->image.palette = NULL;
+ (*metafile)->image.xres = 72.0;
+ (*metafile)->image.yres = 72.0;
(*metafile)->bounds = *frameRect;
(*metafile)->unit = frameUnit;
(*metafile)->metafile_type = type;
stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
if (stat == Ok)
+ {
*result = metafile->record_graphics;
+ metafile->record_graphics->xres = 96.0;
+ metafile->record_graphics->yres = 96.0;
+ }
return stat;
}
return Ok;
}
+static BOOL is_integer_rect(const GpRectF *rect)
+{
+ SHORT x, y, width, height;
+ x = rect->X;
+ y = rect->Y;
+ width = rect->Width;
+ height = rect->Height;
+ if (rect->X != (REAL)x || rect->Y != (REAL)y ||
+ rect->Width != (REAL)width || rect->Height != (REAL)height)
+ return FALSE;
+ return TRUE;
+}
+
+GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
+ GDIPCONST GpRectF* rects, INT count)
+{
+ if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
+ {
+ EmfPlusFillRects *record;
+ GpStatus stat;
+ BOOL integer_rects = TRUE;
+ int i;
+ DWORD brushid;
+ int flags = 0;
+
+ if (brush->bt == BrushTypeSolidColor)
+ {
+ flags |= 0x8000;
+ brushid = ((GpSolidFill*)brush)->color;
+ }
+ else
+ {
+ FIXME("brush serialization not implemented\n");
+ return NotImplemented;
+ }
+
+ for (i=0; i<count; i++)
+ {
+ if (!is_integer_rect(&rects[i]))
+ {
+ integer_rects = FALSE;
+ break;
+ }
+ }
+
+ if (integer_rects)
+ flags |= 0x4000;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
+ (void**)&record);
+ if (stat != Ok)
+ return stat;
+
+ record->Header.Type = EmfPlusRecordTypeFillRects;
+ record->Header.Flags = flags;
+ record->BrushID = brushid;
+ record->Count = count;
+
+ if (integer_rects)
+ {
+ EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
+ for (i=0; i<count; i++)
+ {
+ record_rects[i].X = (SHORT)rects[i].X;
+ record_rects[i].Y = (SHORT)rects[i].Y;
+ record_rects[i].Width = (SHORT)rects[i].Width;
+ record_rects[i].Height = (SHORT)rects[i].Height;
+ }
+ }
+ else
+ memcpy(record+1, rects, sizeof(GpRectF) * count);
+
+ METAFILE_WriteRecords(metafile);
+ }
+
+ return Ok;
+}
+
+GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
+{
+ if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
+ {
+ EmfPlusSetPageTransform *record;
+ GpStatus stat;
+
+ stat = METAFILE_AllocateRecord(metafile,
+ sizeof(EmfPlusSetPageTransform),
+ (void**)&record);
+ if (stat != Ok)
+ return stat;
+
+ record->Header.Type = EmfPlusRecordTypeSetPageTransform;
+ record->Header.Flags = unit;
+ record->PageScale = scale;
+
+ METAFILE_WriteRecords(metafile);
+ }
+
+ return Ok;
+}
+
GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
{
if (hdc != metafile->record_dc)
}
}
+static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
+{
+ GpMatrix *real_transform;
+ GpStatus stat;
+
+ stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
+
+ if (stat == Ok)
+ {
+ REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
+
+ if (metafile->page_unit != UnitDisplay)
+ scale *= metafile->page_scale;
+
+ stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
+
+ if (stat == Ok)
+ stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
+
+ if (stat == Ok)
+ stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
+
+ GdipDeleteMatrix(real_transform);
+ }
+
+ return stat;
+}
+
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)
}
else
{
+ EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
+
METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
switch(recordType)
case EmfPlusRecordTypeGetDC:
METAFILE_PlaybackGetDC((GpMetafile*)metafile);
break;
+ case EmfPlusRecordTypeFillRects:
+ {
+ EmfPlusFillRects *record = (EmfPlusFillRects*)header;
+ GpBrush *brush, *temp_brush=NULL;
+ GpRectF *rects, *temp_rects=NULL;
+
+ if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
+ return InvalidParameter;
+
+ if (flags & 0x4000)
+ {
+ if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
+ return InvalidParameter;
+ }
+ else
+ {
+ if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
+ return InvalidParameter;
+ }
+
+ if (flags & 0x8000)
+ {
+ stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
+ brush = temp_brush;
+ }
+ else
+ {
+ FIXME("brush deserialization not implemented\n");
+ return NotImplemented;
+ }
+
+ if (stat == Ok)
+ {
+ if (flags & 0x4000)
+ {
+ EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
+ int i;
+
+ rects = temp_rects = GdipAlloc(sizeof(GpRectF) * record->Count);
+ if (rects)
+ {
+ for (i=0; i<record->Count; i++)
+ {
+ rects[i].X = int_rects[i].X;
+ rects[i].Y = int_rects[i].Y;
+ rects[i].Width = int_rects[i].Width;
+ rects[i].Height = int_rects[i].Height;
+ }
+ }
+ else
+ stat = OutOfMemory;
+ }
+ else
+ rects = (GpRectF*)(record+1);
+ }
+
+ if (stat == Ok)
+ {
+ stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
+ }
+
+ GdipDeleteBrush(temp_brush);
+ GdipFree(temp_rects);
+
+ return stat;
+ }
+ case EmfPlusRecordTypeSetPageTransform:
+ {
+ EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
+ GpUnit unit = (GpUnit)flags;
+
+ if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
+ return InvalidParameter;
+
+ real_metafile->page_unit = unit;
+ real_metafile->page_scale = record->PageScale;
+
+ return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
+ }
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
struct enum_metafile_data data;
GpStatus stat;
GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
+ GraphicsContainer state;
TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
destPoints, count, srcRect, srcUnit, callback, callbackData,
real_metafile->playback_graphics = graphics;
real_metafile->playback_dc = NULL;
+ real_metafile->src_rect = *srcRect;
memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
- if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
- metafile->metafile_type == MetafileTypeWmfPlaceable ||
- metafile->metafile_type == MetafileTypeWmf))
- stat = METAFILE_PlaybackGetDC((GpMetafile*)metafile);
+ if (stat == Ok)
+ stat = GdipBeginContainer2(graphics, &state);
if (stat == Ok)
- EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
+ {
+ stat = GdipSetPageScale(graphics, 1.0);
+
+ if (stat == Ok)
+ stat = GdipSetPageUnit(graphics, UnitPixel);
+
+ if (stat == Ok)
+ stat = GdipCreateMatrix(&real_metafile->world_transform);
+
+ if (stat == Ok)
+ {
+ real_metafile->page_unit = UnitDisplay;
+ real_metafile->page_scale = 1.0;
+ stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
+ }
+
+ if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
+ metafile->metafile_type == MetafileTypeWmfPlaceable ||
+ metafile->metafile_type == MetafileTypeWmf))
+ stat = METAFILE_PlaybackGetDC(real_metafile);
- METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
+ if (stat == Ok)
+ EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
+
+ METAFILE_PlaybackReleaseDC(real_metafile);
+
+ GdipDeleteMatrix(real_metafile->world_transform);
+ real_metafile->world_transform = NULL;
+
+ GdipEndContainer(graphics, state);
+ }
real_metafile->playback_graphics = NULL;
return FALSE;
}
-MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
+static MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
{
MetafileType result = MetafileTypeInvalid;
EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
return result;
}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
+ MetafileHeader * header)
+{
+ static int calls;
+
+ TRACE("(%p, %p)\n", metafile, header);
+
+ if(!metafile || !header)
+ return InvalidParameter;
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ memset(header, 0, sizeof(MetafileHeader));
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
+ MetafileHeader *header)
+{
+ static int calls;
+
+ if(!hEmf || !header)
+ return InvalidParameter;
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ memset(header, 0, sizeof(MetafileHeader));
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
+ MetafileHeader *header)
+{
+ static int calls;
+
+ TRACE("(%s,%p)\n", debugstr_w(filename), header);
+
+ if(!filename || !header)
+ return InvalidParameter;
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ memset(header, 0, sizeof(MetafileHeader));
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
+ MetafileHeader *header)
+{
+ static int calls;
+
+ TRACE("(%p,%p)\n", stream, header);
+
+ if(!stream || !header)
+ return InvalidParameter;
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ memset(header, 0, sizeof(MetafileHeader));
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
+ GpMetafile **metafile)
+{
+ ENHMETAHEADER header;
+ MetafileType metafile_type;
+
+ TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
+
+ if(!hemf || !metafile)
+ return InvalidParameter;
+
+ if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
+ return GenericError;
+
+ metafile_type = METAFILE_GetEmfType(hemf);
+
+ if (metafile_type == MetafileTypeInvalid)
+ return GenericError;
+
+ *metafile = GdipAlloc(sizeof(GpMetafile));
+ if (!*metafile)
+ return OutOfMemory;
+
+ (*metafile)->image.type = ImageTypeMetafile;
+ (*metafile)->image.format = ImageFormatEMF;
+ (*metafile)->image.frame_count = 1;
+ (*metafile)->image.xres = (REAL)header.szlDevice.cx;
+ (*metafile)->image.yres = (REAL)header.szlDevice.cy;
+ (*metafile)->bounds.X = (REAL)header.rclBounds.left;
+ (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
+ (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
+ (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
+ (*metafile)->unit = UnitPixel;
+ (*metafile)->metafile_type = metafile_type;
+ (*metafile)->hemf = hemf;
+ (*metafile)->preserve_hemf = !delete;
+
+ TRACE("<-- %p\n", *metafile);
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
+ GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
+{
+ UINT read;
+ BYTE *copy;
+ HENHMETAFILE hemf;
+ GpStatus retval = Ok;
+
+ TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
+
+ if(!hwmf || !metafile || !placeable)
+ return InvalidParameter;
+
+ *metafile = NULL;
+ read = GetMetaFileBitsEx(hwmf, 0, NULL);
+ if(!read)
+ return GenericError;
+ copy = GdipAlloc(read);
+ GetMetaFileBitsEx(hwmf, read, copy);
+
+ hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
+ GdipFree(copy);
+
+ /* FIXME: We should store and use hwmf instead of converting to hemf */
+ retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
+
+ if (retval == Ok)
+ {
+ (*metafile)->image.xres = (REAL)placeable->Inch;
+ (*metafile)->image.yres = (REAL)placeable->Inch;
+ (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
+ (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
+ (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
+ placeable->BoundingBox.Left);
+ (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
+ placeable->BoundingBox.Top);
+ (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
+ (*metafile)->image.format = ImageFormatWMF;
+
+ if (delete) DeleteMetaFile(hwmf);
+ }
+ else
+ DeleteEnhMetaFile(hemf);
+ return retval;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
+ GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
+{
+ HMETAFILE hmf = GetMetaFileW(file);
+
+ TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
+
+ if(!hmf) return InvalidParameter;
+
+ return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
+ GpMetafile **metafile)
+{
+ FIXME("(%p, %p): stub\n", file, metafile);
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
+ GpMetafile **metafile)
+{
+ FIXME("(%p, %p): stub\n", stream, metafile);
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
+ UINT limitDpi)
+{
+ static int calls;
+
+ TRACE("(%p,%u)\n", metafile, limitDpi);
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
+ GpMetafile* metafile, BOOL* succ, EmfType emfType,
+ const WCHAR* description, GpMetafile** out_metafile)
+{
+ static int calls;
+
+ TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
+ debugstr_w(description), out_metafile);
+
+ if(!ref || !metafile || !out_metafile)
+ return InvalidParameter;
+
+ *succ = FALSE;
+ *out_metafile = NULL;
+
+ if(!(calls++))
+ FIXME("not implemented\n");
+
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
+ LPBYTE pData16, INT iMapMode, INT eFlags)
+{
+ FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
+ HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
+ MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
+ GpMetafile **metafile)
+{
+ FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+ frameUnit, debugstr_w(desc), metafile);
+
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
+ GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
+ GDIPCONST WCHAR *desc, GpMetafile **metafile)
+{
+ FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+ frameUnit, debugstr_w(desc), metafile);
+
+ return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipConvertToEmfPlusToFile [GDIPLUS.@]
+ */
+
+GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
+ GpMetafile* metafile, BOOL* conversionSuccess,
+ const WCHAR* filename, EmfType emfType,
+ const WCHAR* description, GpMetafile** out_metafile)
+{
+ FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
+ return NotImplemented;
+}
if(iterator->subpath_pos == count){
*startIndex = *endIndex = *resultCount = 0;
- *isClosed = 1;
+ *isClosed = TRUE;
return Ok;
}
short Y;
} packed_point;
+/* Test to see if the path could be stored as an array of shorts */
+static BOOL is_integer_path(const GpPath *path)
+{
+ int i;
+
+ if (!path->pathdata.Count) return FALSE;
+
+ for (i = 0; i < path->pathdata.Count; i++)
+ {
+ short x, y;
+ x = gdip_round(path->pathdata.Points[i].X);
+ y = gdip_round(path->pathdata.Points[i].Y);
+ if (path->pathdata.Points[i].X != (REAL)x || path->pathdata.Points[i].Y != (REAL)y)
+ return FALSE;
+ }
+ return TRUE;
+}
+
/* Everything is measured in DWORDS; round up if there's a remainder */
static inline INT get_pathtypes_size(const GpPath* path)
{
case RegionDataRect:
return needed + sizeof(GpRect);
case RegionDataPath:
- needed += element->elementdata.pathdata.pathheader.size;
- needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
- return needed;
+ {
+ const GpPath *path = element->elementdata.path;
+ DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
+ /* 3 for headers, once again size doesn't count itself */
+ needed += sizeof(DWORD) * 3;
+ if (flags & FLAGS_INTPATH)
+ needed += 2 * sizeof(SHORT) * path->pathdata.Count;
+ else
+ needed += 2 * sizeof(FLOAT) * path->pathdata.Count;
+
+ needed += get_pathtypes_size(path);
+ needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */
+ return needed;
+ }
case RegionDataEmptyRect:
case RegionDataInfiniteRect:
return needed;
/* Does not check parameters, caller must do that */
static inline GpStatus init_region(GpRegion* region, const RegionType type)
{
- region->node.type = type;
- region->header.checksum = 0xdeadbeef;
- region->header.magic = VERSION_MAGIC;
- region->header.num_children = 0;
- region->header.size = sizeheader_size + get_element_size(®ion->node);
+ region->node.type = type;
+ region->num_children = 0;
return Ok;
}
case RegionDataInfiniteRect:
return Ok;
case RegionDataPath:
- (*element2)->elementdata.pathdata.pathheader = element->elementdata.pathdata.pathheader;
- stat = GdipClonePath(element->elementdata.pathdata.path,
- &(*element2)->elementdata.pathdata.path);
+ stat = GdipClonePath(element->elementdata.path, &(*element2)->elementdata.path);
if (stat == Ok) return Ok;
break;
default:
region->node.type = mode;
region->node.elementdata.combine.left = left;
region->node.elementdata.combine.right = right;
-
- region->header.size = sizeheader_size + get_element_size(®ion->node);
- region->header.num_children += 2;
+ region->num_children += 2;
}
/*****************************************************************************
return OutOfMemory;
element = &(*clone)->node;
- (*clone)->header = region->header;
+ (*clone)->num_children = region->num_children;
return clone_element(®ion->node, &element);
}
}
fuse_region(region1, left, right, mode);
- region1->header.num_children += region2->header.num_children;
+ region1->num_children += region2->num_children;
return Ok;
}
GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region)
{
region_element* element;
- GpPoint *pointsi;
- GpPointF *pointsf;
-
GpStatus stat;
- DWORD flags = FLAGS_INTPATH;
- INT count, i;
TRACE("%p, %p\n", path, region);
return stat;
}
element = &(*region)->node;
- count = path->pathdata.Count;
- /* Test to see if the path is an Integer path */
- if (count)
- {
- pointsi = GdipAlloc(sizeof(GpPoint) * count);
- pointsf = GdipAlloc(sizeof(GpPointF) * count);
- if (!(pointsi && pointsf))
- {
- GdipFree(pointsi);
- GdipFree(pointsf);
- GdipDeleteRegion(*region);
- return OutOfMemory;
- }
-
- stat = GdipGetPathPointsI(path, pointsi, count);
- if (stat != Ok)
- {
- GdipDeleteRegion(*region);
- return stat;
- }
- stat = GdipGetPathPoints(path, pointsf, count);
- if (stat != Ok)
- {
- GdipDeleteRegion(*region);
- return stat;
- }
-
- for (i = 0; i < count; i++)
- {
- if (!(pointsi[i].X == pointsf[i].X &&
- pointsi[i].Y == pointsf[i].Y ))
- {
- flags = FLAGS_NOFLAGS;
- break;
- }
- }
- GdipFree(pointsi);
- GdipFree(pointsf);
- }
-
- stat = GdipClonePath(path, &element->elementdata.pathdata.path);
+ stat = GdipClonePath(path, &element->elementdata.path);
if (stat != Ok)
{
GdipDeleteRegion(*region);
return stat;
}
- /* 3 for headers, once again size doesn't count itself */
- element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3));
- switch(flags)
- {
- /* Floats, sent out as floats */
- case FLAGS_NOFLAGS:
- element->elementdata.pathdata.pathheader.size +=
- (sizeof(DWORD) * count * 2);
- break;
- /* INTs, sent out as packed shorts */
- case FLAGS_INTPATH:
- element->elementdata.pathdata.pathheader.size +=
- (sizeof(DWORD) * count);
- break;
- default:
- FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags);
- }
- element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path);
- element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC;
- element->elementdata.pathdata.pathheader.count = count;
- element->elementdata.pathdata.pathheader.flags = flags;
- (*region)->header.size = sizeheader_size + get_element_size(element);
-
return Ok;
}
static inline void write_packed_point(DWORD* location, INT* offset,
const GpPointF* write)
{
- packed_point point;
-
- point.X = write->X;
- point.Y = write->Y;
- memcpy(location + *offset, &point, sizeof(packed_point));
+ packed_point *point = (packed_point *)(location + *offset);
+ point->X = gdip_round(write->X);
+ point->Y = gdip_round(write->Y);
(*offset)++;
}
static inline void write_path_types(DWORD* location, INT* offset,
const GpPath* path)
{
+ INT rounded_size = get_pathtypes_size(path);
+
memcpy(location + *offset, path->pathdata.Types, path->pathdata.Count);
/* The unwritten parts of the DWORD (if any) must be cleared */
- if (path->pathdata.Count % sizeof(DWORD))
+ if (rounded_size - path->pathdata.Count)
ZeroMemory(((BYTE*)location) + (*offset * sizeof(DWORD)) +
- path->pathdata.Count,
- sizeof(DWORD) - path->pathdata.Count % sizeof(DWORD));
- *offset += (get_pathtypes_size(path) / sizeof(DWORD));
+ path->pathdata.Count, rounded_size - path->pathdata.Count);
+ *offset += rounded_size / sizeof(DWORD);
}
static void write_element(const region_element* element, DWORD *buffer,
case RegionDataPath:
{
INT i;
- const GpPath* path = element->elementdata.pathdata.path;
+ const GpPath* path = element->elementdata.path;
+ struct _pathheader
+ {
+ DWORD size;
+ DWORD magic;
+ DWORD count;
+ DWORD flags;
+ } *pathheader;
+
+ pathheader = (struct _pathheader *)(buffer + *filled);
+
+ pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS;
+ /* 3 for headers, once again size doesn't count itself */
+ pathheader->size = sizeof(DWORD) * 3;
+ if (pathheader->flags & FLAGS_INTPATH)
+ pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count;
+ else
+ pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count;
+ pathheader->size += get_pathtypes_size(path);
+ pathheader->magic = VERSION_MAGIC;
+ pathheader->count = path->pathdata.Count;
- memcpy(buffer + *filled, &element->elementdata.pathdata.pathheader,
- sizeof(element->elementdata.pathdata.pathheader));
- *filled += sizeof(element->elementdata.pathdata.pathheader) / sizeof(DWORD);
- switch (element->elementdata.pathdata.pathheader.flags)
+ *filled += 4;
+
+ switch (pathheader->flags & FLAGS_INTPATH)
{
case FLAGS_NOFLAGS:
for (i = 0; i < path->pathdata.Count; i++)
write_packed_point(buffer, filled,
&path->pathdata.Points[i]);
}
+ break;
}
write_path_types(buffer, filled, path);
break;
GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
UINT *needed)
{
+ struct _region_header
+ {
+ DWORD size;
+ DWORD checksum;
+ DWORD magic;
+ DWORD num_children;
+ } *region_header;
INT filled = 0;
+ UINT required;
+ GpStatus status;
TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
- if (!(region && buffer && size))
+ if (!region || !buffer || !size)
return InvalidParameter;
- memcpy(buffer, ®ion->header, sizeof(region->header));
- filled += sizeof(region->header) / sizeof(DWORD);
+ status = GdipGetRegionDataSize(region, &required);
+ if (status != Ok) return status;
+ if (size < required)
+ {
+ if (needed) *needed = size;
+ return InsufficientBuffer;
+ }
+
+ region_header = (struct _region_header *)buffer;
+ region_header->size = sizeheader_size + get_element_size(®ion->node);
+ region_header->checksum = 0;
+ region_header->magic = VERSION_MAGIC;
+ region_header->num_children = region->num_children;
+ filled += 4;
/* With few exceptions, everything written is DWORD aligned,
* so use that as our base */
write_element(®ion->node, (DWORD*)buffer, &filled);
return InvalidParameter;
/* header.size doesn't count header.size and header.checksum */
- *needed = region->header.size + sizeof(DWORD) * 2;
+ *needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(®ion->node);
return Ok;
}
*hrgn = CreateRectRgn(0, 0, 0, 0);
return *hrgn ? Ok : OutOfMemory;
case RegionDataPath:
- return get_path_hrgn(element->elementdata.pathdata.path, graphics, hrgn);
+ return get_path_hrgn(element->elementdata.path, graphics, hrgn);
case RegionDataRect:
{
GpPath* path;
case CombineModeIntersect:
return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
case CombineModeXor: case CombineModeExclude:
- FIXME("cannot exclude from an infinite region\n");
- /* fall-through */
+ left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+ break;
case CombineModeUnion: case CombineModeComplement:
*hrgn = NULL;
return Ok;
*hrgn = left;
return Ok;
case CombineModeXor: case CombineModeComplement:
- FIXME("cannot exclude from an infinite region\n");
- /* fall-through */
+ right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+ break;
case CombineModeUnion: case CombineModeExclude:
DeleteObject(left);
*hrgn = NULL;
{
/* Steal the element from the created region. */
memcpy(element, &new_region->node, sizeof(region_element));
- HeapFree(GetProcessHeap(), 0, new_region);
+ GdipFree(new_region);
}
else
return stat;
}
/* Fall-through to do the actual conversion. */
case RegionDataPath:
+ if (!element->elementdata.path->pathdata.Count)
+ return Ok;
+
stat = GdipTransformMatrixPoints(matrix,
- element->elementdata.pathdata.path->pathdata.Points,
- element->elementdata.pathdata.path->pathdata.Count);
+ element->elementdata.path->pathdata.Points,
+ element->elementdata.path->pathdata.Count);
return stat;
default:
stat = transform_region_element(element->elementdata.combine.left, matrix);
element->elementdata.rect.Y += dy;
return;
case RegionDataPath:
- for(i = 0; i < element->elementdata.pathdata.path->pathdata.Count; i++){
- element->elementdata.pathdata.path->pathdata.Points[i].X += dx;
- element->elementdata.pathdata.path->pathdata.Points[i].Y += dy;
+ for(i = 0; i < element->elementdata.path->pathdata.Count; i++){
+ element->elementdata.path->pathdata.Points[i].X += dx;
+ element->elementdata.path->pathdata.Points[i].Y += dy;
}
return;
default:
reactos/dll/win32/dwmapi # Synced to Wine-1.7.17
reactos/dll/win32/faultrep # Synced to Wine-1.7.1
reactos/dll/win32/fusion # Synced to Wine-1.7.1
-reactos/dll/win32/gdiplus # Synced to Wine-1.7.1
+reactos/dll/win32/gdiplus # Synced to Wine-1.7.17
reactos/dll/win32/hhctrl.ocx # Synced to Wine-1.7.1
reactos/dll/win32/hlink # Synced to Wine-1.7.1
reactos/dll/win32/hnetcfg # Synced to Wine-1.7.1