* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-//#include <stdarg.h>
-//#include <math.h>
-//#include <limits.h>
-
-//#include "windef.h"
-//#include "winbase.h"
-//#include "winuser.h"
-//#include "wingdi.h"
-#include <wine/unicode.h>
-
-#define COBJMACROS
-//#include "objbase.h"
-//#include "ocidl.h"
-//#include "olectl.h"
-//#include "ole2.h"
+#include "gdiplus_private.h"
#include <winreg.h>
-
-//#include "gdiplus.h"
-#include "gdiplus_private.h"
#include <shlwapi.h>
-#include <wine/debug.h>
-//#include "wine/list.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
/* Mike "tamlin" Nordell 2012-09-14 for ReactOS:
* NOTE: Wine uses per-GpGraphics id's ('contid' starting from zero in
GDIPCONST GpBrush *brush, GDIPCONST PointF *positions,
INT flags, GDIPCONST GpMatrix *matrix);
-static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
- GpCoordinateSpace src_space, GpMatrix *matrix);
-
/* Converts from gdiplus path point type to gdi path point type. */
static BYTE convert_path_point_type(BYTE type)
{
(pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
width *= units_to_pixels(pen->width, pen->unit == UnitWorld ? graphics->unit : pen->unit, graphics->xres);
+ width *= graphics->scale;
}
if(pen->dash == DashStyleCustom){
static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_width, INT dst_height,
HDC hdc, INT src_x, INT src_y, INT src_width, INT src_height)
{
- if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE)
+ if (GetDeviceCaps(graphics->hdc, TECHNOLOGY) == DT_RASPRINTER &&
+ GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE)
{
TRACE("alpha blending not supported by device, fallback to StretchBlt\n");
return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
}
-/* Draw non-premultiplied ARGB data to the given graphics object */
+/* Draw ARGB data to the given graphics object */
static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
- const BYTE *src, INT src_width, INT src_height, INT src_stride)
+ const BYTE *src, INT src_width, INT src_height, INT src_stride, const PixelFormat fmt)
{
GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
INT x, y;
- for (x=0; x<src_width; x++)
+ for (y=0; y<src_height; y++)
{
- for (y=0; y<src_height; y++)
+ for (x=0; x<src_width; x++)
{
ARGB dst_color, src_color;
- GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
src_color = ((ARGB*)(src + src_stride * y))[x];
- GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
+
+ if (!(src_color & 0xff000000))
+ continue;
+
+ GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
+ if (fmt & PixelFormatPAlpha)
+ GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over_fgpremult(dst_color, src_color));
+ else
+ GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
}
}
}
static GpStatus alpha_blend_hdc_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
- const BYTE *src, INT src_width, INT src_height, INT src_stride)
+ const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
{
HDC hdc;
HBITMAP hbitmap;
hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
(void**)&temp_bits, NULL, 0);
- if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE)
+ if ((GetDeviceCaps(graphics->hdc, TECHNOLOGY) == DT_RASPRINTER &&
+ GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE) ||
+ fmt & PixelFormatPAlpha)
memcpy(temp_bits, src, src_width * src_height * 4);
else
convert_32bppARGB_to_32bppPARGB(src_width, src_height, temp_bits,
}
static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst_y,
- const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion)
+ const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion, PixelFormat fmt)
{
GpStatus stat=Ok;
size = GetRegionData(hrgn, 0, NULL);
- rgndata = GdipAlloc(size);
+ rgndata = heap_alloc_zero(size);
if (!rgndata)
{
DeleteObject(hrgn);
stat = alpha_blend_bmp_pixels(graphics, rects[i].left, rects[i].top,
&src[(rects[i].left - dst_x) * 4 + (rects[i].top - dst_y) * src_stride],
rects[i].right - rects[i].left, rects[i].bottom - rects[i].top,
- src_stride);
+ src_stride, fmt);
}
- GdipFree(rgndata);
+ heap_free(rgndata);
DeleteObject(hrgn);
save = SaveDC(graphics->hdc);
- if (hrgn)
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ SetViewportOrgEx(graphics->hdc, 0, 0, NULL);
+
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
if (hregion)
ExtSelectClipRgn(graphics->hdc, hregion, RGN_AND);
stat = alpha_blend_hdc_pixels(graphics, dst_x, dst_y, src, src_width,
- src_height, src_stride);
+ src_height, src_stride, fmt);
RestoreDC(graphics->hdc, save);
}
static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
- const BYTE *src, INT src_width, INT src_height, INT src_stride)
+ const BYTE *src, INT src_width, INT src_height, INT src_stride, PixelFormat fmt)
{
- return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL);
+ return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL, fmt);
}
static ARGB blend_colors(ARGB start, ARGB end, REAL position)
{
- ARGB result=0;
- ARGB i;
- INT a1, a2, a3;
+ INT start_a, end_a, final_a;
+ INT pos;
- a1 = (start >> 24) & 0xff;
- a2 = (end >> 24) & 0xff;
+ pos = gdip_round(position * 0xff);
- a3 = (int)(a1*(1.0f - position)+a2*(position));
+ start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
+ end_a = ((end >> 24) & 0xff) * pos;
- result |= a3 << 24;
+ final_a = start_a + end_a;
- for (i=0xff; i<=0xff0000; i = i << 8)
- result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
- return result;
+ if (final_a < 0xff) return 0;
+
+ return (final_a / 0xff) << 24 |
+ ((((start >> 16) & 0xff) * start_a + (((end >> 16) & 0xff) * end_a)) / final_a) << 16 |
+ ((((start >> 8) & 0xff) * start_a + (((end >> 8) & 0xff) * end_a)) / final_a) << 8 |
+ (((start & 0xff) * start_a + ((end & 0xff) * end_a)) / final_a);
}
static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
}
}
-static ARGB transform_color(ARGB color, const ColorMatrix *matrix)
+static BOOL round_color_matrix(const ColorMatrix *matrix, int values[5][5])
+{
+ /* Convert floating point color matrix to int[5][5], return TRUE if it's an identity */
+ BOOL identity = TRUE;
+ int i, j;
+
+ for (i=0; i<4; i++)
+ for (j=0; j<5; j++)
+ {
+ if (matrix->m[j][i] != (i == j ? 1.0 : 0.0))
+ identity = FALSE;
+ values[j][i] = gdip_round(matrix->m[j][i] * 256.0);
+ }
+
+ return identity;
+}
+
+static ARGB transform_color(ARGB color, int matrix[5][5])
{
- REAL val[5], res[4];
+ int val[5], res[4];
int i, j;
unsigned char a, r, g, b;
- val[0] = ((color >> 16) & 0xff) / 255.0; /* red */
- val[1] = ((color >> 8) & 0xff) / 255.0; /* green */
- val[2] = (color & 0xff) / 255.0; /* blue */
- val[3] = ((color >> 24) & 0xff) / 255.0; /* alpha */
- val[4] = 1.0; /* translation */
+ val[0] = ((color >> 16) & 0xff); /* red */
+ val[1] = ((color >> 8) & 0xff); /* green */
+ val[2] = (color & 0xff); /* blue */
+ val[3] = ((color >> 24) & 0xff); /* alpha */
+ val[4] = 255; /* translation */
for (i=0; i<4; i++)
{
- res[i] = 0.0;
+ res[i] = 0;
for (j=0; j<5; j++)
- res[i] += matrix->m[j][i] * val[j];
+ res[i] += matrix[j][i] * val[j];
}
- a = min(max(floorf(res[3]*255.0), 0.0), 255.0);
- r = min(max(floorf(res[0]*255.0), 0.0), 255.0);
- g = min(max(floorf(res[1]*255.0), 0.0), 255.0);
- b = min(max(floorf(res[2]*255.0), 0.0), 255.0);
+ a = min(max(res[3] / 256, 0), 255);
+ r = min(max(res[0] / 256, 0), 255);
+ g = min(max(res[1] / 256, 0), 255);
+ b = min(max(res[2] / 256, 0), 255);
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 (r == g) && (g == b);
}
-static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
- UINT width, UINT height, INT stride, ColorAdjustType type)
+/* returns preferred pixel format for the applied attributes */
+PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
+ UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt)
{
UINT x, y;
INT i;
BYTE min_blue, min_green, min_red;
BYTE max_blue, max_green, max_red;
+ if (!data || fmt != PixelFormat32bppARGB)
+ return PixelFormat32bppARGB;
+
if (attributes->colorkeys[type].enabled)
key = &attributes->colorkeys[type];
else
{
const struct color_remap_table *table;
+ if (!data || fmt != PixelFormat32bppARGB)
+ return PixelFormat32bppARGB;
+
if (attributes->colorremaptables[type].enabled)
table = &attributes->colorremaptables[type];
else
attributes->colormatrices[ColorAdjustTypeDefault].enabled)
{
const struct color_matrix *colormatrices;
+ int color_matrix[5][5];
+ int gray_matrix[5][5];
+ BOOL identity;
+
+ if (!data || fmt != PixelFormat32bppARGB)
+ return PixelFormat32bppARGB;
if (attributes->colormatrices[type].enabled)
colormatrices = &attributes->colormatrices[type];
else
colormatrices = &attributes->colormatrices[ColorAdjustTypeDefault];
- for (x=0; x<width; x++)
- for (y=0; y<height; y++)
- {
- ARGB *src_color;
- src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x);
+ identity = round_color_matrix(&colormatrices->colormatrix, color_matrix);
- if (colormatrices->flags == ColorMatrixFlagsDefault ||
- !color_is_gray(*src_color))
- {
- *src_color = transform_color(*src_color, &colormatrices->colormatrix);
- }
- else if (colormatrices->flags == ColorMatrixFlagsAltGray)
+ if (colormatrices->flags == ColorMatrixFlagsAltGray)
+ identity = (round_color_matrix(&colormatrices->graymatrix, gray_matrix) && identity);
+
+ if (!identity)
+ {
+ for (x=0; x<width; x++)
+ {
+ for (y=0; y<height; y++)
{
- *src_color = transform_color(*src_color, &colormatrices->graymatrix);
+ ARGB *src_color;
+ src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x);
+
+ if (colormatrices->flags == ColorMatrixFlagsDefault ||
+ !color_is_gray(*src_color))
+ {
+ *src_color = transform_color(*src_color, color_matrix);
+ }
+ else if (colormatrices->flags == ColorMatrixFlagsAltGray)
+ {
+ *src_color = transform_color(*src_color, gray_matrix);
+ }
}
}
+ }
}
if (attributes->gamma_enabled[type] ||
{
REAL gamma;
+ if (!data || fmt != PixelFormat32bppARGB)
+ return PixelFormat32bppARGB;
+
if (attributes->gamma_enabled[type])
gamma = attributes->gamma[type];
else
*src_color = (*src_color & 0xff000000) | (red << 16) | (green << 8) | blue;
}
}
+
+ return fmt;
}
/* Given a bitmap and its source rectangle, find the smallest rectangle in the
right = bitmap->width-1;
if (bottom >= bitmap->height)
bottom = bitmap->height-1;
+ if (bottom < top || right < left)
+ /* entirely outside image, just sample a pixel so we don't have to
+ * special-case this later */
+ left = top = right = bottom = 0;
}
else
{
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;
}
}
{
BitmapData lockeddata;
- fill->bitmap_bits = GdipAlloc(sizeof(ARGB) * bitmap->width * bitmap->height);
+ fill->bitmap_bits = heap_alloc_zero(sizeof(ARGB) * bitmap->width * bitmap->height);
if (!fill->bitmap_bits)
stat = OutOfMemory;
if (stat == Ok)
apply_image_attributes(fill->imageattributes, fill->bitmap_bits,
bitmap->width, bitmap->height,
- src_stride, ColorAdjustTypeBitmap);
+ src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
if (stat != Ok)
{
- GdipFree(fill->bitmap_bits);
+ heap_free(fill->bitmap_bits);
fill->bitmap_bits = NULL;
}
}
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;
}
break;
count = custom->pathdata.Count;
- custptf = GdipAlloc(count * sizeof(PointF));
- custpt = GdipAlloc(count * sizeof(POINT));
- tp = GdipAlloc(count);
+ custptf = heap_alloc_zero(count * sizeof(PointF));
+ custpt = heap_alloc_zero(count * sizeof(POINT));
+ tp = heap_alloc_zero(count);
if(!custptf || !custpt || !tp)
goto custend;
PolyDraw(graphics->hdc, custpt, tp, count);
custend:
- GdipFree(custptf);
- GdipFree(custpt);
- GdipFree(tp);
+ heap_free(custptf);
+ heap_free(custpt);
+ heap_free(tp);
break;
default:
break;
static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt,
GDIPCONST BYTE * types, INT count, BOOL caps)
{
- POINT *pti = GdipAlloc(count * sizeof(POINT));
- BYTE *tp = GdipAlloc(count);
- GpPointF *ptcopy = GdipAlloc(count * sizeof(GpPointF));
+ POINT *pti = heap_alloc_zero(count * sizeof(POINT));
+ BYTE *tp = heap_alloc_zero(count);
+ GpPointF *ptcopy = heap_alloc_zero(count * sizeof(GpPointF));
INT i, j;
GpStatus status = GenericError;
for(i = 1; i < count; i++){
if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){
if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier)
- || !(types[i + 1] & PathPointTypeBezier)){
+ || !(types[i + 2] & PathPointTypeBezier)){
ERR("Bad bezier points\n");
goto end;
}
status = Ok;
end:
- GdipFree(pti);
- GdipFree(ptcopy);
- GdipFree(tp);
+ heap_free(pti);
+ heap_free(ptcopy);
+ heap_free(tp);
return status;
}
return result;
}
+typedef enum GraphicsContainerType {
+ BEGIN_CONTAINER,
+ SAVE_GRAPHICS
+} GraphicsContainerType;
+
typedef struct _GraphicsContainerItem {
struct list entry;
GraphicsContainer contid;
+ GraphicsContainerType type;
SmoothingMode smoothing;
CompositingQuality compqual;
} GraphicsContainerItem;
static GpStatus init_container(GraphicsContainerItem** container,
- GDIPCONST GpGraphics* graphics){
+ GDIPCONST GpGraphics* graphics, GraphicsContainerType type){
GpStatus sts;
- *container = GdipAlloc(sizeof(GraphicsContainerItem));
+ *container = heap_alloc_zero(sizeof(GraphicsContainerItem));
if(!(*container))
return OutOfMemory;
(*container)->contid = graphics->contid + 1;
+ (*container)->type = type;
(*container)->smoothing = graphics->smoothing;
(*container)->compqual = graphics->compqual;
sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
if(sts != Ok){
- GdipFree(*container);
+ heap_free(*container);
*container = NULL;
return sts;
}
static void delete_container(GraphicsContainerItem* container)
{
GdipDeleteRegion(container->clip);
- GdipFree(container);
+ heap_free(container);
}
static GpStatus restore_container(GpGraphics* graphics,
rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
}
+ if (graphics->hdc)
+ {
+ POINT points[2];
+
+ points[0].x = rect->X;
+ points[0].y = rect->Y;
+ points[1].x = rect->X + rect->Width;
+ points[1].y = rect->Y + rect->Height;
+
+ DPtoLP(graphics->hdc, points, sizeof(points)/sizeof(points[0]));
+
+ rect->X = min(points[0].x, points[1].x);
+ rect->Y = min(points[0].y, points[1].y);
+ rect->Width = abs(points[1].x - points[0].x);
+ rect->Height = abs(points[1].y - points[0].y);
+ }
+
return stat;
}
HFONT unscaled_font;
TEXTMETRICW textmet;
- if (font->unit == UnitPixel)
+ if (font->unit == UnitPixel || font->unit == UnitWorld)
font_height = font->emSize;
else
{
GpMatrix xform = *matrix;
GdipTransformMatrixPoints(&xform, pt, 3);
}
- if (graphics)
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+
+ GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
(pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
if(graphics == NULL)
return InvalidParameter;
- *graphics = GdipAlloc(sizeof(GpGraphics));
+ *graphics = heap_alloc_zero(sizeof(GpGraphics));
if(!*graphics) return OutOfMemory;
GdipSetMatrixElements(&(*graphics)->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
- GdipFree(*graphics);
+ heap_free(*graphics);
return retval;
}
{
GpStatus retval;
- *graphics = GdipAlloc(sizeof(GpGraphics));
+ *graphics = heap_alloc_zero(sizeof(GpGraphics));
if(!*graphics) return OutOfMemory;
GdipSetMatrixElements(&(*graphics)->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
- GdipFree(*graphics);
+ heap_free(*graphics);
return retval;
}
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);
- GdipFree(graphics);
+
+ /* 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;
+
+ heap_free(graphics);
return Ok;
}
if(graphics->busy)
return ObjectBusy;
- pts = GdipAlloc(sizeof(GpPointF) * count);
+ pts = heap_alloc_zero(sizeof(GpPointF) * count);
if(!pts)
return OutOfMemory;
ret = GdipDrawBeziers(graphics,pen,pts,count);
- GdipFree(pts);
+ heap_free(pts);
return ret;
}
if(!points || count <= 0)
return InvalidParameter;
- ptf = GdipAlloc(sizeof(GpPointF)*count);
+ ptf = heap_alloc_zero(sizeof(GpPointF)*count);
if(!ptf)
return OutOfMemory;
stat = GdipDrawClosedCurve2(graphics, pen, ptf, count, tension);
- GdipFree(ptf);
+ heap_free(ptf);
return stat;
}
if(!points)
return InvalidParameter;
- pointsF = GdipAlloc(sizeof(GpPointF)*count);
+ pointsF = heap_alloc_zero(sizeof(GpPointF)*count);
if(!pointsF)
return OutOfMemory;
}
ret = GdipDrawCurve(graphics,pen,pointsF,count);
- GdipFree(pointsF);
+ heap_free(pointsF);
return ret;
}
if(!points)
return InvalidParameter;
- pointsF = GdipAlloc(sizeof(GpPointF)*count);
+ pointsF = heap_alloc_zero(sizeof(GpPointF)*count);
if(!pointsF)
return OutOfMemory;
}
ret = GdipDrawCurve2(graphics,pen,pointsF,count,tension);
- GdipFree(pointsF);
+ heap_free(pointsF);
return ret;
}
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);
srcheight = units_to_pixels(srcheight, srcUnit, image->yres);
TRACE("src pixels: %f,%f %fx%f\n", srcx, srcy, srcwidth, srcheight);
- if (image->picture)
- {
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- }
-
- if(IPicture_Render(image->picture, graphics->hdc,
- pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
- srcx, srcy, srcwidth, srcheight, NULL) != S_OK)
- {
- if(callback)
- callback(callbackData);
- return GenericError;
- }
- }
- else if (image->type == ImageTypeBitmap)
+ if (image->type == ImageTypeBitmap)
{
GpBitmap* bitmap = (GpBitmap*)image;
- int use_software=0;
+ BOOL do_resampling = FALSE;
+ 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,
graphics->scale, image->xres, image->yres, bitmap->format,
imageAttributes ? imageAttributes->outside_color : 0);
- if (imageAttributes || graphics->alpha_hdc ||
- (graphics->image && graphics->image->type == ImageTypeBitmap) ||
- ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X ||
+ if (ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X ||
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;
+ do_resampling = TRUE;
+
+ if (imageAttributes || graphics->alpha_hdc || do_resampling ||
+ (graphics->image && graphics->image->type == ImageTypeBitmap))
+ 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;
REAL m11, m12, m21, m22, mdx, mdy;
- LPBYTE src_data, dst_data;
+ LPBYTE src_data, dst_data, dst_dyn_data=NULL;
BitmapData lockeddata;
InterpolationMode interpolation = graphics->interpolation;
PixelOffsetMode offset_mode = graphics->pixeloffset;
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;
stat = GdipInvertMatrix(&dst_to_src);
if (stat != Ok) return stat;
- dst_data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
- if (!dst_data) return OutOfMemory;
-
- dst_stride = sizeof(ARGB) * (dst_area.right - dst_area.left);
-
- get_bitmap_sample_size(interpolation, imageAttributes->wrap,
- bitmap, srcx, srcy, srcwidth, srcheight, &src_area);
+ if (do_resampling)
+ {
+ get_bitmap_sample_size(interpolation, imageAttributes->wrap,
+ bitmap, srcx, srcy, srcwidth, srcheight, &src_area);
+ }
+ else
+ {
+ /* Make sure src_area is equal in size to dst_area. */
+ src_area.X = srcx + dst_area.left - pti[0].x;
+ src_area.Y = srcy + dst_area.top - pti[0].y;
+ src_area.Width = dst_area.right - dst_area.left;
+ src_area.Height = dst_area.bottom - dst_area.top;
+ }
TRACE("src_area: %d x %d\n", src_area.Width, src_area.Height);
- src_data = GdipAlloc(sizeof(ARGB) * src_area.Width * src_area.Height);
+ src_data = heap_alloc_zero(sizeof(ARGB) * src_area.Width * src_area.Height);
if (!src_data)
- {
- GdipFree(dst_data);
return OutOfMemory;
- }
src_stride = sizeof(ARGB) * src_area.Width;
- /* Read the bits we need from the source bitmap into an ARGB buffer. */
+ /* Read the bits we need from the source bitmap into a compatible buffer. */
lockeddata.Width = src_area.Width;
lockeddata.Height = src_area.Height;
lockeddata.Stride = src_stride;
- lockeddata.PixelFormat = PixelFormat32bppARGB;
lockeddata.Scan0 = src_data;
+ if (!do_resampling && bitmap->format == PixelFormat32bppPARGB)
+ lockeddata.PixelFormat = apply_image_attributes(imageAttributes, NULL, 0, 0, 0, ColorAdjustTypeBitmap, bitmap->format);
+ else
+ lockeddata.PixelFormat = PixelFormat32bppARGB;
stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf,
- PixelFormat32bppARGB, &lockeddata);
+ lockeddata.PixelFormat, &lockeddata);
if (stat == Ok)
stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
if (stat != Ok)
{
- if (src_data != dst_data)
- GdipFree(src_data);
- GdipFree(dst_data);
+ heap_free(src_data);
return stat;
}
apply_image_attributes(imageAttributes, src_data,
src_area.Width, src_area.Height,
- src_stride, ColorAdjustTypeBitmap);
+ src_stride, ColorAdjustTypeBitmap, lockeddata.PixelFormat);
+
+ if (do_resampling)
+ {
+ /* Transform the bits as needed to the destination. */
+ dst_data = dst_dyn_data = heap_alloc_zero(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
+ if (!dst_data)
+ {
+ heap_free(src_data);
+ return OutOfMemory;
+ }
- /* Transform the bits as needed to the destination. */
- GdipTransformMatrixPoints(&dst_to_src, dst_to_src_points, 3);
+ dst_stride = sizeof(ARGB) * (dst_area.right - dst_area.left);
- x_dx = dst_to_src_points[1].X - dst_to_src_points[0].X;
- x_dy = dst_to_src_points[1].Y - dst_to_src_points[0].Y;
- y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
- y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
+ GdipTransformMatrixPoints(&dst_to_src, dst_to_src_points, 3);
- for (x=dst_area.left; x<dst_area.right; x++)
- {
- for (y=dst_area.top; y<dst_area.bottom; y++)
+ x_dx = dst_to_src_points[1].X - dst_to_src_points[0].X;
+ x_dy = dst_to_src_points[1].Y - dst_to_src_points[0].Y;
+ y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
+ y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
+
+ for (x=dst_area.left; x<dst_area.right; x++)
{
- GpPointF src_pointf;
- ARGB *dst_color;
+ for (y=dst_area.top; y<dst_area.bottom; y++)
+ {
+ GpPointF src_pointf;
+ ARGB *dst_color;
- src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
- src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
+ src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
+ src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
- dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
+ dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
- if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
- *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
- imageAttributes, interpolation, offset_mode);
- else
- *dst_color = 0;
+ if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
+ *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes, interpolation, offset_mode);
+ else
+ *dst_color = 0;
+ }
}
}
-
- GdipFree(src_data);
+ else
+ {
+ dst_data = src_data;
+ dst_stride = src_stride;
+ }
stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
- dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride);
+ dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride,
+ lockeddata.PixelFormat);
- GdipFree(dst_data);
+ heap_free(src_data);
+
+ heap_free(dst_dyn_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;
+ HRGN hrgn;
+ INT save_state;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
bitmap->format == PixelFormat24bppRGB ||
/* 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;
old_hbm = SelectObject(hdc, hbitmap);
}
+ save_state = SaveDC(graphics->hdc);
+
+ stat = get_clip_hrgn(graphics, &hrgn);
+
+ if (stat == Ok && hrgn)
+ {
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
+ }
+
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
{
gdi_alpha_blend(graphics, pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY);
}
+ RestoreDC(graphics->hdc, save_state);
+
if (temp_hdc)
{
SelectObject(hdc, old_hbm);
TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2);
+ if (!pen)
+ return InvalidParameter;
+
+ if (pen->unit == UnitPixel && pen->width <= 0.0)
+ return Ok;
+
pt[0].X = x1;
pt[0].Y = y1;
pt[1].X = x2;
TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
- ptf = GdipAlloc(count * sizeof(GpPointF));
+ ptf = heap_alloc_zero(count * sizeof(GpPointF));
if(!ptf) return OutOfMemory;
for(i = 0; i < count; i ++){
retval = GdipDrawLines(graphics, pen, ptf, count);
- GdipFree(ptf);
+ heap_free(ptf);
return retval;
}
-GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
+static GpStatus GDI32_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
INT save_state;
GpStatus retval;
+ HRGN hrgn=NULL;
- TRACE("(%p, %p, %p)\n", graphics, pen, path);
-
- if(!pen || !graphics)
- return InvalidParameter;
+ save_state = prepare_dc(graphics, pen);
- if(graphics->busy)
- return ObjectBusy;
+ retval = get_clip_hrgn(graphics, &hrgn);
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- return Ok;
- }
+ if (retval != Ok)
+ goto end;
- save_state = prepare_dc(graphics, pen);
+ 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;
}
-GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
- REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
+static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
{
- GpStatus status;
- GpPath *path;
+ GpStatus stat;
+ GpPath* flat_path;
+ GpMatrix* transform;
+ GpRectF gp_bound_rect;
+ GpRect gp_output_area;
+ RECT output_area;
+ INT output_height, output_width;
+ DWORD *output_bits, *brush_bits=NULL;
+ int i;
+ static const BYTE static_dash_pattern[] = {1,1,1,0,1,0,1,0};
+ const BYTE *dash_pattern;
+ INT dash_pattern_size;
+ BYTE *dyn_dash_pattern = NULL;
- TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
- width, height, startAngle, sweepAngle);
+ stat = GdipClonePath(path, &flat_path);
- if(!graphics || !pen)
- return InvalidParameter;
+ if (stat != Ok)
+ return stat;
- if(graphics->busy)
- return ObjectBusy;
+ stat = GdipCreateMatrix(&transform);
- status = GdipCreatePath(FillModeAlternate, &path);
- if (status != Ok) return status;
+ if (stat == Ok)
+ {
+ stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, transform);
- status = GdipAddPathPie(path, x, y, width, height, startAngle, sweepAngle);
- if (status == Ok)
- status = GdipDrawPath(graphics, pen, path);
+ if (stat == Ok)
+ stat = GdipFlattenPath(flat_path, transform, 1.0);
- GdipDeletePath(path);
- return status;
-}
+ GdipDeleteMatrix(transform);
+ }
-GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x,
- INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
-{
- TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
- width, height, startAngle, sweepAngle);
+ /* estimate the output size in pixels, can be larger than necessary */
+ if (stat == Ok)
+ {
+ output_area.left = floorf(flat_path->pathdata.Points[0].X);
+ output_area.right = ceilf(flat_path->pathdata.Points[0].X);
+ output_area.top = floorf(flat_path->pathdata.Points[0].Y);
+ output_area.bottom = ceilf(flat_path->pathdata.Points[0].Y);
- return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
-}
+ for (i=1; i<flat_path->pathdata.Count; i++)
+ {
+ REAL x, y;
+ x = flat_path->pathdata.Points[i].X;
+ y = flat_path->pathdata.Points[i].Y;
+
+ if (floorf(x) < output_area.left) output_area.left = floorf(x);
+ if (floorf(y) < output_area.top) output_area.top = floorf(y);
+ if (ceilf(x) > output_area.right) output_area.right = ceilf(x);
+ if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y);
+ }
-GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
- REAL y, REAL width, REAL height)
-{
- GpStatus status;
- GpPath *path;
+ stat = get_graphics_bounds(graphics, &gp_bound_rect);
+ }
- TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
+ if (stat == Ok)
+ {
+ output_area.left = max(output_area.left, floorf(gp_bound_rect.X));
+ output_area.top = max(output_area.top, floorf(gp_bound_rect.Y));
+ output_area.right = min(output_area.right, ceilf(gp_bound_rect.X + gp_bound_rect.Width));
+ output_area.bottom = min(output_area.bottom, ceilf(gp_bound_rect.Y + gp_bound_rect.Height));
- if(!pen || !graphics)
- return InvalidParameter;
+ output_width = output_area.right - output_area.left + 1;
+ output_height = output_area.bottom - output_area.top + 1;
- if(graphics->busy)
- return ObjectBusy;
+ if (output_width <= 0 || output_height <= 0)
+ {
+ GdipDeletePath(flat_path);
+ return Ok;
+ }
- status = GdipCreatePath(FillModeAlternate, &path);
- if (status != Ok) return status;
+ gp_output_area.X = output_area.left;
+ gp_output_area.Y = output_area.top;
+ gp_output_area.Width = output_width;
+ gp_output_area.Height = output_height;
- status = GdipAddPathRectangle(path, x, y, width, height);
- if (status == Ok)
- status = GdipDrawPath(graphics, pen, path);
+ output_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
+ if (!output_bits)
+ stat = OutOfMemory;
+ }
- GdipDeletePath(path);
- return status;
-}
+ if (stat == Ok)
+ {
+ if (pen->brush->bt != BrushTypeSolidColor)
+ {
+ /* allocate and draw brush output */
+ brush_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
-GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
- INT y, INT width, INT height)
-{
- TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
+ if (brush_bits)
+ {
+ stat = brush_fill_pixels(graphics, pen->brush, brush_bits,
+ &gp_output_area, output_width);
+ }
+ else
+ stat = OutOfMemory;
+ }
- return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
-}
+ if (stat == Ok)
+ {
+ /* convert dash pattern to bool array */
+ switch (pen->dash)
+ {
+ case DashStyleCustom:
+ {
+ dash_pattern_size = 0;
-GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen,
- GDIPCONST GpRectF* rects, INT count)
+ for (i=0; i < pen->numdashes; i++)
+ dash_pattern_size += gdip_round(pen->dashes[i]);
+
+ if (dash_pattern_size != 0)
+ {
+ dash_pattern = dyn_dash_pattern = heap_alloc(dash_pattern_size);
+
+ if (dyn_dash_pattern)
+ {
+ int j=0;
+ for (i=0; i < pen->numdashes; i++)
+ {
+ int k;
+ for (k=0; k < gdip_round(pen->dashes[i]); k++)
+ dyn_dash_pattern[j++] = (i&1)^1;
+ }
+ }
+ else
+ stat = OutOfMemory;
+
+ break;
+ }
+ /* else fall through */
+ }
+ case DashStyleSolid:
+ default:
+ dash_pattern = static_dash_pattern;
+ dash_pattern_size = 1;
+ break;
+ case DashStyleDash:
+ dash_pattern = static_dash_pattern;
+ dash_pattern_size = 4;
+ break;
+ case DashStyleDot:
+ dash_pattern = &static_dash_pattern[4];
+ dash_pattern_size = 2;
+ break;
+ case DashStyleDashDot:
+ dash_pattern = static_dash_pattern;
+ dash_pattern_size = 6;
+ break;
+ case DashStyleDashDotDot:
+ dash_pattern = static_dash_pattern;
+ dash_pattern_size = 8;
+ break;
+ }
+ }
+
+ if (stat == Ok)
+ {
+ /* trace path */
+ GpPointF subpath_start = flat_path->pathdata.Points[0];
+ INT prev_x = INT_MAX, prev_y = INT_MAX;
+ int dash_pos = dash_pattern_size - 1;
+
+ for (i=0; i < flat_path->pathdata.Count; i++)
+ {
+ BYTE type, type2;
+ GpPointF start_point, end_point;
+ GpPoint start_pointi, end_pointi;
+
+ type = flat_path->pathdata.Types[i];
+ if (i+1 < flat_path->pathdata.Count)
+ type2 = flat_path->pathdata.Types[i+1];
+ else
+ type2 = PathPointTypeStart;
+
+ start_point = flat_path->pathdata.Points[i];
+
+ if ((type & PathPointTypePathTypeMask) == PathPointTypeStart)
+ subpath_start = start_point;
+
+ if ((type & PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
+ end_point = subpath_start;
+ else if ((type2 & PathPointTypePathTypeMask) == PathPointTypeStart)
+ continue;
+ else
+ end_point = flat_path->pathdata.Points[i+1];
+
+ start_pointi.X = floorf(start_point.X);
+ start_pointi.Y = floorf(start_point.Y);
+ end_pointi.X = floorf(end_point.X);
+ end_pointi.Y = floorf(end_point.Y);
+
+ /* draw line segment */
+ if (abs(start_pointi.Y - end_pointi.Y) > abs(start_pointi.X - end_pointi.X))
+ {
+ INT x, y, start_y, end_y, step;
+
+ if (start_pointi.Y < end_pointi.Y)
+ {
+ step = 1;
+ start_y = ceilf(start_point.Y) - output_area.top;
+ end_y = end_pointi.Y - output_area.top;
+ }
+ else
+ {
+ step = -1;
+ start_y = start_point.Y - output_area.top;
+ end_y = ceilf(end_point.Y) - output_area.top;
+ }
+
+ for (y=start_y; y != (end_y+step); y+=step)
+ {
+ x = gdip_round( start_point.X +
+ (end_point.X - start_point.X) * (y + output_area.top - start_point.Y) / (end_point.Y - start_point.Y) )
+ - output_area.left;
+
+ if (x == prev_x && y == prev_y)
+ continue;
+
+ prev_x = x;
+ prev_y = y;
+ dash_pos = (dash_pos + 1 == dash_pattern_size) ? 0 : dash_pos + 1;
+
+ if (!dash_pattern[dash_pos])
+ continue;
+
+ if (x < 0 || x >= output_width || y < 0 || y >= output_height)
+ continue;
+
+ if (brush_bits)
+ output_bits[x + y*output_width] = brush_bits[x + y*output_width];
+ else
+ output_bits[x + y*output_width] = ((GpSolidFill*)pen->brush)->color;
+ }
+ }
+ else
+ {
+ INT x, y, start_x, end_x, step;
+
+ if (start_pointi.X < end_pointi.X)
+ {
+ step = 1;
+ start_x = ceilf(start_point.X) - output_area.left;
+ end_x = end_pointi.X - output_area.left;
+ }
+ else
+ {
+ step = -1;
+ start_x = start_point.X - output_area.left;
+ end_x = ceilf(end_point.X) - output_area.left;
+ }
+
+ for (x=start_x; x != (end_x+step); x+=step)
+ {
+ y = gdip_round( start_point.Y +
+ (end_point.Y - start_point.Y) * (x + output_area.left - start_point.X) / (end_point.X - start_point.X) )
+ - output_area.top;
+
+ if (x == prev_x && y == prev_y)
+ continue;
+
+ prev_x = x;
+ prev_y = y;
+ dash_pos = (dash_pos + 1 == dash_pattern_size) ? 0 : dash_pos + 1;
+
+ if (!dash_pattern[dash_pos])
+ continue;
+
+ if (x < 0 || x >= output_width || y < 0 || y >= output_height)
+ continue;
+
+ if (brush_bits)
+ output_bits[x + y*output_width] = brush_bits[x + y*output_width];
+ else
+ output_bits[x + y*output_width] = ((GpSolidFill*)pen->brush)->color;
+ }
+ }
+ }
+ }
+
+ /* draw output image */
+ if (stat == Ok)
+ {
+ stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
+ (BYTE*)output_bits, output_width, output_height, output_width * 4,
+ PixelFormat32bppARGB);
+ }
+
+ heap_free(brush_bits);
+ heap_free(dyn_dash_pattern);
+ heap_free(output_bits);
+ }
+
+ GdipDeletePath(flat_path);
+
+ return stat;
+}
+
+static GpStatus SOFTWARE_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
+{
+ GpStatus stat;
+ GpPath *wide_path;
+ GpMatrix *transform=NULL;
+
+ /* Check if the final pen thickness in pixels is too thin. */
+ if (pen->unit == UnitPixel)
+ {
+ if (pen->width < 1.415)
+ return SOFTWARE_GdipDrawThinPath(graphics, pen, path);
+ }
+ else
+ {
+ GpPointF points[3] = {{0,0}, {1,0}, {0,1}};
+
+ points[1].X = pen->width;
+ points[2].Y = pen->width;
+
+ stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, points, 3);
+
+ if (stat != Ok)
+ return stat;
+
+ if (((points[1].X-points[0].X)*(points[1].X-points[0].X) +
+ (points[1].Y-points[0].Y)*(points[1].Y-points[0].Y) < 2.0001) &&
+ ((points[2].X-points[0].X)*(points[2].X-points[0].X) +
+ (points[2].Y-points[0].Y)*(points[2].Y-points[0].Y) < 2.0001))
+ return SOFTWARE_GdipDrawThinPath(graphics, pen, path);
+ }
+
+ stat = GdipClonePath(path, &wide_path);
+
+ if (stat != Ok)
+ return stat;
+
+ if (pen->unit == UnitPixel)
+ {
+ /* We have to transform this to device coordinates to get the widths right. */
+ stat = GdipCreateMatrix(&transform);
+
+ if (stat == Ok)
+ stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, transform);
+ }
+
+ if (stat == Ok)
+ stat = GdipWidenPath(wide_path, pen, transform, 1.0);
+
+ if (pen->unit == UnitPixel)
+ {
+ /* Transform the path back to world coordinates */
+ if (stat == Ok)
+ stat = GdipInvertMatrix(transform);
+
+ if (stat == Ok)
+ stat = GdipTransformPath(wide_path, transform);
+ }
+
+ /* Actually draw the path */
+ if (stat == Ok)
+ stat = GdipFillPath(graphics, pen->brush, wide_path);
+
+ GdipDeleteMatrix(transform);
+
+ GdipDeletePath(wide_path);
+
+ return stat;
+}
+
+GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
+{
+ GpStatus retval;
+
+ TRACE("(%p, %p, %p)\n", graphics, pen, path);
+
+ if(!pen || !graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ if (path->pathdata.Count == 0)
+ return Ok;
+
+ if (!graphics->hdc)
+ retval = SOFTWARE_GdipDrawPath(graphics, pen, path);
+ else
+ retval = GDI32_GdipDrawPath(graphics, pen, path);
+
+ return retval;
+}
+
+GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
+ REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
+{
+ GpStatus status;
+ GpPath *path;
+
+ TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
+ width, height, startAngle, sweepAngle);
+
+ if(!graphics || !pen)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ status = GdipCreatePath(FillModeAlternate, &path);
+ if (status != Ok) return status;
+
+ status = GdipAddPathPie(path, x, y, width, height, startAngle, sweepAngle);
+ if (status == Ok)
+ status = GdipDrawPath(graphics, pen, path);
+
+ GdipDeletePath(path);
+ return status;
+}
+
+GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x,
+ INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
+{
+ TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
+ width, height, startAngle, sweepAngle);
+
+ return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
+}
+
+GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
+ REAL y, REAL width, REAL height)
+{
+ GpStatus status;
+ GpPath *path;
+
+ TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
+
+ if(!pen || !graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ status = GdipCreatePath(FillModeAlternate, &path);
+ if (status != Ok) return status;
+
+ status = GdipAddPathRectangle(path, x, y, width, height);
+ if (status == Ok)
+ status = GdipDrawPath(graphics, pen, path);
+
+ GdipDeletePath(path);
+ return status;
+}
+
+GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
+ INT y, INT width, INT height)
+{
+ TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
+
+ return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
+}
+
+GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen,
+ GDIPCONST GpRectF* rects, INT count)
{
GpStatus status;
GpPath *path;
if(!rects || count<=0)
return InvalidParameter;
- rectsF = GdipAlloc(sizeof(GpRectF) * count);
+ rectsF = heap_alloc_zero(sizeof(GpRectF) * count);
if(!rectsF)
return OutOfMemory;
}
ret = GdipDrawRectangles(graphics, pen, rectsF, count);
- GdipFree(rectsF);
+ heap_free(rectsF);
return ret;
}
if(count == 1) /* Do nothing */
return Ok;
- ptf = GdipAlloc(sizeof(GpPointF)*count);
+ ptf = heap_alloc_zero(sizeof(GpPointF)*count);
if(!ptf)
return OutOfMemory;
stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill);
- GdipFree(ptf);
+ heap_free(ptf);
return stat;
}
{
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;
if(!rects || count <= 0)
return InvalidParameter;
- rectsF = GdipAlloc(sizeof(GpRectF)*count);
+ rectsF = heap_alloc_zero(sizeof(GpRectF)*count);
if(!rectsF)
return OutOfMemory;
}
ret = GdipFillRectangles(graphics,brush,rectsF,count);
- GdipFree(rectsF);
+ heap_free(rectsF);
return ret;
}
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
+
+ hrgn = NULL;
+ status = get_clip_hrgn(graphics, &hrgn);
+
+ if (status != Ok)
+ {
+ RestoreDC(graphics->hdc, save_state);
+ return status;
+ }
+
+ if (hrgn)
+ {
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
+ }
+
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
{
BeginPath(graphics->hdc);
RestoreDC(graphics->hdc, save_state);
- DeleteObject(hrgn);
return Ok;
}
gp_bound_rect.Width = bound_rect.right - bound_rect.left;
gp_bound_rect.Height = bound_rect.bottom - bound_rect.top;
- pixel_data = GdipAlloc(sizeof(*pixel_data) * gp_bound_rect.Width * gp_bound_rect.Height);
+ pixel_data = heap_alloc_zero(sizeof(*pixel_data) * gp_bound_rect.Width * gp_bound_rect.Height);
if (!pixel_data)
stat = OutOfMemory;
if (stat == Ok)
stat = alpha_blend_pixels_hrgn(graphics, gp_bound_rect.X,
gp_bound_rect.Y, (BYTE*)pixel_data, gp_bound_rect.Width,
- gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion);
+ gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion,
+ PixelFormat32bppARGB);
- GdipFree(pixel_data);
+ heap_free(pixel_data);
}
DeleteObject(hregion);
{
GpRegion *clip_rgn;
GpStatus stat;
+ GpMatrix device_to_world;
TRACE("(%p, %p)\n", graphics, rect);
if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok)
goto cleanup;
+ /* transform to world coordinates */
+ if((stat = get_graphics_transform(graphics, CoordinateSpaceWorld, CoordinateSpaceDevice, &device_to_world)) != Ok)
+ goto cleanup;
+
+ if((stat = GdipTransformRegion(clip_rgn, &device_to_world)) != Ok)
+ goto cleanup;
+
/* get bounds of the region */
stat = GdipGetRegionBounds(clip_rgn, graphics, rect);
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ return METAFILE_GraphicsClear((GpMetafile*)graphics->image, color);
+
if((stat = GdipCreateSolidFill(color, &brush)) != Ok)
return stat;
- if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){
+ if((stat = GdipGetVisibleClipBounds(graphics, &wnd_rect)) != Ok){
GdipDeleteBrush((GpBrush*)brush);
return stat;
}
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));
+ stringdup = heap_alloc_zero((length + 1) * sizeof(WCHAR));
if(!stringdup) return OutOfMemory;
+ if (!format)
+ {
+ stat = GdipStringFormatGetGenericDefault(&dyn_format);
+ if (stat != Ok)
+ {
+ heap_free(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)
{
}
if (hotkeyprefix_count)
- hotkeyprefix_offsets = GdipAlloc(sizeof(INT) * hotkeyprefix_count);
+ hotkeyprefix_offsets = heap_alloc_zero(sizeof(INT) * hotkeyprefix_count);
hotkeyprefix_count = 0;
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);
+ heap_free(stringdup);
+ heap_free(hotkeyprefix_offsets);
+ GdipDeleteStringFormat(dyn_format);
return stat;
}
scaled_rect.Width = layoutRect->Width * args.rel_width;
scaled_rect.Height = layoutRect->Height * args.rel_height;
+ if (scaled_rect.Width >= 1 << 23) scaled_rect.Width = 1 << 23;
+ if (scaled_rect.Height >= 1 << 23) scaled_rect.Height = 1 << 23;
+
get_font_hfont(graphics, font, stringFormat, &gdifont, NULL);
oldfont = SelectObject(hdc, gdifont);
GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
{
+ GpStatus stat;
+
TRACE("(%p)\n", graphics);
if(!graphics)
if(graphics->busy)
return ObjectBusy;
- return GdipSetMatrixElements(&graphics->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
-}
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_ResetWorldTransform((GpMetafile*)graphics->image);
-GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
-{
- return GdipEndContainer(graphics, state);
+ if (stat != Ok)
+ return stat;
+ }
+
+ return GdipSetMatrixElements(&graphics->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
GpMatrixOrder order)
{
+ GpStatus stat;
+
TRACE("(%p, %.2f, %d)\n", graphics, angle, order);
if(!graphics)
if(graphics->busy)
return ObjectBusy;
- return GdipRotateMatrix(&graphics->worldtrans, angle, order);
-}
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_RotateWorldTransform((GpMetafile*)graphics->image, angle, order);
-GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
-{
- return GdipBeginContainer2(graphics, state);
+ if (stat != Ok)
+ return stat;
+ }
+
+ return GdipRotateMatrix(&graphics->worldtrans, angle, order);
}
-GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
- GraphicsContainer *state)
+static GpStatus begin_container(GpGraphics *graphics,
+ GraphicsContainerType type, GraphicsContainer *state)
{
GraphicsContainerItem *container;
GpStatus sts;
- TRACE("(%p, %p)\n", graphics, state);
-
if(!graphics || !state)
return InvalidParameter;
- sts = init_container(&container, graphics);
+ sts = init_container(&container, graphics, type);
if(sts != Ok)
return sts;
list_add_head(&graphics->containers, &container->entry);
*state = graphics->contid = container->contid;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ if (type == BEGIN_CONTAINER)
+ METAFILE_BeginContainerNoParams((GpMetafile*)graphics->image, container->contid);
+ else
+ METAFILE_SaveGraphics((GpMetafile*)graphics->image, container->contid);
+ }
+
return Ok;
}
+GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
+{
+ TRACE("(%p, %p)\n", graphics, state);
+ return begin_container(graphics, SAVE_GRAPHICS, state);
+}
+
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
+ GraphicsContainer *state)
+{
+ TRACE("(%p, %p)\n", graphics, state);
+ return begin_container(graphics, BEGIN_CONTAINER, state);
+}
+
GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
{
- FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
- return NotImplemented;
+ GraphicsContainerItem *container;
+ GpMatrix transform;
+ GpStatus stat;
+ GpRectF scaled_srcrect;
+ REAL scale_x, scale_y;
+
+ TRACE("(%p, %s, %s, %d, %p)\n", graphics, debugstr_rectf(dstrect), debugstr_rectf(srcrect), unit, state);
+
+ if(!graphics || !dstrect || !srcrect || unit < UnitPixel || unit > UnitMillimeter || !state)
+ return InvalidParameter;
+
+ stat = init_container(&container, graphics, BEGIN_CONTAINER);
+ if(stat != Ok)
+ return stat;
+
+ list_add_head(&graphics->containers, &container->entry);
+ *state = graphics->contid = container->contid;
+
+ scale_x = units_to_pixels(1.0, unit, graphics->xres);
+ scale_y = units_to_pixels(1.0, unit, graphics->yres);
+
+ scaled_srcrect.X = scale_x * srcrect->X;
+ scaled_srcrect.Y = scale_y * srcrect->Y;
+ scaled_srcrect.Width = scale_x * srcrect->Width;
+ scaled_srcrect.Height = scale_y * srcrect->Height;
+
+ transform.matrix[0] = dstrect->Width / scaled_srcrect.Width;
+ transform.matrix[1] = 0.0;
+ transform.matrix[2] = 0.0;
+ transform.matrix[3] = dstrect->Height / scaled_srcrect.Height;
+ transform.matrix[4] = dstrect->X - scaled_srcrect.X;
+ transform.matrix[5] = dstrect->Y - scaled_srcrect.Y;
+
+ GdipMultiplyMatrix(&graphics->worldtrans, &transform, MatrixOrderPrepend);
+
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ METAFILE_BeginContainer((GpMetafile*)graphics->image, dstrect, srcrect, unit, container->contid);
+ }
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state)
{
- FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
- return NotImplemented;
+ GpRectF dstrectf, srcrectf;
+
+ TRACE("(%p, %p, %p, %d, %p)\n", graphics, dstrect, srcrect, unit, state);
+
+ if (!dstrect || !srcrect)
+ return InvalidParameter;
+
+ dstrectf.X = dstrect->X;
+ dstrectf.Y = dstrect->Y;
+ dstrectf.Width = dstrect->Width;
+ dstrectf.Height = dstrect->Height;
+
+ srcrectf.X = srcrect->X;
+ srcrectf.Y = srcrect->Y;
+ srcrectf.Width = srcrect->Width;
+ srcrectf.Height = srcrect->Height;
+
+ return GdipBeginContainer(graphics, &dstrectf, &srcrectf, unit, state);
}
GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data)
return NotImplemented;
}
-GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
+static GpStatus end_container(GpGraphics *graphics, GraphicsContainerType type,
+ GraphicsContainer state)
{
GpStatus sts;
GraphicsContainerItem *container, *container2;
- TRACE("(%p, %x)\n", graphics, state);
-
if(!graphics)
return InvalidParameter;
LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
- if(container->contid == state)
+ if(container->contid == state && container->type == type)
break;
}
list_remove(&container->entry);
delete_container(container);
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ if (type == BEGIN_CONTAINER)
+ METAFILE_EndContainer((GpMetafile*)graphics->image, state);
+ else
+ METAFILE_RestoreGraphics((GpMetafile*)graphics->image, state);
+ }
+
return Ok;
}
+GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
+{
+ TRACE("(%p, %x)\n", graphics, state);
+ return end_container(graphics, BEGIN_CONTAINER, state);
+}
+
+GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
+{
+ TRACE("(%p, %x)\n", graphics, state);
+ return end_container(graphics, SAVE_GRAPHICS, state);
+}
+
GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
REAL sy, GpMatrixOrder order)
{
+ GpStatus stat;
+
TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order);
if(!graphics)
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_ScaleWorldTransform((GpMetafile*)graphics->image, sx, sy, order);
+
+ if (stat != Ok)
+ return stat;
+ }
+
return GdipScaleMatrix(&graphics->worldtrans, sx, sy, order);
}
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;
GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
{
+ GpStatus stat;
+
TRACE("(%p, %p)\n", graphics, matrix);
if(!graphics || !matrix)
matrix->matrix[0], matrix->matrix[1], matrix->matrix[2],
matrix->matrix[3], matrix->matrix[4], matrix->matrix[5]);
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_SetWorldTransform((GpMetafile*)graphics->image, matrix);
+
+ if (stat != Ok)
+ return stat;
+ }
+
graphics->worldtrans = *matrix;
return Ok;
GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
REAL dy, GpMatrixOrder order)
{
+ GpStatus stat;
+
TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
if(!graphics)
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_TranslateWorldTransform((GpMetafile*)graphics->image, dx, dy, order);
+
+ if (stat != Ok)
+ return stat;
+ }
+
return GdipTranslateMatrix(&graphics->worldtrans, dx, dy, order);
}
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ status = METAFILE_SetClipRect((GpMetafile*)graphics->image, x, y, width, height, mode);
+ if (status != Ok)
+ return status;
+ }
+
rect.X = x;
rect.Y = y;
rect.Width = width;
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)
{
- INT save_state;
- POINT *pti;
+ GpStatus status;
+ GpPath* path;
TRACE("(%p, %p, %d)\n", graphics, points, count);
if(graphics->busy)
return ObjectBusy;
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- return Ok;
- }
-
- pti = GdipAlloc(sizeof(POINT) * count);
-
- save_state = prepare_dc(graphics, pen);
- SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
+ status = GdipCreatePath(FillModeAlternate, &path);
+ if (status != Ok) return status;
- transform_and_round_points(graphics, pti, (GpPointF*)points, count);
- Polygon(graphics->hdc, pti, count);
+ status = GdipAddPathPolygon(path, points, count);
+ if (status == Ok)
+ status = GdipDrawPath(graphics, pen, path);
- restore_dc(graphics, save_state);
- GdipFree(pti);
+ GdipDeletePath(path);
- return Ok;
+ return status;
}
GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points,
TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
if(count<=0) return InvalidParameter;
- ptf = GdipAlloc(sizeof(GpPointF) * count);
+ ptf = heap_alloc_zero(sizeof(GpPointF) * count);
for(i = 0;i < count; i++){
ptf[i].X = (REAL)points[i].X;
}
ret = GdipDrawPolygon(graphics,pen,ptf,count);
- GdipFree(ptf);
+ heap_free(ptf);
return ret;
}
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ ret = METAFILE_MultiplyWorldTransform((GpMetafile*)graphics->image, matrix, order);
+
+ if (ret != Ok)
+ return ret;
+ }
+
m = graphics->worldtrans;
ret = GdipMultiplyMatrix(&m, matrix, order);
{
stat = METAFILE_GetDC((GpMetafile*)graphics->image, hdc);
}
- else if (!graphics->hdc || graphics->alpha_hdc ||
+ else if (!graphics->hdc ||
(graphics->image && graphics->image->type == ImageTypeBitmap && ((GpBitmap*)graphics->image)->format & PixelFormatAlpha))
{
/* Create a fake HDC and fill it with a constant color. */
/* Write the changed pixels to the real target. */
alpha_blend_pixels(graphics, 0, 0, graphics->temp_bits,
graphics->temp_hbitmap_width, graphics->temp_hbitmap_height,
- graphics->temp_hbitmap_width * 4);
+ graphics->temp_hbitmap_width * 4, PixelFormat32bppARGB);
/* Clean up. */
DeleteDC(graphics->temp_hdc);
/* free everything except root node and header */
delete_element(®ion->node);
memcpy(region, clip, sizeof(GpRegion));
- GdipFree(clip);
+ heap_free(clip);
return Ok;
}
-static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
+GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix)
{
GpStatus stat = Ok;
if(count <= 0)
return InvalidParameter;
- pointsF = GdipAlloc(sizeof(GpPointF) * count);
+ pointsF = heap_alloc_zero(sizeof(GpPointF) * count);
if(!pointsF)
return OutOfMemory;
points[i].X = gdip_round(pointsF[i].X);
points[i].Y = gdip_round(pointsF[i].Y);
}
- GdipFree(pointsF);
+ heap_free(pointsF);
return ret;
}
if (flags & DriverStringOptionsCmapLookup)
{
- glyph_indices = dynamic_glyph_indices = GdipAlloc(sizeof(WORD) * length);
+ glyph_indices = dynamic_glyph_indices = heap_alloc_zero(sizeof(WORD) * length);
if (!glyph_indices)
{
DeleteDC(hdc);
if (max_x < x) max_x = x;
}
- GdipFree(dynamic_glyph_indices);
+ heap_free(dynamic_glyph_indices);
DeleteDC(hdc);
DeleteObject(hfont);
GpPointF pt;
HFONT hfont;
UINT eto_flags=0;
+ GpStatus status;
+ HRGN hrgn;
if (flags & unsupported_flags)
FIXME("Ignoring flags %x\n", flags & unsupported_flags);
SetBkMode(graphics->hdc, TRANSPARENT);
SetTextColor(graphics->hdc, get_gdi_brush_color(brush));
+ status = get_clip_hrgn(graphics, &hrgn);
+
+ if (status == Ok && hrgn)
+ {
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
+ }
+
pt = positions[0];
GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &pt, 1);
if (flags & unsupported_flags)
FIXME("Ignoring flags %x\n", flags & unsupported_flags);
- pti = GdipAlloc(sizeof(POINT) * length);
+ pti = heap_alloc_zero(sizeof(POINT) * length);
if (!pti)
return OutOfMemory;
}
else
{
- real_positions = GdipAlloc(sizeof(PointF) * length);
+ real_positions = heap_alloc_zero(sizeof(PointF) * length);
if (!real_positions)
{
- GdipFree(pti);
+ heap_free(pti);
return OutOfMemory;
}
transform_and_round_points(graphics, pti, real_positions, length);
- GdipFree(real_positions);
+ heap_free(real_positions);
}
get_font_hfont(graphics, font, format, &hfont, matrix);
if (glyphsize == GDI_ERROR)
{
ERR("GetGlyphOutlineW failed\n");
- GdipFree(pti);
+ heap_free(pti);
DeleteDC(hdc);
DeleteObject(hfont);
return GenericError;
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)
{
}
}
- glyph_mask = GdipAlloc(max_glyphsize);
- text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
+ if (max_glyphsize == 0)
+ /* Nothing to draw. */
+ return Ok;
+
+ glyph_mask = heap_alloc_zero(max_glyphsize);
+ text_mask = heap_alloc_zero((max_x - min_x) * (max_y - min_y));
text_mask_stride = max_x - min_x;
if (!(glyph_mask && text_mask))
{
- GdipFree(glyph_mask);
- GdipFree(text_mask);
- GdipFree(pti);
+ heap_free(glyph_mask);
+ heap_free(text_mask);
+ heap_free(pti);
DeleteDC(hdc);
DeleteObject(hfont);
return OutOfMemory;
/* 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);
}
}
- GdipFree(pti);
+ heap_free(pti);
DeleteDC(hdc);
DeleteObject(hfont);
- GdipFree(glyph_mask);
+ heap_free(glyph_mask);
/* get the brush data */
- pixel_data = GdipAlloc(4 * (max_x - min_x) * (max_y - min_y));
+ pixel_data = heap_alloc_zero(4 * (max_x - min_x) * (max_y - min_y));
if (!pixel_data)
{
- GdipFree(text_mask);
+ heap_free(text_mask);
return OutOfMemory;
}
stat = brush_fill_pixels(graphics, (GpBrush*)brush, (DWORD*)pixel_data, &pixel_area, pixel_area.Width);
if (stat != Ok)
{
- GdipFree(text_mask);
- GdipFree(pixel_data);
+ heap_free(text_mask);
+ heap_free(pixel_data);
return stat;
}
}
}
- GdipFree(text_mask);
+ heap_free(text_mask);
/* draw the result */
stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width,
- pixel_area.Height, pixel_data_stride);
+ pixel_area.Height, pixel_data_stride, PixelFormat32bppARGB);
- GdipFree(pixel_data);
+ heap_free(pixel_data);
return stat;
}
brush, positions, flags, matrix);
}
-GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
- MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
-{
- FIXME("(%p %p %d %p %d %p %p): stub\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
- return NotImplemented;
-}
-
/*****************************************************************************
* GdipIsVisibleClipEmpty [GDIPLUS.@]
*/