Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdiplus/brush.c | 2 +- dlls/gdiplus/font.c | 4 ++-- dlls/gdiplus/gdiplus_private.h | 2 ++ dlls/gdiplus/image.c | 6 +++--- dlls/gdiplus/metafile.c | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/gdiplus/brush.c b/dlls/gdiplus/brush.c index 0114a510ca..3aeb654086 100644 --- a/dlls/gdiplus/brush.c +++ b/dlls/gdiplus/brush.c @@ -232,7 +232,7 @@ static const char HatchBrushes[][8] = {
GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result) { - if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0])) + if (hatchstyle < ARRAY_SIZE(HatchBrushes)) { *result = HatchBrushes[hatchstyle]; return Ok; diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index f99b026b25..64778bb226 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -1367,7 +1367,7 @@ static int match_name_table_language( const tt_name_record *name, LANGID lang ) case TT_PLATFORM_MACINTOSH: if (!IsValidCodePage( get_mac_code_page( name ))) return 0; name_lang = GET_BE_WORD(name->language_id); - if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; + if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0; name_lang = mac_langid_table[name_lang]; break; case TT_PLATFORM_APPLE_UNICODE: @@ -1377,7 +1377,7 @@ static int match_name_table_language( const tt_name_record *name, LANGID lang ) case TT_APPLE_ID_ISO_10646: case TT_APPLE_ID_UNICODE_2_0: name_lang = GET_BE_WORD(name->language_id); - if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; + if (name_lang >= ARRAY_SIZE(mac_langid_table)) return 0; name_lang = mac_langid_table[name_lang]; break; default: diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index ea79f1183c..9fff578a28 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -35,6 +35,8 @@
#include "gdiplus.h"
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + #define GP_DEFAULT_PENSTYLE (PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER) #define MAX_ARC_PTS (13) #define MAX_DASHLEN (16) /* this is a limitation of gdi */ diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index b03630c55c..9841857e63 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -2554,7 +2554,7 @@ static UINT vt_to_itemtype(UINT vt) { VT_BLOB, PropertyTagTypeUndefined } }; UINT i; - for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++) + for (i = 0; i < ARRAY_SIZE(vt2type); i++) { if (vt2type[i].vt == vt) return vt2type[i].type; } @@ -3454,10 +3454,10 @@ static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI { if (name.vt == VT_LPSTR) { - for (j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++) + for (j = 0; j < ARRAY_SIZE(keywords); j++) if (!strcmp(keywords[j].name, name.u.pszVal)) break; - if (j < sizeof(keywords)/sizeof(keywords[0]) && !keywords[j].seen) + if (j < ARRAY_SIZE(keywords) && !keywords[j].seen) { keywords[j].seen = TRUE; item = create_prop(keywords[j].propid, &value); diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 77673a7ea3..08dde2fec6 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -606,7 +606,7 @@ void METAFILE_Free(GpMetafile *metafile) if (metafile->record_stream) IStream_Release(metafile->record_stream);
- for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]); i++) + for (i = 0; i < ARRAY_SIZE(metafile->objtable); i++) metafile_free_object_table_entry(metafile, i); }
Signed-off-by: Nikolay Sivov nsivov@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);
+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;
+}
I'm confused by this function. Why are you testing the difference of 2 floats interpreted as integers?
On 5/14/2018 7:02 PM, Vincent Povirk wrote:
+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;
+}
I'm confused by this function. Why are you testing the difference of 2 floats interpreted as integers?
That's a way to compare them, without introducing arbitrary difference constant, that is meaningless out of context of numbers being compared.
The goal of the test is to test that numbers are close enough, in terms of a number of representable floating point values between comparands.
The function was taken as is from existing d3d tests.
OK, assuming the same exponent, I guess that works. You'd have to be careful to avoid test data that's close to a power of 2.
I'm not sure about the assumption that float and int are the same size.
I'm also not clear on why you subtract "negative" values from INT_MIN. What case is that accounting for, and what does it mean?
Well, floating-point math is a pain.
On 14 May 2018 at 18:44, Vincent Povirk vincent@codeweavers.com wrote:
OK, assuming the same exponent, I guess that works. You'd have to be careful to avoid test data that's close to a power of 2.
No, that works. Adjacent (regular) IEEE floats have adjacent integer representations. The cases where it breaks down are things like denormals, NaNs and infinities.
I'm not sure about the assumption that float and int are the same size.
They are everywhere we care about. I suppose you could introduce a C_ASSERT to make sure, but I suspect a whole bunch of other stuff would also break in case either integers or floats aren't 32-bits.
I'm also not clear on why you subtract "negative" values from INT_MIN. What case is that accounting for, and what does it mean?
It's accounting for the case where you're comparing floating point numbers of opposite signs.
Signed-off-by: Vincent Povirk vincent@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdiplus/customlinecap.c | 75 ++++++++++++++++++------------ dlls/gdiplus/tests/customlinecap.c | 5 +- 2 files changed, 46 insertions(+), 34 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index 7fbe8b6b89..c74928eeda 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -282,19 +282,43 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapType(GpCustomLineCap *customCap, CustomL
static void arrowcap_update_path(GpAdjustableArrowCap *cap) { + static const BYTE types_filled[] = + { + PathPointTypeStart, PathPointTypeLine, PathPointTypeLine, PathPointTypeLine | PathPointTypeCloseSubpath + }; + static const BYTE types_unfilled[] = + { + PathPointTypeStart, PathPointTypeLine, PathPointTypeLine + }; GpPointF *points;
- assert(cap->cap.pathdata.Count == 4); + assert(cap->cap.pathdata.Count == 3 || 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->cap.fill) + { + memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled)); + cap->cap.pathdata.Count = 4; + points[0].X = -cap->width / 2.0; + points[0].Y = -cap->height; + points[1].X = 0.0; + points[1].Y = 0.0; + points[2].X = cap->width / 2.0; + points[2].Y = -cap->height; + points[3].X = 0.0; + points[3].Y = -cap->height - cap->middle_inset; + } + else + { + memcpy(cap->cap.pathdata.Types, types_unfilled, sizeof(types_unfilled)); + cap->cap.pathdata.Count = 3; + points[0].X = -cap->width / 4.0; + points[0].Y = -cap->height / 2.0; + points[1].X = 0.0; + points[1].Y = 0.0; + points[2].X = cap->width / 4.0; + points[2].Y = -cap->height / 2.0; + }
if (cap->width == 0.0) cap->cap.inset = 0.0; @@ -306,7 +330,6 @@ GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL f GpAdjustableArrowCap **cap) { GpPathData pathdata; - BYTE types[4]; GpStatus stat;
TRACE("(%0.2f,%0.2f,%i,%p)\n", height, width, fill, cap); @@ -314,22 +337,15 @@ GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL f if (!cap) return InvalidParameter;
- 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; - + /* We'll need 4 points at most. */ 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); + pathdata.Types = NULL; + stat = init_custom_linecap(&(*cap)->cap, &pathdata, fill, LineCapTriangle, width != 0.0 ? height / width : 0.0); if (stat != Ok) { heap_free(*cap); @@ -347,14 +363,13 @@ GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL f
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill) { - static int calls; - TRACE("(%p,%p)\n", cap, fill);
- if(!(calls++)) - FIXME("not implemented\n"); + if (!cap || !fill) + return InvalidParameter;
- return NotImplemented; + *fill = cap->cap.fill; + return Ok; }
GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height) @@ -392,14 +407,14 @@ GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, RE
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill) { - static int calls; - TRACE("(%p,%i)\n", cap, fill);
- if(!(calls++)) - FIXME("not implemented\n"); + if (!cap) + return InvalidParameter;
- return NotImplemented; + cap->cap.fill = fill; + arrowcap_update_path(cap); + return Ok; }
GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height) diff --git a/dlls/gdiplus/tests/customlinecap.c b/dlls/gdiplus/tests/customlinecap.c index 6a22c2668a..e4ec329b93 100644 --- a/dlls/gdiplus/tests/customlinecap.c +++ b/dlls/gdiplus/tests/customlinecap.c @@ -250,16 +250,13 @@ static void test_create_adjustable_cap(void) ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
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);
- 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->cap.fill)
- {
memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled));
cap->cap.pathdata.Count = 4;
points[0].X = -cap->width / 2.0;
points[0].Y = -cap->height;
points[1].X = 0.0;
points[1].Y = 0.0;
points[2].X = cap->width / 2.0;
points[2].Y = -cap->height;
points[3].X = 0.0;
points[3].Y = -cap->height - cap->middle_inset;
Why does this reorder the points in the filled case?
On 5/14/2018 7:17 PM, Vincent Povirk wrote:
- 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->cap.fill)
- {
memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled));
cap->cap.pathdata.Count = 4;
points[0].X = -cap->width / 2.0;
points[0].Y = -cap->height;
points[1].X = 0.0;
points[1].Y = 0.0;
points[2].X = cap->width / 2.0;
points[2].Y = -cap->height;
points[3].X = 0.0;
points[3].Y = -cap->height - cap->middle_inset;
Why does this reorder the points in the filled case?
No particular reason, only to bring two cases closer. If you mean I should have used this order in a first place, sure, I can do that in 2/4.
Signed-off-by: Vincent Povirk vincent@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/gdiplus/graphics.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 5fdbaf1e8a..76aabe74bf 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -1692,6 +1692,13 @@ static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL s if(!custom) break;
+ if (custom->type == CustomLineCapTypeAdjustableArrow) + { + GpAdjustableArrowCap *arrow = (GpAdjustableArrowCap *)custom; + if (arrow->cap.fill && arrow->height <= 0.0) + break; + } + count = custom->pathdata.Count; custptf = heap_alloc_zero(count * sizeof(PointF)); custpt = heap_alloc_zero(count * sizeof(POINT));
Signed-off-by: Vincent Povirk vincent@codeweavers.com