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:
parent
dcccaaf7f3
commit
00fea0298b
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue