[PATCH 2/4] gdiplus: Partially implement arrow caps
Nikolay Sivov
nsivov at codeweavers.com
Sun May 13 23:59:35 CDT 2018
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/gdiplus/customlinecap.c | 196 ++++++++++++++++++++---------
dlls/gdiplus/gdiplus_private.h | 3 +
dlls/gdiplus/tests/customlinecap.c | 79 ++++++++++--
3 files changed, 208 insertions(+), 70 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c
index ca81bee217..7fbe8b6b89 100644
--- a/dlls/gdiplus/customlinecap.c
+++ b/dlls/gdiplus/customlinecap.c
@@ -17,6 +17,7 @@
*/
#include <stdarg.h>
+#include <assert.h>
#include "windef.h"
#include "winbase.h"
@@ -38,11 +39,20 @@ GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
if(!from || !to)
return InvalidParameter;
- *to = heap_alloc_zero(sizeof(GpCustomLineCap));
- if(!*to) return OutOfMemory;
+ if (from->type == CustomLineCapTypeDefault)
+ *to = heap_alloc_zero(sizeof(GpCustomLineCap));
+ else
+ *to = heap_alloc_zero(sizeof(GpAdjustableArrowCap));
- memcpy(*to, from, sizeof(GpCustomLineCap));
+ if (!*to)
+ return OutOfMemory;
+
+ if (from->type == CustomLineCapTypeDefault)
+ **to = *from;
+ else
+ *(GpAdjustableArrowCap *)*to = *(GpAdjustableArrowCap *)from;
+ /* Duplicate path data */
(*to)->pathdata.Points = heap_alloc_zero(from->pathdata.Count * sizeof(PointF));
(*to)->pathdata.Types = heap_alloc_zero(from->pathdata.Count);
@@ -62,12 +72,44 @@ GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
return Ok;
}
+static GpStatus init_custom_linecap(GpCustomLineCap *cap, GpPathData *pathdata, BOOL fill, GpLineCap basecap,
+ REAL base_inset)
+{
+ cap->fill = fill;
+
+ cap->pathdata.Points = heap_alloc_zero(pathdata->Count * sizeof(PointF));
+ cap->pathdata.Types = heap_alloc_zero(pathdata->Count);
+
+ if ((!cap->pathdata.Types || !cap->pathdata.Points) && pathdata->Count)
+ {
+ heap_free(cap->pathdata.Points);
+ heap_free(cap->pathdata.Types);
+ cap->pathdata.Points = NULL;
+ cap->pathdata.Types = NULL;
+ return OutOfMemory;
+ }
+
+ if (pathdata->Points)
+ memcpy(cap->pathdata.Points, pathdata->Points, pathdata->Count * sizeof(PointF));
+ if (pathdata->Types)
+ memcpy(cap->pathdata.Types, pathdata->Types, pathdata->Count);
+ cap->pathdata.Count = pathdata->Count;
+
+ cap->inset = base_inset;
+ cap->cap = basecap;
+ cap->join = LineJoinMiter;
+ cap->scale = 1.0;
+
+ return Ok;
+}
+
/* FIXME: Sometimes when fillPath is non-null and stroke path is null, the native
* version of this function returns NotImplemented. I cannot figure out why. */
GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath,
GpLineCap baseCap, REAL baseInset, GpCustomLineCap **customCap)
{
GpPathData *pathdata;
+ GpStatus stat;
TRACE("%p %p %d %f %p\n", fillPath, strokePath, baseCap, baseInset, customCap);
@@ -77,37 +119,18 @@ GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath
*customCap = heap_alloc_zero(sizeof(GpCustomLineCap));
if(!*customCap) return OutOfMemory;
- (*customCap)->type = CustomLineCapTypeDefault;
- if(strokePath){
- (*customCap)->fill = FALSE;
+ if (strokePath)
pathdata = &strokePath->pathdata;
- }
- else{
- (*customCap)->fill = TRUE;
+ else
pathdata = &fillPath->pathdata;
- }
- (*customCap)->pathdata.Points = heap_alloc_zero(pathdata->Count * sizeof(PointF));
- (*customCap)->pathdata.Types = heap_alloc_zero(pathdata->Count);
-
- if((!(*customCap)->pathdata.Types || !(*customCap)->pathdata.Points) &&
- pathdata->Count){
- heap_free((*customCap)->pathdata.Points);
- heap_free((*customCap)->pathdata.Types);
+ stat = init_custom_linecap(*customCap, pathdata, fillPath != NULL, baseCap, baseInset);
+ if (stat != Ok)
+ {
heap_free(*customCap);
- return OutOfMemory;
+ return stat;
}
- memcpy((*customCap)->pathdata.Points, pathdata->Points, pathdata->Count
- * sizeof(PointF));
- memcpy((*customCap)->pathdata.Types, pathdata->Types, pathdata->Count);
- (*customCap)->pathdata.Count = pathdata->Count;
-
- (*customCap)->inset = baseInset;
- (*customCap)->cap = baseCap;
- (*customCap)->join = LineJoinMiter;
- (*customCap)->scale = 1.0;
-
TRACE("<-- %p\n", *customCap);
return Ok;
@@ -257,17 +280,69 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapType(GpCustomLineCap *customCap, CustomL
return Ok;
}
+static void arrowcap_update_path(GpAdjustableArrowCap *cap)
+{
+ GpPointF *points;
+
+ assert(cap->cap.pathdata.Count == 4);
+
+ points = cap->cap.pathdata.Points;
+ points[0].X = 0.0;
+ points[0].Y = 0.0;
+ points[1].X = -cap->width / 2.0;
+ points[1].Y = -cap->height;
+ points[2].X = 0.0;
+ points[2].Y = -cap->height - cap->middle_inset;
+ points[3].X = cap->width / 2.0;
+ points[3].Y = -cap->height;
+
+ if (cap->width == 0.0)
+ cap->cap.inset = 0.0;
+ else
+ cap->cap.inset = cap->height / cap->width;
+}
+
GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL fill,
GpAdjustableArrowCap **cap)
{
- static int calls;
+ GpPathData pathdata;
+ BYTE types[4];
+ GpStatus stat;
TRACE("(%0.2f,%0.2f,%i,%p)\n", height, width, fill, cap);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap)
+ return InvalidParameter;
- return NotImplemented;
+ if (!fill)
+ FIXME("Arrows without fills are not supported.\n");
+
+ *cap = heap_alloc_zero(sizeof(**cap));
+ if (!*cap)
+ return OutOfMemory;
+
+ types[0] = PathPointTypeStart;
+ types[1] = PathPointTypeLine;
+ types[2] = PathPointTypeLine;
+ types[3] = PathPointTypeLine | PathPointTypeCloseSubpath;
+
+ pathdata.Count = 4;
+ pathdata.Points = NULL;
+ pathdata.Types = types;
+ stat = init_custom_linecap(&(*cap)->cap, &pathdata, TRUE, LineCapTriangle, width != 0.0 ? height / width : 0.0);
+ if (stat != Ok)
+ {
+ heap_free(*cap);
+ return stat;
+ }
+
+ (*cap)->cap.type = CustomLineCapTypeAdjustableArrow;
+ (*cap)->height = height;
+ (*cap)->width = width;
+ (*cap)->middle_inset = 0.0;
+ arrowcap_update_path(*cap);
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill)
@@ -284,38 +359,35 @@ GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height)
{
- static int calls;
-
TRACE("(%p,%p)\n", cap, height);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap || !height)
+ return InvalidParameter;
- return NotImplemented;
+ *height = cap->height;
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL* middle)
{
- static int calls;
-
TRACE("(%p,%p)\n", cap, middle);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap || !middle)
+ return InvalidParameter;
- return NotImplemented;
+ *middle = cap->middle_inset;
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL* width)
{
- static int calls;
-
TRACE("(%p,%p)\n", cap, width);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap || !width)
+ return InvalidParameter;
- return NotImplemented;
+ *width = cap->width;
+ return Ok;
}
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill)
@@ -332,36 +404,36 @@ GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height)
{
- static int calls;
-
TRACE("(%p,%0.2f)\n", cap, height);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap)
+ return InvalidParameter;
- return NotImplemented;
+ cap->height = height;
+ arrowcap_update_path(cap);
+ return Ok;
}
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL middle)
{
- static int calls;
-
TRACE("(%p,%0.2f)\n", cap, middle);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap)
+ return InvalidParameter;
- return NotImplemented;
+ cap->middle_inset = middle;
+ arrowcap_update_path(cap);
+ return Ok;
}
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL width)
{
- static int calls;
-
TRACE("(%p,%0.2f)\n", cap, width);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!cap)
+ return InvalidParameter;
- return NotImplemented;
+ cap->width = width;
+ arrowcap_update_path(cap);
+ return Ok;
}
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 9fff578a28..25b269ba35 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -343,6 +343,9 @@ struct GpCustomLineCap{
struct GpAdjustableArrowCap{
GpCustomLineCap cap;
+ REAL middle_inset;
+ REAL height;
+ REAL width;
};
struct GpImage{
diff --git a/dlls/gdiplus/tests/customlinecap.c b/dlls/gdiplus/tests/customlinecap.c
index bac80adbdb..6a22c2668a 100644
--- a/dlls/gdiplus/tests/customlinecap.c
+++ b/dlls/gdiplus/tests/customlinecap.c
@@ -17,6 +17,7 @@
* 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 <limits.h>
#include "objbase.h"
#include "gdiplus.h"
@@ -25,6 +26,22 @@
#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
#define expectf(expected, got) ok(got == expected, "Expected %.2f, got %.2f\n", expected, got)
+static BOOL compare_float(float f, float g, unsigned int ulps)
+{
+ int x = *(int *)&f;
+ int y = *(int *)&g;
+
+ if (x < 0)
+ x = INT_MIN - x;
+ if (y < 0)
+ y = INT_MIN - y;
+
+ if (abs(x - y) > ulps)
+ return FALSE;
+
+ return TRUE;
+}
+
static void test_constructor_destructor(void)
{
GpCustomLineCap *custom;
@@ -219,21 +236,43 @@ static void test_scale(void)
static void test_create_adjustable_cap(void)
{
+ REAL inset, scale, height, width;
GpAdjustableArrowCap *cap;
- REAL inset, scale;
GpLineJoin join;
GpStatus stat;
GpLineCap base;
+ BOOL ret;
stat = GdipCreateAdjustableArrowCap(10.0, 10.0, TRUE, NULL);
-todo_wine
ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &cap);
-todo_wine
ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
- if (stat != Ok)
- return;
+
+ stat = GdipGetAdjustableArrowCapFillState(cap, NULL);
+todo_wine
+ ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
+
+ ret = FALSE;
+ stat = GdipGetAdjustableArrowCapFillState(cap, &ret);
+todo_wine
+{
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(ret, "Unexpected fill state %d\n", ret);
+}
+ stat = GdipGetAdjustableArrowCapHeight(cap, NULL);
+ ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
+
+ stat = GdipGetAdjustableArrowCapHeight(cap, &height);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(height == 17.0, "Unexpected cap height %f\n", height);
+
+ stat = GdipGetAdjustableArrowCapWidth(cap, NULL);
+ ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
+
+ stat = GdipGetAdjustableArrowCapWidth(cap, &width);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(width == 15.0, "Unexpected cap width %f\n", width);
stat = GdipGetAdjustableArrowCapMiddleInset(cap, NULL);
ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
@@ -247,14 +286,41 @@ todo_wine
ok(base == LineCapTriangle, "Unexpected base cap %d\n", base);
stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquare);
+todo_wine
ok(stat == Ok, "Unexpected return code, %d\n", stat);
stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base);
ok(stat == Ok, "Unexpected return code, %d\n", stat);
+todo_wine
ok(base == LineCapSquare, "Unexpected base cap %d\n", base);
+ /* Base inset */
+ stat = GdipGetAdjustableArrowCapWidth(cap, &width);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+
+ stat = GdipGetAdjustableArrowCapHeight(cap, &height);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+
+ inset = 0.0;
+ stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(compare_float(inset, height / width, 1), "Unexpected inset %f\n", inset);
+
+ stat = GdipSetAdjustableArrowCapMiddleInset(cap, 1.0);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+
+ inset = 0.0;
+ stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(compare_float(inset, height / width, 1), "Unexpected inset %f\n", inset);
+
+ stat = GdipSetAdjustableArrowCapHeight(cap, 2.0 * height);
+ ok(stat == Ok, "Unexpected return code, %d\n", stat);
+
+ inset = 0.0;
stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
ok(stat == Ok, "Unexpected return code, %d\n", stat);
+ ok(compare_float(inset, 2.0 * height / width, 1), "Unexpected inset %f\n", inset);
stat = GdipGetCustomLineCapWidthScale((GpCustomLineCap*)cap, &scale);
ok(stat == Ok, "Unexpected return code, %d\n", stat);
@@ -299,10 +365,7 @@ static void test_captype(void)
/* arrow cap */
stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &arrowcap);
-todo_wine
ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
- if (stat != Ok)
- return;
stat = GdipGetCustomLineCapType((GpCustomLineCap*)arrowcap, &type);
ok(stat == Ok, "Failed to get cap type, %d\n", stat);
--
2.17.0
More information about the wine-devel
mailing list