diff options
author | Federico Mena Quintero <federico@gnome.org> | 2015-02-20 15:53:07 -0600 |
---|---|---|
committer | Federico Mena Quintero <federico@gnome.org> | 2015-02-20 15:53:07 -0600 |
commit | 9fe6fadb403de56fedc937f0f72b9378c5dd311f (patch) | |
tree | 2ade270faa1ec309d6b438ad76b26eeaf360424c | |
parent | 3e15bb2f249606fead047989bb6a9d9f63e22ca1 (diff) | |
download | librsvg-9fe6fadb403de56fedc937f0f72b9378c5dd311f.tar.gz |
RsvgNodeRect: Use RsvgPathBuilder instead of building/parsing a path string
Signed-off-by: Federico Mena Quintero <federico@gnome.org>
-rw-r--r-- | rsvg-shapes.c | 185 |
1 files changed, 101 insertions, 84 deletions
diff --git a/rsvg-shapes.c b/rsvg-shapes.c index 2ee43883..c466b913 100644 --- a/rsvg-shapes.c +++ b/rsvg-shapes.c @@ -330,6 +330,7 @@ _rsvg_node_rect_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a const char *klazz = NULL, *id = NULL, *value; RsvgNodeRect *rect = (RsvgNodeRect *) self; + /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement */ if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "x"))) rect->x = _rsvg_css_parse_length (value); @@ -362,126 +363,142 @@ static void _rsvg_node_rect_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate) { double x, y, w, h, rx, ry; - GString *d = NULL; + double half_w, half_h; + RsvgPathBuilder builder; cairo_path_t *path; RsvgNodeRect *rect = (RsvgNodeRect *) self; - char buf[G_ASCII_DTOSTR_BUF_SIZE]; x = _rsvg_css_normalize_length (&rect->x, ctx, 'h'); y = _rsvg_css_normalize_length (&rect->y, ctx, 'v'); - w = _rsvg_css_normalize_length (&rect->w, ctx, 'h'); - h = _rsvg_css_normalize_length (&rect->h, ctx, 'v'); - rx = _rsvg_css_normalize_length (&rect->rx, ctx, 'h'); - ry = _rsvg_css_normalize_length (&rect->ry, ctx, 'v'); + + /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement + * For now we'll just take the absolute value. + */ + w = fabs (_rsvg_css_normalize_length (&rect->w, ctx, 'h')); + h = fabs (_rsvg_css_normalize_length (&rect->h, ctx, 'v')); + rx = fabs (_rsvg_css_normalize_length (&rect->rx, ctx, 'h')); + ry = fabs (_rsvg_css_normalize_length (&rect->ry, ctx, 'v')); if (w == 0. || h == 0.) - return; + return; if (rect->got_rx) rx = rx; else rx = ry; + if (rect->got_ry) ry = ry; else ry = rx; - if (rx > fabs (w / 2.)) - rx = fabs (w / 2.); - if (ry > fabs (h / 2.)) - ry = fabs (h / 2.); + half_w = w / 2; + half_h = h / 2; + + if (rx > half_w) + rx = half_w; + + if (ry > half_h) + ry = half_h; if (rx == 0) ry = 0; else if (ry == 0) rx = 0; - /* emulate a rect using a path */ - d = g_string_new ("M "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y)); + if (rx == 0) { + /* Easy case, no rounded corners */ - g_string_append (d, " H "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + w - rx)); + rsvg_path_builder_init (&builder, 11); - g_string_append (d, " A"); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ry)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + w)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + ry)); + rsvg_path_builder_move_to (&builder, x, y); + rsvg_path_builder_line_to (&builder, x + w, y); + rsvg_path_builder_line_to (&builder, x + w, y + h); + rsvg_path_builder_line_to (&builder, x, y + h); + rsvg_path_builder_line_to (&builder, x, y); + rsvg_path_builder_close_path (&builder); + } else { + double top_x1, top_x2, top_y; + double bottom_x1, bottom_x2, bottom_y; + double left_x, left_y1, left_y2; + double right_x, right_y1, right_y2; + + /* Hard case, rounded corners + * + * (top_x1, top_y) (top_x2, top_y) + * *--------------------------------* + * / \ + * * (left_x, left_y1) * (right_x, right_y1) + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * * (left_x, left_y2) * (right_x, right_y2) + * \ / + * *--------------------------------* + * (bottom_x1, bottom_y) (bottom_x2, bottom_y) + */ - g_string_append (d, " V "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + h - ry)); + top_x1 = x + rx; + top_x2 = x + w - rx; + top_y = y; - g_string_append (d, " A"); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ry)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + w - rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + h)); + bottom_x1 = top_x1; + bottom_x2 = top_x2; + bottom_y = y + h; - g_string_append (d, " H "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + rx)); + left_x = x; + left_y1 = y + ry; + left_y2 = y + h - ry; - g_string_append (d, " A"); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ry)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + h - ry)); + right_x = x + w; + right_y1 = left_y1; + right_y2 = left_y2; - g_string_append (d, " V "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + ry)); + rsvg_path_builder_init (&builder, 32); /* an estimate; the arc segments may grow the array anyway */ - g_string_append (d, " A"); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ry)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 0.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + rx)); - g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y)); + rsvg_path_builder_move_to (&builder, top_x1, top_y); + rsvg_path_builder_line_to (&builder, top_x2, top_y); - g_string_append (d, " Z"); + rsvg_path_builder_arc (&builder, + top_x2, top_y, + rx, ry, 0, FALSE, TRUE, + right_x, right_y1); - rsvg_state_reinherit_top (ctx, self->state, dominate); + rsvg_path_builder_line_to (&builder, right_x, right_y2); - path = rsvg_parse_path (d->str); + rsvg_path_builder_arc (&builder, + right_x, right_y2, + rx, ry, 0, FALSE, TRUE, + bottom_x2, bottom_y); + + rsvg_path_builder_line_to (&builder, bottom_x1, bottom_y); + + rsvg_path_builder_arc (&builder, + bottom_x1, bottom_y, + rx, ry, 0, FALSE, TRUE, + left_x, left_y2); + + rsvg_path_builder_line_to (&builder, left_x, left_y1); + + rsvg_path_builder_arc (&builder, + left_x, left_y1, + rx, ry, 0, FALSE, TRUE, + top_x1, top_y); + + rsvg_path_builder_close_path (&builder); + } + + path = rsvg_path_builder_finish (&builder); + + rsvg_state_reinherit_top (ctx, self->state, dominate); rsvg_render_path (ctx, path); rsvg_cairo_path_destroy (path); - g_string_free (d, TRUE); } RsvgNode * |