/* * 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 #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; } } GpStatus WINGDIPAPI GdipClonePen(GpPen *pen, GpPen **clonepen) { if(!pen || !clonepen) return InvalidParameter; *clonepen = GdipAlloc(sizeof(GpPen)); if(!*clonepen) return OutOfMemory; memcpy(*clonepen, pen, sizeof(GpPen)); GdipCloneCustomLineCap(pen->customstart, &(*clonepen)->customstart); GdipCloneCustomLineCap(pen->customend, &(*clonepen)->customend); GdipCloneBrush(pen->brush, &(*clonepen)->brush); return Ok; } GpStatus WINGDIPAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit, GpPen **pen) { GpBrush *brush; GdipCreateSolidFill(color, (GpSolidFill **)(&brush)); return GdipCreatePen2(brush, width, unit, pen); } GpStatus WINGDIPAPI GdipCreatePen2(GpBrush *brush, REAL width, GpUnit unit, GpPen **pen) { GpPen *gp_pen; if(!pen || !brush) return InvalidParameter; gp_pen = GdipAlloc(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->brush = brush; if(!((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel))) { FIXME("UnitWorld, UnitPixel only supported units\n"); GdipFree(gp_pen); return NotImplemented; } *pen = gp_pen; return Ok; } GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen) { if(!pen) return InvalidParameter; GdipDeleteBrush(pen->brush); GdipDeleteCustomLineCap(pen->customstart); GdipDeleteCustomLineCap(pen->customend); GdipFree(pen->dashes); GdipFree(pen); return Ok; } GpStatus WINGDIPAPI GdipGetPenBrushFill(GpPen *pen, GpBrush **brush) { if(!pen || !brush) return InvalidParameter; return GdipCloneBrush(pen->brush, brush); } GpStatus WINGDIPAPI GdipGetPenColor(GpPen *pen, ARGB *argb) { if(!pen || !argb) return InvalidParameter; if(pen->brush->bt != BrushTypeSolidColor) return NotImplemented; return GdipGetSolidFillColor(((GpSolidFill*)pen->brush), argb); } GpStatus WINGDIPAPI GdipGetPenDashArray(GpPen *pen, REAL *dash, INT 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 GdipGetPenDashOffset(GpPen *pen, REAL *offset) { if(!pen || !offset) return InvalidParameter; *offset = pen->offset; return Ok; } GpStatus WINGDIPAPI GdipGetPenDashStyle(GpPen *pen, GpDashStyle *dash) { if(!pen || !dash) return InvalidParameter; *dash = pen->dash; return Ok; } GpStatus WINGDIPAPI GdipSetPenBrushFill(GpPen *pen, GpBrush *brush) { if(!pen || !brush) return InvalidParameter; GdipDeleteBrush(pen->brush); return GdipCloneBrush(brush, &pen->brush); } GpStatus WINGDIPAPI GdipSetPenColor(GpPen *pen, ARGB argb) { if(!pen) return InvalidParameter; if(pen->brush->bt != BrushTypeSolidColor) return NotImplemented; return GdipSetSolidFillColor(((GpSolidFill*)pen->brush), argb); } GpStatus WINGDIPAPI GdipSetPenCustomEndCap(GpPen *pen, GpCustomLineCap* customCap) { GpCustomLineCap * cap; GpStatus ret; if(!pen || !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; if(!pen || !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; if(!pen || !dash) return InvalidParameter; for(i = 0; i < count; i++){ sum += dash[i]; if(dash[i] < 0.0) return InvalidParameter; } if(sum == 0.0 && count) return InvalidParameter; GdipFree(pen->dashes); pen->dashes = NULL; if(count > 0) pen->dashes = GdipAlloc(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; } /* FIXME: dash offset not used */ GpStatus WINGDIPAPI GdipSetPenDashOffset(GpPen *pen, REAL offset) { if(!pen) return InvalidParameter; pen->offset = offset; return Ok; } GpStatus WINGDIPAPI GdipSetPenDashStyle(GpPen *pen, GpDashStyle dash) { if(!pen) return InvalidParameter; if(dash != DashStyleCustom){ GdipFree(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) { 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) { 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) { 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) { if(!pen) return InvalidParameter; pen->miterlimit = limit; return Ok; } GpStatus WINGDIPAPI GdipSetPenStartCap(GpPen *pen, GpLineCap cap) { if(!pen) return InvalidParameter; GdipDeleteCustomLineCap(pen->customstart); pen->customstart = NULL; pen->startcap = cap; return Ok; } GpStatus WINGDIPAPI GdipSetPenWidth(GpPen *pen, REAL width) { if(!pen) return InvalidParameter; pen->width = width; return Ok; } GpStatus WINGDIPAPI GdipSetPenMode(GpPen *pen, GpPenAlignment penAlignment) { if(!pen) return InvalidParameter; FIXME("stub (%d)\n", penAlignment); return Ok; }