gdiplus: Partially implement arrow caps.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Vincent Povirk <vincent@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
8463159344
commit
1da650a1cb
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -343,6 +343,9 @@ struct GpCustomLineCap{
|
|||
|
||||
struct GpAdjustableArrowCap{
|
||||
GpCustomLineCap cap;
|
||||
REAL middle_inset;
|
||||
REAL height;
|
||||
REAL width;
|
||||
};
|
||||
|
||||
struct GpImage{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue