From 810fec1399f141dad6d74db670d7d1c502e9750d Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sun, 16 Aug 2026 10:43:19 +0000 Subject: [PATCH 5/7] rsvg: Add rsvg_handle_get_intrinsic_dimensions() and the 2.52 pixel query Both read the already-parsed width, height and viewBox off the root and render nothing. has_width and has_height are always returned as TRUE, matching librsvg 2.54 and later: SVG2 makes those geometry properties default to 100%, so every document has them. The internal length representation normalizes absolute units to inches while parsing, so the reported unit for a length authored in cm, mm, pt or pc is RSVG_UNIT_IN with an equivalent value. Arithmetic over the result is unaffected, including the width-to-height ratio that callers reading these values for scaling actually use; only the authored spelling is lost. --- librsvg/rsvg.h | 12 ++++ rsvg-base.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++- rsvg.symbols | 2 + 3 files changed, 188 insertions(+), 1 deletion(-) diff --git a/librsvg/rsvg.h b/librsvg/rsvg.h index 2d5113705..b53d46128 100644 --- a/librsvg/rsvg.h +++ b/librsvg/rsvg.h @@ -228,6 +228,18 @@ gboolean rsvg_handle_has_sub (RsvgHandle * handle, const char *id); gboolean rsvg_handle_set_stylesheet (RsvgHandle * handle, const guint8 *css, gsize css_len, GError **error); +void rsvg_handle_get_intrinsic_dimensions (RsvgHandle *handle, + gboolean *out_has_width, + RsvgLength *out_width, + gboolean *out_has_height, + RsvgLength *out_height, + gboolean *out_has_viewbox, + RsvgRectangle *out_viewbox); + +gboolean rsvg_handle_get_intrinsic_size_in_pixels (RsvgHandle *handle, + gdouble *out_width, + gdouble *out_height); + /* GIO APIs */ /** diff --git a/rsvg-base.c b/rsvg-base.c index 309ccc980..806b9e702 100644 --- a/rsvg-base.c +++ b/rsvg-base.c @@ -1632,7 +1632,180 @@ rsvg_handle_has_sub (RsvgHandle * handle, return rsvg_defs_lookup (handle->priv->defs, id) != NULL; } -/** +/* Maps this build's internal length representation onto the public RsvgUnit + * enum. Absolute lengths are normalized to inches while parsing, so lengths + * authored as cm/mm/pt/pc come back as RSVG_UNIT_IN with an equivalent value. + * The numeric value is left as-is, so callers doing unit-aware arithmetic get + * correct results; only the authored spelling is lost. + */ +static RsvgUnit +rsvg_unit_from_internal_length (const RsvgInternalLength * in) +{ + switch (in->factor) { + case 'p': + return RSVG_UNIT_PERCENT; + case 'm': + return RSVG_UNIT_EM; + case 'x': + return RSVG_UNIT_EX; + case 'i': + return RSVG_UNIT_IN; + case '\0': + default: + return RSVG_UNIT_PX; + } +} + +static void +rsvg_length_from_internal (const RsvgInternalLength * in, RsvgLength * out) +{ + out->length = in->length; + out->unit = rsvg_unit_from_internal_length (in); +} + +/** + * rsvg_handle_get_intrinsic_dimensions: + * @handle: An #RsvgHandle + * @out_has_width: (out)(optional): Will be set to %TRUE; see below. + * @out_width: (out)(optional): Will be set to the computed value of the + * width property in the toplevel SVG. + * @out_has_height: (out)(optional): Will be set to %TRUE; see below. + * @out_height: (out)(optional): Will be set to the computed value of the + * height property in the toplevel SVG. + * @out_has_viewbox: (out)(optional): Will be set to %TRUE if the toplevel SVG + * has a viewBox attribute. + * @out_viewbox: (out)(optional): Will be set to the value of the + * viewBox attribute in the toplevel SVG. + * + * Queries the width, height and + * viewBox attributes in an SVG document. + * + * As in librsvg 2.54 and later, @out_has_width and @out_has_height are always + * set to %TRUE: per SVG2 those properties default to 100% + * when absent, so every document has them. + * + * Since: 2.46 + */ +void +rsvg_handle_get_intrinsic_dimensions (RsvgHandle * handle, + gboolean * out_has_width, + RsvgLength * out_width, + gboolean * out_has_height, + RsvgLength * out_height, + gboolean * out_has_viewbox, + RsvgRectangle * out_viewbox) +{ + RsvgNodeSvg *root; + + g_return_if_fail (handle != NULL); + + if (out_has_width) + *out_has_width = TRUE; + if (out_has_height) + *out_has_height = TRUE; + if (out_has_viewbox) + *out_has_viewbox = FALSE; + + if (out_width) { + out_width->length = 1.0; + out_width->unit = RSVG_UNIT_PERCENT; + } + if (out_height) { + out_height->length = 1.0; + out_height->unit = RSVG_UNIT_PERCENT; + } + if (out_viewbox) { + out_viewbox->x = out_viewbox->y = 0.0; + out_viewbox->width = out_viewbox->height = 0.0; + } + + root = (RsvgNodeSvg *) handle->priv->treebase; + if (root == NULL) { + g_critical ("rsvg_handle_get_intrinsic_dimensions() called on a handle " + "that is not fully loaded"); + return; + } + + if (out_width) + rsvg_length_from_internal (&root->w, out_width); + if (out_height) + rsvg_length_from_internal (&root->h, out_height); + + if (root->vbox.active) { + if (out_has_viewbox) + *out_has_viewbox = TRUE; + if (out_viewbox) { + out_viewbox->x = root->vbox.rect.x; + out_viewbox->y = root->vbox.rect.y; + out_viewbox->width = root->vbox.rect.width; + out_viewbox->height = root->vbox.rect.height; + } + } +} + +/** + * rsvg_handle_get_intrinsic_size_in_pixels: + * @handle: An #RsvgHandle + * @out_width: (out)(optional): Will be set to the computed width. + * @out_height: (out)(optional): Will be set to the computed height. + * + * Converts an SVG document's intrinsic dimensions to pixels, and returns the + * result. + * + * This only succeeds if the document has both width and + * height in absolute or font-based units; percentages need a + * viewport to be resolved against and make this return %FALSE. + * + * Returns: %TRUE if the dimensions could be converted directly to pixels. + * + * Since: 2.52 + */ +gboolean +rsvg_handle_get_intrinsic_size_in_pixels (RsvgHandle * handle, + gdouble * out_width, + gdouble * out_height) +{ + RsvgNodeSvg *root; + double font_size = 12.0; + double width, height; + + g_return_val_if_fail (handle != NULL, FALSE); + + if (out_width) + *out_width = 0.0; + if (out_height) + *out_height = 0.0; + + root = (RsvgNodeSvg *) handle->priv->treebase; + if (root == NULL) { + g_critical ("rsvg_handle_get_intrinsic_size_in_pixels() called on a handle " + "that is not fully loaded"); + return FALSE; + } + + /* Percentages have no viewport to resolve against here. */ + if (root->w.factor == 'p' || root->h.factor == 'p') + return FALSE; + + if (root->super.state != NULL && root->super.state->has_font_size) + font_size = _rsvg_css_hand_normalize_length (&root->super.state->font_size, + handle->priv->dpi_y, 0.0, 12.0); + + width = _rsvg_css_hand_normalize_length (&root->w, handle->priv->dpi_x, 0.0, font_size); + height = _rsvg_css_hand_normalize_length (&root->h, handle->priv->dpi_y, 0.0, font_size); + + if (!(width > 0.0) || !(height > 0.0)) + return FALSE; + + if (out_width) + *out_width = width; + if (out_height) + *out_height = height; + + return TRUE; +} + +/** * rsvg_set_default_dpi: * @dpi: Dots Per Inch (aka Pixels Per Inch) * diff --git a/rsvg.symbols b/rsvg.symbols index d74dd5cb0..b54607235 100644 --- a/rsvg.symbols +++ b/rsvg.symbols @@ -5,6 +5,8 @@ rsvg_handle_close rsvg_handle_get_base_uri rsvg_handle_get_dimensions rsvg_handle_get_dimensions_sub +rsvg_handle_get_intrinsic_dimensions +rsvg_handle_get_intrinsic_size_in_pixels rsvg_handle_get_position_sub rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf_sub -- 2.43.0