Wireshark-dev: Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2
From: Jakub Zawadzki <darkjames-ws@xxxxxxxxxxxx>
Date: Tue, 4 Jun 2013 23:51:58 +0200
Hi, On Tue, Jun 04, 2013 at 10:28:39PM +0200, Jakub Zawadzki wrote: > On Tue, Jun 04, 2013 at 10:06:05PM +0200, Reinhard Speyerer wrote: > > I noticed today that columns in the hex dump pane are misaligned when > > using wireshark 1.10.0rc2 built with the following configuration > > > > [...] > > > > In my preferences I use the default font (Monospace 10). > > > > Has anybody else also observed this behaviour? > > On not monospaced fonts, yes, still this is new for monospace one. > Can you try some other fixed width font? > > I had once patch to force "alignment" of hexdump for all fonts, > I'll try to find it. Ok, found it. Can you try attached patch?
diff --git ui/gtk/bytes_view.c ui/gtk/bytes_view.c index 55b9c0c..1bc6840 100644 --- ui/gtk/bytes_view.c +++ ui/gtk/bytes_view.c @@ -49,17 +49,26 @@ static GtkWidgetClass *parent_class = NULL; +struct PangoCairoGlyphs { + PangoGlyphInfo *glyphs; + PangoFont *font; + cairo_scaled_font_t *scfont; + int num_glyphs; +}; + struct _BytesView { GtkWidget widget; - PangoContext *context; - PangoFontDescription *font; int font_ascent; int font_descent; int fontsize; + gboolean font_changed; + int font_width; + struct PangoCairoGlyphs glyphs[0x80]; + GtkAdjustment *vadj; GtkAdjustment *hadj; #if GTK_CHECK_VERSION(3, 0, 0) @@ -101,7 +110,7 @@ static void bytes_view_adjustment_set(BytesView *); static void bytes_view_init(BytesView *bv) { - bv->context = NULL; + bv->font_changed = TRUE; bv->encoding = PACKET_CHAR_ENC_CHAR_ASCII; bv->format = BYTES_HEX; @@ -135,10 +144,6 @@ bytes_view_destroy(BytesView *bv) pango_font_description_free(bv->font); bv->font = NULL; } - if (bv->context) { - g_object_unref(bv->context); - bv->context = NULL; - } } #if GTK_CHECK_VERSION(3, 0, 0) @@ -164,27 +169,109 @@ bytes_view_destroy_object(GtkObject *object) #endif static void -bytes_view_ensure_layout(BytesView *bv) +bytes_view_recalc_font(BytesView *bv) { - if (bv->context == NULL) { - bv->context = gtk_widget_get_pango_context(GTK_WIDGET(bv)); - g_object_ref(bv->context); - - { - PangoLanguage *lang; - PangoFontMetrics *metrics; - - /* vte and xchat does it this way */ - lang = pango_context_get_language(bv->context); - metrics = pango_context_get_metrics(bv->context, bv->font, lang); - bv->font_ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - bv->font_descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; - pango_font_metrics_unref(metrics); - - bv->fontsize = bv->font_ascent + bv->font_descent; - } - g_assert(bv->context); - bytes_view_adjustment_set(bv); + PangoContext *context; + + PangoAttrList *attrs; + PangoAttrIterator *iter; + unsigned char ch; + + int font_width; + + context = gtk_widget_get_pango_context(GTK_WIDGET(bv)); + g_object_ref(context); + + { + PangoLanguage *lang; + PangoFontMetrics *metrics; + + /* vte and xchat does it this way */ + lang = pango_context_get_language(context); + metrics = pango_context_get_metrics(context, bv->font, lang); + bv->font_ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; + bv->font_descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; + pango_font_metrics_unref(metrics); + + bv->fontsize = bv->font_ascent + bv->font_descent; + } + + attrs = pango_attr_list_new(); + pango_attr_list_insert_before(attrs, pango_attr_font_desc_new(bv->font)); + iter = pango_attr_list_get_iterator(attrs); + + font_width = 0; + + for (ch = 0x20; ch < 0x7f; ch++) { + GList *run_list; + GList *tmp_list; + int glyph_width = 0; + + run_list = pango_itemize(context, &ch, 0, 1, attrs, iter); + + g_assert(run_list->next == NULL); + + for (tmp_list = run_list; tmp_list; tmp_list = tmp_list->next) { + PangoGlyphString *glyphs; + PangoItem *run_item = tmp_list->data; + cairo_scaled_font_t *scaled_font; + PangoFont *font; + int i; + + /* XXX pango_layout_get_item_properties(run_item, &state->properties); */ + + g_assert(run_item->offset == 0); + + glyphs = pango_glyph_string_new(); + pango_shape(&ch, run_item->length, &run_item->analysis, glyphs); + + for (i = 0; i < glyphs->num_glyphs; i++) + glyph_width += glyphs->glyphs[i].geometry.width; + + g_object_ref(run_item->analysis.font); + + font = run_item->analysis.font; + scaled_font = pango_cairo_font_get_scaled_font((PangoCairoFont *)font); + g_assert(scaled_font != NULL && cairo_scaled_font_status(scaled_font) == CAIRO_STATUS_SUCCESS); + + bv->glyphs[ch].font = font; + bv->glyphs[ch].scfont = scaled_font; + bv->glyphs[ch].glyphs = glyphs->glyphs; + bv->glyphs[ch].num_glyphs = glyphs->num_glyphs; + + pango_item_free(run_item); + } + + if (font_width < glyph_width) + font_width = glyph_width; + + g_list_free(run_list); + } + + for (ch = 0x20; ch < 0x7f; ch++) { + int i; + + // XXX + for (i = 0; i < bv->glyphs[ch].num_glyphs; i++) + bv->glyphs[ch].glyphs[i].geometry.width = font_width / bv->glyphs[ch].num_glyphs; + } + + bv->font_width = font_width; + + pango_attr_iterator_destroy(iter); + pango_attr_list_unref(attrs); + + bytes_view_adjustment_set(bv); + + g_object_unref(context); +} + +static void +bytes_view_ensure_font(BytesView *bv) +{ + if (bv->font_changed) { + bv->font_changed = FALSE; + bytes_view_recalc_font(bv); } } @@ -244,18 +331,12 @@ bytes_view_realize(GtkWidget *widget) #else widget->style = gtk_style_attach(widget->style, win); #endif - bytes_view_ensure_layout(bv); + bytes_view_ensure_font(bv); } static void bytes_view_unrealize(GtkWidget *widget) { - BytesView *bv = BYTES_VIEW(widget); - - if (bv->context) { - g_object_unref(bv->context); - bv->context = NULL; - } /* if there are still events in the queue, this'll avoid segfault */ #if !GTK_CHECK_VERSION(3, 8, 0) gdk_window_set_user_data(gtk_widget_get_window(widget), NULL); @@ -351,67 +432,128 @@ static GSList * _pango_runs_build(BytesView *bv, const char *str, int len) { GSList *runs = NULL; + int i, j; - PangoAttrList *attrs; - PangoAttrIterator *iter; + for (i = 0; i < len;) { + const struct PangoCairoGlyphs *cg = &bv->glyphs[(int) str[i]]; + PangoFont *cur_font = cg->font; - GList *run_list; - GList *tmp_list; + struct PangoCairoGlyphs *new_cg = g_slice_new(struct PangoCairoGlyphs); + int num_glyphs = 0; - attrs = pango_attr_list_new(); - pango_attr_list_insert_before(attrs, pango_attr_font_desc_new(bv->font)); + for (j = i; j < len; j++) { + const struct PangoCairoGlyphs *cjg = &bv->glyphs[(int) str[j]]; - iter = pango_attr_list_get_iterator(attrs); + if (cur_font != cjg->font) + break; - run_list = pango_itemize(bv->context, str, 0, len, attrs, iter); + num_glyphs += cjg->num_glyphs; + } - for (tmp_list = run_list; tmp_list; tmp_list = tmp_list->next) { - PangoLayoutRun *run = g_slice_new(PangoLayoutRun); - PangoItem *run_item = (PangoItem *)tmp_list->data; + g_object_ref(cur_font); - run->item = run_item; + new_cg->font = cur_font; + new_cg->scfont = cg->scfont; + new_cg->num_glyphs = num_glyphs; + new_cg->glyphs = g_malloc(num_glyphs * sizeof(PangoGlyphInfo)); - /* XXX pango_layout_get_item_properties(run_item, &state->properties); */ + num_glyphs = 0; + for (j = i; j < len; j++) { + const struct PangoCairoGlyphs *cjg = &bv->glyphs[(int) str[j]]; + int k; - run->glyphs = pango_glyph_string_new(); - pango_shape(str + run_item->offset, run_item->length, &run_item->analysis, run->glyphs); + if (cur_font != cjg->font) + break; - runs = g_slist_prepend(runs, run); + for (k = 0; k < cjg->num_glyphs; k++) + new_cg->glyphs[num_glyphs + k] = cjg->glyphs[k]; + num_glyphs += cjg->num_glyphs; + } + i = j; + + runs = g_slist_prepend(runs, new_cg); } - g_list_free(run_list); + return g_slist_reverse(runs); +} + +static int +_pango_glyph_string_to_pixels(const struct PangoCairoGlyphs *glyphs) +{ + int width = 0; + int i; - pango_attr_iterator_destroy(iter); - pango_attr_list_unref(attrs); + for (i = 0; i < glyphs->num_glyphs; i++) + width += glyphs->glyphs[i].geometry.width; - return g_slist_reverse(runs); + return width/PANGO_SCALE; +} + +#define STACK_BUFFER_SIZE (512 * sizeof (int)) +#define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T)) + +static void +_pango_cairo_renderer_draw_unknown_glyph (cairo_t *cr _U_, + PangoFont *font _U_, + PangoGlyphInfo *gi _U_, + double cx _U_, + double cy _U_) +{ + g_warning("_pango_cairo_renderer_draw_unknown_glyph()\n"); } static int -_pango_glyph_string_to_pixels(PangoGlyphString *glyphs, PangoFont *font _U_) +_pango_cairo_renderer_draw_glyphs(cairo_t *cr, PangoGlyphInfo *glyphs, gint num_glyphs, double base_x, double base_y) { -#if PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 14 - return pango_glyph_string_get_width(glyphs) / PANGO_SCALE; -#else - PangoRectangle logical_rect; + cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH(cairo_glyph_t)]; + cairo_glyph_t *cairo_glyphs = stack_glyphs; + + int x_position = 0; + int i, count; + + cairo_save(cr); + + if (num_glyphs > (int) G_N_ELEMENTS (stack_glyphs)) + cairo_glyphs = g_new(cairo_glyph_t, num_glyphs); + + count = 0; + for (i = 0; i < num_glyphs; i++) { + PangoGlyphInfo *gi = &glyphs[i]; + + if (gi->glyph != PANGO_GLYPH_EMPTY) { + double cx = base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; + double cy = gi->geometry.y_offset == 0 ? + base_y : + base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE; + + if ((gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG) == 0) { + cairo_glyphs[count].index = gi->glyph; + cairo_glyphs[count].x = cx; + cairo_glyphs[count].y = cy; + count++; + } else + _pango_cairo_renderer_draw_unknown_glyph(cr, NULL, gi, cx, cy); + } + x_position += gi->geometry.width; + } + cairo_show_glyphs(cr, cairo_glyphs, count); - pango_glyph_string_extents(glyphs, font, NULL, &logical_rect); - /* pango_extents_to_pixels(&logical_rect, NULL); */ + if (cairo_glyphs != stack_glyphs) + g_free(cairo_glyphs); - return (logical_rect.width / PANGO_SCALE); -#endif + cairo_restore(cr); + return x_position / PANGO_SCALE; } + static int xtext_draw_layout_line(cairo_t *cr, gint x, gint y, GSList *runs) { while (runs) { - PangoLayoutRun *run = (PangoLayoutRun *)runs->data; + struct PangoCairoGlyphs *cg = runs->data; - cairo_move_to(cr, x, y); - pango_cairo_show_glyph_string(cr, run->item->analysis.font, run->glyphs); - - x += _pango_glyph_string_to_pixels(run->glyphs, run->item->analysis.font); + cairo_set_scaled_font(cr, cg->scfont); + x += _pango_cairo_renderer_draw_glyphs(cr, cg->glyphs, cg->num_glyphs, x, y); runs = runs->next; } return x; @@ -423,9 +565,9 @@ _pango_runs_width(GSList *runs) int width = 0; while (runs) { - PangoLayoutRun *run = (PangoLayoutRun *)runs->data; + const struct PangoCairoGlyphs *cg = runs->data; - width += _pango_glyph_string_to_pixels(run->glyphs, run->item->analysis.font); + width += _pango_glyph_string_to_pixels(cg); runs = runs->next; } return width; @@ -437,11 +579,11 @@ _pango_runs_free(GSList *runs) GSList *list = runs; while (list) { - PangoLayoutRun *run = (PangoLayoutRun *)list->data; - - pango_item_free(run->item); - pango_glyph_string_free(run->glyphs); - g_slice_free(PangoLayoutRun, run); + struct PangoCairoGlyphs *cg = list->data; + + g_object_unref(cg->font); + g_free(cg->glyphs); + g_slice_free(struct PangoCairoGlyphs, cg); list = list->next; } @@ -502,61 +644,31 @@ bytes_view_flush_render(BytesView *bv, void *data, int x, int y, const char *str } static int -_pango_runs_find_index(GSList *runs, int x_pos, const char *str) -{ - int start_pos = 0; - - while (runs) { - PangoLayoutRun *run = (PangoLayoutRun *)runs->data; - int width; - - width = _pango_glyph_string_to_pixels(run->glyphs, run->item->analysis.font); - - if (x_pos >= start_pos && x_pos < start_pos + width) { - gboolean char_trailing; - int pos; - - pango_glyph_string_x_to_index(run->glyphs, - (char *) str + run->item->offset, run->item->length, - &run->item->analysis, - (x_pos - start_pos) * PANGO_SCALE, - &pos, &char_trailing); - - return run->item->offset + pos; - } - - start_pos += width; - runs = runs->next; - } - return -1; -} - -static int bytes_view_flush_pos(BytesView *bv, void *data, int x, int search_x, const char *str, int len) { - int *pos_x = (int *)data; - GSList *line_runs; + int *pos_x = data; int line_width; + int i; if (len < 1) return 0; - line_runs = _pango_runs_build(bv, str, len); - - line_width = _pango_runs_width(line_runs); + line_width = 0; - if (x <= search_x && x + line_width > search_x) { - int off_x = search_x - x; - int pos_run; + for (i = 0; i < len; i++) { + const struct PangoCairoGlyphs *cg = &bv->glyphs[(int) str[i]]; + gboolean before_check, after_check; - if ((pos_run = _pango_runs_find_index(line_runs, off_x, str)) != -1) - *pos_x = (-*pos_x) + pos_run; + before_check = (x + line_width <= search_x); + line_width += _pango_glyph_string_to_pixels(cg); + after_check = (x + line_width <= search_x); - return -1; /* terminate */ - } else - *pos_x -= len; - - _pango_runs_free(line_runs); + if (before_check && !after_check) { + *pos_x = (-*pos_x) + i; + return -1; + } + } + *pos_x -= len; return line_width; } @@ -790,7 +902,7 @@ bytes_view_render(BytesView *bv, cairo_t *cr, GdkRectangle *area) if (!gtk_widget_get_realized(GTK_WIDGET(bv))) return; - bytes_view_ensure_layout(bv); + bytes_view_ensure_font(bv); #if GTK_CHECK_VERSION(3, 0, 0) width = gtk_widget_get_allocated_width(GTK_WIDGET(bv)); @@ -944,9 +1056,9 @@ bytes_view_adjustment_set(BytesView *bv) if (bv->vadj == NULL || bv->hadj == NULL) return; - if (bv->context == NULL) { - bytes_view_ensure_layout(bv); - /* bytes_view_ensure_layout will call bytes_view_adjustment_set() again */ + if (bv->font_changed) { + bytes_view_ensure_font(bv); + /* bytes_view_ensure_font will call bytes_view_adjustment_set() again */ return; } @@ -1303,7 +1415,7 @@ bytes_view_byte_from_xy(BytesView *bv, int x, int y) if (x < MARGIN) return -1; - bytes_view_ensure_layout(bv); + bytes_view_ensure_font(bv); char_y = (int) gtk_adjustment_get_value(bytes_view_ensure_vadj(bv)) + (y / bv->fontsize); off_y = char_y * bv->per_line; @@ -1366,11 +1478,8 @@ bytes_view_set_font(BytesView *bv, PangoFontDescription *font) bv->font = pango_font_description_copy(font); bv->max_width = 0; - if (bv->context) { - g_object_unref(bv->context); - bv->context = NULL; - bytes_view_ensure_layout(bv); - } + bv->font_changed = TRUE; + bytes_view_ensure_font(bv); } void
- Follow-Ups:
- Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- From: Reinhard Speyerer
- Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- References:
- Prev by Date: Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- Next by Date: Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- Previous by thread: Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- Next by thread: Re: [Wireshark-dev] Misaligned columns in hex dump pane with Wireshark 1.10.0rc2 and GTK+ 2.12.0
- Index(es):