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