1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library
3 *
4 * Copyright (C) 2000 Helix Code, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /* Various debugging routines. */
23
24 #include <config.h>
25 #include "gtkhtml-compat.h"
26
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "gtkhtml.h"
33 #include "htmlobject.h"
34 #include "htmltext.h"
35 #include "htmltextslave.h"
36 #include "htmltable.h"
37 #include "htmltablecell.h"
38 #include "htmlclue.h"
39 #include "htmlclueflow.h"
40 #include "htmlframe.h"
41 #include "htmlframeset.h"
42 #include "htmliframe.h"
43 #include "htmlengine.h"
44 #include "htmltype.h"
45 #include "htmlenums.h"
46 #include "htmlenumutils.h"
47
48 #include "gtkhtmldebug.h"
49
50
51 /**
52 * gtk_html_debug_log:
53 * @html: A GtkHTML widget
54 * @format: A format string, in printf() style
55 *
56 * If @html has debugging turned on, print out the message, just like libc
57 * printf(). Otherwise, just do nothing.
58 **/
59 void
gtk_html_debug_log(GtkHTML * html,const gchar * format,...)60 gtk_html_debug_log (GtkHTML *html,
61 const gchar *format,
62 ...)
63 {
64 va_list ap;
65
66 if (!html->debug)
67 return;
68
69 va_start (ap, format);
70 vprintf (format, ap);
71 }
72
73
74 static const gchar *
clueflow_style_to_string(HTMLClueFlowStyle style)75 clueflow_style_to_string (HTMLClueFlowStyle style)
76 {
77 switch (style) {
78 case HTML_CLUEFLOW_STYLE_NORMAL:
79 return "Normal";
80 case HTML_CLUEFLOW_STYLE_H1:
81 return "H1";
82 case HTML_CLUEFLOW_STYLE_H2:
83 return "H2";
84 case HTML_CLUEFLOW_STYLE_H3:
85 return "H3";
86 case HTML_CLUEFLOW_STYLE_H4:
87 return "H4";
88 case HTML_CLUEFLOW_STYLE_H5:
89 return "H5";
90 case HTML_CLUEFLOW_STYLE_H6:
91 return "H6";
92 case HTML_CLUEFLOW_STYLE_ADDRESS:
93 return "Address";
94 case HTML_CLUEFLOW_STYLE_PRE:
95 return "Pre";
96 case HTML_CLUEFLOW_STYLE_LIST_ITEM:
97 return "List Item";
98 default:
99 return "UNKNOWN";
100 }
101 }
102
103 static const gchar *
direction_to_string(HTMLDirection dir)104 direction_to_string (HTMLDirection dir)
105 {
106 switch (dir) {
107 case HTML_DIRECTION_DERIVED:
108 return "derived";
109 case HTML_DIRECTION_RTL:
110 return "rtl";
111 case HTML_DIRECTION_LTR:
112 return "ltr";
113 default:
114 return "UNKNOWN";
115 }
116 }
117
118
119 void
gtk_html_debug_dump_table(HTMLObject * o,gint level)120 gtk_html_debug_dump_table (HTMLObject *o,
121 gint level)
122 {
123 gint c, r;
124 HTMLTable *table = HTML_TABLE (o);
125
126 for (r = 0; r < table->totalRows; r++) {
127 for (c = 0; c < table->totalCols; c++) {
128 gtk_html_debug_dump_tree (HTML_OBJECT (table->cells[r][c]), level);
129 }
130 }
131
132 }
133
134 static void
gtk_html_debug_dump_table_simple(HTMLObject * o,gint level)135 gtk_html_debug_dump_table_simple (HTMLObject *o,
136 gint level)
137 {
138 gint c, r;
139 HTMLTable *table = HTML_TABLE (o);
140
141 for (r = 0; r < table->totalRows; r++) {
142 for (c = 0; c < table->totalCols; c++) {
143 gtk_html_debug_dump_tree_simple (HTML_OBJECT (table->cells[r][c]), level);
144 }
145 }
146
147 }
148
149 void
gtk_html_debug_dump_object(HTMLObject * obj,gint level)150 gtk_html_debug_dump_object (HTMLObject *obj,
151 gint level)
152 {
153 gint i;
154 for (i = 0; i < level; i++)
155 g_print (" ");
156
157 g_print ("ObjectType: %s Pos: %d, %d, MinWidth: %d, Width: %d PrefWidth: %d MaxWidth: %d Ascent %d Descent %d Direction %s",
158 html_type_name (HTML_OBJECT_TYPE (obj)),
159 obj->x, obj->y, obj->min_width, obj->width, obj->pref_width, obj->max_width, obj->ascent, obj->descent,
160 direction_to_string (html_object_get_direction (obj)));
161
162 if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_CLUEFLOW) {
163 g_print (" [%s, %d]",
164 clueflow_style_to_string (HTML_CLUEFLOW (obj)->style), HTML_CLUEFLOW (obj)->levels->len);
165 g_print (" levels: [");
166 for (i = 0; i < HTML_CLUEFLOW (obj)->levels->len; i++) {
167 g_print ("%d", HTML_CLUEFLOW (obj)->levels->data[i]);
168 if (i < HTML_CLUEFLOW (obj)->levels->len - 1)
169 g_print (" ");
170 }
171 g_print ("]");
172 }
173 else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TEXTSLAVE) {
174 GSList *cur;
175 gint width;
176 gint ii, io, tw, offset;
177 gchar *sl_text = g_strndup (html_text_get_text (HTML_TEXT (HTML_TEXT_SLAVE (obj)->owner),
178 HTML_TEXT_SLAVE (obj)->posStart),
179 html_text_get_index (HTML_TEXT (HTML_TEXT_SLAVE (obj)->owner),
180 HTML_TEXT_SLAVE (obj)->posStart
181 + HTML_TEXT_SLAVE (obj)->posLen)
182 - html_text_get_index (HTML_TEXT (HTML_TEXT_SLAVE (obj)->owner),
183 HTML_TEXT_SLAVE (obj)->posStart));
184 g_print ("[start %d end %d len %d] \"%s\"\n",
185 HTML_TEXT_SLAVE (obj)->posStart,
186 HTML_TEXT_SLAVE (obj)->posStart + HTML_TEXT_SLAVE (obj)->posLen - 1,
187 HTML_TEXT_SLAVE (obj)->posLen,
188 sl_text);
189 g_free (sl_text);
190
191 width = 0;
192 if (HTML_TEXT_SLAVE (obj)->glyph_items)
193 for (cur = HTML_TEXT_SLAVE (obj)->glyph_items; cur; cur = cur->next) {
194 HTMLTextSlaveGlyphItem *sgi = (HTMLTextSlaveGlyphItem *) cur->data;
195 PangoItem *item = sgi->glyph_item.item;
196 PangoRectangle log_rect;
197
198 pango_glyph_string_extents (sgi->glyph_item.glyphs, sgi->glyph_item.item->analysis.font, NULL, &log_rect);
199 g_print ("type: %d item level: %d offset: %d length: %d width: %d chars %d glyphs %d\n", sgi->type, item->analysis.level, item->offset, item->length, log_rect.width, item->num_chars, sgi->glyph_item.glyphs->num_glyphs);
200 width += log_rect.width;
201
202 }
203
204 g_print ("total width by glyph string extents (in engine units): %d\n", (gint)(0.5 + width / PANGO_SCALE));
205
206 ii = html_text_get_item_index (HTML_TEXT_SLAVE (obj)->owner, NULL, HTML_TEXT_SLAVE (obj)->posStart, &io);
207 tw = 0;
208 offset = 0;
209 while (offset < HTML_TEXT_SLAVE (obj)->posLen) {
210 tw += HTML_TEXT_SLAVE (obj)->owner->pi->entries[ii].widths[io];
211 g_print ("%d ", HTML_TEXT_SLAVE (obj)->owner->pi->entries[ii].widths[io]);
212 html_text_pi_forward (HTML_TEXT_SLAVE (obj)->owner->pi, &ii, &io);
213 offset++;
214 }
215
216 g_print ("\ntotal width by widths in entries (in engine units): %d", (gint)(0.5 + tw / PANGO_SCALE));
217 }
218
219 g_print ("\n");
220
221 switch (HTML_OBJECT_TYPE (obj)) {
222 case HTML_TYPE_TABLE:
223 gtk_html_debug_dump_table (obj, level + 1);
224 break;
225 case HTML_TYPE_TEXT:
226 case HTML_TYPE_LINKTEXT: {
227 HTMLText *text = HTML_TEXT (obj);
228 for (i = 0; i < level; i++)
229 g_print (" ");
230 g_print ("Text (len %d bytes %d): \"%s\"\n",
231 text->text_len, text->text_bytes, text->text);
232 /* debug_spell_errors (text->spell_errors); */
233 if (text->pi) {
234 for (i =0; i < text->pi->n; i++)
235 g_print ("item %d offset: %d length: %d\n", i, text->pi->entries[i].glyph_item.item->offset, text->pi->entries[i].glyph_item.item->length);
236
237 for (i = 0; i < text->text_len; i++) {
238 union {
239 PangoLogAttr attr;
240 guint as_int;
241 } u;
242 u.attr = text->pi->attrs[i];
243 g_print ("log attrs[%d]: %d\n\t", i, u.as_int & 0x7ff);
244 if (u.attr.is_line_break)
245 g_print ("line break, ");
246 if (u.attr.is_mandatory_break)
247 g_print ("mandatory break, ");
248 if (u.attr.is_char_break)
249 g_print ("char break, ");
250 if (u.attr.is_white)
251 g_print ("white, ");
252 if (u.attr.is_cursor_position)
253 g_print ("cursor position, ");
254 if (u.attr.is_word_start)
255 g_print ("word start, ");
256 if (u.attr.is_word_end)
257 g_print ("word end, ");
258 if (u.attr.is_sentence_boundary)
259 g_print ("sentence boundary, ");
260 if (u.attr.is_sentence_start)
261 g_print ("sentence start, ");
262 if (u.attr.is_sentence_end)
263 g_print ("sentence end, ");
264 g_print ("\n");
265 }
266 }
267 gtk_html_debug_list_links (text);
268 gtk_html_debug_list_text_attrs (text);
269 break;
270 }
271 case HTML_TYPE_CLUEV:
272 g_print ("Direction: %s\n", direction_to_string (HTML_CLUEV (obj)->dir));
273 case HTML_TYPE_CLUEH:
274 case HTML_TYPE_CLUEFLOW:
275 /* g_print ("Head: %p Tail: %p\n", HTML_CLUE (obj)->head, HTML_CLUE (obj)->tail); */
276 case HTML_TYPE_CLUEALIGNED:
277 case HTML_TYPE_TABLECELL:
278 for (i = 0; i < level; i++) g_print (" ");
279 g_print ("HAlign: %s VAlign: %s\n",
280 html_halign_name (HTML_CLUE (obj)->halign),
281 html_valign_name (HTML_CLUE (obj)->valign));
282 gtk_html_debug_dump_tree (HTML_CLUE (obj)->head, level + 1);
283 break;
284 case HTML_TYPE_IFRAME:
285 gtk_html_debug_dump_tree (GTK_HTML (HTML_IFRAME (obj)->html)->engine->clue, level + 1);
286 break;
287 case HTML_TYPE_FRAME:
288 gtk_html_debug_dump_tree (GTK_HTML (HTML_FRAME (obj)->html)->engine->clue, level + 1);
289 break;
290 case HTML_TYPE_IMAGE:
291 for (i = 0; i < level; i++) g_print (" ");
292 g_print ("Location: %s\n", HTML_IMAGE (obj)->image_ptr->url);
293 break;
294 case HTML_TYPE_FRAMESET: {
295 for (i = 0; i < HTML_FRAMESET (obj)->frames->len; i++)
296 gtk_html_debug_dump_tree (g_ptr_array_index (HTML_FRAMESET (obj)->frames, i), level + 1);
297 }
298 break;
299 default:
300 break;
301 }
302 }
303
304 void
gtk_html_debug_dump_tree(HTMLObject * o,gint level)305 gtk_html_debug_dump_tree (HTMLObject *o,
306 gint level)
307 {
308 HTMLObject *obj;
309
310 obj = o;
311 while (obj) {
312 gtk_html_debug_dump_object (obj, level);
313 obj = obj->next;
314 }
315 }
316
317 static void
dump_data(GQuark key_id,gpointer data,gpointer user_data)318 dump_data (GQuark key_id,
319 gpointer data,
320 gpointer user_data)
321 {
322 gint i, level = GPOINTER_TO_INT (user_data);
323
324 for (i = 0; i < level; i++)
325 g_print ("\t");
326
327 printf ("%s: '%s'\n", g_quark_to_string (key_id), (gchar *) data);
328 }
329
330 static void
dump_object_simple(HTMLObject * obj,gint level)331 dump_object_simple (HTMLObject *obj,
332 gint level)
333 {
334 gint i;
335
336 for (i = 0; i < level; i++)
337 g_print ("\t");
338
339 if (html_object_is_text (obj)) {
340 HTMLText *text = HTML_TEXT (obj);
341 g_print ("%s `%s'\n",
342 html_type_name (HTML_OBJECT_TYPE (obj)),
343 text->text);
344 /* g_print ("len %d bytes %d\n", text->text_len, text->text_bytes); */
345 } else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TEXTSLAVE) {
346 HTMLTextSlave *slave = HTML_TEXT_SLAVE (obj);
347 gchar *text;
348
349 text = alloca (slave->posLen + 1);
350 text[slave->posLen] = 0;
351 strncpy (text, slave->owner->text + slave->posStart, slave->posLen);
352 g_print ("%s `%s'\n",
353 html_type_name (HTML_OBJECT_TYPE (obj)),
354 text);
355 } else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TABLECELL) {
356 g_print ("%s %d,%d\n", html_type_name (HTML_OBJECT_TYPE (obj)),
357 HTML_TABLE_CELL (obj)->row, HTML_TABLE_CELL (obj)->col);
358 } else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TABLE) {
359 g_print ("%s %d,%d\n", html_type_name (HTML_OBJECT_TYPE (obj)),
360 HTML_TABLE (obj)->totalRows, HTML_TABLE (obj)->totalCols);
361 } else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_IFRAME) {
362 g_print ("%s\n", html_type_name (HTML_OBJECT_TYPE (obj)));
363 gtk_html_debug_dump_tree_simple (GTK_HTML (HTML_IFRAME (obj)->html)->engine->clue, level + 1);
364 } else if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_FRAME) {
365 g_print ("%s\n", html_type_name (HTML_OBJECT_TYPE (obj)));
366 gtk_html_debug_dump_tree_simple (GTK_HTML (HTML_FRAME (obj)->html)->engine->clue, level + 1);
367 } else
368 g_print ("%s\n", html_type_name (HTML_OBJECT_TYPE (obj)));
369
370 if (obj->object_data)
371 g_datalist_foreach (&obj->object_data, dump_data, GINT_TO_POINTER (level));
372 }
373
374 void
gtk_html_debug_dump_object_type(HTMLObject * o)375 gtk_html_debug_dump_object_type (HTMLObject *o)
376 {
377 dump_object_simple (o, 0);
378 }
379
380 void
gtk_html_debug_dump_tree_simple(HTMLObject * o,gint level)381 gtk_html_debug_dump_tree_simple (HTMLObject *o,
382 gint level)
383 {
384 HTMLObject *obj;
385
386 for (obj = o; obj != NULL; obj = obj->next) {
387 if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TEXTSLAVE)
388 continue;
389
390 dump_object_simple (obj, level);
391
392 switch (HTML_OBJECT_TYPE (obj)) {
393 case HTML_TYPE_CLUEH:
394 case HTML_TYPE_CLUEV:
395 case HTML_TYPE_CLUEFLOW:
396 case HTML_TYPE_CLUEALIGNED:
397 case HTML_TYPE_TABLECELL:
398 gtk_html_debug_dump_tree_simple (HTML_CLUE (obj)->head, level + 1);
399 break;
400 case HTML_TYPE_TABLE:
401 gtk_html_debug_dump_table_simple (obj, level + 1);
402 break;
403 default:
404 break;
405 }
406 }
407 }
408
409 void
gtk_html_debug_dump_list_simple(GList * list,gint level)410 gtk_html_debug_dump_list_simple (GList *list,
411 gint level)
412 {
413 HTMLObject *obj;
414 GList *p;
415
416 for (p = list; p != NULL; p = p->next) {
417 obj = HTML_OBJECT (p->data);
418
419 if (HTML_OBJECT_TYPE (obj) == HTML_TYPE_TEXTSLAVE)
420 continue;
421
422 dump_object_simple (obj, level);
423 }
424 }
425
426 #define D_ATTR_TYPE(x, s) if ((attr = pango_attr_iterator_get (iter, PANGO_ATTR_ ## x))) g_print ("%3d-%3d: %s\n", attr->start_index, attr->end_index, s);
427 #define D_ATTR_TYPE_INT(x, s) if ((attr = pango_attr_iterator_get (iter, PANGO_ATTR_ ## x))) { g_print ("%3d-%3d: %s %d\n", attr->start_index, attr->end_index, s, ((PangoAttrInt *)attr)->value); }
428
429 static void
gtk_html_debug_list_attrs(PangoAttrList * attrs)430 gtk_html_debug_list_attrs (PangoAttrList *attrs)
431 {
432 PangoAttrIterator *iter = pango_attr_list_get_iterator (attrs);
433 PangoAttribute *attr;
434
435 do {
436 D_ATTR_TYPE (INVALID, "Invalid");
437 D_ATTR_TYPE (LANGUAGE, "Language");
438 D_ATTR_TYPE (FAMILY, "Family");
439 D_ATTR_TYPE (STYLE, "Style");
440 D_ATTR_TYPE (WEIGHT, "Weight");
441 D_ATTR_TYPE (VARIANT, "Variant");
442 D_ATTR_TYPE (STRETCH, "Stretch");
443 D_ATTR_TYPE_INT (SIZE, "Size");
444 D_ATTR_TYPE (FONT_DESC, "Font Desc");
445 D_ATTR_TYPE (FOREGROUND, "Foreground");
446 D_ATTR_TYPE (BACKGROUND, "Background");
447 D_ATTR_TYPE (UNDERLINE, "Underline");
448 D_ATTR_TYPE (STRIKETHROUGH, "Strikethrough");
449 D_ATTR_TYPE (RISE, "Rise");
450 D_ATTR_TYPE (SHAPE, "Shape");
451 D_ATTR_TYPE (SCALE, "Scale");
452 g_print ("------------\n");
453 } while (pango_attr_iterator_next (iter));
454
455 pango_attr_iterator_destroy (iter);
456 }
457
458 void
gtk_html_debug_list_text_attrs(HTMLText * text)459 gtk_html_debug_list_text_attrs (HTMLText *text)
460 {
461 gtk_html_debug_list_attrs (text->attr_list);
462 }
463
464 void
gtk_html_debug_list_links(HTMLText * text)465 gtk_html_debug_list_links (HTMLText *text)
466 {
467 GSList *l;
468
469 for (l = text->links; l; l = l->next)
470 if (l->data) {
471 Link *link = (Link *) l->data;
472
473 g_print ("%d-%d(%d-%d): %s#%s\n", link->start_offset, link->end_offset, link->start_index, link->end_index, link->url, link->target);
474 }
475 }
476