#include "gdiplus.h"
#include "gdiplus_private.h"
#include "wine/debug.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
}
}
+static ARGB blend_colors(ARGB start, ARGB end, REAL position)
+{
+ ARGB result=0;
+ ARGB i;
+ for (i=0xff; i<=0xff0000; i = i << 8)
+ result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
+ return result;
+}
+
+static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
+{
+ REAL blendfac;
+
+ /* clamp to between 0.0 and 1.0, using the wrap mode */
+ if (brush->wrap == WrapModeTile)
+ {
+ position = fmodf(position, 1.0f);
+ if (position < 0.0f) position += 1.0f;
+ }
+ else /* WrapModeFlip* */
+ {
+ position = fmodf(position, 2.0f);
+ if (position < 0.0f) position += 2.0f;
+ if (position > 1.0f) position = 2.0f - position;
+ }
+
+ if (brush->blendcount == 1)
+ blendfac = position;
+ else
+ {
+ int i=1;
+ REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac;
+ REAL range;
+
+ /* locate the blend positions surrounding this position */
+ while (position > brush->blendpos[i])
+ i++;
+
+ /* interpolate between the blend positions */
+ left_blendpos = brush->blendpos[i-1];
+ left_blendfac = brush->blendfac[i-1];
+ right_blendpos = brush->blendpos[i];
+ right_blendfac = brush->blendfac[i];
+ range = right_blendpos - left_blendpos;
+ blendfac = (left_blendfac * (right_blendpos - position) +
+ right_blendfac * (position - left_blendpos)) / range;
+ }
+
+ if (brush->pblendcount == 0)
+ return blend_colors(brush->startcolor, brush->endcolor, blendfac);
+ else
+ {
+ int i=1;
+ ARGB left_blendcolor, right_blendcolor;
+ REAL left_blendpos, right_blendpos;
+
+ /* locate the blend colors surrounding this position */
+ while (blendfac > brush->pblendpos[i])
+ i++;
+
+ /* interpolate between the blend colors */
+ left_blendpos = brush->pblendpos[i-1];
+ left_blendcolor = brush->pblendcolor[i-1];
+ right_blendpos = brush->pblendpos[i];
+ right_blendcolor = brush->pblendcolor[i];
+ blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos);
+ return blend_colors(left_blendcolor, right_blendcolor, blendfac);
+}
+}
+
+static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
+{
+ switch (brush->bt)
+ {
+ case BrushTypeLinearGradient:
+ {
+ GpLineGradient *line = (GpLineGradient*)brush;
+ RECT rc;
+
+ SelectClipPath(graphics->hdc, RGN_AND);
+ if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
+ {
+ GpPointF endpointsf[2];
+ POINT endpointsi[2];
+ POINT poly[4];
+
+ SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
+
+ endpointsf[0] = line->startpoint;
+ endpointsf[1] = line->endpoint;
+ transform_and_round_points(graphics, endpointsi, endpointsf, 2);
+
+ if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
+ {
+ /* vertical-ish gradient */
+ int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
+ int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */
+ int width;
+ COLORREF col;
+ HBRUSH hbrush, hprevbrush;
+ int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */
+ int x;
+ int tilt; /* horizontal distance covered by a gradient line */
+
+ startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
+ endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
+ width = endx - startx;
+ startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
+ tilt = startx - startbottomx;
+
+ if (startx >= startbottomx)
+ {
+ leftx = rc.left;
+ rightx = rc.right + tilt;
+ }
+ else
+ {
+ leftx = rc.left + tilt;
+ rightx = rc.right;
+ }
+
+ poly[0].y = rc.bottom;
+ poly[1].y = rc.top;
+ poly[2].y = rc.top;
+ poly[3].y = rc.bottom;
+
+ for (x=leftx; x<=rightx; x++)
+ {
+ ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width);
+ col = ARGB2COLORREF(argb);
+ hbrush = CreateSolidBrush(col);
+ hprevbrush = SelectObject(graphics->hdc, hbrush);
+ poly[0].x = x - tilt - 1;
+ poly[1].x = x - 1;
+ poly[2].x = x;
+ poly[3].x = x - tilt;
+ Polygon(graphics->hdc, poly, 4);
+ SelectObject(graphics->hdc, hprevbrush);
+ DeleteObject(hbrush);
+ }
+ }
+ else if (endpointsi[0].y != endpointsi[1].y)
+ {
+ /* horizontal-ish gradient */
+ int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
+ int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */
+ int height;
+ COLORREF col;
+ HBRUSH hbrush, hprevbrush;
+ int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */
+ int y;
+ int tilt; /* vertical distance covered by a gradient line */
+
+ starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
+ endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
+ height = endy - starty;
+ startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
+ tilt = starty - startrighty;
+
+ if (starty >= startrighty)
+ {
+ topy = rc.top;
+ bottomy = rc.bottom + tilt;
+ }
+ else
+ {
+ topy = rc.top + tilt;
+ bottomy = rc.bottom;
+ }
+
+ poly[0].x = rc.right;
+ poly[1].x = rc.left;
+ poly[2].x = rc.left;
+ poly[3].x = rc.right;
+
+ for (y=topy; y<=bottomy; y++)
+ {
+ ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height);
+ col = ARGB2COLORREF(argb);
+ hbrush = CreateSolidBrush(col);
+ hprevbrush = SelectObject(graphics->hdc, hbrush);
+ poly[0].y = y - tilt - 1;
+ poly[1].y = y - 1;
+ poly[2].y = y;
+ poly[3].y = y - tilt;
+ Polygon(graphics->hdc, poly, 4);
+ SelectObject(graphics->hdc, hprevbrush);
+ DeleteObject(hbrush);
+ }
+ }
+ /* else startpoint == endpoint */
+ }
+ break;
+ }
+ case BrushTypeSolidColor:
+ {
+ GpSolidFill *fill = (GpSolidFill*)brush;
+ if (fill->bmp)
+ {
+ RECT rc;
+ /* partially transparent fill */
+
+ SelectClipPath(graphics->hdc, RGN_AND);
+ if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
+ {
+ HDC hdc = CreateCompatibleDC(NULL);
+ HBITMAP oldbmp;
+ BLENDFUNCTION bf;
+
+ if (!hdc) break;
+
+ oldbmp = SelectObject(hdc, fill->bmp);
+
+ bf.BlendOp = AC_SRC_OVER;
+ bf.BlendFlags = 0;
+ bf.SourceConstantAlpha = 255;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+
+ GdiAlphaBlend(graphics->hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hdc, 0, 0, 1, 1, bf);
+
+ SelectObject(hdc, oldbmp);
+ DeleteDC(hdc);
+ }
+
+ break;
+ }
+ /* else fall through */
+ }
+ default:
+ SelectObject(graphics->hdc, brush->gdibrush);
+ FillPath(graphics->hdc);
+ break;
+ }
+}
+
/* GdipDrawPie/GdipFillPie helper function */
static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
REAL height, REAL startAngle, REAL sweepAngle)
return result;
}
+typedef struct _GraphicsContainerItem {
+ struct list entry;
+ GraphicsContainer contid;
+
+ SmoothingMode smoothing;
+ CompositingQuality compqual;
+ InterpolationMode interpolation;
+ CompositingMode compmode;
+ TextRenderingHint texthint;
+ REAL scale;
+ GpUnit unit;
+ PixelOffsetMode pixeloffset;
+ UINT textcontrast;
+ GpMatrix* worldtrans;
+ GpRegion* clip;
+} GraphicsContainerItem;
+
+static GpStatus init_container(GraphicsContainerItem** container,
+ GDIPCONST GpGraphics* graphics){
+ GpStatus sts;
+
+ *container = GdipAlloc(sizeof(GraphicsContainerItem));
+ if(!(*container))
+ return OutOfMemory;
+
+ (*container)->contid = graphics->contid + 1;
+
+ (*container)->smoothing = graphics->smoothing;
+ (*container)->compqual = graphics->compqual;
+ (*container)->interpolation = graphics->interpolation;
+ (*container)->compmode = graphics->compmode;
+ (*container)->texthint = graphics->texthint;
+ (*container)->scale = graphics->scale;
+ (*container)->unit = graphics->unit;
+ (*container)->textcontrast = graphics->textcontrast;
+ (*container)->pixeloffset = graphics->pixeloffset;
+
+ sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
+ if(sts != Ok){
+ GdipFree(*container);
+ *container = NULL;
+ return sts;
+ }
+
+ sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
+ if(sts != Ok){
+ GdipDeleteMatrix((*container)->worldtrans);
+ GdipFree(*container);
+ *container = NULL;
+ return sts;
+ }
+
+ return Ok;
+}
+
+static void delete_container(GraphicsContainerItem* container){
+ GdipDeleteMatrix(container->worldtrans);
+ GdipDeleteRegion(container->clip);
+ GdipFree(container);
+}
+
+static GpStatus restore_container(GpGraphics* graphics,
+ GDIPCONST GraphicsContainerItem* container){
+ GpStatus sts;
+ GpMatrix *newTrans;
+ GpRegion *newClip;
+
+ sts = GdipCloneMatrix(container->worldtrans, &newTrans);
+ if(sts != Ok)
+ return sts;
+
+ sts = GdipCloneRegion(container->clip, &newClip);
+ if(sts != Ok){
+ GdipDeleteMatrix(newTrans);
+ return sts;
+ }
+
+ GdipDeleteMatrix(graphics->worldtrans);
+ graphics->worldtrans = newTrans;
+
+ GdipDeleteRegion(graphics->clip);
+ graphics->clip = newClip;
+
+ graphics->contid = container->contid - 1;
+
+ graphics->smoothing = container->smoothing;
+ graphics->compqual = container->compqual;
+ graphics->interpolation = container->interpolation;
+ graphics->compmode = container->compmode;
+ graphics->texthint = container->texthint;
+ graphics->scale = container->scale;
+ graphics->unit = container->unit;
+ graphics->textcontrast = container->textcontrast;
+ graphics->pixeloffset = container->pixeloffset;
+
+ return Ok;
+}
+
+static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
+{
+ RECT wnd_rect;
+
+ if(graphics->hwnd) {
+ if(!GetClientRect(graphics->hwnd, &wnd_rect))
+ return GenericError;
+
+ rect->X = wnd_rect.left;
+ rect->Y = wnd_rect.top;
+ rect->Width = wnd_rect.right - wnd_rect.left;
+ rect->Height = wnd_rect.bottom - wnd_rect.top;
+ }else{
+ rect->X = 0;
+ rect->Y = 0;
+ rect->Width = GetDeviceCaps(graphics->hdc, HORZRES);
+ rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
+ }
+
+ return Ok;
+}
+
+/* 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)
+{
+ GpStatus stat;
+ GpRectF rectf;
+ GpRegion* tmp;
+
+ if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
+ return stat;
+
+ if((stat = GdipCreateRegion(&tmp)) != Ok)
+ return stat;
+
+ if((stat = GdipCombineRegionRect(tmp, &rectf, CombineModeReplace)) != Ok)
+ goto end;
+
+ if((stat = GdipCombineRegionRegion(tmp, graphics->clip, CombineModeIntersect)) != Ok)
+ goto end;
+
+ stat = GdipCombineRegionRegion(rgn, tmp, CombineModeReplace);
+
+end:
+ GdipDeleteRegion(tmp);
+ return stat;
+}
+
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
{
TRACE("(%p, %p)\n", hdc, graphics);
TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics);
if(hDevice != NULL) {
- FIXME("Don't know how to hadle parameter hDevice\n");
+ FIXME("Don't know how to handle parameter hDevice\n");
return NotImplemented;
}
(*graphics)->hdc = hdc;
(*graphics)->hwnd = WindowFromDC(hdc);
+ (*graphics)->owndc = FALSE;
(*graphics)->smoothing = SmoothingModeDefault;
(*graphics)->compqual = CompositingQualityDefault;
(*graphics)->interpolation = InterpolationModeDefault;
(*graphics)->scale = 1.0;
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
+ list_init(&(*graphics)->containers);
+ (*graphics)->contid = 0;
return Ok;
}
GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
{
GpStatus ret;
+ HDC hdc;
TRACE("(%p, %p)\n", hwnd, graphics);
- if((ret = GdipCreateFromHDC(GetDC(hwnd), graphics)) != Ok)
+ hdc = GetDC(hwnd);
+
+ if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok)
+ {
+ ReleaseDC(hwnd, hdc);
return ret;
+ }
(*graphics)->hwnd = hwnd;
+ (*graphics)->owndc = TRUE;
return Ok;
}
(*metafile)->image.type = ImageTypeMetafile;
+ memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
(*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch);
(*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Right) / ((REAL) placeable->Inch);
(*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right
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)
{
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
{
+ GraphicsContainerItem *cont, *next;
TRACE("(%p)\n", graphics);
if(!graphics) return InvalidParameter;
if(graphics->busy) return ObjectBusy;
- if(graphics->hwnd)
+ if(graphics->owndc)
ReleaseDC(graphics->hwnd, graphics->hdc);
+ LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
+ list_remove(&cont->entry);
+ delete_container(cont);
+ }
+
GdipDeleteRegion(graphics->clip);
GdipDeleteMatrix(graphics->worldtrans);
GdipFree(graphics);
TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
- if(!points || count <= 0)
+ if(!points)
return InvalidParameter;
pointsF = GdipAlloc(sizeof(GpPointF)*count);
if(graphics->busy)
return ObjectBusy;
+ if(count < 2)
+ return InvalidParameter;
+
pt = GdipAlloc(len_pt * sizeof(GpPointF));
+ if(!pt)
+ return OutOfMemory;
+
tension = tension * TENSION_CONST;
calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
- if(!points || count <= 0)
+ if(!points)
return InvalidParameter;
pointsF = GdipAlloc(sizeof(GpPointF)*count);
return ret;
}
+GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen,
+ GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments,
+ REAL tension)
+{
+ TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
+
+ if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
+ return InvalidParameter;
+ }
+
+ return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension);
+}
+
+GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen,
+ GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments,
+ REAL tension)
+{
+ TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
+
+ if(count < 0){
+ return OutOfMemory;
+ }
+
+ if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
+ return InvalidParameter;
+ }
+
+ return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension);
+}
+
GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
REAL y, REAL width, REAL height)
{
GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y)
{
+ UINT width, height;
+ GpPointF points[3];
+
TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y);
- /* IPicture::Render uses LONG coords */
- return GdipDrawImageI(graphics,image,roundr(x),roundr(y));
+ if(!graphics || !image)
+ return InvalidParameter;
+
+ GdipGetImageWidth(image, &width);
+ GdipGetImageHeight(image, &height);
+
+ /* FIXME: we should use the graphics and image dpi, somehow */
+
+ points[0].X = points[2].X = x;
+ points[0].Y = points[1].Y = y;
+ points[1].X = x + width;
+ points[2].Y = y + height;
+
+ return GdipDrawImagePointsRect(graphics, image, points, 3, 0, 0, width, height,
+ UnitPixel, NULL, NULL, NULL);
}
GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
INT y)
{
- UINT width, height, srcw, srch;
-
TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
- if(!graphics || !image)
- return InvalidParameter;
+ return GdipDrawImage(graphics, image, (REAL)x, (REAL)y);
+}
- GdipGetImageWidth(image, &width);
- GdipGetImageHeight(image, &height);
+GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
+ REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
+ GpUnit srcUnit)
+{
+ GpPointF points[3];
+ TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
- srcw = width * (((REAL) INCH_HIMETRIC) /
- ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX)));
- srch = height * (((REAL) INCH_HIMETRIC) /
- ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY)));
+ points[0].X = points[2].X = x;
+ points[0].Y = points[1].Y = y;
- if(image->type != ImageTypeMetafile){
- y += height;
- height *= -1;
- }
+ /* FIXME: convert image coordinates to Graphics coordinates? */
+ points[1].X = x + srcwidth;
+ points[2].Y = y + srcheight;
- IPicture_Render(image->picture, graphics->hdc, x, y, width, height,
- 0, 0, srcw, srch, NULL);
+ return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
+ srcwidth, srcheight, srcUnit, NULL, NULL, NULL);
+}
- return Ok;
+GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image,
+ INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight,
+ GpUnit srcUnit)
+{
+ return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
+}
+
+GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image,
+ GDIPCONST GpPointF *dstpoints, INT count)
+{
+ FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics *graphics, GpImage *image,
+ GDIPCONST GpPoint *dstpoints, INT count)
+{
+ FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
+ return NotImplemented;
}
/* FIXME: partially implemented (only works for rectangular parallelograms) */
if(!graphics || !image || !points || count != 3)
return InvalidParameter;
- if(srcUnit == UnitInch)
- dx = dy = (REAL) INCH_HIMETRIC;
- else if(srcUnit == UnitPixel){
- dx = ((REAL) INCH_HIMETRIC) /
- ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
- dy = ((REAL) INCH_HIMETRIC) /
- ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
- }
- else
- return NotImplemented;
-
memcpy(ptf, points, 3 * sizeof(GpPointF));
transform_and_round_points(graphics, pti, ptf, 3);
- /* IPicture renders bitmaps with the y-axis reversed
- * FIXME: flipping for unknown image type might not be correct. */
- if(image->type != ImageTypeMetafile){
- INT temp;
- temp = pti[0].y;
- pti[0].y = pti[2].y;
- pti[2].y = temp;
- }
-
- 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 * dx, srcy * dy,
- srcwidth * dx, srcheight * dy,
- NULL) != S_OK){
- if(callback)
- callback(callbackData);
- return GenericError;
+ if (image->picture)
+ {
+ if(srcUnit == UnitInch)
+ dx = dy = (REAL) INCH_HIMETRIC;
+ else if(srcUnit == UnitPixel){
+ dx = ((REAL) INCH_HIMETRIC) /
+ ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
+ dy = ((REAL) INCH_HIMETRIC) /
+ ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
+ }
+ else
+ return NotImplemented;
+
+ 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 * dx, srcy * dy,
+ srcwidth * dx, srcheight * dy,
+ NULL) != S_OK){
+ if(callback)
+ callback(callbackData);
+ return GenericError;
+ }
+ }
+ else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
+ {
+ HDC hdc;
+ GpBitmap* bitmap = (GpBitmap*)image;
+ int temp_hdc=0, temp_bitmap=0;
+ HBITMAP hbitmap, old_hbm=NULL;
+
+ if (srcUnit == UnitInch)
+ dx = dy = 96.0; /* FIXME: use the image resolution */
+ else if (srcUnit == UnitPixel)
+ dx = dy = 1.0;
+ else
+ return NotImplemented;
+
+ if (bitmap->format == PixelFormat32bppARGB)
+ {
+ BITMAPINFOHEADER bih;
+ BYTE *temp_bits;
+
+ /* we need a bitmap with premultiplied alpha */
+ hdc = CreateCompatibleDC(0);
+ temp_hdc = 1;
+ temp_bitmap = 1;
+
+ bih.biSize = sizeof(BITMAPINFOHEADER);
+ bih.biWidth = bitmap->width;
+ bih.biHeight = -bitmap->height;
+ bih.biPlanes = 1;
+ bih.biBitCount = 32;
+ bih.biCompression = BI_RGB;
+ bih.biSizeImage = 0;
+ bih.biXPelsPerMeter = 0;
+ bih.biYPelsPerMeter = 0;
+ bih.biClrUsed = 0;
+ bih.biClrImportant = 0;
+
+ hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
+ (void**)&temp_bits, NULL, 0);
+
+ convert_32bppARGB_to_32bppPARGB(bitmap->width, bitmap->height,
+ temp_bits, bitmap->width*4, bitmap->bits, bitmap->stride);
+ }
+ else
+ {
+ hbitmap = bitmap->hbitmap;
+ hdc = bitmap->hdc;
+ temp_hdc = (hdc == 0);
+ }
+
+ if (temp_hdc)
+ {
+ if (!hdc) hdc = CreateCompatibleDC(0);
+ old_hbm = SelectObject(hdc, hbitmap);
+ }
+
+ if (bitmap->format == PixelFormat32bppARGB || bitmap->format == PixelFormat32bppPARGB)
+ {
+ BLENDFUNCTION bf;
+
+ bf.BlendOp = AC_SRC_OVER;
+ bf.BlendFlags = 0;
+ bf.SourceConstantAlpha = 255;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+
+ GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+ hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf);
+ }
+ else
+ {
+ StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+ hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY);
+ }
+
+ if (temp_hdc)
+ {
+ SelectObject(hdc, old_hbm);
+ DeleteDC(hdc);
+ }
+
+ if (temp_bitmap)
+ DeleteObject(hbitmap);
+ }
+ else
+ {
+ ERR("GpImage with no IPicture or HBITMAP?!\n");
+ return NotImplemented;
}
return Ok;
HFONT gdifont;
LOGFONTW lfw;
TEXTMETRICW textmet;
- GpPointF pt[2], rectcpy[4];
+ GpPointF pt[3], rectcpy[4];
POINT corners[4];
WCHAR* stringdup;
REAL angle, ang_cos, ang_sin, rel_width, rel_height;
- INT sum = 0, height = 0, fit, fitcpy, save_state, i, j, lret, nwidth,
- nheight;
+ INT sum = 0, height = 0, offsety = 0, fit, fitcpy, save_state, i, j, lret, nwidth,
+ nheight, lineend;
SIZE size;
+ POINT drawbase;
+ UINT drawflags;
RECT drawcoord;
+ TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length),
+ length, font, debugstr_rectf(rect), format, brush);
+
if(!graphics || !string || !font || !brush || !rect)
return InvalidParameter;
return NotImplemented;
}
- if(format)
+ if(format){
TRACE("may be ignoring some format flags: attr %x\n", format->attr);
+ /* Should be no need to explicitly test for StringAlignmentNear as
+ * that is default behavior if no alignment is passed. */
+ if(format->vertalign != StringAlignmentNear){
+ RectF bounds;
+ GdipMeasureString(graphics, string, length, font, rect, format, &bounds, 0, 0);
+
+ if(format->vertalign == StringAlignmentCenter)
+ offsety = (rect->Height - bounds.Height) / 2;
+ else if(format->vertalign == StringAlignmentFar)
+ offsety = (rect->Height - bounds.Height);
+ }
+ }
+
if(length == -1) length = lstrlenW(string);
stringdup = GdipAlloc(length * sizeof(WCHAR));
SetBkMode(graphics->hdc, TRANSPARENT);
SetTextColor(graphics->hdc, brush->lb.lbColor);
+ pt[0].X = 0.0;
+ pt[0].Y = 0.0;
+ pt[1].X = 1.0;
+ pt[1].Y = 0.0;
+ pt[2].X = 0.0;
+ pt[2].Y = 1.0;
+ GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+ angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
+ ang_cos = cos(angle);
+ ang_sin = sin(angle);
+ 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)+
+ (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X));
+
rectcpy[3].X = rectcpy[0].X = rect->X;
- rectcpy[1].Y = rectcpy[0].Y = rect->Y;
+ rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety;
rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
- rectcpy[3].Y = rectcpy[2].Y = rect->Y + rect->Height;
+ rectcpy[3].Y = rectcpy[2].Y = rect->Y + offsety + rect->Height;
transform_and_round_points(graphics, corners, rectcpy, 4);
- if(roundr(rect->Width) == 0 && roundr(rect->Height) == 0){
- rel_width = rel_height = 1.0;
- nwidth = nheight = INT_MAX;
- }
- else{
- rel_width = sqrt((corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) +
- (corners[1].y - corners[0].y) * (corners[1].y - corners[0].y))
- / rect->Width;
- rel_height = sqrt((corners[2].x - corners[1].x) * (corners[2].x - corners[1].x) +
- (corners[2].y - corners[1].y) * (corners[2].y - corners[1].y))
- / rect->Height;
-
+ if (roundr(rect->Width) == 0)
+ nwidth = INT_MAX;
+ else
nwidth = roundr(rel_width * rect->Width);
+
+ if (roundr(rect->Height) == 0)
+ nheight = INT_MAX;
+ else
nheight = roundr(rel_height * rect->Height);
+
+ if (roundr(rect->Width) != 0 && roundr(rect->Height) != 0)
+ {
+ /* FIXME: If only the width or only the height is 0, we should probably still clip */
rgn = CreatePolygonRgn(corners, 4, ALTERNATE);
SelectClipRgn(graphics->hdc, rgn);
}
lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height);
lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width);
- pt[0].X = 0.0;
- pt[0].Y = 0.0;
- pt[1].X = 1.0;
- pt[1].Y = 0.0;
- GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
- angle = gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
- ang_cos = cos(angle);
- ang_sin = sin(angle);
- lfw.lfEscapement = lfw.lfOrientation = -roundr((angle / M_PI) * 1800.0);
+ lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
gdifont = CreateFontIndirectW(&lfw);
DeleteObject(SelectObject(graphics->hdc, CreateFontIndirectW(&lfw)));
for(i = 0, j = 0; i < length; i++){
- if(!isprint(string[i]) && (string[i] != '\n'))
+ if(!isprintW(string[i]) && (string[i] != '\n'))
continue;
stringdup[j] = string[i];
j++;
}
- stringdup[j] = 0;
length = j;
+ if (!format || format->align == StringAlignmentNear)
+ {
+ drawbase.x = corners[0].x;
+ drawbase.y = corners[0].y;
+ drawflags = DT_NOCLIP | DT_EXPANDTABS;
+ }
+ else if (format->align == StringAlignmentCenter)
+ {
+ drawbase.x = (corners[0].x + corners[1].x)/2;
+ drawbase.y = (corners[0].y + corners[1].y)/2;
+ drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_CENTER;
+ }
+ else /* (format->align == StringAlignmentFar) */
+ {
+ drawbase.x = corners[1].x;
+ drawbase.y = corners[1].y;
+ drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_RIGHT;
+ }
+
while(sum < length){
- drawcoord.left = corners[0].x + roundr(ang_sin * (REAL) height);
- drawcoord.top = corners[0].y + roundr(ang_cos * (REAL) height);
+ drawcoord.left = drawcoord.right = drawbase.x + roundr(ang_sin * (REAL) height);
+ drawcoord.top = drawcoord.bottom = drawbase.y + roundr(ang_cos * (REAL) height);
GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
nwidth, &fit, NULL, &size);
fitcpy = fit;
if(fit == 0){
- DrawTextW(graphics->hdc, stringdup + sum, 1, &drawcoord, DT_NOCLIP |
- DT_EXPANDTABS);
+ DrawTextW(graphics->hdc, stringdup + sum, 1, &drawcoord, drawflags);
break;
}
/* Line break code (may look strange, but it imitates windows). */
if(lret < fit)
- fit = lret; /* this is not an off-by-one error */
+ lineend = fit = lret; /* this is not an off-by-one error */
else if(fit < (length - sum)){
if(*(stringdup + sum + fit) == ' ')
while(*(stringdup + sum + fit) == ' ')
break;
}
}
+ lineend = fit;
+ while(*(stringdup + sum + lineend - 1) == ' ' ||
+ *(stringdup + sum + lineend - 1) == '\t')
+ lineend--;
}
- DrawTextW(graphics->hdc, stringdup + sum, min(length - sum, fit),
- &drawcoord, DT_NOCLIP | DT_EXPANDTABS);
+ else
+ lineend = fit;
+ DrawTextW(graphics->hdc, stringdup + sum, min(length - sum, lineend),
+ &drawcoord, drawflags);
sum += fit + (lret < fitcpy ? 1 : 0);
height += size.cy;
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
transform_and_round_points(graphics, pti, ptf, 2);
+ BeginPath(graphics->hdc);
Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
: WINDING));
goto end;
EndPath(graphics->hdc);
- FillPath(graphics->hdc);
+ brush_fill_path(graphics, brush);
retval = Ok;
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
+ BeginPath(graphics->hdc);
draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
: WINDING));
transform_and_round_points(graphics, pti, ptf, count);
+
+ BeginPath(graphics->hdc);
Polygon(graphics->hdc, pti, count);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
: WINDING));
transform_and_round_points(graphics, pti, ptf, count);
+
+ BeginPath(graphics->hdc);
Polygon(graphics->hdc, pti, count);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
transform_and_round_points(graphics, pti, ptf, 4);
+ BeginPath(graphics->hdc);
Polygon(graphics->hdc, pti, 4);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
save_state = SaveDC(graphics->hdc);
EndPath(graphics->hdc);
- SelectObject(graphics->hdc, brush->gdibrush);
- SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
transform_and_round_points(graphics, pti, ptf, 4);
+ BeginPath(graphics->hdc);
Polygon(graphics->hdc, pti, 4);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
RestoreDC(graphics->hdc, save_state);
return ret;
}
+/*****************************************************************************
+ * GdipFillRegion [GDIPLUS.@]
+ */
GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
GpRegion* region)
{
+ INT save_state;
+ GpStatus status;
+ HRGN hrgn;
+ RECT rc;
+
+ TRACE("(%p, %p, %p)\n", graphics, brush, region);
+
if (!(graphics && brush && region))
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
- FIXME("(%p, %p, %p): stub\n", graphics, brush, region);
+ status = GdipGetRegionHRgn(region, graphics, &hrgn);
+ if(status != Ok)
+ return status;
- return NotImplemented;
+ save_state = SaveDC(graphics->hdc);
+ EndPath(graphics->hdc);
+
+ ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
+
+ if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
+ {
+ BeginPath(graphics->hdc);
+ Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom);
+ EndPath(graphics->hdc);
+
+ brush_fill_path(graphics, brush);
+ }
+
+ RestoreDC(graphics->hdc, save_state);
+
+ DeleteObject(hrgn);
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
return NotImplemented;
}
+/*****************************************************************************
+ * GdipGetClipBounds [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect)
+{
+ TRACE("(%p, %p)\n", graphics, rect);
+
+ if(!graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ return GdipGetRegionBounds(graphics->clip, graphics, rect);
+}
+
+/*****************************************************************************
+ * GdipGetClipBoundsI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetClipBoundsI(GpGraphics *graphics, GpRect *rect)
+{
+ TRACE("(%p, %p)\n", graphics, rect);
+
+ if(!graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ return GdipGetRegionBoundsI(graphics->clip, graphics, rect);
+}
+
/* FIXME: Compositing mode is not used anywhere except the getter/setter. */
GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics,
CompositingMode *mode)
return Ok;
}
+GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect)
+{
+ GpRegion *clip_rgn;
+ GpStatus stat;
+
+ TRACE("(%p, %p)\n", graphics, rect);
+
+ if(!graphics || !rect)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ /* intersect window and graphics clipping regions */
+ if((stat = GdipCreateRegion(&clip_rgn)) != Ok)
+ return stat;
+
+ if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok)
+ goto cleanup;
+
+ /* get bounds of the region */
+ stat = GdipGetRegionBounds(clip_rgn, graphics, rect);
+
+cleanup:
+ GdipDeleteRegion(clip_rgn);
+
+ return stat;
+}
+
+GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect)
+{
+ GpRectF rectf;
+ GpStatus stat;
+
+ TRACE("(%p, %p)\n", graphics, rect);
+
+ if(!graphics || !rect)
+ return InvalidParameter;
+
+ if((stat = GdipGetVisibleClipBounds(graphics, &rectf)) == Ok)
+ {
+ rect->X = roundr(rectf.X);
+ rect->Y = roundr(rectf.Y);
+ rect->Width = roundr(rectf.Width);
+ rect->Height = roundr(rectf.Height);
+ }
+
+ return stat;
+}
+
GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
{
TRACE("(%p, %p)\n", graphics, matrix);
{
GpSolidFill *brush;
GpStatus stat;
- RECT rect;
+ GpRectF wnd_rect;
TRACE("(%p, %x)\n", graphics, color);
if((stat = GdipCreateSolidFill(color, &brush)) != Ok)
return stat;
- if(graphics->hwnd){
- if(!GetWindowRect(graphics->hwnd, &rect)){
- GdipDeleteBrush((GpBrush*)brush);
- return GenericError;
- }
-
- GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)(rect.right - rect.left),
- (REAL)(rect.bottom - rect.top));
+ if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){
+ GdipDeleteBrush((GpBrush*)brush);
+ return stat;
}
- else
- GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)GetDeviceCaps(graphics->hdc, HORZRES),
- (REAL)GetDeviceCaps(graphics->hdc, VERTRES));
+
+ GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y,
+ wnd_rect.Width, wnd_rect.Height);
GdipDeleteBrush((GpBrush*)brush);
GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result)
{
- FIXME("(%p, %.2f, %.2f, %p) stub\n", graphics, x, y, result);
+ GpStatus stat;
+ GpRegion* rgn;
+ GpPointF pt;
+
+ TRACE("(%p, %.2f, %.2f, %p)\n", graphics, x, y, result);
if(!graphics || !result)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
- return NotImplemented;
+ pt.X = x;
+ pt.Y = y;
+ if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, &pt, 1)) != Ok)
+ return stat;
+
+ if((stat = GdipCreateRegion(&rgn)) != Ok)
+ return stat;
+
+ if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
+ goto cleanup;
+
+ stat = GdipIsVisibleRegionPoint(rgn, pt.X, pt.Y, graphics, result);
+
+cleanup:
+ GdipDeleteRegion(rgn);
+ return stat;
}
GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result)
{
- FIXME("(%p, %d, %d, %p) stub\n", graphics, x, y, result);
+ return GdipIsVisiblePoint(graphics, (REAL)x, (REAL)y, result);
+}
+
+GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result)
+{
+ GpStatus stat;
+ GpRegion* rgn;
+ GpPointF pts[2];
+
+ TRACE("(%p %.2f %.2f %.2f %.2f %p)\n", graphics, x, y, width, height, result);
if(!graphics || !result)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
- return NotImplemented;
+ pts[0].X = x;
+ pts[0].Y = y;
+ pts[1].X = x + width;
+ pts[1].Y = y + height;
+
+ if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
+ CoordinateSpaceWorld, pts, 2)) != Ok)
+ return stat;
+
+ pts[1].X -= pts[0].X;
+ pts[1].Y -= pts[0].Y;
+
+ if((stat = GdipCreateRegion(&rgn)) != Ok)
+ return stat;
+
+ if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
+ goto cleanup;
+
+ stat = GdipIsVisibleRegionRect(rgn, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, graphics, result);
+
+cleanup:
+ GdipDeleteRegion(rgn);
+ return stat;
+}
+
+GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result)
+{
+ return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
}
GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
HFONT oldfont;
WCHAR* stringdup;
INT sum = 0, height = 0, fit, fitcpy, max_width = 0, i, j, lret, nwidth,
- nheight;
+ nheight, lineend;
SIZE size;
+ TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
+ debugstr_wn(string, length), length, font, debugstr_rectf(rect), format,
+ bounds, codepointsfitted, linesfilled);
+
if(!graphics || !string || !font || !rect)
return InvalidParameter;
nwidth = nheight = INT_MAX;
for(i = 0, j = 0; i < length; i++){
- if(!isprint(string[i]) && (string[i] != '\n'))
+ if(!isprintW(string[i]) && (string[i] != '\n'))
continue;
stringdup[j] = string[i];
/* Line break code (may look strange, but it imitates windows). */
if(lret < fit)
- fit = lret; /* this is not an off-by-one error */
+ lineend = fit = lret; /* this is not an off-by-one error */
else if(fit < (length - sum)){
if(*(stringdup + sum + fit) == ' ')
while(*(stringdup + sum + fit) == ' ')
break;
}
}
+ lineend = fit;
+ while(*(stringdup + sum + lineend - 1) == ' ' ||
+ *(stringdup + sum + lineend - 1) == '\t')
+ lineend--;
}
+ else
+ lineend = fit;
- GetTextExtentExPointW(graphics->hdc, stringdup + sum, fit,
+ GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
nwidth, &j, NULL, &size);
sum += fit + (lret < fitcpy ? 1 : 0);
GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
{
- static int calls;
-
- if(!graphics)
- return InvalidParameter;
-
- if(!(calls++))
- FIXME("graphics state not implemented\n");
-
- return Ok;
+ return GdipEndContainer(graphics, state);
}
GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
{
- static int calls;
+ return GdipBeginContainer2(graphics, state);
+}
+
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
+ GraphicsContainer *state)
+{
+ GraphicsContainerItem *container;
+ GpStatus sts;
+
+ TRACE("(%p, %p)\n", graphics, state);
if(!graphics || !state)
return InvalidParameter;
- if(!(calls++))
- FIXME("graphics state not implemented\n");
+ sts = init_container(&container, graphics);
+ if(sts != Ok)
+ return sts;
+
+ list_add_head(&graphics->containers, &container->entry);
+ *state = graphics->contid = container->contid;
- *state = 0xdeadbeef;
return Ok;
}
-GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, GraphicsContainer *state)
+GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
{
- FIXME("(%p, %p)\n", graphics, state);
+ FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
+ return NotImplemented;
+}
- if(!graphics || !state)
- return InvalidParameter;
+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;
+}
- *state = 0xdeadbeef;
- return Ok;
+GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data)
+{
+ FIXME("(%p, %d, %p): stub\n", graphics, sizeData, data);
+ return NotImplemented;
}
-GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsState state)
+GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
{
- FIXME("(%p, 0x%x)\n", graphics, state);
+ GpStatus sts;
+ GraphicsContainerItem *container, *container2;
- if(!graphics || !state)
+ TRACE("(%p, %x)\n", graphics, state);
+
+ if(!graphics)
return InvalidParameter;
+ LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
+ if(container->contid == state)
+ break;
+ }
+
+ /* did not find a matching container */
+ if(&container->entry == &graphics->containers)
+ return Ok;
+
+ sts = restore_container(graphics, container);
+ if(sts != Ok)
+ return sts;
+
+ /* remove all of the containers on top of the found container */
+ LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
+ if(container->contid == state)
+ break;
+ list_remove(&container->entry);
+ delete_container(container);
+ }
+
+ list_remove(&container->entry);
+ delete_container(container);
+
return Ok;
}
return Ok;
}
+GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y)
+{
+ static int calls;
+
+ TRACE("(%p,%i,%i)\n", graphics, x, y);
+
+ if (!(calls++))
+ FIXME("not implemented\n");
+
+ return NotImplemented;
+}
+
GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
{
TRACE("(%p, %d)\n", graphics, mode);
return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order);
}
+/*****************************************************************************
+ * GdipSetClipHrgn [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode mode)
+{
+ GpRegion *region;
+ GpStatus status;
+
+ TRACE("(%p, %p, %d)\n", graphics, hrgn, mode);
+
+ if(!graphics)
+ return InvalidParameter;
+
+ status = GdipCreateRegionHrgn(hrgn, ®ion);
+ if(status != Ok)
+ return status;
+
+ status = GdipSetClipRegion(graphics, region, mode);
+
+ GdipDeleteRegion(region);
+ return status;
+}
+
GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode)
{
TRACE("(%p, %p, %d)\n", graphics, path, mode);
GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpPointF *points, INT count)
{
+ GpMatrix *matrix;
+ GpStatus stat;
+ REAL unitscale;
+
if(!graphics || !points || count <= 0)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
- FIXME("(%p, %d, %d, %p, %d): stub\n", graphics, dst_space, src_space, points, count);
+ TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
- return NotImplemented;
+ if (src_space == dst_space) return Ok;
+
+ stat = GdipCreateMatrix(&matrix);
+ if (stat == Ok)
+ {
+ unitscale = convert_unit(graphics->hdc, graphics->unit);
+
+ if(graphics->unit != UnitDisplay)
+ unitscale *= 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/unitscale, 1.0/unitscale, MatrixOrderAppend);
+ break;
+ }
+
+ /* transform from CoordinateSpacePage to dst_space */
+ switch (dst_space)
+ {
+ case CoordinateSpaceWorld:
+ {
+ GpMatrix *inverted_transform;
+ stat = GdipCloneMatrix(graphics->worldtrans, &inverted_transform);
+ if (stat == Ok)
+ {
+ stat = GdipInvertMatrix(inverted_transform);
+ if (stat == Ok)
+ GdipMultiplyMatrix(matrix, inverted_transform, MatrixOrderAppend);
+ GdipDeleteMatrix(inverted_transform);
+ }
+ break;
+ }
+ case CoordinateSpacePage:
+ break;
+ case CoordinateSpaceDevice:
+ GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend);
+ break;
+ }
+
+ if (stat == Ok)
+ stat = GdipTransformMatrixPoints(matrix, points, count);
+
+ GdipDeleteMatrix(matrix);
+ }
+
+ return stat;
}
GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpPoint *points, INT count)
{
- FIXME("(%p, %d, %d, %p, %d): stub\n", graphics, dst_space, src_space, points, count);
+ GpPointF *pointsF;
+ GpStatus ret;
+ INT i;
- return NotImplemented;
+ TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
+
+ if(count <= 0)
+ return InvalidParameter;
+
+ pointsF = GdipAlloc(sizeof(GpPointF) * count);
+ if(!pointsF)
+ return OutOfMemory;
+
+ for(i = 0; i < count; i++){
+ pointsF[i].X = (REAL)points[i].X;
+ pointsF[i].Y = (REAL)points[i].Y;
+ }
+
+ ret = GdipTransformPoints(graphics, dst_space, src_space, pointsF, count);
+
+ if(ret == Ok)
+ for(i = 0; i < count; i++){
+ points[i].X = roundr(pointsF[i].X);
+ points[i].Y = roundr(pointsF[i].Y);
+ }
+ GdipFree(pointsF);
+
+ return ret;
}
HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void)
return NULL;
}
+
+/*****************************************************************************
+ * GdipTranslateClip [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipTranslateClip(GpGraphics *graphics, REAL dx, REAL dy)
+{
+ TRACE("(%p, %.2f, %.2f)\n", graphics, dx, dy);
+
+ if(!graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ return GdipTranslateRegion(graphics->clip, dx, dy);
+}
+
+/*****************************************************************************
+ * GdipTranslateClipI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy)
+{
+ TRACE("(%p, %d, %d)\n", graphics, dx, dy);
+
+ if(!graphics)
+ return InvalidParameter;
+
+ if(graphics->busy)
+ return ObjectBusy;
+
+ return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy);
+}
+
+
+/*****************************************************************************
+ * GdipMeasureDriverString [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
+ GDIPCONST GpFont *font, GDIPCONST PointF *positions,
+ INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox)
+{
+ FIXME("(%p %p %d %p %p %d %p %p): stub\n", graphics, text, length, font, positions, flags, matrix, boundingBox);
+ return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipDrawDriverString [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
+ GDIPCONST GpFont *font, GDIPCONST GpBrush *brush,
+ GDIPCONST PointF *positions, INT flags,
+ GDIPCONST GpMatrix *matrix )
+{
+ FIXME("(%p %p %d %p %p %p %d %p): stub\n", graphics, text, length, font, brush, positions, flags, matrix);
+ return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipRecordMetafileI [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
+ MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
+{
+ FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
+ return NotImplemented;
+}