* 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 "winreg.h"
+#include "shlwapi.h"
+
+#include "gdiplus.h"
#include "gdiplus_private.h"
+#include "wine/debug.h"
+#include "wine/list.h"
-#include <winreg.h>
-#include <shlwapi.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
#define GDIP_GET_NEW_CONTID_FOR(pGpGraphics) \
(UINT)(InterlockedExchangeAdd(&g_priv_contid,GDIP_CONTID_STEP))
+
+/* ReactOS FIXME: Inspect */
+#define fmax max
+
/* looks-right constants */
#define ANCHOR_WIDTH (2.0)
#define MAX_ITERS (50)
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;
+
+ pt[0].X = 0.0;
+ pt[0].Y = 0.0;
+ pt[1].X = 1.0;
+ pt[1].Y = 1.0;
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, pt, 2);
+ width *= sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) +
+ (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
}
if(pen->dash == DashStyleCustom){
RestoreDC(graphics->hdc, state);
}
-/* This helper applies all the changes that the points listed in ptf need in
- * order to be drawn on the device context. In the end, this should include at
- * least:
- * -scaling by page unit
- * -applying world transformation
- * -converting from float to int
- * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
- * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
- * gdi to draw, and these functions would irreparably mess with line widths.
- */
-static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
- GpPointF *ptf, INT count)
+static void round_points(POINT *pti, GpPointF *ptf, INT count)
{
- REAL scale_x, scale_y;
- GpMatrix matrix;
int i;
- scale_x = units_to_pixels(1.0, graphics->unit, graphics->xres);
- scale_y = units_to_pixels(1.0, graphics->unit, graphics->yres);
-
- /* apply page scale */
- if(graphics->unit != UnitDisplay)
- {
- scale_x *= graphics->scale;
- scale_y *= graphics->scale;
- }
-
- matrix = graphics->worldtrans;
- GdipScaleMatrix(&matrix, scale_x, scale_y, MatrixOrderAppend);
- GdipTransformMatrixPoints(&matrix, ptf, count);
-
for(i = 0; i < count; i++){
pti[i].x = gdip_round(ptf[i].X);
pti[i].y = gdip_round(ptf[i].Y);
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");
static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
{
- /* clipping region is in device coords */
- return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
+ GpRegion *rgn;
+ GpMatrix transform;
+ GpStatus stat;
+ BOOL identity;
+
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, &transform);
+
+ if (stat == Ok)
+ stat = GdipIsMatrixIdentity(&transform, &identity);
+
+ if (stat == Ok)
+ stat = GdipCloneRegion(graphics->clip, &rgn);
+
+ if (stat == Ok)
+ {
+ if (!identity)
+ stat = GdipTransformRegion(rgn, &transform);
+
+ if (stat == Ok)
+ stat = GdipGetRegionHRgn(rgn, NULL, hrgn);
+
+ GdipDeleteRegion(rgn);
+ }
+
+ if (stat == Ok && graphics->gdi_clip)
+ {
+ if (*hrgn)
+ CombineRgn(*hrgn, *hrgn, graphics->gdi_clip, RGN_AND);
+ else
+ {
+ *hrgn = CreateRectRgn(0,0,0,0);
+ CombineRgn(*hrgn, graphics->gdi_clip, graphics->gdi_clip, RGN_COPY);
+ }
+ }
+
+ return stat;
}
-/* 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);
+ 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, fmt);
+}
+
+/* NOTE: start and end pixels must be in pre-multiplied ARGB format */
+static inline ARGB blend_colors_premult(ARGB start, ARGB end, REAL position)
{
- return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL);
+ UINT pos = position * 255.0f + 0.5f;
+ return
+ (((((start >> 24) ) << 8) + (((end >> 24) ) - ((start >> 24) )) * pos) >> 8) << 24 |
+ (((((start >> 16) & 0xff) << 8) + (((end >> 16) & 0xff) - ((start >> 16) & 0xff)) * pos) >> 8) << 16 |
+ (((((start >> 8) & 0xff) << 8) + (((end >> 8) & 0xff) - ((start >> 8) & 0xff)) * pos) >> 8) << 8 |
+ (((((start ) & 0xff) << 8) + (((end ) & 0xff) - ((start ) & 0xff)) * pos) >> 8);
}
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 = (INT)(position * 255.0f + 0.5f);
- 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)
REAL blendfac;
/* clamp to between 0.0 and 1.0, using the wrap mode */
+ position = (position - brush->rect.X) / brush->rect.Width;
if (brush->wrap == WrapModeTile)
{
position = fmodf(position, 1.0f);
}
}
-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;
}
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;
+ if ((attributes->noop[type] == IMAGEATTR_NOOP_UNDEFINED &&
+ attributes->noop[ColorAdjustTypeDefault] == IMAGEATTR_NOOP_SET) ||
+ (attributes->noop[type] == IMAGEATTR_NOOP_SET))
+ return fmt;
+
if (attributes->colorkeys[type].enabled ||
attributes->colorkeys[ColorAdjustTypeDefault].enabled)
{
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
{
if (y < 0)
y = height*2 + y % (height * 2);
- if ((attributes->wrap & 1) == 1)
+ if (attributes->wrap & WrapModeTileFlipX)
{
- /* Flip X */
if ((x / width) % 2 == 0)
x = x % width;
else
else
x = x % width;
- if ((attributes->wrap & 2) == 2)
+ if (attributes->wrap & WrapModeTileFlipY)
{
- /* Flip Y */
if ((y / height) % 2 == 0)
y = y % height;
else
return ((DWORD*)(bits))[(x - src_rect->X) + (y - src_rect->Y) * src_rect->Width];
}
+static inline int positive_ceilf(float f)
+{
+ return f - (int)f > 0.0f ? f + 1.0f : f;
+}
+
static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width,
UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
InterpolationMode interpolation, PixelOffsetMode offset_mode)
ARGB top, bottom;
float x_offset;
- leftxf = floorf(point->X);
- leftx = (INT)leftxf;
- rightx = (INT)ceilf(point->X);
- topyf = floorf(point->Y);
- topy = (INT)topyf;
- bottomy = (INT)ceilf(point->Y);
+ leftx = (INT)point->X;
+ leftxf = (REAL)leftx;
+ rightx = positive_ceilf(point->X);
+ topy = (INT)point->Y;
+ topyf = (REAL)topy;
+ bottomy = positive_ceilf(point->Y);
if (leftx == rightx && topy == bottomy)
return sample_bitmap_pixel(src_rect, bits, width, height,
}
}
+static ARGB resample_bitmap_pixel_premult(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width,
+ UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
+ InterpolationMode interpolation, PixelOffsetMode offset_mode)
+{
+ static int fixme;
+
+ switch (interpolation)
+ {
+ default:
+ if (!fixme++)
+ FIXME("Unimplemented interpolation %i\n", interpolation);
+ /* fall-through */
+ case InterpolationModeBilinear:
+ {
+ REAL leftxf, topyf;
+ INT leftx, rightx, topy, bottomy;
+ ARGB topleft, topright, bottomleft, bottomright;
+ ARGB top, bottom;
+ float x_offset;
+
+ leftx = (INT)point->X;
+ leftxf = (REAL)leftx;
+ rightx = positive_ceilf(point->X);
+ topy = (INT)point->Y;
+ topyf = (REAL)topy;
+ bottomy = positive_ceilf(point->Y);
+
+ if (leftx == rightx && topy == bottomy)
+ return sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, topy, attributes);
+
+ topleft = sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, topy, attributes);
+ topright = sample_bitmap_pixel(src_rect, bits, width, height,
+ rightx, topy, attributes);
+ bottomleft = sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, bottomy, attributes);
+ bottomright = sample_bitmap_pixel(src_rect, bits, width, height,
+ rightx, bottomy, attributes);
+
+ x_offset = point->X - leftxf;
+ top = blend_colors_premult(topleft, topright, x_offset);
+ bottom = blend_colors_premult(bottomleft, bottomright, x_offset);
+
+ return blend_colors_premult(top, bottom, point->Y - topyf);
+ }
+ case InterpolationModeNearestNeighbor:
+ {
+ FLOAT pixel_offset;
+ switch (offset_mode)
+ {
+ default:
+ case PixelOffsetModeNone:
+ case PixelOffsetModeHighSpeed:
+ pixel_offset = 0.5;
+ break;
+
+ case PixelOffsetModeHalf:
+ case PixelOffsetModeHighQuality:
+ pixel_offset = 0.0;
+ break;
+ }
+ return sample_bitmap_pixel(src_rect, bits, width, height,
+ floorf(point->X + pixel_offset), point->Y + pixel_offset, attributes);
+ }
+
+ }
+}
+
static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL y)
{
return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
}
-static BOOL brush_can_fill_path(GpBrush *brush)
+/* is_fill is TRUE if filling regions, FALSE for drawing primitives */
+static BOOL brush_can_fill_path(GpBrush *brush, BOOL is_fill)
{
switch (brush->bt)
{
case BrushTypeSolidColor:
- return TRUE;
+ {
+ if (is_fill)
+ return TRUE;
+ else
+ {
+ /* cannot draw semi-transparent colors */
+ return (((GpSolidFill*)brush)->color & 0xff000000) == 0xff000000;
+ }
+ }
case BrushTypeHatchFill:
{
GpHatch *hatch = (GpHatch*)brush;
}
}
-static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
+static GpStatus brush_fill_path(GpGraphics *graphics, GpBrush *brush)
{
+ GpStatus status = Ok;
switch (brush->bt)
{
case BrushTypeSolidColor:
RECT rc;
/* partially transparent fill */
- SelectClipPath(graphics->hdc, RGN_AND);
+ if (!SelectClipPath(graphics->hdc, RGN_AND))
+ {
+ status = GenericError;
+ DeleteObject(bmp);
+ break;
+ }
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
{
HDC hdc = CreateCompatibleDC(NULL);
- if (!hdc) break;
+ if (!hdc)
+ {
+ status = OutOfMemory;
+ DeleteObject(bmp);
+ break;
+ }
SelectObject(hdc, bmp);
gdi_alpha_blend(graphics, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
HBRUSH gdibrush, old_brush;
gdibrush = create_gdi_brush(brush);
- if (!gdibrush) return;
+ if (!gdibrush)
+ {
+ status = OutOfMemory;
+ break;
+ }
old_brush = SelectObject(graphics->hdc, gdibrush);
FillPath(graphics->hdc);
break;
}
}
+
+ return status;
}
static BOOL brush_can_fill_pixels(GpBrush *brush)
case BrushTypeLinearGradient:
{
GpLineGradient *fill = (GpLineGradient*)brush;
- GpPointF draw_points[3], line_points[3];
+ GpPointF draw_points[3];
GpStatus stat;
- static const GpRectF box_1 = { 0.0, 0.0, 1.0, 1.0 };
- GpMatrix *world_to_gradient; /* FIXME: Store this in the brush? */
int x, y;
draw_points[0].X = fill_area->X;
/* Transform the points to a co-ordinate space where X is the point's
* position in the gradient, 0.0 being the start point and 1.0 the
* end point. */
- stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
- CoordinateSpaceDevice, draw_points, 3);
+ stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
+ WineCoordinateSpaceGdiDevice, draw_points, 3);
if (stat == Ok)
{
- line_points[0] = fill->startpoint;
- line_points[1] = fill->endpoint;
- line_points[2].X = fill->startpoint.X + (fill->startpoint.Y - fill->endpoint.Y);
- line_points[2].Y = fill->startpoint.Y + (fill->endpoint.X - fill->startpoint.X);
-
- stat = GdipCreateMatrix3(&box_1, line_points, &world_to_gradient);
- }
-
- if (stat == Ok)
- {
- stat = GdipInvertMatrix(world_to_gradient);
+ GpMatrix world_to_gradient = fill->transform;
+ stat = GdipInvertMatrix(&world_to_gradient);
if (stat == Ok)
- stat = GdipTransformMatrixPoints(world_to_gradient, draw_points, 3);
-
- GdipDeleteMatrix(world_to_gradient);
+ stat = GdipTransformMatrixPoints(&world_to_gradient, draw_points, 3);
}
if (stat == Ok)
draw_points[2].Y = fill_area->Y+1;
/* Transform the points to the co-ordinate space of the bitmap. */
- stat = GdipTransformPoints(graphics, CoordinateSpaceWorld,
- CoordinateSpaceDevice, draw_points, 3);
+ stat = gdip_transform_points(graphics, CoordinateSpaceWorld,
+ WineCoordinateSpaceGdiDevice, draw_points, 3);
if (stat == Ok)
{
{
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;
}
}
if (stat != Ok)
return stat;
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &world_to_device);
if (stat == Ok)
{
REAL blend_amount, pdy, pdx;
pdy = yf - center_point.Y;
pdx = xf - center_point.X;
- blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
- outer_color = blend_colors(start_color, end_color, blend_amount);
+
+ if (fabs(pdx) <= 0.001 && fabs(pdy) <= 0.001)
+ {
+ /* Too close to center point, don't try to calculate outer color */
+ outer_color = start_color;
+ }
+ else
+ {
+ blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy );
+ outer_color = blend_colors(start_color, end_color, blend_amount);
+ }
}
distance = (end_point.Y - start_point.Y) * (start_point.X - xf) +
ptf[3].X = x2 - dbig;
ptf[2].X = x2 + dsmall;
- transform_and_round_points(graphics, pt, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
+
+ round_points(pt, ptf, 4);
+
Polygon(graphics->hdc, pt, 4);
break;
ptf[2].X = x2;
ptf[2].Y = y2;
- transform_and_round_points(graphics, pt, ptf, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Polygon(graphics->hdc, pt, 3);
break;
ptf[1].X = x2 + dx;
ptf[1].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 2);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 2);
+
+ round_points(pt, ptf, 2);
+
Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
break;
ptf[2].X = x2 + dx;
ptf[2].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 3);
+
+ round_points(pt, ptf, 3);
+
Polygon(graphics->hdc, pt, 3);
break;
ptf[3].X = x2 + dx;
ptf[3].Y = y2 + dy;
- transform_and_round_points(graphics, pt, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
+
+ round_points(pt, ptf, 4);
+
Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
pt[2].y, pt[3].x, pt[3].y);
if(!custom)
break;
+ if (custom->type == CustomLineCapTypeAdjustableArrow)
+ {
+ GpAdjustableArrowCap *arrow = (GpAdjustableArrowCap *)custom;
+ if (arrow->cap.fill && arrow->height <= 0.0)
+ 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;
GdipTranslateMatrix(&matrix, x2, y2, MatrixOrderAppend);
GdipTransformMatrixPoints(&matrix, custptf, count);
- transform_and_round_points(graphics, custpt, custptf, count);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, custptf, count);
+
+ round_points(custpt, custptf, count);
for(i = 0; i < count; i++)
tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
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;
}
}
}
- transform_and_round_points(graphics, pti, ptcopy, count);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptcopy, count);
+
+ round_points(pti, ptcopy, count);
for(i = 0; i < count; i++){
tp[i] = convert_path_point_type(types[i]);
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,
return Ok;
}
-static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+static GpStatus get_graphics_device_bounds(GpGraphics* graphics, GpRectF* rect)
{
RECT wnd_rect;
GpStatus stat=Ok;
return stat;
}
+static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+{
+ GpStatus stat = get_graphics_device_bounds(graphics, rect);
+
+ if (stat == Ok && graphics->hdc)
+ {
+ GpPointF points[4], min_point, max_point;
+ int i;
+
+ points[0].X = points[2].X = rect->X;
+ points[0].Y = points[1].Y = rect->Y;
+ points[1].X = points[3].X = rect->X + rect->Width;
+ points[2].Y = points[3].Y = rect->Y + rect->Height;
+
+ gdip_transform_points(graphics, CoordinateSpaceDevice, WineCoordinateSpaceGdiDevice, points, 4);
+
+ min_point = max_point = points[0];
+
+ for (i=1; i<4; i++)
+ {
+ if (points[i].X < min_point.X) min_point.X = points[i].X;
+ if (points[i].Y < min_point.Y) min_point.Y = points[i].Y;
+ if (points[i].X > max_point.X) max_point.X = points[i].X;
+ if (points[i].Y > max_point.Y) max_point.Y = points[i].Y;
+ }
+
+ rect->X = min_point.X;
+ rect->Y = min_point.Y;
+ rect->Width = max_point.X - min_point.X;
+ rect->Height = max_point.Y - min_point.Y;
+ }
+
+ return stat;
+}
+
/* on success, rgn will contain the region of the graphics object which
* is visible after clipping has been applied */
static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn)
GpRectF rectf;
GpRegion* tmp;
+ /* Ignore graphics image bounds for metafiles */
+ if (graphics->image && graphics->image_type == ImageTypeMetafile)
+ return GdipCombineRegionRegion(rgn, graphics->clip, CombineModeReplace);
+
if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
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);
+
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, 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));
return GdipCreateFromHDC2(hdc, NULL, graphics);
}
+static void get_gdi_transform(GpGraphics *graphics, GpMatrix *matrix)
+{
+ XFORM xform;
+
+ if (graphics->hdc == NULL)
+ {
+ GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ return;
+ }
+
+ GetTransform(graphics->hdc, 0x204, &xform);
+ GdipSetMatrixElements(matrix, xform.eM11, xform.eM12, xform.eM21, xform.eM22, xform.eDx, xform.eDy);
+}
+
GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics)
{
GpStatus retval;
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;
}
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
list_init(&(*graphics)->containers);
+#ifdef __REACTOS__
(*graphics)->contid = GDIP_GET_NEW_CONTID_FOR(*graphics);
+#else
+ (*graphics)->contid = 0;
+#endif
+ get_gdi_transform(*graphics, &(*graphics)->gdi_transform);
+
+ (*graphics)->gdi_clip = CreateRectRgn(0,0,0,0);
+ if (!GetClipRgn(hdc, (*graphics)->gdi_clip))
+ {
+ DeleteObject((*graphics)->gdi_clip);
+ (*graphics)->gdi_clip = NULL;
+ }
TRACE("<-- %p\n", *graphics);
{
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);
+ GdipSetMatrixElements(&(*graphics)->gdi_transform, 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;
}
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
list_init(&(*graphics)->containers);
+#ifdef __REACTOS__
(*graphics)->contid = GDIP_GET_NEW_CONTID_FOR(*graphics);
+#else
+ (*graphics)->contid = 0;
+#endif
TRACE("<-- %p\n", *graphics);
GdipDeleteRegion(graphics->clip);
+ DeleteObject(graphics->gdi_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);
+ 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;
}
TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
debugstr_pointf(&points[2]));
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ return METAFILE_DrawImagePointsRect((GpMetafile*)graphics->image,
+ image, points, count, srcx, srcy, srcwidth, srcheight,
+ srcUnit, imageAttributes, callback, callbackData);
+ }
+
memcpy(ptf, points, 3 * sizeof(GpPointF));
/* Ensure source width/height is positive */
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))
return Ok;
- transform_and_round_points(graphics, pti, ptf, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4);
+ round_points(pti, ptf, 4);
TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]),
wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
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;
+ 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->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)
+ do_resampling = TRUE;
+
+ if (imageAttributes || graphics->alpha_hdc || do_resampling ||
+ (graphics->image && graphics->image->type == ImageTypeBitmap))
use_software = TRUE;
if (use_software)
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);
+ stat = get_graphics_device_bounds(graphics, &graphics_bounds);
if (stat != Ok) return stat;
if (graphics_bounds.X > dst_area.left) dst_area.left = floorf(graphics_bounds.X);
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 if (imageAttributes != &defaultImageAttributes)
+ lockeddata.PixelFormat = PixelFormat32bppARGB;
+ else
+ lockeddata.PixelFormat = PixelFormat32bppPARGB;
stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf,
- PixelFormat32bppARGB, &lockeddata);
+ lockeddata.PixelFormat, &lockeddata);
if (stat == Ok)
stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
if (stat != Ok)
{
- 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)
+ {
+ REAL delta_xx, delta_xy, delta_yx, delta_yy;
+
+ /* 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);
+
+ 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;
+
+ delta_yy = dst_area.top * y_dy;
+ delta_yx = dst_area.top * y_dx;
- for (x=dst_area.left; x<dst_area.right; x++)
- {
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;
+ delta_xx = dst_area.left * x_dx;
+ delta_xy = dst_area.left * x_dy;
- dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
+ for (x=dst_area.left; x<dst_area.right; x++)
+ {
+ GpPointF src_pointf;
+ ARGB *dst_color;
+
+ src_pointf.X = dst_to_src_points[0].X + delta_xx + delta_yx;
+ src_pointf.Y = dst_to_src_points[0].Y + delta_xy + delta_yy;
+
+ 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)
+ {
+ if (lockeddata.PixelFormat != PixelFormat32bppPARGB)
+ *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes, interpolation, offset_mode);
+ else
+ *dst_color = resample_bitmap_pixel_premult(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes, interpolation, offset_mode);
+ }
+ else
+ *dst_color = 0;
+
+ delta_xx += x_dx;
+ delta_yx += y_dx;
+ }
- 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;
+ delta_xy += x_dy;
+ delta_yy += y_dy;
}
}
+ else
+ {
+ dst_data = src_data;
+ dst_stride = src_stride;
+ }
- GdipFree(src_data);
+ gdi_transform_acquire(graphics);
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);
+ gdi_transform_release(graphics);
+
+ heap_free(src_data);
+
+ heap_free(dst_dyn_data);
return stat;
}
HDC hdc;
BOOL temp_hdc = FALSE, temp_bitmap = FALSE;
HBITMAP hbitmap, old_hbm=NULL;
+ HRGN hrgn;
+ INT save_state;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
bitmap->format == PixelFormat24bppRGB ||
old_hbm = SelectObject(hdc, hbitmap);
}
+ save_state = SaveDC(graphics->hdc);
+
+ stat = get_clip_hrgn(graphics, &hrgn);
+
+ if (stat == Ok)
+ {
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+ DeleteObject(hrgn);
+ }
+
+ gdi_transform_acquire(graphics);
+
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);
}
+ gdi_transform_release(graphics);
+
+ 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;
-
- if(graphics->busy)
- return ObjectBusy;
-
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- return Ok;
- }
-
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);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+
+ gdi_transform_acquire(graphics);
retval = draw_poly(graphics, pen, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, TRUE);
+ gdi_transform_release(graphics);
+
end:
restore_dc(graphics, save_state);
DeleteObject(hrgn);
return retval;
}
+static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, 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;
+
+ stat = GdipClonePath(path, &flat_path);
+
+ if (stat != Ok)
+ return stat;
+
+ stat = GdipCreateMatrix(&transform);
+
+ if (stat == Ok)
+ {
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
+ CoordinateSpaceWorld, transform);
+
+ if (stat == Ok)
+ stat = GdipFlattenPath(flat_path, transform, 1.0);
+
+ GdipDeleteMatrix(transform);
+ }
+
+ /* 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);
+
+ 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);
+ }
+
+ stat = get_graphics_device_bounds(graphics, &gp_bound_rect);
+ }
+
+ 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));
+
+ output_width = output_area.right - output_area.left + 1;
+ output_height = output_area.bottom - output_area.top + 1;
+
+ if (output_width <= 0 || output_height <= 0)
+ {
+ GdipDeletePath(flat_path);
+ return Ok;
+ }
+
+ 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;
+
+ output_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
+ if (!output_bits)
+ stat = OutOfMemory;
+ }
+
+ if (stat == Ok)
+ {
+ if (pen->brush->bt != BrushTypeSolidColor)
+ {
+ /* allocate and draw brush output */
+ brush_bits = heap_alloc_zero(output_width * output_height * sizeof(DWORD));
+
+ if (brush_bits)
+ {
+ stat = brush_fill_pixels(graphics, pen->brush, brush_bits,
+ &gp_output_area, output_width);
+ }
+ else
+ stat = OutOfMemory;
+ }
+
+ if (stat == Ok)
+ {
+ /* convert dash pattern to bool array */
+ switch (pen->dash)
+ {
+ case DashStyleCustom:
+ {
+ dash_pattern_size = 0;
+
+ 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);
+
+ if(start_pointi.X == end_pointi.X && start_pointi.Y == end_pointi.Y)
+ continue;
+
+ /* 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)
+ {
+ gdi_transform_acquire(graphics);
+
+ stat = alpha_blend_pixels(graphics, output_area.left, output_area.top,
+ (BYTE*)output_bits, output_width, output_height, output_width * 4,
+ PixelFormat32bppARGB);
+
+ gdi_transform_release(graphics);
+ }
+
+ 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;
+ REAL flatness=1.0;
+
+ /* 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 = gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice,
+ 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, WineCoordinateSpaceGdiDevice,
+ CoordinateSpaceWorld, transform);
+ }
+ else
+ {
+ /* Set flatness based on the final coordinate space */
+ GpMatrix t;
+
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
+ CoordinateSpaceWorld, &t);
+
+ if (stat != Ok)
+ return stat;
+
+ flatness = 1.0/sqrt(fmax(
+ t.matrix[0] * t.matrix[0] + t.matrix[1] * t.matrix[1],
+ t.matrix[2] * t.matrix[2] + t.matrix[3] * t.matrix[3]));
+ }
+
+ if (stat == Ok)
+ stat = GdipWidenPath(wide_path, pen, transform, flatness);
+
+ 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->image && graphics->image->type == ImageTypeMetafile)
+ retval = METAFILE_DrawPath((GpMetafile*)graphics->image, pen, path);
+ else if (!graphics->hdc || graphics->alpha_hdc || !brush_can_fill_path(pen->brush, FALSE))
+ 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)
{
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;
}
GpStatus retval;
HRGN hrgn=NULL;
- if(!graphics->hdc || !brush_can_fill_path(brush))
+ if(!graphics->hdc || !brush_can_fill_path(brush, TRUE))
return NotImplemented;
save_state = SaveDC(graphics->hdc);
if (retval != Ok)
goto end;
- if (hrgn)
- ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+
+ gdi_transform_acquire(graphics);
BeginPath(graphics->hdc);
retval = draw_poly(graphics, NULL, path->pathdata.Points,
path->pathdata.Types, path->pathdata.Count, FALSE);
- if(retval != Ok)
- goto end;
-
- EndPath(graphics->hdc);
- brush_fill_path(graphics, brush);
+ if(retval == Ok)
+ {
+ EndPath(graphics->hdc);
+ retval = brush_fill_path(graphics, brush);
+ }
- retval = Ok;
+ gdi_transform_release(graphics);
end:
RestoreDC(graphics->hdc, save_state);
if(graphics->busy)
return ObjectBusy;
+ if (!path->pathdata.Count)
+ return Ok;
+
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ return METAFILE_FillPath((GpMetafile*)graphics->image, brush, path);
+
if (!graphics->image && !graphics->alpha_hdc)
stat = GDI32_GdipFillPath(graphics, brush, path);
if(!rects || count <= 0)
return InvalidParameter;
- rectsF = GdipAlloc(sizeof(GpRectF)*count);
+ rectsF = heap_alloc_zero(sizeof(GpRectF)*count);
if(!rectsF)
return OutOfMemory;
for(i = 0; i < count; i++){
rectsF[i].X = (REAL)rects[i].X;
rectsF[i].Y = (REAL)rects[i].Y;
- rectsF[i].X = (REAL)rects[i].Width;
+ rectsF[i].Width = (REAL)rects[i].Width;
rectsF[i].Height = (REAL)rects[i].Height;
}
ret = GdipFillRectangles(graphics,brush,rectsF,count);
- GdipFree(rectsF);
+ heap_free(rectsF);
return ret;
}
HRGN hrgn;
RECT rc;
- if(!graphics->hdc || !brush_can_fill_path(brush))
+ if(!graphics->hdc || !brush_can_fill_path(brush, TRUE))
return NotImplemented;
- status = GdipGetRegionHRgn(region, graphics, &hrgn);
- if(status != Ok)
- return status;
-
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
+ hrgn = NULL;
+ status = get_clip_hrgn(graphics, &hrgn);
+ if (status != Ok)
+ {
+ RestoreDC(graphics->hdc, save_state);
+ return status;
+ }
+
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+ DeleteObject(hrgn);
+
+ status = GdipGetRegionHRgn(region, graphics, &hrgn);
+ if (status != Ok)
+ {
+ RestoreDC(graphics->hdc, save_state);
+ return status;
+ }
+
ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+ DeleteObject(hrgn);
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
{
Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom);
EndPath(graphics->hdc);
- brush_fill_path(graphics, brush);
+ status = brush_fill_path(graphics, brush);
}
RestoreDC(graphics->hdc, save_state);
- DeleteObject(hrgn);
- return Ok;
+ return status;
}
static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush,
if (!brush_can_fill_pixels(brush))
return NotImplemented;
- stat = get_graphics_bounds(graphics, &graphics_bounds);
+ stat = gdi_transform_acquire(graphics);
+
+ if (stat == Ok)
+ stat = get_graphics_device_bounds(graphics, &graphics_bounds);
if (stat == Ok)
stat = GdipCloneRegion(region, &temp_region);
if (stat == Ok)
{
- stat = get_graphics_transform(graphics, CoordinateSpaceDevice,
+ stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice,
CoordinateSpaceWorld, &world_to_device);
if (stat == Ok)
if (stat == Ok && GetRgnBox(hregion, &bound_rect) == NULLREGION)
{
DeleteObject(hregion);
+ gdi_transform_release(graphics);
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);
}
+ gdi_transform_release(graphics);
+
return stat;
}
{
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_count=0;
INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=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)
- {
- GdipFree(stringdup);
- return stat;
- }
- format = dyn_format;
- }
+ format = &default_drawstring_format;
nwidth = rect->Width;
nheight = rect->Height;
}
if (hotkeyprefix_count)
- hotkeyprefix_offsets = GdipAlloc(sizeof(INT) * hotkeyprefix_count);
+ hotkeyprefix_offsets = heap_alloc_zero(sizeof(INT) * hotkeyprefix_count);
hotkeyprefix_count = 0;
break;
}
- GdipFree(stringdup);
- GdipFree(hotkeyprefix_offsets);
- GdipDeleteStringFormat(dyn_format);
+ heap_free(stringdup);
+ heap_free(hotkeyprefix_offsets);
return stat;
}
RectF scaled_rect;
REAL margin_x;
- TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_w(string),
+ TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_wn(string, length),
length, font, debugstr_rectf(layoutRect), stringFormat, regionCount, regions);
if (!(graphics && string && font && layoutRect && stringFormat && regions))
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, pt, 3);
args.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));
args.rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
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);
args.regions = regions;
+ gdi_transform_acquire(graphics);
+
stat = gdip_format_string(hdc, string, length, font, &scaled_rect, stringFormat,
(stringFormat->attr & StringFormatFlagsNoClip) != 0, measure_ranges_callback, &args);
+ gdi_transform_release(graphics);
+
SelectObject(hdc, oldfont);
DeleteObject(gdifont);
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, pt, 3);
args.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));
args.rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
args.linesfilled = &lines;
lines = glyphs = 0;
+ gdi_transform_acquire(graphics);
+
gdip_format_string(hdc, string, length, font, &scaled_rect, format, TRUE,
measure_string_callback, &args);
+ gdi_transform_release(graphics);
+
if (linesfilled) *linesfilled = lines;
if (codepointsfitted) *codepointsfitted = glyphs;
/* Should be no need to explicitly test for StringAlignmentNear as
* that is default behavior if no alignment is passed. */
- if(format->vertalign != StringAlignmentNear){
+ if(format->line_align != StringAlignmentNear){
RectF bounds, in_rect = *rect;
in_rect.Height = 0.0; /* avoid height clipping */
GdipMeasureString(graphics, string, length, font, &in_rect, format, &bounds, 0, 0);
TRACE("bounds %s\n", debugstr_rectf(&bounds));
- if(format->vertalign == StringAlignmentCenter)
+ if(format->line_align == StringAlignmentCenter)
offsety = (rect->Height - bounds.Height) / 2;
- else if(format->vertalign == StringAlignmentFar)
+ else if(format->line_align == StringAlignmentFar)
offsety = (rect->Height - bounds.Height);
}
- TRACE("vertical align %d, offsety %f\n", format->vertalign, offsety);
+ TRACE("line align %d, offsety %f\n", format->line_align, offsety);
}
save_state = SaveDC(hdc);
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, pt, 3);
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));
rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
rectcpy[1].Y = rectcpy[0].Y = rect->Y;
rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
rectcpy[3].Y = rectcpy[2].Y = rect->Y + rect->Height;
- transform_and_round_points(graphics, corners, rectcpy, 4);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, rectcpy, 4);
+ round_points(corners, rectcpy, 4);
margin_x = (format && format->generic_typographic) ? 0.0 : font->emSize / 6.0;
margin_x *= units_scale(font->unit, graphics->unit, graphics->xres);
args.rel_width = rel_width;
args.rel_height = rel_height;
+ gdi_transform_acquire(graphics);
+
GetTextMetricsW(hdc, &textmetric);
args.ascent = textmetric.tmAscent / rel_height;
gdip_format_string(hdc, string, length, font, &scaled_rect, format, TRUE,
draw_string_callback, &args);
+ gdi_transform_release(graphics);
+
DeleteObject(rgn);
DeleteObject(gdifont);
GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
{
+ GpStatus stat;
+
TRACE("(%p)\n", graphics);
if(!graphics)
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile) {
+ stat = METAFILE_ResetWorldTransform((GpMetafile*)graphics->image);
+
+ if (stat != Ok)
+ return stat;
+ }
+
return GdipSetMatrixElements(&graphics->worldtrans, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
-GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
-{
- return GdipEndContainer(graphics, state);
-}
-
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);
}
if(graphics->busy)
return ObjectBusy;
+ if(graphics->compmode == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetCompositingMode, mode);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->compmode = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->compqual == quality)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetCompositingQuality, quality);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->compqual = quality;
return Ok;
if (mode == InterpolationModeHighQuality)
mode = InterpolationModeHighQualityBicubic;
+ if (mode == graphics->interpolation)
+ return Ok;
+
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetInterpolationMode, mode);
+ if (stat != Ok)
+ return stat;
+ }
+
graphics->interpolation = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->pixeloffset == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetPixelOffsetMode, mode);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->pixeloffset = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->smoothing == mode)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile) {
+ GpStatus stat;
+ BOOL antialias = (mode != SmoothingModeDefault &&
+ mode != SmoothingModeNone && mode != SmoothingModeHighSpeed);
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetAntiAliasMode, (mode << 1) + antialias);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->smoothing = mode;
return Ok;
if(graphics->busy)
return ObjectBusy;
+ if(graphics->texthint == hint)
+ return Ok;
+
+ if(graphics->image && graphics->image->type == ImageTypeMetafile) {
+ GpStatus stat;
+
+ stat = METAFILE_AddSimpleProperty((GpMetafile*)graphics->image,
+ EmfPlusRecordTypeSetTextRenderingHint, hint);
+ if(stat != Ok)
+ return stat;
+ }
+
graphics->texthint = hint;
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);
}
{
GpRegion *region;
GpStatus status;
+ GpMatrix transform;
TRACE("(%p, %p, %d)\n", graphics, hrgn, mode);
if(graphics->busy)
return ObjectBusy;
- /* hrgn is already in device units */
+ /* hrgn is in gdi32 device units */
status = GdipCreateRegionHrgn(hrgn, ®ion);
- if(status != Ok)
- return status;
- status = GdipCombineRegionRegion(graphics->clip, region, mode);
+ if (status == Ok)
+ {
+ status = get_graphics_transform(graphics, CoordinateSpaceDevice, WineCoordinateSpaceGdiDevice, &transform);
+
+ if (status == Ok)
+ status = GdipTransformRegion(region, &transform);
+
+ if (status == Ok)
+ status = GdipCombineRegionRegion(graphics->clip, region, mode);
- GdipDeleteRegion(region);
+ GdipDeleteRegion(region);
+ }
return status;
}
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;
if (status == Ok)
{
GpMatrix world_to_device;
+ BOOL identity;
get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
- status = GdipTransformRegion(region, &world_to_device);
+ status = GdipIsMatrixIdentity(&world_to_device, &identity);
+ if (status == Ok && !identity)
+ status = GdipTransformRegion(region, &world_to_device);
if (status == Ok)
status = GdipCombineRegionRegion(graphics->clip, region, mode);
if(graphics->busy)
return ObjectBusy;
+ if (graphics->image && graphics->image->type == ImageTypeMetafile)
+ {
+ status = METAFILE_SetClipRegion((GpMetafile*)graphics->image, region, mode);
+ if (status != Ok)
+ return status;
+ }
+
status = GdipCloneRegion(region, &clip);
if (status == Ok)
{
GpMatrix world_to_device;
+ BOOL identity;
get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
- status = GdipTransformRegion(clip, &world_to_device);
+ status = GdipIsMatrixIdentity(&world_to_device, &identity);
+ if (status == Ok && !identity)
+ status = GdipTransformRegion(clip, &world_to_device);
if (status == Ok)
status = GdipCombineRegionRegion(graphics->clip, clip, mode);
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;
+}
+
+GpStatus gdi_transform_acquire(GpGraphics *graphics)
+{
+ if (graphics->gdi_transform_acquire_count == 0 && graphics->hdc)
+ {
+ graphics->gdi_transform_save = SaveDC(graphics->hdc);
+ SetGraphicsMode(graphics->hdc, GM_COMPATIBLE);
+ SetMapMode(graphics->hdc, MM_TEXT);
+ SetWindowOrgEx(graphics->hdc, 0, 0, NULL);
+ SetViewportOrgEx(graphics->hdc, 0, 0, NULL);
+ }
+ graphics->gdi_transform_acquire_count++;
+ return Ok;
+}
+GpStatus gdi_transform_release(GpGraphics *graphics)
+{
+ if (graphics->gdi_transform_acquire_count <= 0)
+ {
+ ERR("called without matching gdi_transform_acquire\n");
+ return GenericError;
+ }
+ if (graphics->gdi_transform_acquire_count == 1 && graphics->hdc)
+ {
+ RestoreDC(graphics->hdc, graphics->gdi_transform_save);
+ }
+ graphics->gdi_transform_acquire_count--;
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;
scale_y *= graphics->scale;
}
- /* transform from src_space to CoordinateSpacePage */
- switch (src_space)
- {
- case CoordinateSpaceWorld:
- GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
- break;
- case CoordinateSpacePage:
- break;
- case CoordinateSpaceDevice:
- GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
- break;
- }
-
- /* transform from CoordinateSpacePage to dst_space */
- switch (dst_space)
+ if (dst_space < src_space)
{
- case CoordinateSpaceWorld:
+ /* transform towards world space */
+ switch ((int)src_space)
+ {
+ case WineCoordinateSpaceGdiDevice:
+ {
+ GpMatrix gdixform;
+ gdixform = graphics->gdi_transform;
+ stat = GdipInvertMatrix(&gdixform);
+ if (stat != Ok)
+ break;
+ GdipMultiplyMatrix(matrix, &gdixform, MatrixOrderAppend);
+ if (dst_space == CoordinateSpaceDevice)
+ break;
+ /* else fall-through */
+ }
+ case CoordinateSpaceDevice:
+ GdipScaleMatrix(matrix, 1.0/scale_x, 1.0/scale_y, MatrixOrderAppend);
+ if (dst_space == CoordinateSpacePage)
+ break;
+ /* else fall-through */
+ case CoordinateSpacePage:
{
GpMatrix inverted_transform = graphics->worldtrans;
stat = GdipInvertMatrix(&inverted_transform);
GdipMultiplyMatrix(matrix, &inverted_transform, MatrixOrderAppend);
break;
}
- case CoordinateSpacePage:
- break;
- case CoordinateSpaceDevice:
- GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
- break;
+ }
+ }
+ else
+ {
+ /* transform towards device space */
+ switch ((int)src_space)
+ {
+ case CoordinateSpaceWorld:
+ GdipMultiplyMatrix(matrix, &graphics->worldtrans, MatrixOrderAppend);
+ if (dst_space == CoordinateSpacePage)
+ break;
+ /* else fall-through */
+ case CoordinateSpacePage:
+ GdipScaleMatrix(matrix, scale_x, scale_y, MatrixOrderAppend);
+ if (dst_space == CoordinateSpaceDevice)
+ break;
+ /* else fall-through */
+ case CoordinateSpaceDevice:
+ {
+ GdipMultiplyMatrix(matrix, &graphics->gdi_transform, MatrixOrderAppend);
+ break;
+ }
+ }
}
}
return stat;
}
-GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
- GpCoordinateSpace src_space, GpPointF *points, INT count)
+GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
+ GpCoordinateSpace src_space, GpPointF *points, INT count)
{
GpMatrix matrix;
GpStatus stat;
- if(!graphics || !points || count <= 0)
+ stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
+ if (stat != Ok) return stat;
+
+ return GdipTransformMatrixPoints(&matrix, points, count);
+}
+
+GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
+ GpCoordinateSpace src_space, GpPointF *points, INT count)
+{
+ if(!graphics || !points || count <= 0 ||
+ dst_space < 0 || dst_space > CoordinateSpaceDevice ||
+ src_space < 0 || src_space > CoordinateSpaceDevice)
return InvalidParameter;
if(graphics->busy)
if (src_space == dst_space) return Ok;
- stat = get_graphics_transform(graphics, dst_space, src_space, &matrix);
- if (stat != Ok) return stat;
-
- return GdipTransformMatrixPoints(&matrix, points, count);
+ return gdip_transform_points(graphics, dst_space, src_space, points, count);
}
GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
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;
}
GpMatrix xform = *matrix;
GdipTransformMatrixPoints(&xform, pt, 3);
}
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, pt, 3);
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));
rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
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)
+ {
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY);
+ DeleteObject(hrgn);
+ }
+
pt = positions[0];
- GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &pt, 1);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, &pt, 1);
get_font_hfont(graphics, font, format, &hfont, matrix);
SelectObject(graphics->hdc, hfont);
SetTextAlign(graphics->hdc, TA_BASELINE|TA_LEFT);
+ gdi_transform_acquire(graphics);
+
ExtTextOutW(graphics->hdc, gdip_round(pt.X), gdip_round(pt.Y), eto_flags, NULL, text, length, NULL);
+ gdi_transform_release(graphics);
+
RestoreDC(graphics->hdc, save_state);
DeleteObject(hfont);
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;
{
real_position = positions[0];
- transform_and_round_points(graphics, pti, &real_position, 1);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, &real_position, 1);
+ round_points(pti, &real_position, 1);
}
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;
}
memcpy(real_positions, positions, sizeof(PointF) * length);
- transform_and_round_points(graphics, pti, real_positions, length);
+ gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, real_positions, length);
+ round_points(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;
/* Nothing to draw. */
return Ok;
- glyph_mask = GdipAlloc(max_glyphsize);
- text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y));
+ 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;
}
}
- 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);
+
+ gdi_transform_acquire(graphics);
/* 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);
+ gdi_transform_release(graphics);
+
+ 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.@]
*/
return NotImplemented;
}
+
+GpStatus WINGDIPAPI GdipGraphicsSetAbort(GpGraphics *graphics, GdiplusAbort *pabort)
+{
+ TRACE("(%p, %p)\n", graphics, pabort);
+
+ if (!graphics)
+ return InvalidParameter;
+
+ if (pabort)
+ FIXME("Abort callback is not supported.\n");
+
+ return Ok;
+}