d2d1: Implement GetBounds() for path geometries.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-09-14 15:10:57 +03:00 committed by Alexandre Julliard
parent dcccaaf7f3
commit 00fea0298b
3 changed files with 221 additions and 2 deletions

View File

@ -392,6 +392,8 @@ struct d2d_geometry
enum d2d_geometry_state state;
D2D1_FILL_MODE fill_mode;
UINT32 segment_count;
D2D1_RECT_F bounds;
} path;
struct
{

View File

@ -3079,9 +3079,106 @@ static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *if
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
{
FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
size_t i;
return E_NOTIMPL;
TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
return D2DERR_WRONG_STATE;
bounds->left = FLT_MAX;
bounds->top = FLT_MAX;
bounds->right = -FLT_MAX;
bounds->bottom = -FLT_MAX;
if (!transform)
{
if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
{
for (i = 0; i < geometry->u.path.figure_count; ++i)
d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
}
*bounds = geometry->u.path.bounds;
return S_OK;
}
for (i = 0; i < geometry->u.path.figure_count; ++i)
{
const struct d2d_figure *figure = &geometry->u.path.figures[i];
enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
D2D1_RECT_F bezier_bounds;
D2D1_POINT_2F p, p1, p2;
size_t j, bezier_idx;
/* Single vertex figures are reduced by CloseFigure(). */
if (figure->vertex_count == 0)
{
d2d_point_transform(&p, transform, figure->bounds.left, figure->bounds.top);
d2d_rect_expand(bounds, &p);
continue;
}
for (j = 0; j < figure->vertex_count; ++j)
{
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
continue;
p = figure->vertices[j];
type = figure->vertex_types[j];
d2d_point_transform(&p, transform, p.x, p.y);
d2d_rect_expand(bounds, &p);
break;
}
for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
{
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
|| figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
continue;
switch (type)
{
case D2D_VERTEX_TYPE_LINE:
p = figure->vertices[j];
d2d_point_transform(&p, transform, p.x, p.y);
d2d_rect_expand(bounds, &p);
break;
case D2D_VERTEX_TYPE_BEZIER:
p1 = figure->original_bezier_controls[bezier_idx++];
d2d_point_transform(&p1, transform, p1.x, p1.y);
p2 = figure->vertices[j];
d2d_point_transform(&p2, transform, p2.x, p2.y);
d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
d2d_rect_union(bounds, &bezier_bounds);
p = p2;
break;
default:
FIXME("Unhandled vertex type %#x.\n", type);
p = figure->vertices[j];
d2d_point_transform(&p, transform, p.x, p.y);
d2d_rect_expand(bounds, &p);
break;
}
type = figure->vertex_types[j];
}
if (type == D2D_VERTEX_TYPE_BEZIER)
{
p1 = figure->original_bezier_controls[bezier_idx++];
d2d_point_transform(&p1, transform, p1.x, p1.y);
p2 = figure->vertices[0];
d2d_point_transform(&p2, transform, p2.x, p2.y);
d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
d2d_rect_union(bounds, &bezier_bounds);
}
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
@ -3428,6 +3525,10 @@ void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory
{
d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
geometry->u.path.bounds.left = FLT_MAX;
geometry->u.path.bounds.right = -FLT_MAX;
geometry->u.path.bounds.top = FLT_MAX;
geometry->u.path.bounds.bottom = -FLT_MAX;
}
static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)

View File

@ -1739,6 +1739,7 @@ static void test_path_geometry(void)
ID2D1Factory *factory;
BOOL match, contains;
D2D1_COLOR_F color;
D2D1_RECT_F rect;
ULONG refcount;
UINT32 count;
HWND window;
@ -2216,6 +2217,7 @@ static void test_path_geometry(void)
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
set_point(&point, 123.0f, 456.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
hr = ID2D1GeometrySink_Close(sink);
@ -2227,6 +2229,102 @@ static void test_path_geometry(void)
hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
ok(count == 1, "Got unexpected segment count %u.\n", count);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, 123.0f, 456.0f, 123.0f, 456.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 80.0f, 640.0f);
scale_matrix(&matrix, 2.0f, 0.5f);
hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, 326.0f, 868.0f, 326.0f, 868.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
ID2D1PathGeometry_Release(geometry);
/* Close right after Open(). */
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
/* Not open yet. */
set_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(hr == D2DERR_WRONG_STATE, "Unexpected hr %#x.\n", hr);
match = compare_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
/* Open, not closed. */
set_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(hr == D2DERR_WRONG_STATE, "Unexpected hr %#x.\n", hr);
match = compare_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
hr = ID2D1PathGeometry_GetFigureCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get figure count, hr %#x.\n", hr);
ok(count == 0, "Got unexpected figure count %u.\n", count);
hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
ok(count == 0, "Got unexpected segment count %u.\n", count);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
ok(rect.left > rect.right && rect.top > rect.bottom,
"Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", rect.left, rect.top, rect.right, rect.bottom);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 10.0f, 20.0f);
scale_matrix(&matrix, 10.0f, 20.0f);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
ok(rect.left > rect.right && rect.top > rect.bottom,
"Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", rect.left, rect.top, rect.right, rect.bottom);
ID2D1PathGeometry_Release(geometry);
/* GetBounds() with bezier segments. */
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
fill_geometry_sink_bezier(sink);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, 5.0f, 20.0f, 75.0f, 752.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 80.0f, 640.0f);
scale_matrix(&matrix, 2.0f, 0.5f);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, 90.0f, 650.0f, 230.0f, 1016.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
ID2D1PathGeometry_Release(geometry);
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
@ -2342,6 +2440,24 @@ static void test_path_geometry(void)
ok(count == 44, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, 5.0f, 20.0f, 235.0f, 300.0f, 0);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 100.0f, 50.0f);
scale_matrix(&matrix, 2.0f, 1.5f);
rotate_matrix(&matrix, M_PI / 4.0f);
set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
match = compare_rect(&rect, -3.17192993e+02f, 8.71231079e+01f, 4.04055908e+02f, 6.17453125e+02f, 1);
ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
rect.left, rect.top, rect.right, rect.bottom);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);