| /* |
| * Copyright (C) 2007 Google (Evan Stade) |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| |
| #include "objbase.h" |
| |
| #include "gdiplus.h" |
| #include "gdiplus_private.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); |
| |
| static DWORD gdip_to_gdi_dash(GpDashStyle dash) |
| { |
| switch(dash){ |
| case DashStyleSolid: |
| return PS_SOLID; |
| case DashStyleDash: |
| return PS_DASH; |
| case DashStyleDot: |
| return PS_DOT; |
| case DashStyleDashDot: |
| return PS_DASHDOT; |
| case DashStyleDashDotDot: |
| return PS_DASHDOTDOT; |
| case DashStyleCustom: |
| return PS_USERSTYLE; |
| default: |
| ERR("Not a member of GpDashStyle enumeration\n"); |
| return 0; |
| } |
| } |
| |
| static DWORD gdip_to_gdi_join(GpLineJoin join) |
| { |
| switch(join){ |
| case LineJoinRound: |
| return PS_JOIN_ROUND; |
| case LineJoinBevel: |
| return PS_JOIN_BEVEL; |
| case LineJoinMiter: |
| case LineJoinMiterClipped: |
| return PS_JOIN_MITER; |
| default: |
| ERR("Not a member of GpLineJoin enumeration\n"); |
| return 0; |
| } |
| } |
| |
| static GpPenType bt_to_pt(GpBrushType bt) |
| { |
| switch(bt){ |
| case BrushTypeSolidColor: |
| return PenTypeSolidColor; |
| case BrushTypeHatchFill: |
| return PenTypeHatchFill; |
| case BrushTypeTextureFill: |
| return PenTypeTextureFill; |
| case BrushTypePathGradient: |
| return PenTypePathGradient; |
| case BrushTypeLinearGradient: |
| return PenTypeLinearGradient; |
| default: |
| return PenTypeUnknown; |
| } |
| } |
| |
| GpStatus WINGDIPAPI GdipClonePen(GpPen *pen, GpPen **clonepen) |
| { |
| GpStatus stat; |
| |
| TRACE("(%p, %p)\n", pen, clonepen); |
| |
| if(!pen || !clonepen) |
| return InvalidParameter; |
| |
| *clonepen = heap_alloc_zero(sizeof(GpPen)); |
| if(!*clonepen) return OutOfMemory; |
| |
| **clonepen = *pen; |
| |
| (*clonepen)->customstart = NULL; |
| (*clonepen)->customend = NULL; |
| (*clonepen)->brush = NULL; |
| (*clonepen)->dashes = NULL; |
| |
| stat = GdipCloneBrush(pen->brush, &(*clonepen)->brush); |
| |
| if (stat == Ok && pen->customstart) |
| stat = GdipCloneCustomLineCap(pen->customstart, &(*clonepen)->customstart); |
| |
| if (stat == Ok && pen->customend) |
| stat = GdipCloneCustomLineCap(pen->customend, &(*clonepen)->customend); |
| |
| if (stat == Ok && pen->dashes) |
| { |
| (*clonepen)->dashes = heap_alloc_zero(pen->numdashes * sizeof(REAL)); |
| if ((*clonepen)->dashes) |
| memcpy((*clonepen)->dashes, pen->dashes, pen->numdashes * sizeof(REAL)); |
| else |
| stat = OutOfMemory; |
| } |
| |
| if (stat != Ok) |
| { |
| GdipDeletePen(*clonepen); |
| *clonepen = NULL; |
| return stat; |
| } |
| |
| TRACE("<-- %p\n", *clonepen); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit, |
| GpPen **pen) |
| { |
| GpBrush *brush; |
| GpStatus status; |
| |
| TRACE("(%x, %.2f, %d, %p)\n", color, width, unit, pen); |
| |
| GdipCreateSolidFill(color, (GpSolidFill **)(&brush)); |
| status = GdipCreatePen2(brush, width, unit, pen); |
| GdipDeleteBrush(brush); |
| return status; |
| } |
| |
| GpStatus WINGDIPAPI GdipCreatePen2(GpBrush *brush, REAL width, GpUnit unit, |
| GpPen **pen) |
| { |
| GpPen *gp_pen; |
| GpBrush *clone_brush; |
| |
| TRACE("(%p, %.2f, %d, %p)\n", brush, width, unit, pen); |
| |
| if(!pen || !brush) |
| return InvalidParameter; |
| |
| gp_pen = heap_alloc_zero(sizeof(GpPen)); |
| if(!gp_pen) return OutOfMemory; |
| |
| gp_pen->style = GP_DEFAULT_PENSTYLE; |
| gp_pen->width = width; |
| gp_pen->unit = unit; |
| gp_pen->endcap = LineCapFlat; |
| gp_pen->join = LineJoinMiter; |
| gp_pen->miterlimit = 10.0; |
| gp_pen->dash = DashStyleSolid; |
| gp_pen->offset = 0.0; |
| gp_pen->customstart = NULL; |
| gp_pen->customend = NULL; |
| GdipSetMatrixElements(&gp_pen->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); |
| |
| if(!((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel))) { |
| FIXME("UnitWorld, UnitPixel only supported units\n"); |
| heap_free(gp_pen); |
| return NotImplemented; |
| } |
| |
| GdipCloneBrush(brush, &clone_brush); |
| gp_pen->brush = clone_brush; |
| |
| *pen = gp_pen; |
| |
| TRACE("<-- %p\n", *pen); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen) |
| { |
| TRACE("(%p)\n", pen); |
| |
| if(!pen) return InvalidParameter; |
| |
| GdipDeleteBrush(pen->brush); |
| GdipDeleteCustomLineCap(pen->customstart); |
| GdipDeleteCustomLineCap(pen->customend); |
| heap_free(pen->dashes); |
| heap_free(pen); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenBrushFill(GpPen *pen, GpBrush **brush) |
| { |
| TRACE("(%p, %p)\n", pen, brush); |
| |
| if(!pen || !brush) |
| return InvalidParameter; |
| |
| return GdipCloneBrush(pen->brush, brush); |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenColor(GpPen *pen, ARGB *argb) |
| { |
| TRACE("(%p, %p)\n", pen, argb); |
| |
| if(!pen || !argb) |
| return InvalidParameter; |
| |
| if(pen->brush->bt != BrushTypeSolidColor) |
| return NotImplemented; |
| |
| return GdipGetSolidFillColor(((GpSolidFill*)pen->brush), argb); |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenCustomEndCap(GpPen *pen, GpCustomLineCap** customCap) |
| { |
| TRACE("(%p, %p)\n", pen, customCap); |
| |
| if(!pen || !customCap) |
| return InvalidParameter; |
| |
| if(!pen->customend){ |
| *customCap = NULL; |
| return Ok; |
| } |
| |
| return GdipCloneCustomLineCap(pen->customend, customCap); |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenCustomStartCap(GpPen *pen, GpCustomLineCap** customCap) |
| { |
| TRACE("(%p, %p)\n", pen, customCap); |
| |
| if(!pen || !customCap) |
| return InvalidParameter; |
| |
| if(!pen->customstart){ |
| *customCap = NULL; |
| return Ok; |
| } |
| |
| return GdipCloneCustomLineCap(pen->customstart, customCap); |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenDashArray(GpPen *pen, REAL *dash, INT count) |
| { |
| TRACE("(%p, %p, %d)\n", pen, dash, count); |
| |
| if(!pen || !dash || count > pen->numdashes) |
| return InvalidParameter; |
| |
| /* note: if you pass a negative value for count, it crashes native gdiplus. */ |
| if(count < 0) |
| return GenericError; |
| |
| memcpy(dash, pen->dashes, count * sizeof(REAL)); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenDashCap197819(GpPen *pen, GpDashCap *dashCap) |
| { |
| TRACE("(%p, %p)\n", pen, dashCap); |
| |
| if(!pen || !dashCap) |
| return InvalidParameter; |
| |
| *dashCap = pen->dashcap; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenDashCount(GpPen *pen, INT *count) |
| { |
| TRACE("(%p, %p)\n", pen, count); |
| |
| if(!pen || !count) |
| return InvalidParameter; |
| |
| *count = pen->numdashes; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenDashOffset(GpPen *pen, REAL *offset) |
| { |
| TRACE("(%p, %p)\n", pen, offset); |
| |
| if(!pen || !offset) |
| return InvalidParameter; |
| |
| *offset = pen->offset; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenDashStyle(GpPen *pen, GpDashStyle *dash) |
| { |
| TRACE("(%p, %p)\n", pen, dash); |
| |
| if(!pen || !dash) |
| return InvalidParameter; |
| |
| *dash = pen->dash; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenEndCap(GpPen *pen, GpLineCap *endCap) |
| { |
| TRACE("(%p, %p)\n", pen, endCap); |
| |
| if(!pen || !endCap) |
| return InvalidParameter; |
| |
| *endCap = pen->endcap; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenFillType(GpPen *pen, GpPenType* type) |
| { |
| TRACE("(%p, %p)\n", pen, type); |
| |
| if(!pen || !type) |
| return InvalidParameter; |
| |
| *type = bt_to_pt(pen->brush->bt); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenLineJoin(GpPen *pen, GpLineJoin *lineJoin) |
| { |
| TRACE("(%p, %p)\n", pen, lineJoin); |
| |
| if(!pen || !lineJoin) |
| return InvalidParameter; |
| |
| *lineJoin = pen->join; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenMode(GpPen *pen, GpPenAlignment *mode) |
| { |
| TRACE("(%p, %p)\n", pen, mode); |
| |
| if(!pen || !mode) |
| return InvalidParameter; |
| |
| *mode = pen->align; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenMiterLimit(GpPen *pen, REAL *miterLimit) |
| { |
| TRACE("(%p, %p)\n", pen, miterLimit); |
| |
| if(!pen || !miterLimit) |
| return InvalidParameter; |
| |
| *miterLimit = pen->miterlimit; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenStartCap(GpPen *pen, GpLineCap *startCap) |
| { |
| TRACE("(%p, %p)\n", pen, startCap); |
| |
| if(!pen || !startCap) |
| return InvalidParameter; |
| |
| *startCap = pen->startcap; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenUnit(GpPen *pen, GpUnit *unit) |
| { |
| TRACE("(%p, %p)\n", pen, unit); |
| |
| if(!pen || !unit) |
| return InvalidParameter; |
| |
| *unit = pen->unit; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenWidth(GpPen *pen, REAL *width) |
| { |
| TRACE("(%p, %p)\n", pen, width); |
| |
| if(!pen || !width) |
| return InvalidParameter; |
| |
| *width = pen->width; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipResetPenTransform(GpPen *pen) |
| { |
| TRACE("(%p)\n", pen); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| GdipSetMatrixElements(&pen->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenTransform(GpPen *pen, GpMatrix *matrix) |
| { |
| static int calls; |
| |
| TRACE("(%p,%p)\n", pen, matrix); |
| |
| if(!pen || !matrix) |
| return InvalidParameter; |
| |
| if(!(calls++)) |
| FIXME("(%p,%p) Semi-stub\n", pen, matrix); |
| |
| pen->transform = *matrix; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenTransform(GpPen *pen, GpMatrix *matrix) |
| { |
| TRACE("(%p,%p)\n", pen, matrix); |
| |
| if(!pen || !matrix) |
| return InvalidParameter; |
| |
| *matrix = pen->transform; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipTranslatePenTransform(GpPen *pen, REAL dx, REAL dy, GpMatrixOrder order) |
| { |
| static int calls; |
| |
| TRACE("(%p,%0.2f,%0.2f,%u)\n", pen, dx, dy, order); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(!(calls++)) |
| FIXME("not implemented\n"); |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipScalePenTransform(GpPen *pen, REAL sx, REAL sy, GpMatrixOrder order) |
| { |
| static int calls; |
| |
| TRACE("(%p,%0.2f,%0.2f,%u)\n", pen, sx, sy, order); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(!(calls++)) |
| FIXME("(%p, %.2f, %.2f, %d) stub\n", pen, sx, sy, order); |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipRotatePenTransform(GpPen *pen, REAL angle, GpMatrixOrder order) |
| { |
| static int calls; |
| |
| TRACE("(%p,%0.2f,%u)\n", pen, angle, order); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(!(calls++)) |
| FIXME("not implemented\n"); |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipMultiplyPenTransform(GpPen *pen, GDIPCONST GpMatrix *matrix, |
| GpMatrixOrder order) |
| { |
| static int calls; |
| |
| TRACE("(%p,%p,%u)\n", pen, matrix, order); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(!(calls++)) |
| FIXME("not implemented\n"); |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenBrushFill(GpPen *pen, GpBrush *brush) |
| { |
| TRACE("(%p, %p)\n", pen, brush); |
| |
| if(!pen || !brush) |
| return InvalidParameter; |
| |
| GdipDeleteBrush(pen->brush); |
| return GdipCloneBrush(brush, &pen->brush); |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenColor(GpPen *pen, ARGB argb) |
| { |
| TRACE("(%p, %x)\n", pen, argb); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(pen->brush->bt != BrushTypeSolidColor) |
| return NotImplemented; |
| |
| return GdipSetSolidFillColor(((GpSolidFill*)pen->brush), argb); |
| } |
| |
| GpStatus WINGDIPAPI GdipGetPenCompoundCount(GpPen *pen, INT *count) |
| { |
| FIXME("(%p, %p): stub\n", pen, count); |
| |
| if (!pen || !count) |
| return InvalidParameter; |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenCompoundArray(GpPen *pen, GDIPCONST REAL *dash, |
| INT count) |
| { |
| FIXME("(%p, %p, %i): stub\n", pen, dash, count); |
| |
| if (!pen || !dash || count < 2 || count%2 == 1) |
| return InvalidParameter; |
| |
| return NotImplemented; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenCustomEndCap(GpPen *pen, GpCustomLineCap* customCap) |
| { |
| GpCustomLineCap * cap; |
| GpStatus ret; |
| |
| TRACE("(%p, %p)\n", pen, customCap); |
| |
| /* native crashes on pen == NULL, customCap != NULL */ |
| if(!customCap) return InvalidParameter; |
| |
| if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){ |
| GdipDeleteCustomLineCap(pen->customend); |
| pen->endcap = LineCapCustom; |
| pen->customend = cap; |
| } |
| |
| return ret; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenCustomStartCap(GpPen *pen, GpCustomLineCap* customCap) |
| { |
| GpCustomLineCap * cap; |
| GpStatus ret; |
| |
| TRACE("(%p, %p)\n", pen, customCap); |
| |
| /* native crashes on pen == NULL, customCap != NULL */ |
| if(!customCap) return InvalidParameter; |
| |
| if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){ |
| GdipDeleteCustomLineCap(pen->customstart); |
| pen->startcap = LineCapCustom; |
| pen->customstart = cap; |
| } |
| |
| return ret; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenDashArray(GpPen *pen, GDIPCONST REAL *dash, |
| INT count) |
| { |
| INT i; |
| REAL sum = 0; |
| |
| TRACE("(%p, %p, %d)\n", pen, dash, count); |
| |
| if(!pen || !dash) |
| return InvalidParameter; |
| |
| if(count <= 0) |
| return OutOfMemory; |
| |
| for(i = 0; i < count; i++){ |
| sum += dash[i]; |
| if(dash[i] < 0.0) |
| return InvalidParameter; |
| } |
| |
| if(sum == 0.0 && count) |
| return InvalidParameter; |
| |
| heap_free(pen->dashes); |
| pen->dashes = NULL; |
| |
| if(count > 0) |
| pen->dashes = heap_alloc_zero(count * sizeof(REAL)); |
| if(!pen->dashes){ |
| pen->numdashes = 0; |
| return OutOfMemory; |
| } |
| |
| GdipSetPenDashStyle(pen, DashStyleCustom); |
| memcpy(pen->dashes, dash, count * sizeof(REAL)); |
| pen->numdashes = count; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenDashCap197819(GpPen *pen, GpDashCap dashCap) |
| { |
| TRACE("(%p, %d)\n", pen, dashCap); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| pen->dashcap = dashCap; |
| |
| return Ok; |
| } |
| |
| /* FIXME: dash offset not used */ |
| GpStatus WINGDIPAPI GdipSetPenDashOffset(GpPen *pen, REAL offset) |
| { |
| TRACE("(%p, %.2f)\n", pen, offset); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| pen->offset = offset; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenDashStyle(GpPen *pen, GpDashStyle dash) |
| { |
| TRACE("(%p, %d)\n", pen, dash); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| if(dash != DashStyleCustom){ |
| heap_free(pen->dashes); |
| pen->dashes = NULL; |
| pen->numdashes = 0; |
| } |
| |
| pen->dash = dash; |
| pen->style &= ~(PS_ALTERNATE | PS_SOLID | PS_DASH | PS_DOT | PS_DASHDOT | |
| PS_DASHDOTDOT | PS_NULL | PS_USERSTYLE | PS_INSIDEFRAME); |
| pen->style |= gdip_to_gdi_dash(dash); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenEndCap(GpPen *pen, GpLineCap cap) |
| { |
| TRACE("(%p, %d)\n", pen, cap); |
| |
| if(!pen) return InvalidParameter; |
| |
| /* The old custom cap gets deleted even if the new style is LineCapCustom. */ |
| GdipDeleteCustomLineCap(pen->customend); |
| pen->customend = NULL; |
| pen->endcap = cap; |
| |
| return Ok; |
| } |
| |
| /* FIXME: startcap, dashcap not used. */ |
| GpStatus WINGDIPAPI GdipSetPenLineCap197819(GpPen *pen, GpLineCap start, |
| GpLineCap end, GpDashCap dash) |
| { |
| TRACE("%p, %d, %d, %d)\n", pen, start, end, dash); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| GdipDeleteCustomLineCap(pen->customend); |
| GdipDeleteCustomLineCap(pen->customstart); |
| pen->customend = NULL; |
| pen->customstart = NULL; |
| |
| pen->startcap = start; |
| pen->endcap = end; |
| pen->dashcap = dash; |
| |
| return Ok; |
| } |
| |
| /* FIXME: Miter line joins behave a bit differently than they do in windows. |
| * Both kinds of miter joins clip if the angle is less than 11 degrees. */ |
| GpStatus WINGDIPAPI GdipSetPenLineJoin(GpPen *pen, GpLineJoin join) |
| { |
| TRACE("(%p, %d)\n", pen, join); |
| |
| if(!pen) return InvalidParameter; |
| |
| pen->join = join; |
| pen->style &= ~(PS_JOIN_ROUND | PS_JOIN_BEVEL | PS_JOIN_MITER); |
| pen->style |= gdip_to_gdi_join(join); |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenMiterLimit(GpPen *pen, REAL limit) |
| { |
| TRACE("(%p, %.2f)\n", pen, limit); |
| |
| if(!pen) |
| return InvalidParameter; |
| |
| pen->miterlimit = limit; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenStartCap(GpPen *pen, GpLineCap cap) |
| { |
| TRACE("(%p, %d)\n", pen, cap); |
| |
| if(!pen) return InvalidParameter; |
| |
| GdipDeleteCustomLineCap(pen->customstart); |
| pen->customstart = NULL; |
| pen->startcap = cap; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenWidth(GpPen *pen, REAL width) |
| { |
| TRACE("(%p, %.2f)\n", pen, width); |
| |
| if(!pen) return InvalidParameter; |
| |
| pen->width = width; |
| |
| return Ok; |
| } |
| |
| GpStatus WINGDIPAPI GdipSetPenMode(GpPen *pen, GpPenAlignment mode) |
| { |
| TRACE("(%p, %d)\n", pen, mode); |
| |
| if(!pen) return InvalidParameter; |
| |
| pen->align = mode; |
| |
| return Ok; |
| } |