[PATCH 01/12] d2d1: Store cubic bezier control points.

Connor McAdams conmanx360 at gmail.com
Mon Feb 24 20:32:12 CST 2020


Store cubic bezier control points alongside quadratic control points.

Signed-off-by: Connor McAdams <conmanx360 at gmail.com>
---
 dlls/d2d1/geometry.c | 102 +++++++++++++++++++++++++++++--------------
 1 file changed, 70 insertions(+), 32 deletions(-)

diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index e7bb809359..a8e6a3f2b7 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -59,6 +59,12 @@ struct d2d_segment_idx
     size_t control_idx;
 };
 
+struct d2d_bezier_controls
+{
+    D2D1_POINT_2F c0, c1;
+    D2D1_POINT_2F cq0;
+};
+
 struct d2d_figure
 {
     D2D1_POINT_2F *vertices;
@@ -67,11 +73,11 @@ struct d2d_figure
     size_t vertex_types_size;
     size_t vertex_count;
 
-    D2D1_POINT_2F *bezier_controls;
+    struct d2d_bezier_controls *bezier_controls;
     size_t bezier_controls_size;
     size_t bezier_control_count;
 
-    D2D1_POINT_2F *original_bezier_controls;
+    struct d2d_bezier_controls *original_bezier_controls;
     size_t original_bezier_control_count;
 
     D2D1_RECT_F bounds;
@@ -409,6 +415,15 @@ static void d2d_point_normalise(D2D1_POINT_2F *p)
         d2d_point_scale(p, 1.0f / l);
 }
 
+static void d2d_bezier_quad_to_cubic(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1,
+        const D2D1_POINT_2F *p2, D2D1_POINT_2F *c0, D2D1_POINT_2F *c1)
+{
+    c0->x = p0->x * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->x;
+    c0->y = p0->y * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->y;
+    c1->x = p2->x * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->x;
+    c1->y = p2->y * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->y;
+}
+
 /* This implementation is based on the paper "Adaptive Precision
  * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and
  * associated (Public Domain) code by Jonathan Richard Shewchuk. */
@@ -613,7 +628,8 @@ static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F verte
     return TRUE;
 }
 
-static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *p)
+static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *c0,
+        const D2D1_POINT_2F *c1, const D2D1_POINT_2F *cq0)
 {
     if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
             figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
@@ -624,13 +640,16 @@ static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t i
 
     memmove(&figure->bezier_controls[idx + 1], &figure->bezier_controls[idx],
             (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls));
-    figure->bezier_controls[idx] = *p;
+    figure->bezier_controls[idx].cq0 = *cq0;
+    figure->bezier_controls[idx].c0 = *c0;
+    figure->bezier_controls[idx].c1 = *c1;
     ++figure->bezier_control_count;
 
     return TRUE;
 }
 
-static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p)
+static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *c0, const D2D1_POINT_2F *c1,
+        const D2D1_POINT_2F *cq0)
 {
     if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size,
             figure->bezier_control_count + 1, sizeof(*figure->bezier_controls)))
@@ -639,7 +658,9 @@ static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_
         return FALSE;
     }
 
-    figure->bezier_controls[figure->bezier_control_count++] = *p;
+    figure->bezier_controls[figure->bezier_control_count].cq0 = *cq0;
+    figure->bezier_controls[figure->bezier_control_count].c0 = *c0;
+    figure->bezier_controls[figure->bezier_control_count++].c1 = *c1;
 
     return TRUE;
 }
@@ -1727,7 +1748,7 @@ static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
 
     figure = &geometry->u.path.figures[idx_p->figure_idx];
     p[0] = &figure->vertices[idx_p->vertex_idx];
-    p[1] = &figure->bezier_controls[idx_p->control_idx];
+    p[1] = &figure->bezier_controls[idx_p->control_idx].cq0;
     next = idx_p->vertex_idx + 1;
     if (next == figure->vertex_count)
         next = 0;
@@ -1805,7 +1826,7 @@ static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
 
     figure = &geometry->u.path.figures[idx_p->figure_idx];
     p[0] = &figure->vertices[idx_p->vertex_idx];
-    p[1] = &figure->bezier_controls[idx_p->control_idx];
+    p[1] = &figure->bezier_controls[idx_p->control_idx].cq0;
     next = idx_p->vertex_idx + 1;
     if (next == figure->vertex_count)
         next = 0;
@@ -1813,7 +1834,7 @@ static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
 
     figure = &geometry->u.path.figures[idx_q->figure_idx];
     q[0] = &figure->vertices[idx_q->vertex_idx];
