From 8fc990dfd08009e834aa35f4eb2bd273e57e1319 Mon Sep 17 00:00:00 2001 From: Mathias Hasselmann Date: Wed, 20 Jun 2007 08:31:46 +0000 Subject: [PATCH] Implement height for width for GtkLabel. 2007-06-20 Mathias Hasselmann * gtk/gtklabel.c, tests/autotestextendedlayout.c: Implement height for width for GtkLabel. svn path=/branches/extended-layout/; revision=18203 --- ChangeLog.gtk-extended-layout | 7 +- gtk/gtklabel.c | 35 +++- tests/autotestextendedlayout.c | 288 ++++++++++++++++++++++++--------- 3 files changed, 244 insertions(+), 86 deletions(-) diff --git a/ChangeLog.gtk-extended-layout b/ChangeLog.gtk-extended-layout index 3440020524..c595b65100 100644 --- a/ChangeLog.gtk-extended-layout +++ b/ChangeLog.gtk-extended-layout @@ -1,3 +1,8 @@ +2007-06-20 Mathias Hasselmann + + * gtk/gtklabel.c, tests/autotestextendedlayout.c: + Implement height for width for GtkLabel. + 2007-06-20 Mathias Hasselmann * tests/autotestextendedlayout.c: Correct some assumptions, @@ -29,7 +34,7 @@ 2007-05-29 Mathias Hasselmann - * testextendedlayout.c: Create initial heigth-for-width test. + * testextendedlayout.c: Create initial height-for-width test. 2007-05-29 Mathias Hasselmann diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 23628d491d..f4cc891373 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -4234,17 +4234,40 @@ gtk_label_do_popup (GtkLabel *label, static GtkExtendedLayoutFeatures gtk_label_extended_layout_get_features (GtkExtendedLayout *layout) { - return GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH - | GTK_EXTENDED_LAYOUT_NATURAL_SIZE - | GTK_EXTENDED_LAYOUT_BASELINES; + GtkLabel *label; + + label = GTK_LABEL (layout); + + if (label->wrap) + return + GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH | + GTK_EXTENDED_LAYOUT_NATURAL_SIZE | + GTK_EXTENDED_LAYOUT_BASELINES; + + return + GTK_EXTENDED_LAYOUT_NATURAL_SIZE | + GTK_EXTENDED_LAYOUT_BASELINES; } static gint gtk_label_extended_layout_get_height_for_width (GtkExtendedLayout *layout, gint width) { - g_return_val_if_fail (GTK_IS_LABEL (layout), -1); - return -1; + PangoLayout *tmp; + GtkLabel *label; + gint height; + + label = GTK_LABEL (layout); + + g_return_val_if_fail (label->wrap, -1); + + gtk_label_ensure_layout (label); + tmp = pango_layout_copy (label->layout); + pango_layout_set_width (tmp, PANGO_SCALE * width); + pango_layout_get_pixel_size (tmp, NULL, &height); + g_object_unref (tmp); + + return height; } static void @@ -4252,6 +4275,7 @@ gtk_label_extended_layout_get_natural_size (GtkExtendedLayout *layout, GtkRequisition *requisition) { g_return_if_fail (GTK_IS_LABEL (layout)); + g_return_if_reached (); } static gint @@ -4263,7 +4287,6 @@ gtk_label_extended_layout_get_baselines (GtkExtendedLayout *layout, GSList *lines; label = GTK_LABEL (layout); - gtk_label_ensure_layout (label); lines = pango_layout_get_lines_readonly (label->layout); num_lines = g_slist_length (lines); diff --git a/tests/autotestextendedlayout.c b/tests/autotestextendedlayout.c index f10911e455..797b651153 100644 --- a/tests/autotestextendedlayout.c +++ b/tests/autotestextendedlayout.c @@ -1,21 +1,36 @@ #include -#include +#include #include #include -#define test(condition) \ - log_test((condition), G_STRFUNC, #condition) -#define testf(condition, format, ...) \ - log_test((condition), G_STRFUNC, \ - #condition " (" format ")", __VA_ARGS__) -#define testi(expected, number) G_STMT_START { \ - const gint i = (expected), j = (number); \ - log_test(i == j, G_STRFUNC, #number " is " #expected \ - " (actual number %d)", j); \ - } G_STMT_END +/*****************************************************************************/ +#define log_test(condition) \ + log_test_impl(G_STRFUNC, (condition), #condition) +#define log_testf(condition, format, ...) \ + log_test_impl(G_STRFUNC, (condition), #condition " (" format ")", __VA_ARGS__) +#define log_testi(expected, number) G_STMT_START { \ + const gint i = (expected), j = (number); \ + log_test_impl(G_STRFUNC, i == j, \ + #number " is " #expected " (actual number %d)", j); \ + } G_STMT_END + +#define log_info(format, ...) \ + g_print ("INFO: %s: " format "\n", G_STRFUNC, __VA_ARGS__); #define log_int_array(values, length) \ - log_int_array_impl (G_STRFUNC, #values, (values), (length)) + log_int_array_impl (G_STRFUNC, #values, (values), (length)) +#define log_int(value) \ + log_info (#value " is %d\n", (value)); + +/*****************************************************************************/ + +static const gchar lorem_ipsum[] = + "" + "Lorem ipsum dolor sit amet, consectetuer " + "adipiscing elit. Aliquam sed erat. Proin lectus " + "orci, venenatis pharetra, egestas id, tincidunt " + "vel, eros. Integer fringilla. Aenean justo ipsum, " + "luctus ut, volutpat laoreet, vehicula in, libero."; static int num_failures = 0; static int num_warnings = 0; @@ -24,6 +39,8 @@ static int num_criticals = 0; static GLogFunc default_log_handler; +/*****************************************************************************/ + static void log_int_array_impl (const gchar *function, const gchar *var_name, @@ -51,9 +68,9 @@ log_int_array_impl (const gchar *function, } static void -log_test (gboolean passed, - const gchar *function, - const gchar *test_name, ...) +log_test_impl (const gchar *function, + gboolean passed, + const gchar *test_name, ...) { va_list args; char *str; @@ -87,8 +104,121 @@ log_override_cb (const gchar *log_domain, (* default_log_handler) (log_domain, log_level, message, user_data); } +/*****************************************************************************/ + static void -test_label (void) +gtk_label_test_baselines (void) +{ + GtkExtendedLayout *layout; + GtkWidget *widget; + GtkLabel *label; + + gint num_baselines; + gint *baselines; + + widget = g_object_ref_sink (gtk_label_new (NULL)); + layout = GTK_EXTENDED_LAYOUT (widget); + label = GTK_LABEL (widget); + + baselines = NULL; + gtk_label_set_text (label, NULL); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (1, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + baselines = NULL; + gtk_label_set_text (label, ""); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (1, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + baselines = NULL; + gtk_label_set_text (label, "First Line"); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (1, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + baselines = NULL; + gtk_label_set_text (label, "First Line\n"); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (2, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + baselines = NULL; + gtk_label_set_text (label, "First Line\nSecond Line"); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (2, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + baselines = NULL; + gtk_label_set_markup (label, "First Line\nSecond Line\nThird Line"); + num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); + log_int_array (baselines, num_baselines); + log_testi (3, num_baselines); + log_test (NULL != baselines); + g_free (baselines); + + g_object_unref (widget); +} + +static void +gtk_label_test_height_for_width (void) +{ + GtkExtendedLayout *layout; + GtkWidget *widget; + GtkLabel *label; + + PangoLayout *ref; + gint i, cx, cy, rcx, rcy; + double cy_min, cy_max; + + widget = g_object_ref_sink (gtk_label_new (NULL)); + layout = GTK_EXTENDED_LAYOUT (widget); + label = GTK_LABEL (widget); + + gtk_label_set_markup (label, lorem_ipsum); + gtk_label_set_line_wrap_mode (label, PANGO_WRAP_CHAR); + gtk_label_set_line_wrap (label, TRUE); + + ref = pango_layout_copy (gtk_label_get_layout (label)); + pango_layout_set_width (ref, -1); + pango_layout_get_pixel_size (ref, &rcx, &rcy); + g_object_unref (ref); + + log_info ("preferred layout size: %d \303\227 %d", rcx, rcy); + + for (i = 5; i >= 1; --i) + { + cy = gtk_extended_layout_get_height_for_width (layout, cx = rcx * i); + log_info ("scale is %d, so width is %d. results in height of %d.", i, cx, cy); + log_testi (rcy, cy); + } + + cy_min = rcy; + cy_max = rcy * 2.5; + + for (i = 2, cx = rcx / 2; cx >= rcy; ++i, cx = rcx / i, cy_min = cy, cy_max += rcy) + { + cy = gtk_extended_layout_get_height_for_width (layout, cx); + log_info ("scale is 1/%d, so width is %d. results in height of %d.", i, cx, cy); + log_testf (cy_min <= cy && cy <= cy_max, "%f <= %d <= %f", cy_min, cy, cy_max); + } + + g_object_unref (widget); +} + +static void +gtk_label_test_extended_layout (void) { GtkExtendedLayoutFeatures features; GtkExtendedLayoutIface *iface; @@ -96,83 +226,83 @@ test_label (void) GtkWidget *widget; GtkLabel *label; - gint *baselines; - gint num_baselines; - widget = g_object_ref_sink (gtk_label_new (NULL)); - iface = GTK_EXTENDED_LAYOUT_GET_IFACE (widget); layout = GTK_EXTENDED_LAYOUT (widget); label = GTK_LABEL (widget); - /* basic properties */ + /* vtable */ + + log_test (GTK_IS_EXTENDED_LAYOUT (label)); + iface = GTK_EXTENDED_LAYOUT_GET_IFACE (label); + + log_test (NULL != iface->get_features); + log_test (NULL != iface->get_height_for_width); + log_test (NULL == iface->get_width_for_height); + log_test (NULL != iface->get_natural_size); + log_test (NULL != iface->get_baselines); + + /* feature set */ - test (GTK_IS_EXTENDED_LAYOUT (label)); features = gtk_extended_layout_get_features (layout); - test (NULL != iface->get_features); - test (NULL != iface->get_height_for_width); - test (NULL == iface->get_width_for_height); - test (NULL != iface->get_natural_size); - test (NULL != iface->get_baselines); + log_test (0 == (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH)); + log_test (0 == (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT)); + log_test (0 != (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)); + log_test (0 != (features & GTK_EXTENDED_LAYOUT_BASELINES)); - test (0 != (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH)); - test (0 == (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT)); - test (0 != (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)); - test (0 != (features & GTK_EXTENDED_LAYOUT_BASELINES)); + gtk_label_set_line_wrap (label, TRUE); + features = gtk_extended_layout_get_features (layout); + + log_test (0 != (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH)); + log_test (0 == (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT)); + log_test (0 != (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)); + log_test (0 != (features & GTK_EXTENDED_LAYOUT_BASELINES)); + + g_object_unref (widget); /* baseline support */ - baselines = NULL; - gtk_label_set_text (label, NULL); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (1, num_baselines); - test (NULL != baselines); - g_free (baselines); + gtk_label_test_baselines (); + gtk_label_test_height_for_width (); - baselines = NULL; - gtk_label_set_text (label, ""); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (1, num_baselines); - test (NULL != baselines); - g_free (baselines); + /* height for width */ +/* + PangoLayout *tmp; - baselines = NULL; - gtk_label_set_text (label, "First Line"); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (1, num_baselines); - test (NULL != baselines); - g_free (baselines); + log_info ("requisition: %d, %d", req.width, req.height); - baselines = NULL; - gtk_label_set_text (label, "First Line\n"); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (2, num_baselines); - test (NULL != baselines); - g_free (baselines); + for (i = -5; i < 6; ++i) + { + const gint e = i < 4 ? 1 : 2; - baselines = NULL; - gtk_label_set_text (label, "First Line\nSecond Line"); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (2, num_baselines); - test (NULL != baselines); - g_free (baselines); + const gdouble sy_lower = + i + 1 < 0 ? (abs(i + 1) + 1) : + i + 1 > 0 ? 1.0 / (abs(i + 1) + 1) : 1; + const gdouble sy_upper = + i - e < 0 ? (abs(i - e) + 1) : + i - e > 0 ? 1.0 / (abs(i - e) + 1) : 1; - baselines = NULL; - gtk_label_set_markup (label, "First Line\nSecond Line\nThird Line"); - num_baselines = gtk_extended_layout_get_baselines (layout, &baselines); - log_int_array (baselines, num_baselines); - testi (3, num_baselines); - test (NULL != baselines); - g_free (baselines); + double sy; - g_object_unref (widget); + width = + i < 0 ? req.width / (abs(i) + 1) : + i > 0 ? req.width * (abs(i) + 1) : + req.width; + + height = gtk_extended_layout_get_height_for_width (layout, width); + sy = (double)height / req.height; + + log_info ("scale is %s%d, so width is %d, height is %d", + i < 0 ? "1/" : "", abs(i) + 1, width, height); + + log_testf (sy_lower <= sy && sy <= sy_upper, + "%f <= %f <= %f", sy_lower, sy, sy_upper); + } +*/ } +/*****************************************************************************/ + int main(int argc, char **argv) { @@ -180,12 +310,12 @@ main(int argc, char **argv) gtk_init (&argc, &argv); - test_label (); + gtk_label_test_extended_layout (); - testi (0, num_warnings); - testi (0, num_errors); - testi (0, num_criticals); - testi (0, num_failures); + log_testi (0, num_warnings); + log_testi (0, num_errors); + log_testi (0, num_criticals); + log_testi (0, num_failures); return MAX(0, num_failures - 1); }