Getting CSS properties defined in em (etc.) in px rounds toward 0, delivering 1 too few pixels
I came across this from this case discussed on IRC:
dboles
- I'm setting [CSS min-width] programmatically via a CssProvider, using an em unit, and the Inspector shows the [CSS property value] as 26.666.... px. So far, so good! But the widget truncates that down to 26px, which (A) seems wrong and (B) leads to problems in my case
- (basically I'm manually doing a formatted label next to a scale, and trying to be clever by requesting the min needed size in a way that'll scale as the font size does, but because of the rounding down, the label expands as i get to a higher value with a wider format)
Company
- dboles: seems browsers round up, so we should use ceil(), too
dboles
- yay!
- that definitely seems right; the widget should get at least what was requested via CSS
This seems pretty plainly wrong: if we have to round to a value in pixels, it needs to be at least what was theoretically requested in CSS, not just below that.
The practical implications seem quite obvious too, although my specific case might not be... I (via a process that is as ugly as it is painstaking) request a size I need in em
, but GTK+ gives me less in px
- so, as the value of my scale moves around a threshold, the label changes size and makes my whole UI to right of that shift around. There are probably better use cases than this, anyway.
Here is a test case showing the problem: the em
value of min-width
requested in the CSS resolves (rounded) to 207 px, but via CssGadget.get_number()
, the widget actually gets allocated 206 px.
#include <gtk/gtk.h>
int
main (int argc,
char **argv)
{
gtk_init (&argc, &argv);
GtkWidget *label = gtk_label_new ("just a test");
GtkStyleContext *style_context = gtk_widget_get_style_context (label);
GtkCssProvider *css_provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (css_provider,
"label { font-size: 10px; min-width: 20.66em }",
-1, NULL);
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
GValue value = G_VALUE_INIT;
gtk_style_context_get_property (style_context, "min-width", GTK_STATE_FLAG_NORMAL, &value);
g_assert (G_VALUE_HOLDS_INT (&value));
int min_width = g_value_get_int (&value);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_add (GTK_CONTAINER (window), label);
gtk_widget_show_all (window);
int allocated_width = gtk_widget_get_allocated_width (label);
g_print ("CSS : %i\nwidget: %i\n", min_width, allocated_width);
}
output:
CSS : 207
widget: 206
My initial thought was just to change get_number()
, which is in gtkcssgadget.c
in GTK+ 3 and gtksizerequest.c
in GTK+ 4, to round away from 0. However, apparently that may not imitate the web, although the size properties do:
dboles
- presumably (most?) other properties that should use ceil() too
Company
- dboles: no
- dboles: most other properties (read: margin, padding and border) have been tested by me and do exactly what they do in browsers
- dboles: so if you want to change any other property, test what happens in a browser first
On that basis (do as the browsers do, even if it's stupid), we would only ceil()
the sizes from min-(width|height)
, not any other use of get_number()
, which means making them do _gtk_css_number_value_get (blah)
directly (or implementing a new get_number_ceil()
, or etc.)