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) 1997 Martin Jones (mjones@kde.org)
5 * Copyright (C) 1997 Torben Weis (weis@kde.org)
6 * Copyright (C) 1999 Anders Carlsson (andersca@gnu.org)
7 * Copyright (C) 2000 Helix Code, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "gtkhtmldebug.h"
30 #include "htmlcolor.h"
31 #include "htmlcolorset.h"
32 #include "htmlengine.h"
33 #include "htmlengine-edit.h"
34 #include "htmlengine-edit-table.h"
35 #include "htmlengine-save.h"
36 #include "htmlimage.h"
37 #include "htmlpainter.h"
38 #include "htmlplainpainter.h"
39 #include "htmlsearch.h"
40 #include "htmltable.h"
41 #include "htmltablepriv.h"
42 #include "htmltablecell.h"
43
44 /* #define GTKHTML_DEBUG_TABLE */
45
46 #define COLUMN_MIN(table, i) \
47 (g_array_index (table->columnMin, gint, i))
48
49 #define COLUMN_PREF(table, i) \
50 (g_array_index (table->columnPref, gint, i))
51
52 #define COLUMN_FIX(table, i) \
53 (g_array_index (table->columnFixed, gint, i))
54
55 #define COLUMN_OPT(table, i) \
56 (g_array_index (table->columnOpt, gint, i))
57
58 #define ROW_HEIGHT(table, i) \
59 (g_array_index (table->rowHeights, gint, i))
60
61
62 HTMLTableClass html_table_class;
63 static HTMLObjectClass *parent_class = NULL;
64
65 static void do_cspan (HTMLTable *table, gint row, gint col, HTMLTableCell *cell);
66 static void do_rspan (HTMLTable *table, gint row);
67
68 static void html_table_set_max_width (HTMLObject *o, HTMLPainter *painter, gint max_width);
69
70
71
72 static inline gboolean
invalid_cell(HTMLTable * table,gint r,gint c)73 invalid_cell (HTMLTable *table,
74 gint r,
75 gint c)
76 {
77 return (table->cells[r][c] == NULL
78 || c != table->cells[r][c]->col
79 || r != table->cells[r][c]->row);
80 }
81
82 /* HTMLObject methods. */
83
84 static void
destroy(HTMLObject * o)85 destroy (HTMLObject *o)
86 {
87 HTMLTable *table = HTML_TABLE (o);
88 HTMLTableCell *cell;
89 guint r, c;
90
91 if (table->allocRows && table->totalCols)
92 for (r = table->allocRows - 1; ; r--) {
93 for (c = table->totalCols - 1; ; c--) {
94 if ((cell = table->cells[r][c]) && cell->row == r && cell->col == c)
95 html_object_destroy (HTML_OBJECT (cell));
96 if (c == 0)
97 break;
98 }
99 g_free (table->cells[r]);
100 if (r == 0)
101 break;
102 }
103 g_free (table->cells);
104
105 g_array_free (table->columnMin, TRUE);
106 g_array_free (table->columnPref, TRUE);
107 g_array_free (table->columnOpt, TRUE);
108 g_array_free (table->columnFixed, TRUE);
109 g_array_free (table->rowHeights, TRUE);
110
111 if (table->bgColor)
112 gdk_color_free (table->bgColor);
113 if (table->bgPixmap)
114 html_image_factory_unregister (table->bgPixmap->factory, table->bgPixmap, NULL);
115
116 HTML_OBJECT_CLASS (parent_class)->destroy (o);
117 }
118
119 static void
copy_sized(HTMLObject * self,HTMLObject * dest,gint rows,gint cols)120 copy_sized (HTMLObject *self,
121 HTMLObject *dest,
122 gint rows,
123 gint cols)
124 {
125 HTMLTable *d = HTML_TABLE (dest);
126 HTMLTable *s = HTML_TABLE (self);
127 gint r;
128
129 memcpy (dest, self, sizeof (HTMLTable));
130 (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);
131
132 d->bgColor = s->bgColor ? gdk_color_copy (s->bgColor) : NULL;
133 d->caption = s->caption ? HTML_CLUEV (html_object_dup (HTML_OBJECT (s->caption))) : NULL;
134 d->bgPixmap = s->bgPixmap ? html_image_factory_register (s->bgPixmap->factory, NULL, s->bgPixmap->url, FALSE) : NULL;
135
136 d->columnMin = g_array_new (FALSE, FALSE, sizeof (gint));
137 d->columnFixed = g_array_new (FALSE, FALSE, sizeof (gint));
138 d->columnPref = g_array_new (FALSE, FALSE, sizeof (gint));
139 d->columnOpt = g_array_new (FALSE, FALSE, sizeof (gint));
140 d->rowHeights = g_array_new (FALSE, FALSE, sizeof (gint));
141
142 d->totalCols = cols;
143 d->totalRows = rows;
144 d->allocRows = rows;
145
146 d->cells = g_new (HTMLTableCell **, rows);
147 for (r = 0; r < rows; r++)
148 d->cells[r] = g_new0 (HTMLTableCell *, cols);
149
150 dest->change = HTML_CHANGE_ALL_CALC;
151 }
152
153 static void
copy(HTMLObject * self,HTMLObject * dest)154 copy (HTMLObject *self,
155 HTMLObject *dest)
156 {
157 copy_sized (self, dest, HTML_TABLE (self)->totalRows, HTML_TABLE (self)->totalCols);
158 }
159
160 static HTMLObject * op_copy (HTMLObject *self, HTMLObject *parent, HTMLEngine *e, GList *from, GList *to, guint *len);
161
162 static HTMLObject *
copy_as_leaf(HTMLObject * self,HTMLObject * parent,HTMLEngine * e,GList * from,GList * to,guint * len)163 copy_as_leaf (HTMLObject *self,
164 HTMLObject *parent,
165 HTMLEngine *e,
166 GList *from,
167 GList *to,
168 guint *len)
169 {
170 if ((!from || GPOINTER_TO_INT (from->data) == 0)
171 && (!to || GPOINTER_TO_INT (to->data) == html_object_get_length (self)))
172 return op_copy (self, parent, e, NULL, NULL, len);
173 else
174 return html_engine_new_text_empty (e);
175 }
176
177 static HTMLObject *
op_copy(HTMLObject * self,HTMLObject * parent,HTMLEngine * e,GList * from,GList * to,guint * len)178 op_copy (HTMLObject *self,
179 HTMLObject *parent,
180 HTMLEngine *e,
181 GList *from,
182 GList *to,
183 guint *len)
184 {
185 HTMLTableCell *start, *end;
186 HTMLTable *nt, *t;
187 gint r, c, rows, cols, start_col;
188
189 g_assert (HTML_IS_TABLE (self));
190
191 if ((from || to)
192 && (!from || !from->next)
193 && (!to || !to->next))
194 return copy_as_leaf (self, parent, e, from, to, len);
195
196 t = HTML_TABLE (self);
197 nt = g_new0 (HTMLTable, 1);
198
199 start = HTML_TABLE_CELL ((from && from->next) ? from->data : html_object_head (self));
200 end = HTML_TABLE_CELL ((to && to->next) ? to->data : html_object_tail (self));
201
202 if (!start || !end) {
203 copy_sized (self, HTML_OBJECT (nt), 0, 0);
204 (*len) ++;
205 return HTML_OBJECT (nt);
206 }
207
208 rows = end->row - start->row + 1;
209 cols = end->row == start->row ? end->col - start->col + 1 : t->totalCols;
210
211 copy_sized (self, HTML_OBJECT (nt), rows, cols);
212
213 start_col = end->row == start->row ? start->col : 0;
214
215 #ifdef GTKHTML_DEBUG_TABLE
216 printf ("cols: %d rows: %d\n", cols, rows);
217 #endif
218 for (r = 0; r < rows; r++)
219 for (c = 0; c < cols; c++) {
220 HTMLTableCell *cell = t->cells[start->row + r][c + start_col];
221
222 if (!cell || (end->row != start->row
223 && ((r == 0 && c < start->col) || (r == rows - 1 && c > end->col)))) {
224 html_table_set_cell (nt, r, c, html_engine_new_cell (e, nt));
225 html_table_cell_set_position (nt->cells[r][c], r, c);
226 } else {
227 if (cell->row == r + start->row && cell->col == c + start_col) {
228 HTMLTableCell *cell_copy;
229 cell_copy = HTML_TABLE_CELL
230 (html_object_op_copy (HTML_OBJECT (cell), HTML_OBJECT (nt), e,
231 html_object_get_bound_list (HTML_OBJECT (cell), from),
232 html_object_get_bound_list (HTML_OBJECT (cell), to),
233 len));
234 html_table_set_cell (nt, r, c, cell_copy);
235 html_table_cell_set_position (cell_copy, r, c);
236 } else {
237 if (cell->row - start->row >= 0 && cell->col - start_col >= 0) {
238 nt->cells[r][c] = nt->cells[cell->row - start->row][cell->col - start_col];
239 } else {
240 html_table_set_cell (nt, r, c, html_engine_new_cell (e, nt));
241 html_table_cell_set_position (nt->cells[r][c], r, c);
242 }
243 }
244 }
245 (*len) ++;
246 }
247 (*len) ++;
248
249 #ifdef GTKHTML_DEBUG_TABLE
250 printf ("copy end: %d\n", *len);
251 #endif
252
253 return HTML_OBJECT (nt);
254 }
255
256 static gint
get_n_children(HTMLObject * self)257 get_n_children (HTMLObject *self)
258 {
259 HTMLTable *t = HTML_TABLE (self);
260 guint r, c, n_children = 0;
261
262 for (r = 0; r < t->totalRows; r++)
263 for (c = 0; c < t->totalCols; c++)
264 if (t->cells[r][c] && t->cells[r][c]->row == r && t->cells[r][c]->col == c)
265 n_children++;
266
267 /* printf ("table n_children %d\n", n_children); */
268
269 return n_children;
270 }
271
272 static HTMLObject *
get_child(HTMLObject * self,gint index)273 get_child (HTMLObject *self,
274 gint index)
275 {
276 HTMLTable *t = HTML_TABLE (self);
277 HTMLObject *child = NULL;
278 guint r, c, n = 0;
279
280 for (r = 0; r < t->totalRows && !child; r++)
281 for (c = 0; c < t->totalCols; c++)
282 if (t->cells[r][c] && t->cells[r][c]->row == r && t->cells[r][c]->col == c) {
283 if (n == index) {
284 child = HTML_OBJECT (t->cells[r][c]);
285 break;
286 }
287 n++;
288 }
289
290 /* printf ("table ref %d child %p\n", index, child); */
291
292 return child;
293 }
294
295 static gint
get_child_index(HTMLObject * self,HTMLObject * child)296 get_child_index (HTMLObject *self,
297 HTMLObject *child)
298 {
299 HTMLTable *t = HTML_TABLE (self);
300 guint r, c;
301 gint n = 0;
302
303 for (r = 0; r < t->totalRows; r++)
304 for (c = 0; c < t->totalCols; c++) {
305 if (t->cells[r][c] && t->cells[r][c]->row == r && t->cells[r][c]->col == c) {
306 if (HTML_OBJECT (t->cells[r][c]) == child) {
307 /* printf ("table child %p index %d\n", child, n); */
308 return n;
309 }
310 n++;
311 }
312 }
313
314 /* printf ("table child %p index %d\n", child, -1); */
315
316 return -1;
317 }
318
319 static guint
get_recursive_length(HTMLObject * self)320 get_recursive_length (HTMLObject *self)
321 {
322 HTMLTable *t = HTML_TABLE (self);
323 guint r, c, len = 0;
324
325 for (r = 0; r < t->totalRows; r++)
326 for (c = 0; c < t->totalCols; c++)
327 if (t->cells[r][c] && t->cells[r][c]->row == r && t->cells[r][c]->col == c)
328 len += html_object_get_recursive_length (HTML_OBJECT (t->cells[r][c])) + 1;
329
330 /* if (len > 0)
331 * len--; */
332 len++;
333 return len;
334 }
335
336 static void
remove_cell(HTMLTable * t,HTMLTableCell * cell)337 remove_cell (HTMLTable *t,
338 HTMLTableCell *cell)
339 {
340 gint r, c;
341
342 g_return_if_fail (t);
343 g_return_if_fail (HTML_IS_TABLE (t));
344 g_return_if_fail (cell);
345 g_return_if_fail (HTML_IS_TABLE_CELL (cell));
346
347 #ifdef GTKHTML_DEBUG_TABLE
348 printf ("remove cell: %d,%d %d,%d %d,%d\n",
349 cell->row, cell->col, cell->rspan, cell->cspan, t->totalCols, t->totalRows);
350 #endif
351
352 for (r = 0; r < cell->rspan && r + cell->row < t->totalRows; r++)
353 for (c = 0; c < cell->cspan && c + cell->col < t->totalCols; c++) {
354
355 #ifdef GTKHTML_DEBUG_TABLE
356 printf ("clear: %d,%d (%d,%d) %d,%d\n",
357 cell->row + r, cell->col + c, cell->rspan, cell->cspan, r, c);
358 #endif
359
360 t->cells[cell->row + r][cell->col + c] = NULL;
361 }
362 HTML_OBJECT (cell)->parent = NULL;
363 }
364
365 static HTMLObject *
cut_whole(HTMLObject * self,guint * len)366 cut_whole (HTMLObject *self,
367 guint *len)
368 {
369 if (self->parent)
370 html_object_remove_child (self->parent, self);
371 *len = html_object_get_recursive_length (self) + 1;
372
373 #ifdef GTKHTML_DEBUG_TABLE
374 printf ("removed whole table len: %d\n", *len);
375 #endif
376 return self;
377 }
378
379 static HTMLObject *
cut_partial(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len)380 cut_partial (HTMLObject *self,
381 HTMLEngine *e,
382 GList *from,
383 GList *to,
384 GList *left,
385 GList *right,
386 guint *len)
387 {
388 HTMLObject *rv;
389
390 HTMLTableCell *start, *end, *cell;
391 HTMLTable *t, *nt;
392 gint r, c;
393 gint start_row, start_col, end_row, end_col;
394
395 #ifdef GTKHTML_DEBUG_TABLE
396 printf ("partial cut\n");
397 #endif
398 start = HTML_TABLE_CELL (from && from->next ? from->data : html_object_head (self));
399 end = HTML_TABLE_CELL (to && to->next ? to->data : html_object_tail (self));
400
401 start_row = start->row;
402 start_col = start->col;
403 end_row = end->row;
404 end_col = end->col;
405
406 t = HTML_TABLE (self);
407 rv = HTML_OBJECT (g_new0 (HTMLTable, 1));
408 nt = HTML_TABLE (rv);
409 copy_sized (self, rv, t->totalRows, t->totalCols);
410
411 for (r = 0; r < t->totalRows; r++) {
412 for (c = 0; c < t->totalCols; c++) {
413 cell = t->cells[r][c];
414 if (cell && cell->row == r && cell->col == c) {
415 if (((r == start_row && c < start_col) || r < start_row)
416 || ((r == end_row && c > end_col) || r > end_row)) {
417 html_table_set_cell (nt, r, c, html_engine_new_cell (e, nt));
418 html_table_cell_set_position (nt->cells[r][c], r, c);
419 } else {
420 HTMLTableCell *cell_cut;
421
422 cell_cut = HTML_TABLE_CELL
423 (html_object_op_cut
424 (HTML_OBJECT (cell), e,
425 html_object_get_bound_list (HTML_OBJECT (cell), from),
426 html_object_get_bound_list (HTML_OBJECT (cell), to),
427 left ? left->next : NULL, right ? right->next : NULL, len));
428 html_table_set_cell (nt, r, c, cell_cut);
429 html_table_cell_set_position (cell_cut, r, c);
430
431 if (t->cells[r][c] == NULL) {
432 html_table_set_cell (t, r, c, html_engine_new_cell (e, t));
433 html_table_cell_set_position (t->cells[r][c], r, c);
434 }
435 }
436 (*len) ++;
437 }
438 }
439 }
440 (*len) ++;
441
442 #ifdef GTKHTML_DEBUG_TABLE
443 printf ("removed partial table len: %d\n", *len);
444 gtk_html_debug_dump_tree_simple (rv, 0);
445 #endif
446
447 return rv;
448 }
449
450 static HTMLObject *
op_cut(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len)451 op_cut (HTMLObject *self,
452 HTMLEngine *e,
453 GList *from,
454 GList *to,
455 GList *left,
456 GList *right,
457 guint *len)
458 {
459 if ((!from || !from->next) && (!to || !to->next))
460 return (*parent_class->op_cut) (self, e, from, to, left, right, len);
461
462 if (from || to)
463 return cut_partial (self, e, from, to, left, right, len);
464 else
465 return cut_whole (self, len);
466 }
467
468 static void
split(HTMLObject * self,HTMLEngine * e,HTMLObject * child,gint offset,gint level,GList ** left,GList ** right)469 split (HTMLObject *self,
470 HTMLEngine *e,
471 HTMLObject *child,
472 gint offset,
473 gint level,
474 GList **left,
475 GList **right)
476 {
477 HTMLObject *dup;
478 HTMLTable *t = HTML_TABLE (self);
479 HTMLTable *dup_table;
480 HTMLTableCell *dup_cell;
481 HTMLTableCell *cell;
482 gint r, c;
483
484 if (*left == NULL && *right == NULL) {
485 (*parent_class->split)(self, e, child, offset, level, left, right);
486 return;
487 }
488
489 dup_cell = HTML_TABLE_CELL ((*right)->data);
490 cell = HTML_TABLE_CELL ((*left)->data);
491
492 if (dup_cell->row == t->totalRows - 1 && dup_cell->col == t->totalCols - 1 && html_clue_is_empty (HTML_CLUE (dup_cell))) {
493 dup = html_engine_new_text_empty (e);
494 html_object_destroy ((*right)->data);
495 g_list_free (*right);
496 *right = NULL;
497 } else {
498
499 #ifdef GTKHTML_DEBUG_TABLE
500 printf ("before split\n");
501 printf ("-- self --\n");
502 gtk_html_debug_dump_tree_simple (self, 0);
503 printf ("-- child --\n");
504 gtk_html_debug_dump_tree_simple (child, 0);
505 printf ("-- child end --\n");
506 #endif
507
508 dup = HTML_OBJECT (g_new0 (HTMLTable, 1));
509 dup_table = HTML_TABLE (dup);
510 copy_sized (self, dup, t->totalRows, t->totalCols);
511 for (r = 0; r < t->totalRows; r++) {
512 for (c = 0; c < t->totalCols; c++) {
513 HTMLTableCell *cc;
514
515 cc = t->cells[r][c];
516 if (cc && cc->row == r && cc->col == c) {
517 if ((r == cell->row && c < cell->col) || r < cell->row) {
518 /* empty cell in dup table */
519 html_table_set_cell (dup_table, r, c, html_engine_new_cell (e, dup_table));
520 html_table_cell_set_position (dup_table->cells[r][c], r, c);
521 } else if ((r == dup_cell->row && c > dup_cell->col) || r > dup_cell->row) {
522 /* move cc to dup table */
523 remove_cell (t, cc);
524 html_table_set_cell (dup_table, r, c, cc);
525 html_table_cell_set_position (dup_table->cells[r][c], r, c);
526 /* place empty cell in t table */
527 html_table_set_cell (t, r, c, html_engine_new_cell (e, t));
528 html_table_cell_set_position (t->cells[r][c], r, c);
529
530 } else {
531 if (r == cell->row && c == cell->col) {
532 if (r != dup_cell->row || c != dup_cell->col) {
533 /* empty cell in dup table */
534 html_table_set_cell (dup_table, r, c,
535 html_engine_new_cell (e, dup_table));
536 html_table_cell_set_position (dup_table->cells[r][c], r, c);
537 }
538
539 }
540 if (r == dup_cell->row && c == dup_cell->col) {
541 /* dup_cell to dup table */
542 if ((r != cell->row || c != cell->col)
543 && HTML_OBJECT (dup_cell)->parent == self)
544 remove_cell (t, cell);
545
546 html_table_set_cell (dup_table, r, c, dup_cell);
547 html_table_cell_set_position (dup_table->cells[r][c], r, c);
548
549 if (r != cell->row || c != cell->col) {
550 /* empty cell in orig table */
551 html_table_set_cell (t, r, c, html_engine_new_cell (e, t));
552 html_table_cell_set_position (t->cells[r][c], r, c);
553 }
554 }
555 }
556 }
557 }
558 }
559 }
560 html_clue_append_after (HTML_CLUE (self->parent), dup, self);
561
562 *left = g_list_prepend (*left, self);
563 *right = g_list_prepend (*right, dup);
564
565 html_object_change_set (self, HTML_CHANGE_ALL_CALC);
566 html_object_change_set (dup, HTML_CHANGE_ALL_CALC);
567
568 #ifdef GTKHTML_DEBUG_TABLE
569 printf ("after split\n");
570 printf ("-- self --\n");
571 gtk_html_debug_dump_tree_simple (self, 0);
572 printf ("-- dup --\n");
573 gtk_html_debug_dump_tree_simple (dup, 0);
574 printf ("-- end split --\n");
575 #endif
576
577 level--;
578 if (level)
579 html_object_split (self->parent, e, dup, 0, level, left, right);
580 }
581
582 static gboolean
could_merge(HTMLTable * t1,HTMLTable * t2)583 could_merge (HTMLTable *t1,
584 HTMLTable *t2)
585 {
586 gint r, c;
587 gboolean first = TRUE;
588
589 if (t1->specified_width != t2->specified_width
590 || t1->spacing != t2->spacing
591 || t1->padding != t2->padding
592 || t1->border != t2->border
593 || t1->capAlign != t2->capAlign
594 || (t1->bgColor && t2->bgColor && !gdk_color_equal (t1->bgColor, t2->bgColor))
595 || (t1->bgColor && !t2->bgColor) || (!t1->bgColor && t2->bgColor)
596 || t1->bgPixmap != t2->bgPixmap
597 || t1->totalCols != t2->totalCols || t1->totalRows != t2->totalRows)
598 return FALSE;
599
600 for (r = 0; r < t1->totalRows; r++) {
601 for (c = 0; c < t1->totalCols; c++) {
602 HTMLTableCell *c1, *c2;
603
604 c1 = t1->cells[r][c];
605 c2 = t2->cells[r][c];
606 if (!c1 || !c2)
607 return FALSE;
608
609 if (first) {
610 if (!html_clue_is_empty (HTML_CLUE (c2)))
611 first = FALSE;
612 } else {
613 if (!html_clue_is_empty (HTML_CLUE (c1)))
614 return FALSE;
615 }
616 }
617 }
618
619 return TRUE;
620 }
621
622 static HTMLTableCell *
object_get_parent_cell(HTMLObject * o,HTMLObject * parent_table)623 object_get_parent_cell (HTMLObject *o,
624 HTMLObject *parent_table)
625 {
626 while (o) {
627 if (o->parent == parent_table)
628 return HTML_TABLE_CELL (o);
629 o = o->parent;
630 }
631
632 return NULL;
633 }
634
635 static void
update_cursor(HTMLCursor * cursor,HTMLTableCell * c)636 update_cursor (HTMLCursor *cursor,
637 HTMLTableCell *c)
638 {
639 cursor->object = html_object_get_head_leaf (HTML_OBJECT (c));
640 cursor->offset = 0;
641 }
642
643 static void
move_cell(HTMLTable * t1,HTMLTable * t2,HTMLTableCell * c1,HTMLTableCell * c2,HTMLTableCell * cursor_cell_1,HTMLTableCell * cursor_cell_2,gint r,gint c,HTMLCursor * cursor_1,HTMLCursor * cursor_2)644 move_cell (HTMLTable *t1,
645 HTMLTable *t2,
646 HTMLTableCell *c1,
647 HTMLTableCell *c2,
648 HTMLTableCell *cursor_cell_1,
649 HTMLTableCell *cursor_cell_2,
650 gint r,
651 gint c,
652 HTMLCursor *cursor_1,
653 HTMLCursor *cursor_2)
654 {
655 if (cursor_1 && cursor_cell_1 == c1)
656 update_cursor (cursor_1, c2);
657 if (cursor_2 && cursor_cell_2 == c1)
658 update_cursor (cursor_2, c2);
659 remove_cell (t1, c1);
660 html_object_destroy (HTML_OBJECT (c1));
661 remove_cell (t2, c2);
662 html_table_set_cell (t1, r, c, c2);
663 html_table_cell_set_position (t1->cells[r][c], r, c);
664 }
665
666 static gboolean
merge(HTMLObject * self,HTMLObject * with,HTMLEngine * e,GList ** left,GList ** right,HTMLCursor * cursor)667 merge (HTMLObject *self,
668 HTMLObject *with,
669 HTMLEngine *e,
670 GList **left,
671 GList **right,
672 HTMLCursor *cursor)
673 {
674 HTMLTable *t1 = HTML_TABLE (self);
675 HTMLTable *t2 = HTML_TABLE (with);
676 HTMLTableCell *cursor_cell_1 = NULL;
677 HTMLTableCell *cursor_cell_2 = NULL;
678 HTMLTableCell *cursor_cell_3 = NULL;
679 HTMLTableCell *prev_c1 = NULL;
680 HTMLTableCell *t1_tail = NULL;
681 gint r, c;
682 gboolean first = TRUE;
683 gboolean cursor_in_t2;
684
685 #ifdef GTKHTML_DEBUG_TABLE
686 printf ("before merge\n");
687 printf ("-- self --\n");
688 gtk_html_debug_dump_tree_simple (self, 0);
689 printf ("-- with --\n");
690 gtk_html_debug_dump_tree_simple (with, 0);
691 printf ("-- end with --\n");
692 #endif
693
694 if (!could_merge (t1, t2))
695 return FALSE;
696
697 g_list_free (*left);
698 *left = NULL;
699 g_list_free (*right);
700 *right = NULL;
701
702 cursor_in_t2 = object_get_parent_cell (e->cursor->object, HTML_OBJECT (t2)) != NULL;
703
704 cursor_cell_1 = HTML_TABLE_CELL (object_get_parent_cell (e->cursor->object, HTML_OBJECT (t1)));
705 if (cursor)
706 cursor_cell_2 = HTML_TABLE_CELL (object_get_parent_cell (cursor->object, HTML_OBJECT (t1)));
707 cursor_cell_3 = HTML_TABLE_CELL (object_get_parent_cell (e->cursor->object, HTML_OBJECT (t2)));
708
709 for (r = 0; r < t1->totalRows; r++) {
710 for (c = 0; c < t1->totalCols; c++) {
711 HTMLTableCell *c1, *c2;
712
713 c1 = t1->cells[r][c];
714 c2 = t2->cells[r][c];
715
716 if (first) {
717 if (!html_clue_is_empty (HTML_CLUE (c2))) {
718 t1_tail = prev_c1;
719 if (html_clue_is_empty (HTML_CLUE (c1))) {
720 move_cell (t1, t2, c1, c2, cursor_cell_1, cursor_cell_2,
721 r, c, e->cursor, cursor);
722 c1 = c2;
723 } else {
724 *left = html_object_tails_list (HTML_OBJECT (c1));
725 *right = html_object_heads_list (HTML_OBJECT (c2));
726 html_object_remove_child (HTML_OBJECT (t2), HTML_OBJECT (c2));
727 if (e->cursor->object == HTML_OBJECT (t1)) {
728 GList *list;
729
730 e->cursor->object = html_object_get_tail_leaf (HTML_OBJECT (c1));
731 e->cursor->offset = html_object_get_length (e->cursor->object);
732 e->cursor->position -= (t1->totalRows - c1->row - 1) * t1->totalCols
733 + (t1->totalCols - c1->col);
734 for (list = *left; list; list = list->next)
735 if (list->data && HTML_IS_TABLE (list->data))
736 e->cursor->position--;
737
738 /* printf ("3rd dec: %d t1_tail %d,%d\n",
739 (t1->totalRows - c1->row - 1) * t1->totalCols
740 + (t1->totalCols - c1->col), c1->row, c1->col); */
741
742 }
743 }
744 first = FALSE;
745 } else {
746 if (cursor_cell_3 && cursor_cell_3 == c2)
747 e->cursor->object = html_object_get_head_leaf (HTML_OBJECT (c1));
748 }
749 } else {
750 move_cell (t1, t2, c1, c2, cursor_cell_1, cursor_cell_2,
751 r, c, e->cursor, cursor);
752 c1 = c2;
753 }
754 prev_c1 = c1;
755 }
756 }
757
758 if (!t1_tail)
759 t1_tail = prev_c1;
760
761 if (e->cursor->object == self && t1_tail) {
762 e->cursor->object = html_object_get_tail_leaf (HTML_OBJECT (t1_tail));
763 e->cursor->offset = html_object_get_length (HTML_OBJECT (e->cursor->object));
764 e->cursor->position -= (t1->totalRows - t1_tail->row - 1) * t1->totalCols
765 + (t1->totalCols - t1_tail->col);
766 /* printf ("1st dec: %d t1_tail %d,%d\n", (t1->totalRows - t1_tail->row - 1)*t1->totalCols
767 * + (t1->totalCols - t1_tail->col), t1_tail->row, t1_tail->col); */
768 }
769
770 if (cursor_in_t2 && cursor && cursor_cell_2) {
771 e->cursor->position -= cursor_cell_2->row * t1->totalCols + cursor_cell_2->col + 1;
772 /* printf ("2nd dec: %d cell_2 %d,%d\n", cursor_cell_2->row * t1->totalCols + cursor_cell_2->col + 1,
773 * cursor_cell_2->row, cursor_cell_2->col); */
774 }
775
776 if (cursor && cursor->object == with)
777 cursor->object = self;
778
779 return TRUE;
780 }
781
782 static void
remove_child(HTMLObject * self,HTMLObject * child)783 remove_child (HTMLObject *self,
784 HTMLObject *child)
785 {
786 remove_cell (HTML_TABLE (self), HTML_TABLE_CELL (child));
787 }
788
789 static gboolean
accepts_cursor(HTMLObject * self)790 accepts_cursor (HTMLObject *self)
791 {
792 return TRUE;
793 }
794
795 static gboolean
is_container(HTMLObject * object)796 is_container (HTMLObject *object)
797 {
798 return TRUE;
799 }
800
801 static void
forall(HTMLObject * self,HTMLEngine * e,HTMLObjectForallFunc func,gpointer data)802 forall (HTMLObject *self,
803 HTMLEngine *e,
804 HTMLObjectForallFunc func,
805 gpointer data)
806 {
807 HTMLTableCell *cell;
808 HTMLTable *table;
809 guint r, c;
810
811 table = HTML_TABLE (self);
812
813 for (r = 0; r < table->totalRows; r++) {
814 for (c = 0; c < table->totalCols; c++) {
815 cell = table->cells[r][c];
816
817 if (cell == NULL || cell->col != c || cell->row != r)
818 continue;
819
820 html_object_forall (HTML_OBJECT (cell), e, func, data);
821 }
822 }
823 (* func) (self, e, data);
824 }
825
826 static void
previous_rows_do_cspan(HTMLTable * table,gint c)827 previous_rows_do_cspan (HTMLTable *table,
828 gint c)
829 {
830 gint i;
831 if (c)
832 for (i = 0; i < table->totalRows - 1; i++)
833 if (table->cells[i][c - 1])
834 do_cspan (table, i, c, table->cells[i][c - 1]);
835 }
836
837 static void
expand_columns(HTMLTable * table,gint num)838 expand_columns (HTMLTable *table,
839 gint num)
840 {
841 gint r;
842
843 for (r = 0; r < table->allocRows; r++) {
844 table->cells[r] = g_renew (HTMLTableCell *, table->cells[r], table->totalCols + num);
845 memset (table->cells[r] + table->totalCols, 0, num * sizeof (HTMLTableCell *));
846 }
847 table->totalCols += num;
848 }
849
850 static void
inc_columns(HTMLTable * table,gint num)851 inc_columns (HTMLTable *table,
852 gint num)
853 {
854 expand_columns (table, num);
855 previous_rows_do_cspan (table, table->totalCols - num);
856 }
857
858 static void
expand_rows(HTMLTable * table,gint num)859 expand_rows (HTMLTable *table,
860 gint num)
861 {
862 gint r;
863
864 table->cells = g_renew (HTMLTableCell **, table->cells, table->allocRows + num);
865
866 for (r = table->allocRows; r < table->allocRows + num; r++) {
867 table->cells[r] = g_new (HTMLTableCell *, table->totalCols);
868 memset (table->cells[r], 0, table->totalCols * sizeof (HTMLTableCell *));
869 }
870
871 table->allocRows += num;
872 }
873
874 static void
inc_rows(HTMLTable * table,gint num)875 inc_rows (HTMLTable *table,
876 gint num)
877 {
878 if (table->totalRows + num > table->allocRows)
879 expand_rows (table, num + MAX (10, table->allocRows >> 2));
880 table->totalRows += num;
881 if (table->totalRows - num > 0)
882 do_rspan (table, table->totalRows - num);
883 }
884
885 static inline gint
cell_end_col(HTMLTable * table,HTMLTableCell * cell)886 cell_end_col (HTMLTable *table,
887 HTMLTableCell *cell)
888 {
889 return MIN (table->totalCols, cell->col + cell->cspan);
890 }
891
892 static inline gint
cell_end_row(HTMLTable * table,HTMLTableCell * cell)893 cell_end_row (HTMLTable *table,
894 HTMLTableCell *cell)
895 {
896 return MIN (table->totalRows, cell->row + cell->rspan);
897 }
898
899 #define ARR(i) (g_array_index (array, gint, i))
900 #define LL (unsigned long long)
901
902 static gboolean
calc_column_width_step(HTMLTable * table,HTMLPainter * painter,GArray * array,gint * sizes,gint (* calc_fn)(HTMLObject *,HTMLPainter *),gint span)903 calc_column_width_step (HTMLTable *table,
904 HTMLPainter *painter,
905 GArray *array,
906 gint *sizes,
907 gint (*calc_fn)(HTMLObject *, HTMLPainter *), gint span)
908 {
909 gboolean has_greater_cspan = FALSE;
910 gint r, c, i, pixel_size = html_painter_get_pixel_size (painter);
911 gint border_extra = table->border ? 2 : 0;
912
913 for (c = 0; c < table->totalCols - span + 1; c++) {
914 for (r = 0; r < table->totalRows; r++) {
915 HTMLTableCell *cell = table->cells[r][c];
916 gint col_width, span_width, cspan, new_width, added;
917
918 if (!cell || cell->col != c || cell->row != r)
919 continue;
920 cspan = MIN (cell->cspan, table->totalCols - cell->col);
921 if (cspan > span)
922 has_greater_cspan = TRUE;
923 if (cspan != span)
924 continue;
925
926 col_width = (*calc_fn) (HTML_OBJECT (cell), painter)
927 - (span - 1) * (table->spacing + border_extra) * pixel_size;
928 if (col_width <= 0)
929 continue;
930 span_width = ARR (cell->col + span) - ARR (cell->col);
931 added = 0;
932 for (i = 0; i < span; i++) {
933 if (span_width) {
934 new_width = (LL col_width * (ARR (cell->col + i + 1) - ARR (cell->col)))
935 / span_width;
936 if (LL col_width * (ARR (cell->col + i + 1) - ARR (cell->col))
937 - LL new_width * span_width > LL (new_width + 1) * span_width
938 - LL col_width * (ARR (cell->col + i + 1) - ARR (cell->col)))
939 new_width++;
940 } else {
941 new_width = added + col_width / span;
942 if (col_width - LL span * new_width > LL span * (new_width + 1) - col_width)
943 new_width++;
944 }
945 new_width -= added;
946 added += new_width;
947
948 if (sizes[cell->col + i] < new_width)
949 sizes[cell->col + i] = new_width;
950 }
951 /* printf ("%d added %d col_width %d span_width %d\n",
952 * col_width - added, added, col_width, span_width); */
953 }
954 }
955
956 return has_greater_cspan;
957 }
958
959 static void
calc_column_width_template(HTMLTable * table,HTMLPainter * painter,GArray * array,gint (* calc_fn)(HTMLObject *,HTMLPainter *),GArray * pref)960 calc_column_width_template (HTMLTable *table,
961 HTMLPainter *painter,
962 GArray *array,
963 gint (*calc_fn)(HTMLObject *, HTMLPainter *), GArray *pref)
964 {
965 gint c, add, span;
966 gint pixel_size = html_painter_get_pixel_size (painter);
967 gint border_extra = table->border ? 1 : 0;
968 gint cell_space = pixel_size * (table->spacing + 2 * border_extra);
969 gint *arr;
970 gboolean next = TRUE;
971
972 g_array_set_size (array, table->totalCols + 1);
973 for (c = 0; c <= table->totalCols; c++)
974 ARR (c) = pixel_size * (table->border + table->spacing);
975
976 span = 1;
977 while (span <= table->totalCols && next) {
978 arr = g_new0 (gint, table->totalCols);
979 next = calc_column_width_step (table, painter, pref, arr, calc_fn, span);
980 add = 0;
981 for (c = 0; c < table->totalCols; c++) {
982 ARR (c + 1) += add;
983 if (ARR (c + 1) - ARR (c) < arr[c]) {
984 add += arr[c] - (ARR (c + 1) - ARR (c));
985 ARR (c + 1) = ARR (c) + arr[c];
986 }
987 }
988 g_free (arr);
989 span++;
990 }
991
992 for (c = 0; c < table->totalCols; c++)
993 ARR (c + 1) += (c + 1) * cell_space;
994 }
995
996 static void
do_cspan(HTMLTable * table,gint row,gint col,HTMLTableCell * cell)997 do_cspan (HTMLTable *table,
998 gint row,
999 gint col,
1000 HTMLTableCell *cell)
1001 {
1002 gint i;
1003
1004 g_assert (cell);
1005 g_assert (cell->col <= col);
1006
1007 for (i = col - cell->col; i < cell->cspan && cell->col + i < table->totalCols; i++)
1008 html_table_set_cell (table, row, cell->col + i, cell);
1009 }
1010
1011 static void
prev_col_do_cspan(HTMLTable * table,gint row)1012 prev_col_do_cspan (HTMLTable *table,
1013 gint row)
1014 {
1015 g_assert (row >= 0);
1016
1017 /* add previous column cell which has cspan > 1 */
1018 while (table->col < table->totalCols && table->cells[row][table->col] != 0) {
1019 html_table_alloc_cell (table, row, table->col + table->cells[row][table->col]->cspan);
1020 do_cspan (table, row, table->col + 1, table->cells[row][table->col]);
1021 table->col += (table->cells[row][table->col])->cspan;
1022 }
1023 }
1024
1025 static void
do_rspan(HTMLTable * table,gint row)1026 do_rspan (HTMLTable *table,
1027 gint row)
1028 {
1029 gint i;
1030
1031 g_assert (row > 0);
1032
1033 for (i = 0; i < table->totalCols; i++)
1034 if (table->cells[row - 1][i]
1035 && (table->cells[row - 1][i])->row + (table->cells[row - 1][i])->rspan
1036 > row) {
1037 html_table_set_cell (table, table->row, i, table->cells[table->row - 1][i]);
1038 do_cspan (table, table->row, i + 1, table->cells[table->row -1][i]);
1039 }
1040 }
1041
1042 void
html_table_set_cell(HTMLTable * table,gint r,gint c,HTMLTableCell * cell)1043 html_table_set_cell (HTMLTable *table,
1044 gint r,
1045 gint c,
1046 HTMLTableCell *cell)
1047 {
1048 if (!table->cells[r][c]) {
1049 #ifdef GTKHTML_DEBUG_TABLE
1050 printf ("set cell: %d,%d %p\n", r, c, cell);
1051 #endif
1052 table->cells[r][c] = cell;
1053 HTML_OBJECT (cell)->parent = HTML_OBJECT (table);
1054 }
1055 }
1056
1057 void
html_table_alloc_cell(HTMLTable * table,gint r,gint c)1058 html_table_alloc_cell (HTMLTable *table,
1059 gint r,
1060 gint c)
1061 {
1062 if (c >= table->totalCols)
1063 inc_columns (table, c + 1 - table->totalCols);
1064
1065 if (r >= table->totalRows)
1066 inc_rows (table, r + 1 - table->totalRows);
1067 }
1068
1069 #define RSPAN (MIN (cell->row + cell->rspan, table->totalRows) - cell->row - 1)
1070
1071 static void
calc_row_heights(HTMLTable * table,HTMLPainter * painter)1072 calc_row_heights (HTMLTable *table,
1073 HTMLPainter *painter)
1074 {
1075 HTMLTableCell *cell;
1076 gint r, c, rl, height, pixel_size = html_painter_get_pixel_size (painter);
1077 gint border_extra = table->border ? 2 : 0;
1078
1079 g_array_set_size (table->rowHeights, table->totalRows + 1);
1080 for (r = 0; r <= table->totalRows; r++)
1081 ROW_HEIGHT (table, r) = pixel_size * (table->border + table->spacing);
1082
1083 for (r = 0; r < table->totalRows; r++) {
1084 if (ROW_HEIGHT (table, r + 1) < ROW_HEIGHT (table, r))
1085 ROW_HEIGHT (table, r + 1) = ROW_HEIGHT (table, r);
1086 for (c = 0; c < table->totalCols; c++) {
1087 cell = table->cells[r][c];
1088 if (cell && cell->row == r && cell->col == c) {
1089 rl = cell_end_row (table, cell);
1090 height = (ROW_HEIGHT (table, cell->row)
1091 + HTML_OBJECT (cell)->ascent + HTML_OBJECT (cell)->descent
1092 + (pixel_size * (table->spacing + border_extra)));
1093 if (height > ROW_HEIGHT (table, rl))
1094 ROW_HEIGHT (table, rl) = height;
1095 }
1096 }
1097 /* printf ("height %d: %d\n", r, ROW_HEIGHT (table, r)); */
1098 }
1099 /* printf ("height %d: %d\n", r, ROW_HEIGHT (table, r)); */
1100 }
1101
1102 static void
calc_cells_size(HTMLTable * table,HTMLPainter * painter,GList ** changed_objs)1103 calc_cells_size (HTMLTable *table,
1104 HTMLPainter *painter,
1105 GList **changed_objs)
1106 {
1107 HTMLTableCell *cell;
1108 gint r, c;
1109
1110 for (r = 0; r < table->totalRows; r++)
1111 for (c = 0; c < table->totalCols; c++) {
1112 cell = table->cells[r][c];
1113 if (cell && cell->col == c && cell->row == r)
1114 html_object_calc_size (HTML_OBJECT (cell), painter, changed_objs);
1115 }
1116 }
1117
1118 static void
html_table_set_cells_position(HTMLTable * table,HTMLPainter * painter)1119 html_table_set_cells_position (HTMLTable *table,
1120 HTMLPainter *painter)
1121 {
1122 HTMLTableCell *cell;
1123 gint r, c, rl, pixel_size = html_painter_get_pixel_size (painter);
1124 gint border_extra = table->border ? 1 : 0;
1125
1126 for (r = 0; r < table->totalRows; r++)
1127 for (c = 0; c < table->totalCols; c++) {
1128 cell = table->cells[r][c];
1129 if (cell && cell->row == r && cell->col == c) {
1130 rl = cell_end_row (table, cell);
1131 HTML_OBJECT (cell)->x = COLUMN_OPT (table, c) + pixel_size * border_extra;
1132 HTML_OBJECT (cell)->y = ROW_HEIGHT (table, rl) + pixel_size * (- table->spacing)
1133 - HTML_OBJECT (cell)->descent;
1134 /* printf ("y: %d\n", HTML_OBJECT (cell)->y); */
1135 html_object_set_max_height (HTML_OBJECT (cell), painter,
1136 ROW_HEIGHT (table, rl) - ROW_HEIGHT (table, cell->row)
1137 - pixel_size * (table->spacing + border_extra));
1138 }
1139 }
1140 }
1141
1142 static void
add_clear_area(GList ** changed_objs,HTMLObject * o,gint x,gint w)1143 add_clear_area (GList **changed_objs,
1144 HTMLObject *o,
1145 gint x,
1146 gint w)
1147 {
1148 HTMLObjectClearRectangle *cr;
1149
1150 if (!changed_objs)
1151 return;
1152
1153 cr = g_new (HTMLObjectClearRectangle, 1);
1154
1155 cr->object = o;
1156 cr->x = x;
1157 cr->y = 0;
1158 cr->width = w;
1159 cr->height = o->ascent + o->descent;
1160
1161 *changed_objs = g_list_prepend (*changed_objs, cr);
1162 /* NULL meens: clear rectangle follows */
1163 *changed_objs = g_list_prepend (*changed_objs, NULL);
1164 }
1165
1166 static void
html_table_set_max_height(HTMLObject * o,HTMLPainter * painter,gint height)1167 html_table_set_max_height (HTMLObject *o,
1168 HTMLPainter *painter,
1169 gint height)
1170 {
1171 /* for now just remember it, it will be passed down once size is calculated */
1172 HTML_TABLE (o)->max_height = height;
1173 }
1174
1175 static gboolean
html_table_real_calc_size(HTMLObject * o,HTMLPainter * painter,GList ** changed_objs)1176 html_table_real_calc_size (HTMLObject *o,
1177 HTMLPainter *painter,
1178 GList **changed_objs)
1179 {
1180 HTMLTable *table = HTML_TABLE (o);
1181 gint old_width, old_ascent, pixel_size;
1182
1183 old_width = o->width;
1184 old_ascent = o->ascent;
1185 pixel_size = html_painter_get_pixel_size (painter);
1186
1187 if (!table->columnOpt->data)
1188 html_table_set_max_width (o, painter, o->max_width);
1189
1190 calc_cells_size (table, painter, changed_objs);
1191 calc_row_heights (table, painter);
1192 html_table_set_cells_position (table, painter);
1193
1194 o->ascent = ROW_HEIGHT (table, table->totalRows) + pixel_size * table->border;
1195 o->width = COLUMN_OPT (table, table->totalCols) + pixel_size * table->border;
1196
1197 if (o->width != old_width || o->ascent != old_ascent) {
1198 html_object_add_to_changed (changed_objs, o);
1199 if (o->width < old_width) {
1200 if (o->parent && HTML_IS_CLUEFLOW (o->parent)) {
1201 switch (HTML_CLUE (o->parent)->halign) {
1202 case HTML_HALIGN_NONE:
1203 case HTML_HALIGN_LEFT:
1204 add_clear_area (changed_objs, o, o->width, old_width - o->width);
1205 break;
1206 case HTML_HALIGN_RIGHT:
1207 add_clear_area (changed_objs, o, - (old_width - o->width), old_width - o->width);
1208 break;
1209 case HTML_HALIGN_CENTER:
1210 /* FIXME +/-1 pixel */
1211 add_clear_area (changed_objs, o, -(old_width - o->width) / 2,
1212 (old_width - o->width) / 2);
1213 add_clear_area (changed_objs, o, o->width,
1214 (old_width - o->width) / 2);
1215 break;
1216 }
1217 }
1218 }
1219 return TRUE;
1220 }
1221
1222 return FALSE;
1223 }
1224
1225 #define NEW_INDEX(l,h) ((l+h) / 2)
1226 #undef ARR
1227 #define ARR(i) g_array_index (a, gint, i)
1228
1229 static gint
bin_search_index(GArray * a,gint l,gint h,gint val)1230 bin_search_index (GArray *a,
1231 gint l,
1232 gint h,
1233 gint val)
1234 {
1235 gint i;
1236
1237 i = NEW_INDEX (l, h);
1238
1239 while (l < h && val != ARR (i)) {
1240 if (val < ARR (i))
1241 h = i - 1;
1242 else
1243 l = i + 1;
1244 i = NEW_INDEX (l, h);
1245 }
1246
1247 return i;
1248 }
1249
1250 static inline gint
to_index(gint val,gint l,gint h)1251 to_index (gint val,
1252 gint l,
1253 gint h)
1254 {
1255 return MIN (MAX (val, l), h);
1256 }
1257
1258 static void
get_bounds(HTMLTable * table,gint x,gint y,gint width,gint height,gint * sc,gint * ec,gint * sr,gint * er)1259 get_bounds (HTMLTable *table,
1260 gint x,
1261 gint y,
1262 gint width,
1263 gint height,
1264 gint *sc,
1265 gint *ec,
1266 gint *sr,
1267 gint *er)
1268 {
1269 g_return_if_fail (table->rowHeights);
1270 g_return_if_fail (table->columnOpt);
1271 g_return_if_fail (table->rowHeights->data);
1272 g_return_if_fail (table->columnOpt->data);
1273
1274 *sr = to_index (bin_search_index (table->rowHeights, 0, table->totalRows, y), 0, table->totalRows - 1);
1275 if (y < ROW_HEIGHT (table, *sr) && (*sr) > 0)
1276 (*sr)--;
1277 *er = to_index (bin_search_index (table->rowHeights, *sr, table->totalRows, y + height), 0, table->totalRows - 1);
1278 if (y > ROW_HEIGHT (table, *er) && (*er) < table->totalRows - 1)
1279 (*er)++;
1280
1281 *sc = to_index (bin_search_index (table->columnOpt, 0, table->totalCols, x), 0, table->totalCols-1);
1282 if (x < COLUMN_OPT (table, *sc) && (*sc) > 0)
1283 (*sc)--;
1284 *ec = to_index (bin_search_index (table->columnOpt, *sc, table->totalCols, x + width), 0, table->totalCols - 1);
1285 if (x > COLUMN_OPT (table, *ec) && (*ec) < table->totalCols - 1)
1286 (*ec)++;
1287 }
1288
1289 static void
draw_background_helper(HTMLTable * table,HTMLPainter * p,GdkRectangle * paint,gint tx,gint ty)1290 draw_background_helper (HTMLTable *table,
1291 HTMLPainter *p,
1292 GdkRectangle *paint,
1293 gint tx,
1294 gint ty)
1295 {
1296 GdkPixbuf *pixbuf = NULL;
1297 GdkColor *color = table->bgColor;
1298 HTMLObject *o = HTML_OBJECT (table);
1299
1300 if (table->bgPixmap && table->bgPixmap->animation)
1301 pixbuf = gdk_pixbuf_animation_get_static_image (table->bgPixmap->animation);
1302
1303 if (color)
1304 html_painter_alloc_color (p, color);
1305
1306 if (!HTML_IS_PLAIN_PAINTER (p))
1307 html_painter_draw_background (p,
1308 color,
1309 pixbuf,
1310 tx + paint->x,
1311 ty + paint->y,
1312 paint->width,
1313 paint->height,
1314 paint->x - o->x,
1315 paint->y - (o->y - o->ascent));
1316 }
1317
1318 static void
draw(HTMLObject * o,HTMLPainter * p,gint x,gint y,gint width,gint height,gint tx,gint ty)1319 draw (HTMLObject *o,
1320 HTMLPainter *p,
1321 gint x,
1322 gint y,
1323 gint width,
1324 gint height,
1325 gint tx,
1326 gint ty)
1327 {
1328 HTMLTableCell *cell;
1329 HTMLTable *table = HTML_TABLE (o);
1330 gint pixel_size;
1331 gint r, c, start_row, end_row, start_col, end_col;
1332 GdkRectangle paint;
1333
1334 if (!html_object_intersect (o, &paint, x, y, width, height))
1335 return;
1336
1337 pixel_size = html_painter_get_pixel_size (p);
1338
1339 /* Draw the background */
1340 draw_background_helper (table, p, &paint, tx, ty);
1341
1342 tx += o->x;
1343 ty += o->y - o->ascent;
1344
1345 /* Draw the cells */
1346 get_bounds (table, x - o->x, y - o->y + o->ascent, width, height, &start_col, &end_col, &start_row, &end_row);
1347 for (r = start_row; r <= end_row; r++) {
1348 for (c = start_col; c <= end_col; c++) {
1349 cell = table->cells[r][c];
1350
1351 if (cell == NULL)
1352 continue;
1353 if (c < end_col && cell == table->cells[r][c + 1])
1354 continue;
1355 if (r < end_row && table->cells[r + 1][c] == cell)
1356 continue;
1357
1358 html_object_draw (HTML_OBJECT (cell), p,
1359 x - o->x, y - o->y + o->ascent,
1360 width,
1361 height,
1362 tx, ty);
1363 }
1364 }
1365
1366 /* Draw the border */
1367 if (table->border > 0 && table->rowHeights->len > 0) {
1368 gint capOffset;
1369
1370 capOffset = 0;
1371
1372 if (table->caption && table->capAlign == HTML_VALIGN_TOP)
1373 g_print ("FIXME: Support captions\n");
1374
1375 html_painter_draw_border (p, html_object_get_bg_color (o->parent, p),
1376 tx, ty + capOffset,
1377 HTML_OBJECT (table)->width,
1378 ROW_HEIGHT (table, table->totalRows) +
1379 pixel_size * table->border, HTML_BORDER_OUTSET,
1380 pixel_size * table->border);
1381
1382 /* Draw borders around each cell */
1383 for (r = start_row; r <= end_row; r++) {
1384 for (c = start_col; c <= end_col; c++) {
1385 if ((cell = table->cells[r][c]) == 0)
1386 continue;
1387 if (c < end_col &&
1388 cell == table->cells[r][c + 1])
1389 continue;
1390 if (r < end_row &&
1391 table->cells[r + 1][c] == cell)
1392 continue;
1393
1394 html_painter_draw_border (p, html_object_get_bg_color (HTML_OBJECT (cell), p),
1395 tx + COLUMN_OPT (table, cell->col),
1396 ty + ROW_HEIGHT (table, cell->row) + capOffset,
1397 (COLUMN_OPT (table, c + 1)
1398 - COLUMN_OPT (table, cell->col)
1399 - pixel_size * table->spacing),
1400 (ROW_HEIGHT (table, r + 1)
1401 - ROW_HEIGHT (table, cell->row)
1402 - pixel_size * table->spacing),
1403 HTML_BORDER_INSET, pixel_size);
1404
1405 }
1406 }
1407 }
1408 }
1409
1410 static gint
calc_min_width(HTMLObject * o,HTMLPainter * painter)1411 calc_min_width (HTMLObject *o,
1412 HTMLPainter *painter)
1413 {
1414 HTMLTable *table = HTML_TABLE (o);
1415
1416 calc_column_width_template (table, painter, table->columnPref, html_object_calc_preferred_width, table->columnPref);
1417 calc_column_width_template (table, painter, table->columnMin, html_object_calc_min_width, table->columnPref);
1418
1419 return o->flags & HTML_OBJECT_FLAG_FIXEDWIDTH
1420 ? MAX (html_painter_get_pixel_size (painter) * table->specified_width,
1421 COLUMN_MIN (table, table->totalCols) + table->border * html_painter_get_pixel_size (painter))
1422 : COLUMN_MIN (table, table->totalCols) + table->border * html_painter_get_pixel_size (painter);
1423 }
1424
1425 static gint
calc_preferred_width(HTMLObject * o,HTMLPainter * painter)1426 calc_preferred_width (HTMLObject *o,
1427 HTMLPainter *painter)
1428 {
1429 HTMLTable *table = HTML_TABLE (o);
1430 gint min_width;
1431
1432 /* note that calculating min width prepares columnPref for us */
1433 min_width = html_object_calc_min_width (o, painter);
1434
1435 calc_column_width_template (table, painter, table->columnFixed,
1436 (gint (*)(HTMLObject *, HTMLPainter *)) html_table_cell_get_fixed_width,
1437 table->columnPref);
1438
1439 return o->flags & HTML_OBJECT_FLAG_FIXEDWIDTH
1440 ? MAX (html_painter_get_pixel_size (painter) * table->specified_width, min_width)
1441 : COLUMN_PREF (table, table->totalCols) + table->border * html_painter_get_pixel_size (painter);
1442 }
1443
1444 #define PERC(c) (col_percent [c + 1] - col_percent [c])
1445
1446 static gboolean
calc_percentage_step(HTMLTable * table,gint * col_percent,gint * span_percent,gint span)1447 calc_percentage_step (HTMLTable *table,
1448 gint *col_percent,
1449 gint *span_percent,
1450 gint span)
1451 {
1452 HTMLTableCell *cell;
1453 gboolean higher_span = FALSE;
1454 gint r, c, cl, cspan;
1455
1456 for (c = 0; c < table->totalCols; c++)
1457 for (r = 0; r < table->totalRows; r++) {
1458 cell = table->cells[r][c];
1459
1460 if (!cell || cell->col != c || cell->row != r)
1461 continue;
1462
1463 if (HTML_OBJECT (cell)->flags & HTML_OBJECT_FLAG_FIXEDWIDTH || !cell->percent_width)
1464 continue;
1465
1466 cspan = MIN (cell->cspan, table->totalCols - cell->col);
1467 if (cspan > span)
1468 higher_span = TRUE;
1469 if (cspan != span)
1470 continue;
1471
1472 cl = cell_end_col (table, cell);
1473 if (col_percent[cl] - col_percent[c] < cell->fixed_width) {
1474 gint cp, part, added, pleft, not_percented, np;
1475 part = 0;
1476 not_percented = 0;
1477 for (cp = 0; cp < span; cp++)
1478 if (!PERC (c + cp))
1479 not_percented++;
1480
1481 np = 1;
1482 added = 0;
1483 pleft = cell->fixed_width - (col_percent[cl] - col_percent[c]);
1484 for (cp = 0; cp < span; cp++) {
1485 if (not_percented) {
1486 if (!PERC (c + cp)) {
1487 part = np * pleft / not_percented;
1488 if (np * pleft - part * not_percented >
1489 (part + 1) * not_percented - np * pleft)
1490 part++;
1491 np++;
1492 }
1493 } else {
1494 part = ((col_percent[c + cp + 1] - col_percent[c]) * pleft)
1495 / (col_percent[cl] - col_percent[cell->col]);
1496 if ((col_percent[c + cp + 1] - col_percent[c]) * pleft
1497 - part * (col_percent[cl] - col_percent[c])
1498 > (part + 1) * (col_percent[cl] - col_percent[c])
1499 - (col_percent[c + cp + 1] - col_percent[c]) * pleft)
1500 part++;
1501 }
1502 part -= added;
1503 added += part;
1504 span_percent[c + cp] = PERC (c + cp) + part;
1505 }
1506 }
1507 }
1508
1509 return higher_span;
1510 }
1511
1512 static void
calc_col_percentage(HTMLTable * table,gint * col_percent)1513 calc_col_percentage (HTMLTable *table,
1514 gint *col_percent)
1515 {
1516 gint c, span, *percent, add;
1517 gboolean next = TRUE;
1518
1519 percent = g_new0 (gint, table->totalCols);
1520 for (span = 1; next && span <= table->totalCols; span++) {
1521 for (c = 0; c < table->totalCols; c++)
1522 percent[c] = 0;
1523
1524 next = calc_percentage_step (table, col_percent, percent, span);
1525 add = 0;
1526
1527 for (c = 0; c < table->totalCols; c++) {
1528 col_percent[c + 1] += add;
1529 if (PERC (c) < percent[c]) {
1530 add += percent[c] - PERC (c);
1531 col_percent[c + 1] = col_percent[c] + percent[c];
1532 }
1533 }
1534 }
1535 g_free (percent);
1536 }
1537
1538 static gint
calc_not_percented(HTMLTable * table,gint * col_percent)1539 calc_not_percented (HTMLTable *table,
1540 gint *col_percent)
1541 {
1542 gint c, not_percented;
1543
1544 not_percented = 0;
1545 for (c = 0; c < table->totalCols; c++)
1546 if (col_percent[c + 1] == col_percent[c])
1547 not_percented++;
1548
1549 return not_percented;
1550 }
1551
1552 static gint
divide_into_percented(HTMLTable * table,gint * col_percent,gint * max_size,gint max_width,gint left)1553 divide_into_percented (HTMLTable *table,
1554 gint *col_percent,
1555 gint *max_size,
1556 gint max_width,
1557 gint left)
1558 {
1559 gint added, add, c, to_fill, request, filled;
1560
1561 to_fill = 0;
1562 for (c = 0; c < table->totalCols; c++) {
1563 request = (LL max_width * (PERC (c))) / 100;
1564 if (max_size[c] < request)
1565 to_fill += request - max_size[c];
1566 }
1567
1568 /* printf ("to fill %d\n", to_fill); */
1569 left = MIN (to_fill, left);
1570 added = 0;
1571 filled = 0;
1572 if (left) {
1573 for (c = 0; c < table->totalCols; c++) {
1574 request = (LL max_width * (PERC (c))) / 100;
1575 if (max_size[c] < request) {
1576 add = LL left * (request - max_size[c] + filled) / to_fill;
1577 if (LL left * (request - max_size[c] + filled) - LL add * to_fill >
1578 LL (add + 1) * to_fill - LL left * (request - max_size[c] + filled))
1579 add++;
1580 add -= added;
1581 added += add;
1582 filled += request - max_size[c];
1583 max_size[c] += add;
1584 }
1585 }
1586 }
1587 /* printf ("%d added %d left %d\n", left - added, added, left); */
1588
1589 return added;
1590 }
1591
1592 #define PREF(i) (g_array_index (pref, gint, i))
1593
1594 static gboolean
calc_lowest_fill(HTMLTable * table,GArray * pref,gint * max_size,gint * col_percent,gint pixel_size,gint * ret_col,gint * ret_total_pref,gint * ret_total)1595 calc_lowest_fill (HTMLTable *table,
1596 GArray *pref,
1597 gint *max_size,
1598 gint *col_percent,
1599 gint pixel_size,
1600 gint *ret_col,
1601 gint *ret_total_pref,
1602 gint *ret_total)
1603 {
1604 gint c, pw, border_extra = table->border ? 2 : 0, min_fill = COLUMN_PREF (table, table->totalCols);
1605
1606 *ret_total_pref = 0;
1607 *ret_total = 0;
1608 for (c = 0; c < table->totalCols; c++)
1609 if (col_percent[c + 1] == col_percent[c]) {
1610 pw = PREF (c + 1) - PREF (c)
1611 - pixel_size * (table->spacing + border_extra);
1612 /* printf ("col %d pw %d size %d\n", c, pw, max_size [c]); */
1613 if (max_size[c] < pw) {
1614 if (pw - max_size[c] < min_fill) {
1615 *ret_col = c;
1616 min_fill = pw - max_size[c];
1617 }
1618
1619 (*ret_total_pref) += pw;
1620 (*ret_total) += max_size[c];
1621 }
1622 }
1623
1624 return min_fill == COLUMN_PREF (table, table->totalCols) ? FALSE : TRUE;
1625 }
1626
1627 inline static gint
divide_upto_preferred_width(HTMLTable * table,HTMLPainter * painter,GArray * pref,gint * col_percent,gint * max_size,gint left)1628 divide_upto_preferred_width (HTMLTable *table,
1629 HTMLPainter *painter,
1630 GArray *pref,
1631 gint *col_percent,
1632 gint *max_size,
1633 gint left)
1634 {
1635 gint added, part, c, pw, pixel_size = html_painter_get_pixel_size (painter);
1636 gint total, total_pref, to_divide, min_col, min_fill, min_pw, processed_pw, border_extra = table->border ? 2 : 0;
1637
1638 /* printf ("cols: %d left: %d\n", table->totalCols, left); */
1639 while (left > 0 && calc_lowest_fill (table, pref, max_size, col_percent, pixel_size, &min_col, &total_pref, &total)) {
1640 min_pw = PREF (min_col + 1) - PREF (min_col)
1641 - pixel_size * (table->spacing + border_extra);
1642 /* printf ("min: %d left: %d\n", min_col, left); */
1643 to_divide = MIN (total_pref - total, left);
1644 if (min_pw - max_size[min_col] < ((gdouble) min_pw * to_divide) / total_pref) {
1645 added = min_pw - max_size[min_col];
1646 left -= added;
1647 min_fill = to_divide - added;
1648 max_size[min_col] += added;
1649 total_pref -= min_pw;
1650 } else {
1651 min_fill = to_divide;
1652 }
1653
1654 /* printf ("min satisfied %d, (%d=%d) left: %d\n", min_fill, max_size [min_col], min_pw, left); */
1655 processed_pw = 0;
1656 added = 0;
1657
1658 for (c = 0; c < table->totalCols; c++) {
1659 if (col_percent[c + 1] == col_percent[c]) {
1660 pw = PREF (c + 1) - PREF (c)
1661 - pixel_size * (table->spacing + border_extra);
1662 if (max_size[c] < pw) {
1663 processed_pw += pw;
1664 part = (LL min_fill * processed_pw) / total_pref;
1665 if (LL min_fill * processed_pw - LL part * total_pref
1666 > LL (part + 1) * total_pref - LL min_fill * processed_pw)
1667 part++;
1668 part -= added;
1669 if (max_size[c] + part > pw)
1670 part = pw - max_size[c];
1671 added += part;
1672 max_size[c] += part;
1673 left -= part;
1674 /* printf ("cell %d add: %d --> %d\n", c, part, max_size [c]); */
1675 }
1676 }
1677 }
1678 }
1679
1680 /* printf ("cols: %d left: %d (END)\n", table->totalCols, left); */
1681
1682 return left;
1683 }
1684
1685 inline static void
divide_left_by_preferred_width(HTMLTable * table,HTMLPainter * painter,gint * col_percent,gint * max_size,gint left)1686 divide_left_by_preferred_width (HTMLTable *table,
1687 HTMLPainter *painter,
1688 gint *col_percent,
1689 gint *max_size,
1690 gint left)
1691 {
1692 gint added, part, c, pref, pw, pixel_size = html_painter_get_pixel_size (painter);
1693 gint total_fill, processed_pw, border_extra = table->border ? 2 : 0;
1694
1695 /* printf ("round 2 left: %d\n", left); */
1696 #define PW(c) COLUMN_PREF (table, c + 1) - COLUMN_PREF (table, c)
1697 #define FW(c) COLUMN_FIX (table, c + 1) - COLUMN_FIX (table, c)
1698 pref = 0;
1699 for (c = 0; c < table->totalCols; c++)
1700 if (col_percent[c + 1] == col_percent[c] && PW (c) > FW (c))
1701 pref += COLUMN_PREF (table, c + 1) - COLUMN_PREF (table, c)
1702 - pixel_size * (table->spacing + border_extra);
1703 /* printf ("col pref: %d size: %d\n", COLUMN_PREF (table, c + 1)
1704 * - COLUMN_PREF (table, c)
1705 * - pixel_size * (table->spacing + border_extra), max_size[c]); */
1706
1707 added = 0;
1708 processed_pw = 0;
1709 total_fill = left;
1710
1711 if (pref)
1712 for (c = 0; c < table->totalCols; c++) {
1713 if (col_percent[c + 1] == col_percent[c] && PW (c) > FW (c)) {
1714 pw = COLUMN_PREF (table, c + 1) - COLUMN_PREF (table, c)
1715 - pixel_size * (table->spacing + border_extra);
1716 processed_pw += pw;
1717 part = (LL total_fill * processed_pw) / pref;
1718 /* printf ("pw %d part %d total %d processed %d\n",
1719 * pw, part, total_fill, processed_pw); */
1720 if (LL total_fill * processed_pw - LL part * pref
1721 > LL (part + 1) * pref - LL total_fill * processed_pw)
1722 part++;
1723 part -= added;
1724 max_size[c] += part;
1725 added += part;
1726 left -= part;
1727 /* printf ("col %d (add %d) --> %d (pw=%d)\n", c, part, max_size [c], pw); */
1728 }
1729 }
1730
1731 /* printf ("------------------------------------\n*left*: %d\n-------------------------------\n", left); */
1732 }
1733
1734 inline static void
divide_into_variable_all(HTMLTable * table,HTMLPainter * painter,gint * col_percent,gint * max_size,gint left)1735 divide_into_variable_all (HTMLTable *table,
1736 HTMLPainter *painter,
1737 gint *col_percent,
1738 gint *max_size,
1739 gint left)
1740 {
1741 /* printf ("left %d cols: %d\n", left, table->totalCols); */
1742 html_object_calc_preferred_width (HTML_OBJECT (table), painter);
1743
1744 left = divide_upto_preferred_width (table, painter, table->columnFixed, col_percent, max_size, left);
1745 left = divide_upto_preferred_width (table, painter, table->columnPref, col_percent, max_size, left);
1746
1747 if (left)
1748 divide_left_by_preferred_width (table, painter, col_percent, max_size, left);
1749 }
1750
1751 inline static void
divide_into_percented_all(HTMLTable * table,gint * col_percent,gint * max_size,gint max_width,gint left)1752 divide_into_percented_all (HTMLTable *table,
1753 gint *col_percent,
1754 gint *max_size,
1755 gint max_width,
1756 gint left)
1757 {
1758 gdouble sub_percent, percent;
1759 gint c, sub_width, width;
1760 gboolean all_active, *active;
1761
1762 active = g_new (gboolean, table->totalCols);
1763 for (c = 0; c < table->totalCols; c++)
1764 active[c] = TRUE;
1765
1766 percent = col_percent[table->totalCols];
1767 width = max_width;
1768 do {
1769 sub_percent = 0.0;
1770 sub_width = width;
1771 all_active = TRUE;
1772 for (c = 0; c < table->totalCols; c++) {
1773 if (active[c]) {
1774 if (max_size[c] < ((gdouble) width * PERC (c)) / percent)
1775 sub_percent += PERC (c);
1776 else {
1777 sub_width -= max_size[c];
1778 all_active = FALSE;
1779 active[c] = FALSE;
1780 }
1781 }
1782 }
1783 percent = sub_percent;
1784 width = sub_width;
1785 } while (!all_active);
1786
1787 /* printf ("sub_width %d\n", sub_width); */
1788 for (c = 0; c < table->totalCols; c++)
1789 if (active[c] && max_size[c] < ((gdouble) width * PERC (c)) / percent)
1790 max_size[c] = ((gdouble) width) * (PERC (c)) / percent;
1791
1792 g_free (active);
1793 }
1794
1795 #define CSPAN (MIN (cell->col + cell->cspan, table->totalCols) - cell->col - 1)
1796
1797 static void
html_table_set_cells_max_width(HTMLTable * table,HTMLPainter * painter,gint * max_size)1798 html_table_set_cells_max_width (HTMLTable *table,
1799 HTMLPainter *painter,
1800 gint *max_size)
1801 {
1802 HTMLTableCell *cell;
1803 gint r, c, size, pixel_size = html_painter_get_pixel_size (painter);
1804 gint border_extra = table->border ? 2 : 0;
1805 size = 0;
1806
1807 for (r = 0; r < table->totalRows; r++)
1808 for (c = 0; c < table->totalCols; c++) {
1809 cell = table->cells[r][c];
1810 if (cell) {
1811 size = max_size[c] + (cell->col != c ? size : 0);
1812 if (cell_end_col (table, cell) - 1 == c && cell->row == r)
1813 html_object_set_max_width (HTML_OBJECT (cell), painter, size
1814 + pixel_size * (table->spacing + border_extra) * CSPAN);
1815 }
1816 }
1817 }
1818
1819 static void
set_columns_optimal_width(HTMLTable * table,gint * max_size,gint pixel_size)1820 set_columns_optimal_width (HTMLTable *table,
1821 gint *max_size,
1822 gint pixel_size)
1823 {
1824 gint c;
1825
1826 g_array_set_size (table->columnOpt, table->totalCols + 1);
1827 COLUMN_OPT (table, 0) = COLUMN_MIN (table, 0);
1828
1829 for (c = 0; c < table->totalCols; c++)
1830 COLUMN_OPT (table, c + 1) = COLUMN_OPT (table, c) + max_size[c]
1831 + pixel_size * (table->spacing + (table->border ? 2 : 0));
1832 }
1833
1834 static void
divide_left_width(HTMLTable * table,HTMLPainter * painter,gint * max_size,gint max_width,gint width_left)1835 divide_left_width (HTMLTable *table,
1836 HTMLPainter *painter,
1837 gint *max_size,
1838 gint max_width,
1839 gint width_left)
1840 {
1841 gint not_percented, c;
1842 gint *col_percent;
1843
1844 if (!width_left)
1845 return;
1846
1847 col_percent = g_new (gint, table->totalCols + 1);
1848 for (c = 0; c <= table->totalCols; c++)
1849 col_percent[c] = 0;
1850
1851 calc_col_percentage (table, col_percent);
1852 /* printf ("width_left: %d percented: %d\n", width_left, col_percent [table->totalCols]); */
1853 not_percented = calc_not_percented (table, col_percent);
1854 if (not_percented < table->totalCols)
1855 width_left -= divide_into_percented (table, col_percent, max_size, max_width, width_left);
1856
1857 /* printf ("width_left: %d\n", width_left); */
1858 if (width_left > 0) {
1859 if (not_percented)
1860 divide_into_variable_all (table, painter, col_percent, max_size, width_left);
1861 else
1862 divide_into_percented_all (table, col_percent, max_size, max_width, width_left);
1863 }
1864
1865 g_free (col_percent);
1866 }
1867
1868 static gint *
alloc_max_size(HTMLTable * table,gint pixel_size)1869 alloc_max_size (HTMLTable *table,
1870 gint pixel_size)
1871 {
1872 gint *max_size, c, border_extra = table->border ? 2 : 0;
1873
1874 max_size = g_new (gint, table->totalCols);
1875 for (c = 0; c < table->totalCols; c++)
1876 max_size[c] = COLUMN_MIN (table, c + 1) - COLUMN_MIN (table, c) - pixel_size * (table->spacing + border_extra);
1877
1878 return max_size;
1879 }
1880
1881 static void
html_table_set_max_width(HTMLObject * o,HTMLPainter * painter,gint max_width)1882 html_table_set_max_width (HTMLObject *o,
1883 HTMLPainter *painter,
1884 gint max_width)
1885 {
1886 HTMLTable *table = HTML_TABLE (o);
1887 gint *max_size, pixel_size, glue, border_extra = table->border ? 2 : 0;
1888 gint min_width;
1889
1890 /* printf ("max_width: %d\n", max_width); */
1891 pixel_size = html_painter_get_pixel_size (painter);
1892 o->max_width = MAX (html_object_calc_min_width (o, painter), max_width);
1893 max_width = o->flags & HTML_OBJECT_FLAG_FIXEDWIDTH
1894 ? pixel_size * table->specified_width
1895 : (o->percent
1896 ? ((gdouble) MIN (100, o->percent) / 100 * max_width)
1897 : MIN (html_object_calc_preferred_width (HTML_OBJECT (table), painter), max_width));
1898 min_width = html_object_calc_min_width (o, painter);
1899 if (max_width < min_width)
1900 max_width = min_width;
1901 /* printf ("corected to: %d\n", max_width); */
1902 glue = pixel_size * (table->border * 2 + (table->totalCols + 1) * table->spacing
1903 + (table->totalCols * border_extra));
1904 max_width -= glue;
1905 max_size = alloc_max_size (table, pixel_size);
1906
1907 divide_left_width (table, painter, max_size, max_width,
1908 max_width + glue - COLUMN_MIN (table, table->totalCols)
1909 - pixel_size * table->border);
1910
1911 html_table_set_cells_max_width (table, painter, max_size);
1912 set_columns_optimal_width (table, max_size, pixel_size);
1913
1914 /* printf ("max_width %d opt_width %d\n", o->max_width, COLUMN_OPT (table, table->totalCols) +); */
1915
1916 g_free (max_size);
1917 }
1918
1919 static void
reset(HTMLObject * o)1920 reset (HTMLObject *o)
1921 {
1922 HTMLTable *table = HTML_TABLE (o);
1923 HTMLTableCell *cell;
1924 guint r, c;
1925
1926 for (r = 0; r < table->totalRows; r++)
1927 for (c = 0; c < table->totalCols; c++) {
1928 cell = table->cells[r][c];
1929 if (cell && cell->row == r && cell->col == c)
1930 html_object_reset (HTML_OBJECT (cell));
1931 }
1932 }
1933
1934 static HTMLAnchor *
find_anchor(HTMLObject * self,const gchar * name,gint * x,gint * y)1935 find_anchor (HTMLObject *self,
1936 const gchar *name,
1937 gint *x,
1938 gint *y)
1939 {
1940 HTMLTable *table;
1941 HTMLTableCell *cell;
1942 HTMLAnchor *anchor;
1943 guint r, c;
1944
1945 table = HTML_TABLE (self);
1946
1947 *x += self->x;
1948 *y += self->y - self->ascent;
1949
1950 for (r = 0; r < table->totalRows; r++) {
1951 for (c = 0; c < table->totalCols; c++) {
1952 if ((cell = table->cells[r][c]) == 0)
1953 continue;
1954
1955 if (c < table->totalCols - 1
1956 && cell == table->cells[r][c + 1])
1957 continue;
1958 if (r < table->totalRows - 1
1959 && table->cells[r + 1][c] == cell)
1960 continue;
1961
1962 anchor = html_object_find_anchor (HTML_OBJECT (cell),
1963 name, x, y);
1964
1965 if (anchor != NULL)
1966 return anchor;
1967 }
1968 }
1969 *x -= self->x;
1970 *y -= self->y - self->ascent;
1971
1972 return 0;
1973 }
1974
1975 static HTMLObject *
check_point(HTMLObject * self,HTMLPainter * painter,gint x,gint y,guint * offset_return,gboolean for_cursor)1976 check_point (HTMLObject *self,
1977 HTMLPainter *painter,
1978 gint x,
1979 gint y,
1980 guint *offset_return,
1981 gboolean for_cursor)
1982 {
1983 HTMLTableCell *cell;
1984 HTMLObject *obj;
1985 HTMLTable *table;
1986 gint r, c, start_row, end_row, start_col, end_col, hsb, hsa, tbc;
1987
1988 if (x < self->x || x >= self->x + self->width
1989 || y >= self->y + self->descent || y < self->y - self->ascent)
1990 return NULL;
1991
1992 table = HTML_TABLE (self);
1993 hsb = table->spacing >> 1;
1994 hsa = hsb + (table->spacing & 1);
1995 tbc = table->border ? 1 : 0;
1996
1997 if (for_cursor) {
1998 /* table boundaries */
1999 if (x == self->x || x == self->x + self->width - 1) {
2000 if (offset_return)
2001 *offset_return = x == self->x ? 0 : 1;
2002 return self;
2003 }
2004
2005 /* border */
2006 if (x < self->x + table->border + hsb || y < self->y - self->ascent + table->border + hsb) {
2007 if (offset_return)
2008 *offset_return = 0;
2009 return self;
2010 }
2011 if (x > self->x + self->width - table->border - hsa || y > self->y + self->descent - table->border - hsa) {
2012 if (offset_return)
2013 *offset_return = 1;
2014 return self;
2015 }
2016 }
2017
2018 x -= self->x;
2019 y -= self->y - self->ascent;
2020
2021 get_bounds (table, x, y, 0, 0, &start_col, &end_col, &start_row, &end_row);
2022 for (r = start_row; r <= end_row; r++) {
2023 for (c = 0; c < table->totalCols; c++) {
2024 HTMLObject *co;
2025 gint cx, cy;
2026
2027 cell = table->cells[r][c];
2028 if (cell == NULL)
2029 continue;
2030
2031 if (c < end_col - 1 && cell == table->cells[r][c + 1])
2032 continue;
2033 if (r < end_row - 1 && table->cells[r + 1][c] == cell)
2034 continue;
2035
2036 co = HTML_OBJECT (cell);
2037 cx = x;
2038 cy = y;
2039 if (for_cursor) {
2040 /* correct to include cell spacing */
2041 if (x < co->x && x >= co->x - hsa - tbc)
2042 cx = co->x;
2043 if (x >= co->x + co->width && x < co->x + co->width + hsb + tbc)
2044 cx = co->x + co->width - 1;
2045 if (y < co->y - co->ascent && y >= co->y - co->ascent - hsa - tbc)
2046 cy = co->y - co->ascent;
2047 if (y >= co->y + co->descent && y < co->y + co->descent + hsb + tbc)
2048 cy = co->y + co->descent - 1;
2049 }
2050
2051 obj = html_object_check_point (HTML_OBJECT (cell), painter, cx, cy, offset_return, for_cursor);
2052 if (obj != NULL)
2053 return obj;
2054 }
2055 }
2056
2057 if (!for_cursor) {
2058 if (x >= 0 && y >= 0 && x < self->width && y < self->ascent + self->descent) {
2059 if (offset_return) {
2060 if (x < self->width / 2)
2061 *offset_return = 0;
2062 else
2063 *offset_return = 1;
2064 }
2065 return self;
2066 }
2067 }
2068
2069 return NULL;
2070 }
2071
2072 static gboolean
search(HTMLObject * obj,HTMLSearch * info)2073 search (HTMLObject *obj,
2074 HTMLSearch *info)
2075 {
2076 HTMLTable *table = HTML_TABLE (obj);
2077 HTMLTableCell *cell;
2078 HTMLObject *cur = NULL;
2079 guint r, c, i, j;
2080 gboolean next = FALSE;
2081
2082 /* search_next? */
2083 if (html_search_child_on_stack (info, obj)) {
2084 cur = html_search_pop (info);
2085 next = TRUE;
2086 }
2087
2088 if (info->forward) {
2089 for (r = 0; r < table->totalRows; r++) {
2090 for (c = 0; c < table->totalCols; c++) {
2091
2092 if ((cell = table->cells[r][c]) == 0)
2093 continue;
2094 if (c < table->totalCols - 1 &&
2095 cell == table->cells[r][c + 1])
2096 continue;
2097 if (r < table->totalRows - 1 &&
2098 cell == table->cells[r + 1][c])
2099 continue;
2100
2101 if (next && cur) {
2102 if (HTML_OBJECT (cell) == cur) {
2103 cur = NULL;
2104 }
2105 continue;
2106 }
2107
2108 html_search_push (info, HTML_OBJECT (cell));
2109 if (html_object_search (HTML_OBJECT (cell), info)) {
2110 return TRUE;
2111 }
2112 html_search_pop (info);
2113 }
2114 }
2115 } else {
2116 for (i = 0, r = table->totalRows - 1; i < table->totalRows; i++, r--) {
2117 for (j = 0, c = table->totalCols - 1; j < table->totalCols; j++, c--) {
2118
2119 if ((cell = table->cells[r][c]) == 0)
2120 continue;
2121 if (c < table->totalCols - 1 &&
2122 cell == table->cells[r][c + 1])
2123 continue;
2124 if (r < table->totalRows - 1 &&
2125 cell == table->cells[r + 1][c])
2126 continue;
2127
2128 if (next && cur) {
2129 if (HTML_OBJECT (cell) == cur) {
2130 cur = NULL;
2131 }
2132 continue;
2133 }
2134
2135 html_search_push (info, HTML_OBJECT (cell));
2136 if (html_object_search (HTML_OBJECT (cell), info)) {
2137 return TRUE;
2138 }
2139 html_search_pop (info);
2140 }
2141 }
2142 }
2143
2144 if (next) {
2145 return html_search_next_parent (info);
2146 }
2147
2148 return FALSE;
2149 }
2150
2151 static void
append_selection_string(HTMLObject * self,GString * buffer)2152 append_selection_string (HTMLObject *self,
2153 GString *buffer)
2154 {
2155 HTMLTable *table;
2156 HTMLTableCell *cell;
2157 gboolean tab;
2158 gint r, c, len, rlen, tabs;
2159
2160 table = HTML_TABLE (self);
2161 for (r = 0; r < table->totalRows; r++) {
2162 tab = FALSE;
2163 tabs = 0;
2164 rlen = buffer->len;
2165 for (c = 0; c < table->totalCols; c++) {
2166 if ((cell = table->cells[r][c]) == 0)
2167 continue;
2168 if (c < table->totalCols - 1 &&
2169 cell == table->cells[r][c + 1])
2170 continue;
2171 if (r < table->totalRows - 1 &&
2172 table->cells[r + 1][c] == cell)
2173 continue;
2174 if (tab) {
2175 g_string_append_c (buffer, '\t');
2176 tabs++;
2177 }
2178 len = buffer->len;
2179 html_object_append_selection_string (HTML_OBJECT (cell), buffer);
2180 /* remove last \n from added text */
2181 if (buffer->len != len) {
2182 tab = TRUE;
2183 if (buffer->str[buffer->len - 1] == '\n')
2184 g_string_truncate (buffer, buffer->len - 1);
2185 }
2186 }
2187 if (rlen + tabs == buffer->len)
2188 g_string_truncate (buffer, rlen);
2189 else if (r + 1 < table->totalRows)
2190 g_string_append_c (buffer, '\n');
2191 }
2192 }
2193
2194 static HTMLObject *
head(HTMLObject * self)2195 head (HTMLObject *self)
2196 {
2197 HTMLTable *table;
2198 gint r, c;
2199
2200 table = HTML_TABLE (self);
2201 for (r = 0; r < table->totalRows; r++)
2202 for (c = 0; c < table->totalCols; c++) {
2203 if (invalid_cell (table, r, c))
2204 continue;
2205 return HTML_OBJECT (table->cells[r][c]);
2206 }
2207 return NULL;
2208 }
2209
2210 static HTMLObject *
tail(HTMLObject * self)2211 tail (HTMLObject *self)
2212 {
2213 HTMLTable *table;
2214 gint r, c;
2215
2216 table = HTML_TABLE (self);
2217 for (r = table->totalRows - 1; r >= 0; r--)
2218 for (c = table->totalCols - 1; c >= 0; c--) {
2219 if (invalid_cell (table, r, c))
2220 continue;
2221 return HTML_OBJECT (table->cells[r][c]);
2222 }
2223 return NULL;
2224 }
2225
2226 static HTMLObject *
next(HTMLObject * self,HTMLObject * child)2227 next (HTMLObject *self,
2228 HTMLObject *child)
2229 {
2230 HTMLTable *table;
2231 gint r, c;
2232
2233 table = HTML_TABLE (self);
2234 r = HTML_TABLE_CELL (child)->row;
2235 c = HTML_TABLE_CELL (child)->col + 1;
2236 for (; r < table->totalRows; r++) {
2237 for (; c < table->totalCols; c++) {
2238 if (invalid_cell (table, r, c))
2239 continue;
2240 return HTML_OBJECT (table->cells[r][c]);
2241 }
2242 c = 0;
2243 }
2244 return NULL;
2245 }
2246
2247 static HTMLObject *
prev(HTMLObject * self,HTMLObject * child)2248 prev (HTMLObject *self,
2249 HTMLObject *child)
2250 {
2251 HTMLTable *table;
2252 gint r, c;
2253
2254 table = HTML_TABLE (self);
2255 r = HTML_TABLE_CELL (child)->row;
2256 c = HTML_TABLE_CELL (child)->col - 1;
2257 for (; r >= 0; r--) {
2258 for (; c >=0; c--) {
2259 if (invalid_cell (table, r, c))
2260 continue;
2261 return HTML_OBJECT (table->cells[r][c]);
2262 }
2263 c = table->totalCols - 1;
2264 }
2265 return NULL;
2266 }
2267
2268 #define SB if (!html_engine_save_output_string (state,
2269 #define SE )) return FALSE
2270
2271 static gboolean
save(HTMLObject * self,HTMLEngineSaveState * state)2272 save (HTMLObject *self,
2273 HTMLEngineSaveState *state)
2274 {
2275 HTMLTable *table;
2276 gint r, c;
2277
2278 table = HTML_TABLE (self);
2279
2280 SB "<TABLE" SE;
2281 if (table->bgColor)
2282 SB " BGCOLOR=\"#%02x%02x%02x\"",
2283 table->bgColor->red >> 8,
2284 table->bgColor->green >> 8,
2285 table->bgColor->blue >> 8 SE;
2286 if (table->bgPixmap) {
2287 gchar * url = html_image_resolve_image_url (state->engine->widget, table->bgPixmap->url);
2288 if (!html_engine_save_delims_and_vals (state, " BACKGROUND=\"", url, "\"", NULL))
2289 {
2290 g_free (url);
2291 return FALSE;
2292 }
2293 g_free (url);
2294 }
2295 if (table->spacing != 2)
2296 SB " CELLSPACING=\"%d\"", table->spacing SE;
2297 if (table->padding != 1)
2298 SB " CELLPADDING=\"%d\"", table->padding SE;
2299 if (self->percent > 0) {
2300 SB " WIDTH=\"%d%%\"", self->percent SE;
2301 } else if (self->flags & HTML_OBJECT_FLAG_FIXEDWIDTH)
2302 SB " WIDTH=\"%d\"", table->specified_width SE;
2303 if (table->border)
2304 SB " BORDER=\"%d\"", table->border SE;
2305 SB ">\n" SE;
2306
2307 for (r = 0; r < table->totalRows; r++) {
2308 SB "<TR>\n" SE;
2309 for (c = 0; c < table->totalCols; c++) {
2310 if (!table->cells[r][c]
2311 || table->cells[r][c]->row != r
2312 || table->cells[r][c]->col != c)
2313 continue;
2314 if (!html_object_save (HTML_OBJECT (table->cells[r][c]), state))
2315 return FALSE;
2316 }
2317 SB "</TR>\n" SE;
2318 }
2319 SB "</TABLE>" SE;
2320
2321 return TRUE;
2322 }
2323
2324 static gboolean
save_plain(HTMLObject * self,HTMLEngineSaveState * state,gint requested_width)2325 save_plain (HTMLObject *self,
2326 HTMLEngineSaveState *state,
2327 gint requested_width)
2328 {
2329 HTMLTable *table;
2330 gint r, c;
2331 gboolean result = TRUE;
2332
2333 table = HTML_TABLE (self);
2334
2335 for (r = 0; r < table->totalRows; r++) {
2336 for (c = 0; c < table->totalCols; c++) {
2337 if (!table->cells[r][c]
2338 || table->cells[r][c]->row != r
2339 || table->cells[r][c]->col != c)
2340 continue;
2341 /* FIXME the width calculation for the column here is completely broken */
2342 result &= html_object_save_plain (HTML_OBJECT (table->cells[r][c]), state, requested_width / table->totalCols);
2343 }
2344 }
2345
2346 return result;
2347 }
2348
2349 static gboolean
check_row_split(HTMLTable * table,HTMLPainter * painter,gint r,gint * min_y)2350 check_row_split (HTMLTable *table,
2351 HTMLPainter *painter,
2352 gint r,
2353 gint *min_y)
2354 {
2355 HTMLTableCell *cell;
2356 gboolean changed = FALSE;
2357 gint c, cs;
2358
2359 for (c = 0; c < table->totalCols; c++) {
2360 gint y1, y2;
2361
2362 cell = table->cells[r][c];
2363 if (cell == NULL || cell->col != c)
2364 continue;
2365
2366 y1 = HTML_OBJECT (cell)->y - HTML_OBJECT (cell)->ascent;
2367 y2 = HTML_OBJECT (cell)->y + HTML_OBJECT (cell)->descent;
2368
2369 if (y1 <= *min_y && *min_y < y2) {
2370 cs = html_object_check_page_split (HTML_OBJECT (cell), painter, *min_y - y1) + y1;
2371 /* printf ("r %d min_y: %d y1: %d y2: %d --> cs=%d\n", *min_y, y1, y2, cs); */
2372
2373 if (cs < *min_y) {
2374 *min_y = cs;
2375 changed = TRUE;
2376 }
2377 }
2378 }
2379
2380 return changed;
2381 }
2382
2383 static gint
check_page_split(HTMLObject * self,HTMLPainter * painter,gint y)2384 check_page_split (HTMLObject *self,
2385 HTMLPainter *painter,
2386 gint y)
2387 {
2388 HTMLTable *table;
2389 gint r, min_y;
2390
2391 table = HTML_TABLE (self);
2392 r = to_index (bin_search_index (table->rowHeights, 0, table->totalRows, y), 0, table->totalRows - 1);
2393 if (y < ROW_HEIGHT (table, r) && r > 0)
2394 r--;
2395
2396 /* printf ("y: %d rh: %d rh+1: %d\n", y, ROW_HEIGHT (table, r), ROW_HEIGHT (table, r+1)); */
2397
2398 /* if (r >= table->totalRows)
2399 * return MIN (y, ROW_HEIGHT (table, table->totalRows)); */
2400
2401 min_y = MIN (y, ROW_HEIGHT (table, r + 1));
2402 while (check_row_split (table, painter, r, &min_y));
2403
2404 /* printf ("min_y=%d\n", min_y); */
2405
2406 return min_y;
2407 }
2408
2409 static GdkColor *
get_bg_color(HTMLObject * o,HTMLPainter * p)2410 get_bg_color (HTMLObject *o,
2411 HTMLPainter *p)
2412 {
2413
2414 return HTML_TABLE (o)->bgColor
2415 ? HTML_TABLE (o)->bgColor
2416 : html_object_get_bg_color (o->parent, p);
2417 }
2418
2419
2420 void
html_table_type_init(void)2421 html_table_type_init (void)
2422 {
2423 html_table_class_init (&html_table_class, HTML_TYPE_TABLE, sizeof (HTMLTable));
2424 }
2425
2426 void
html_table_class_init(HTMLTableClass * klass,HTMLType type,guint object_size)2427 html_table_class_init (HTMLTableClass *klass,
2428 HTMLType type,
2429 guint object_size)
2430 {
2431 HTMLObjectClass *object_class;
2432
2433 object_class = HTML_OBJECT_CLASS (klass);
2434
2435 html_object_class_init (object_class, type, object_size);
2436
2437 object_class->copy = copy;
2438 object_class->op_copy = op_copy;
2439 object_class->op_cut = op_cut;
2440 object_class->split = split;
2441 object_class->merge = merge;
2442 object_class->accepts_cursor = accepts_cursor;
2443 object_class->calc_size = html_table_real_calc_size;
2444 object_class->draw = draw;
2445 object_class->destroy = destroy;
2446 object_class->calc_min_width = calc_min_width;
2447 object_class->calc_preferred_width = calc_preferred_width;
2448 object_class->set_max_width = html_table_set_max_width;
2449 object_class->set_max_height = html_table_set_max_height;
2450 object_class->reset = reset;
2451 object_class->check_point = check_point;
2452 object_class->find_anchor = find_anchor;
2453 object_class->is_container = is_container;
2454 object_class->forall = forall;
2455 object_class->search = search;
2456 object_class->append_selection_string = append_selection_string;
2457 object_class->head = head;
2458 object_class->tail = tail;
2459 object_class->next = next;
2460 object_class->prev = prev;
2461 object_class->save = save;
2462 object_class->save_plain = save_plain;
2463 object_class->check_page_split = check_page_split;
2464 object_class->get_bg_color = get_bg_color;
2465 object_class->get_recursive_length = get_recursive_length;
2466 object_class->remove_child = remove_child;
2467 object_class->get_n_children = get_n_children;
2468 object_class->get_child = get_child;
2469 object_class->get_child_index = get_child_index;
2470
2471 parent_class = &html_object_class;
2472 }
2473
2474 void
html_table_init(HTMLTable * table,HTMLTableClass * klass,gint width,gint percent,gint padding,gint spacing,gint border)2475 html_table_init (HTMLTable *table,
2476 HTMLTableClass *klass,
2477 gint width,
2478 gint percent,
2479 gint padding,
2480 gint spacing,
2481 gint border)
2482 {
2483 HTMLObject *object;
2484 gint r;
2485
2486 object = HTML_OBJECT (table);
2487
2488 html_object_init (object, HTML_OBJECT_CLASS (klass));
2489
2490 object->percent = percent;
2491
2492 table->specified_width = width;
2493 if (width == 0)
2494 object->flags &= ~ HTML_OBJECT_FLAG_FIXEDWIDTH;
2495 else
2496 object->flags |= HTML_OBJECT_FLAG_FIXEDWIDTH;
2497
2498 table->padding = padding;
2499 table->spacing = spacing;
2500 table->border = border;
2501 table->caption = NULL;
2502 table->capAlign = HTML_VALIGN_TOP;
2503 table->bgColor = NULL;
2504 table->bgPixmap = NULL;
2505
2506 table->row = 0;
2507 table->col = 0;
2508
2509 table->totalCols = 1; /* this should be expanded to the maximum number
2510 of cols by the first row parsed */
2511 table->totalRows = 1;
2512 table->allocRows = 5; /* allocate five rows initially */
2513
2514 table->cells = g_new0 (HTMLTableCell **, table->allocRows);
2515 for (r = 0; r < table->allocRows; r++)
2516 table->cells[r] = g_new0 (HTMLTableCell *, table->totalCols);;
2517
2518 table->columnMin = g_array_new (FALSE, FALSE, sizeof (gint));
2519 table->columnFixed = g_array_new (FALSE, FALSE, sizeof (gint));
2520 table->columnPref = g_array_new (FALSE, FALSE, sizeof (gint));
2521 table->columnOpt = g_array_new (FALSE, FALSE, sizeof (gint));
2522 table->rowHeights = g_array_new (FALSE, FALSE, sizeof (gint));
2523 }
2524
2525 HTMLObject *
html_table_new(gint width,gint percent,gint padding,gint spacing,gint border)2526 html_table_new (gint width,
2527 gint percent,
2528 gint padding,
2529 gint spacing,
2530 gint border)
2531 {
2532 HTMLTable *table;
2533
2534 table = g_new (HTMLTable, 1);
2535 html_table_init (table, &html_table_class,
2536 width, percent, padding, spacing, border);
2537
2538 return HTML_OBJECT (table);
2539 }
2540
2541
2542
2543 void
html_table_add_cell(HTMLTable * table,HTMLTableCell * cell)2544 html_table_add_cell (HTMLTable *table,
2545 HTMLTableCell *cell)
2546 {
2547 html_table_alloc_cell (table, table->row, table->col);
2548 prev_col_do_cspan (table, table->row);
2549
2550 /* look for first free cell */
2551 while (table->cells[table->row][table->col] && table->col < table->totalCols)
2552 table->col++;
2553
2554 html_table_alloc_cell (table, table->row, table->col);
2555 html_table_set_cell (table, table->row, table->col, cell);
2556 html_table_cell_set_position (cell, table->row, table->col);
2557 do_cspan (table, table->row, table->col, cell);
2558 }
2559
2560 void
html_table_start_row(HTMLTable * table)2561 html_table_start_row (HTMLTable *table)
2562 {
2563 table->col = 0;
2564 }
2565
2566 void
html_table_end_row(HTMLTable * table)2567 html_table_end_row (HTMLTable *table)
2568 {
2569 if (table->row >= table->totalRows)
2570 inc_rows (table, 1);
2571 table->row++;
2572 }
2573
2574 gint
html_table_end_table(HTMLTable * table)2575 html_table_end_table (HTMLTable *table)
2576 {
2577 gint r, c, cells = 0;
2578
2579 for (r = 0; r < table->totalRows; r++)
2580 for (c = 0; c < table->totalCols; c++)
2581 if (table->cells[r][c]) {
2582 if (HTML_CLUE (table->cells[r][c])->head == NULL) {
2583 HTMLTableCell *cell = table->cells[r][c];
2584
2585 remove_cell (table, cell);
2586 html_object_destroy (HTML_OBJECT (cell));
2587 } else
2588 cells++;
2589 }
2590 return cells;
2591 }
2592