From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/d2d1_private.h | 10 +++ dlls/d2d1/geometry.c | 185 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 183 insertions(+), 12 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 9ec099fcff3..6faf58f9d27 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -511,11 +511,21 @@ struct d2d_curve_outline_vertex D2D1_POINT_2F prev, next; }; +struct d2d_geometry; + +struct d2d_geometry_ops +{ + void (*stream)(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink); +}; + struct d2d_geometry { ID2D1Geometry ID2D1Geometry_iface; LONG refcount; + const struct d2d_geometry_ops *ops; + ID2D1Factory *factory; D2D_MATRIX_3X2_F transform; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index b2de24ae5dc..9566113183c 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3037,12 +3037,14 @@ static void d2d_geometry_cleanup(struct d2d_geometry *geometry) } static void d2d_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, - const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl) + const D2D1_MATRIX_3X2_F *transform, const struct ID2D1GeometryVtbl *vtbl, + const struct d2d_geometry_ops *ops) { geometry->ID2D1Geometry_iface.lpVtbl = vtbl; geometry->refcount = 1; ID2D1Factory_AddRef(geometry->factory = factory); geometry->transform = *transform; + geometry->ops = ops; } static inline struct d2d_geometry *impl_from_ID2D1GeometrySink(ID2D1GeometrySink *iface) @@ -4253,15 +4255,101 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *ifac return S_OK; } -static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink) +static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { - struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface); unsigned int flags = 0; + D2D1_POINT_2F point; - TRACE("iface %p, sink %p.\n", iface, sink); + for (size_t i = 0; i < geometry->u.path.figure_count; ++i) + { + const struct d2d_figure *figure = &geometry->u.path.figures[i]; + union + { + const struct d2d_segment *segment; + const struct d2d_segment_beziers *beziers; + const struct d2d_segment_quadratic_beziers *quad_beziers; + const struct d2d_segment_lines *lines; + const struct d2d_segment_arcs *arcs; + } s = { (struct d2d_segment *)figure->segments.data }; + size_t size = 0; - if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED) - return D2DERR_WRONG_STATE; + d2d_point_transform(&point, transform, figure->vertices[0].x, figure->vertices[0].y); + ID2D1GeometrySink_BeginFigure(sink, point, figure->flags & D2D_FIGURE_FLAG_HOLLOW ? + D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED); + + for (size_t j = 0; j < figure->segments.count; ++j) + { + if (flags != s.segment->flags) + { + ID2D1GeometrySink_SetSegmentFlags(sink, s.segment->flags); + flags = s.segment->flags; + } + + switch (s.segment->type) + { + case D2D_SEGMENT_TYPE_BEZIERS: + for (unsigned int k = 0; k < s.beziers->count; ++k) + { + D2D1_BEZIER_SEGMENT bezier_segment; + d2d_point_transform(&bezier_segment.point1, transform, s.beziers->segments[k].point1.x, s.beziers->segments[k].point1.y); + d2d_point_transform(&bezier_segment.point2, transform, s.beziers->segments[k].point2.x, s.beziers->segments[k].point2.y); + d2d_point_transform(&bezier_segment.point3, transform, s.beziers->segments[k].point3.x, s.beziers->segments[k].point3.y); + ID2D1GeometrySink_AddBeziers(sink, &bezier_segment, 1); + } + size = FIELD_OFFSET(struct d2d_segment_beziers, segments[s.beziers->count]); + break; + case D2D_SEGMENT_TYPE_QUADRATIC_BEZIERS: + for (unsigned int k = 0; k < s.quad_beziers->count; ++k) + { + D2D1_QUADRATIC_BEZIER_SEGMENT bezier_segment; + d2d_point_transform(&bezier_segment.point1, transform, s.quad_beziers->segments[k].point1.x, s.quad_beziers->segments[k].point1.y); + d2d_point_transform(&bezier_segment.point2, transform, s.quad_beziers->segments[k].point2.x, s.quad_beziers->segments[k].point2.y); + ID2D1GeometrySink_AddQuadraticBeziers(sink, &bezier_segment, 1); + } + size = FIELD_OFFSET(struct d2d_segment_quadratic_beziers, segments[s.quad_beziers->count]); + break; + case D2D_SEGMENT_TYPE_LINES: + for (unsigned int k = 0; k < s.lines->count; ++k) + { + d2d_point_transform(&point, transform, s.lines->points[k].x, s.lines->points[k].y); + ID2D1GeometrySink_AddLines(sink, &point, 1); + } + size = FIELD_OFFSET(struct d2d_segment_lines, points[s.lines->count]); + break; + case D2D_SEGMENT_TYPE_ARCS: + for (unsigned int k = 0; k < s.arcs->count; ++k) + { + D2D1_ARC_SEGMENT arc = s.arcs->segments[k]; + + d2d_point_transform(&arc.point, transform, arc.point.x, arc.point.y); + d2d_point_transform(&point, transform, arc.size.width, 0.0f); + arc.size.width = d2d_point_length(&point); + d2d_point_transform(&point, transform, 0.0f, arc.size.height); + arc.size.height = d2d_point_length(&point); + ID2D1GeometrySink_AddArc(sink, &arc); + } + size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); + break; + default: + ; + } + + s.segment = (struct d2d_segment *)((uint8_t *)s.segment + size); + } + + ID2D1GeometrySink_EndFigure(sink, figure->flags & D2D_FIGURE_FLAG_CLOSED ? + D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + } +} + +static void d2d_path_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + unsigned int flags = 0; + + if (transform) + return d2d_path_geometry_transformed_stream(geometry, transform, sink); for (size_t i = 0; i < geometry->u.path.figure_count; ++i) { @@ -4316,6 +4404,18 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *if ID2D1GeometrySink_EndFigure(sink, figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); } +} + +static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Stream(ID2D1PathGeometry1 *iface, ID2D1GeometrySink *sink) +{ + struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface); + + TRACE("iface %p, sink %p.\n", iface, sink); + + if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED) + return D2DERR_WRONG_STATE; + + d2d_path_geometry_stream(geometry, NULL, sink); return S_OK; } @@ -4384,9 +4484,15 @@ static const struct ID2D1PathGeometry1Vtbl d2d_path_geometry_vtbl = d2d_path_geometry1_ComputePointAndSegmentAtLength, }; +static const struct d2d_geometry_ops d2d_path_geometry_ops = +{ + .stream = d2d_path_geometry_stream, +}; + void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory) { - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl, + &d2d_path_geometry_ops); geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl; geometry->u.path.bounds.left = FLT_MAX; geometry->u.path.bounds.right = -FLT_MAX; @@ -4672,13 +4778,24 @@ static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl = d2d_ellipse_geometry_GetEllipse, }; +static void d2d_ellipse_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_ellipse_geometry_ops = +{ + .stream = d2d_ellipse_geometry_stream, +}; + HRESULT d2d_ellipse_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ELLIPSE *ellipse) { D2D1_POINT_2F *v, v1, v2, v3, v4; struct d2d_face *f; float l, r, t, b; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_ellipse_geometry_vtbl, + &d2d_ellipse_geometry_ops); geometry->u.ellipse.ellipse = *ellipse; if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices)))) @@ -5101,6 +5218,16 @@ static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl = d2d_rectangle_geometry_GetRect, }; +static void d2d_rectangle_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_rectangle_geometry_ops = +{ + .stream = d2d_rectangle_geometry_stream, +}; + HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_RECT_F *rect) { struct d2d_face *f; @@ -5122,7 +5249,8 @@ HRESULT d2d_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory {-1.0f, 0.0f}, }; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rectangle_geometry_vtbl, + &d2d_rectangle_geometry_ops); geometry->u.rectangle.rect = *rect; if (!(geometry->fill.vertices = malloc(4 * sizeof(*geometry->fill.vertices)))) @@ -5449,6 +5577,16 @@ static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geom d2d_rounded_rectangle_geometry_GetRoundedRect, }; +static void d2d_rounded_rectangle_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_rounded_rectangle_geometry_ops = +{ + .stream = d2d_rounded_rectangle_geometry_stream, +}; + HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, const D2D1_ROUNDED_RECT *rounded_rect) { @@ -5457,7 +5595,8 @@ HRESULT d2d_rounded_rectangle_geometry_init(struct d2d_geometry *geometry, float l, r, t, b; float rx, ry; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_rounded_rectangle_geometry_vtbl, + &d2d_rounded_rectangle_geometry_ops); geometry->u.rounded_rectangle.rounded_rect = *rounded_rect; if (!(geometry->fill.vertices = malloc(8 * sizeof(*geometry->fill.vertices)))) @@ -5813,6 +5952,16 @@ static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl = d2d_transformed_geometry_GetTransform, }; +static void d2d_transformed_geometry_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_transformed_geometry_ops = +{ + .stream = d2d_transformed_geometry_stream, +}; + void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory, ID2D1Geometry *src_geometry, const D2D_MATRIX_3X2_F *transform) { @@ -5823,7 +5972,8 @@ void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory * g = src_impl->transform; d2d_matrix_multiply(&g, transform); - d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl); + d2d_geometry_init(geometry, factory, &g, (ID2D1GeometryVtbl *)&d2d_transformed_geometry_vtbl, + &d2d_transformed_geometry_ops); ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry); geometry->u.transformed.transform = *transform; geometry->fill = src_impl->fill; @@ -6084,12 +6234,23 @@ static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl = d2d_geometry_group_GetSourceGeometries, }; +static void d2d_geometry_group_stream(struct d2d_geometry *geometry, + const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) +{ +} + +static const struct d2d_geometry_ops d2d_geometry_group_ops = +{ + .stream = d2d_geometry_group_stream, +}; + HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count) { unsigned int i; - d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl); + d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl, + &d2d_geometry_group_ops); if (!(geometry->u.group.src_geometries = calloc(geometry_count, sizeof(*geometries)))) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043