-    q[1] = &figure->bezier_controls[idx_q->control_idx];
+    q[1] = &figure->bezier_controls[idx_q->control_idx].cq0;
     next = idx_q->vertex_idx + 1;
     if (next == figure->vertex_count)
         next = 0;
@@ -1864,7 +1885,7 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
     enum d2d_vertex_type vertex_type;
     const D2D1_POINT_2F *p[3];
     struct d2d_figure *figure;
-    D2D1_POINT_2F q[2];
+    D2D1_POINT_2F q[2], c[2];
     float t, t_prev;
 
     for (i = 0; i < intersections->intersection_count; ++i)
@@ -1898,7 +1919,7 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
         }
 
         p[0] = &figure->vertices[inter->vertex_idx + vertex_offset];
-        p[1] = &figure->bezier_controls[inter->control_idx + control_offset];
+        p[1] = &figure->bezier_controls[inter->control_idx + control_offset].cq0;
         next = inter->vertex_idx + vertex_offset + 1;
         if (next == figure->vertex_count)
             next = 0;
@@ -1907,8 +1928,13 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry,
         d2d_point_lerp(&q[0], p[0], p[1], t);
         d2d_point_lerp(&q[1], p[1], p[2], t);
 
-        figure->bezier_controls[inter->control_idx + control_offset] = q[0];
-        if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &q[1])))
+        d2d_bezier_quad_to_cubic(p[0], &q[0], &inter->p, &c[0], &c[1]);
+        figure->bezier_controls[inter->control_idx + control_offset].cq0 = q[0];
+        figure->bezier_controls[inter->control_idx + control_offset].c0 = c[0];
+        figure->bezier_controls[inter->control_idx + control_offset].c1 = c[1];
+
+        d2d_bezier_quad_to_cubic(&inter->p, &q[1], p[2], &c[0], &c[1]);
+        if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &c[0], &c[1], &q[1])))
             return FALSE;
         ++control_offset;
 
@@ -2285,7 +2311,7 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
         {
             prev_type = figure->vertex_types[figure->vertex_count - 1];
             if (prev_type == D2D_VERTEX_TYPE_BEZIER)
-                prev = &figure->bezier_controls[figure->bezier_control_count - 1];
+                prev = &figure->bezier_controls[figure->bezier_control_count - 1].cq0;
             else
                 prev = &figure->vertices[figure->vertex_count - 1];
         }
@@ -2293,13 +2319,13 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
         {
             prev_type = figure->vertex_types[i - 1];
             if (prev_type == D2D_VERTEX_TYPE_BEZIER)
-                prev = &figure->bezier_controls[bezier_idx - 1];
+                prev = &figure->bezier_controls[bezier_idx - 1].cq0;
             else
                 prev = &figure->vertices[i - 1];
         }
 
         if (type == D2D_VERTEX_TYPE_BEZIER)
-            next = &figure->bezier_controls[bezier_idx++];
+            next = &figure->bezier_controls[bezier_idx++].cq0;
         else if (i == figure->vertex_count - 1)
             next = &figure->vertices[0];
         else
@@ -2541,7 +2567,7 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if
         d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
                 &p, &beziers[i].point3);
 
-        if (!d2d_figure_add_bezier_control(figure, &p))
+        if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1, &beziers[i].point2, &p))
         {
             ERR("Failed to add bezier control.\n");
             geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
@@ -2661,7 +2687,7 @@ static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
 
     figure = &geometry->u.path.figures[idx_p->figure_idx];
     a[0] = &figure->vertices[idx_p->vertex_idx];
-    a[1] = &figure->bezier_controls[idx_p->control_idx];
+    a[1] = &figure->bezier_controls[idx_p->control_idx].cq0;
     if (idx_p->vertex_idx == figure->vertex_count - 1)
         a[2] = &figure->vertices[0];
     else
@@ -2669,7 +2695,7 @@ static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
 
     figure = &geometry->u.path.figures[idx_q->figure_idx];
     b[0] = &figure->vertices[idx_q->vertex_idx];
-    b[1] = &figure->bezier_controls[idx_q->control_idx];
+    b[1] = &figure->bezier_controls[idx_q->control_idx].cq0;
     if (idx_q->vertex_idx == figure->vertex_count - 1)
         b[2] = &figure->vertices[0];
     else
@@ -2747,19 +2773,19 @@ static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct
         next = 0;
 
     return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
-            &figure->bezier_controls[idx->control_idx], &figure->vertices[next]);
+            &figure->bezier_controls[idx->control_idx].cq0, &figure->vertices[next]);
 }
 
 static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
 {
     const D2D1_POINT_2F *p[3];
     struct d2d_figure *figure;
-    D2D1_POINT_2F q[3];
+    D2D1_POINT_2F q[3], c[2];
     size_t next;
 
     figure = &geometry->u.path.figures[idx->figure_idx];
     p[0] = &figure->vertices[idx->vertex_idx];
-    p[1] = &figure->bezier_controls[idx->control_idx];
+    p[1] = &figure->bezier_controls[idx->control_idx].cq0;
     next = idx->vertex_idx + 1;
     if (next == figure->vertex_count)
         next = 0;
@@ -2769,8 +2795,15 @@ static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struc
     d2d_point_lerp(&q[1], p[1], p[2], 0.5f);
     d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
 
-    figure->bezier_controls[idx->control_idx] = q[0];
-    if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &q[1])))
+    d2d_bezier_quad_to_cubic(p[0], &q[0], &q[2], &c[0], &c[1]);
+
+    figure->bezier_controls[idx->control_idx].cq0 = q[0];
+    figure->bezier_controls[idx->control_idx].c0 = c[0];
+    figure->bezier_controls[idx->control_idx].c1 = c[1];
+
+    d2d_bezier_quad_to_cubic(&q[0], &q[1], p[2], &c[0], &c[1]);
+
+    if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &c[0], &c[1], &q[1])))
         return FALSE;
     if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
         return FALSE;
@@ -2841,7 +2874,7 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
 
         figure = &geometry->u.path.figures[idx_p.figure_idx];
         p[0] = &figure->vertices[idx_p.vertex_idx];
-        p[1] = &figure->bezier_controls[idx_p.control_idx];
+        p[1] = &figure->bezier_controls[idx_p.control_idx].cq0;
 
         i = idx_p.vertex_idx + 1;
         if (d2d_path_geometry_point_inside(geometry, p[1], FALSE))
@@ -2940,6 +2973,7 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr
 {
     struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
     struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
+    D2D1_POINT_2F p0, p1, p2, c[2];
     unsigned int i;
 
     TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
@@ -2954,11 +2988,15 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr
     {
         D2D1_RECT_F bezier_bounds;
 
-        d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1],
-                &beziers[i].point1, &beziers[i].point2);
+        p0 = figure->vertices[figure->vertex_count - 1];
+        p1 = beziers[i].point1;
+        p2 = beziers[i].point2;
+        d2d_bezier_quad_to_cubic(&p0, &p1, &p2, &c[0], &c[1]);
+
+        d2d_rect_get_bezier_bounds(&bezier_bounds, &p0, &p1, &p2);
 
         figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER;
-        if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1))
+        if (!d2d_figure_add_bezier_control(figure, &c[0], &c[1], &p1))
         {
             ERR("Failed to add bezier.\n");
             geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
@@ -3165,7 +3203,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *
                     break;
 
                 case D2D_VERTEX_TYPE_BEZIER:
-                    p1 = figure->original_bezier_controls[bezier_idx++];
+                    p1 = figure->original_bezier_controls[bezier_idx++].cq0;
                     d2d_point_transform(&p1, transform, p1.x, p1.y);
                     p2 = figure->vertices[j];
                     d2d_point_transform(&p2, transform, p2.x, p2.y);
@@ -3187,7 +3225,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *
 
         if (type == D2D_VERTEX_TYPE_BEZIER)
         {
-            p1 = figure->original_bezier_controls[bezier_idx++];
+            p1 = figure->original_bezier_controls[bezier_idx++].cq0;
             d2d_point_transform(&p1, transform, p1.x, p1.y);
             p2 = figure->vertices[0];
             d2d_point_transform(&p2, transform, p2.x, p2.y);
@@ -3369,7 +3407,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
                     break;
 
                 case D2D_VERTEX_TYPE_BEZIER:
-                    p1 = figure->original_bezier_controls[bezier_idx++];
+                    p1 = figure->original_bezier_controls[bezier_idx++].cq0;
                     if (transform)
                         d2d_point_transform(&p1, transform, p1.x, p1.y);
                     p2 = figure->vertices[j];
@@ -3393,7 +3431,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
 
         if (type == D2D_VERTEX_TYPE_BEZIER)
         {
-            p1 = figure->original_bezier_controls[bezier_idx++];
+            p1 = figure->original_bezier_controls[bezier_idx++].cq0;
             if (transform)
                 d2d_point_transform(&p1, transform, p1.x, p1.y);
             p2 = figure->vertices[0];
-- 
2.20.1




More information about the wine-devel mailing list