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, 2000 Helix Code, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <config.h>
25 #include "htmlclue.h"
26 #include "htmlclueflow.h"
27 #include "htmlobject.h"
28 #include "htmlsearch.h"
29 #include "htmltextslave.h"
30 #include "htmltype.h"
31
32
33 #define HC_CLASS(x) (HTML_CLUE_CLASS (HTML_OBJECT (x)->klass))
34
35 HTMLClueClass html_clue_class;
36 static HTMLObjectClass *parent_class = NULL;
37
38 static void set_parent (HTMLObject *o, HTMLObject *tail, HTMLObject *parent);
39
40 /* HTMLObject methods. */
41
42 static void
destroy(HTMLObject * o)43 destroy (HTMLObject *o)
44 {
45 HTMLObject *p;
46 HTMLObject *next;
47
48 for (p = HTML_CLUE (o)->head; p != NULL; p = next) {
49 next = p->next;
50 html_object_destroy (p);
51 }
52 HTML_CLUE (o)->head = NULL;
53 HTML_CLUE (o)->tail = NULL;
54
55 HTML_OBJECT_CLASS (parent_class)->destroy (o);
56 }
57
58 static gint
get_n_children(HTMLObject * o)59 get_n_children (HTMLObject *o)
60 {
61 HTMLObject *cur = HTML_CLUE (o)->head;
62 gint n_children = 0;
63
64 while (cur) {
65 n_children++;
66 cur = html_object_next_not_slave (cur);
67 }
68
69 return n_children;
70 }
71
72 static HTMLObject *
get_child(HTMLObject * o,gint index)73 get_child (HTMLObject *o,
74 gint index)
75 {
76 HTMLObject *cur = HTML_CLUE (o)->head;
77
78 g_return_val_if_fail (index >= 0, NULL);
79
80 while (cur) {
81 if (!index)
82 break;
83 index--;
84 cur = html_object_next_not_slave (cur);
85 }
86
87 return cur;
88 }
89
90 static gint
get_child_index(HTMLObject * self,HTMLObject * child)91 get_child_index (HTMLObject *self,
92 HTMLObject *child)
93 {
94 HTMLObject *cur = HTML_CLUE (self)->head;
95 gint index = 0;
96
97 while (cur) {
98 if (cur == child)
99 return index;
100 index++;
101 cur = html_object_next_not_slave (cur);
102 }
103
104 return -1;
105 }
106
107 static guint
get_recursive_length(HTMLObject * self)108 get_recursive_length (HTMLObject *self)
109 {
110 HTMLObject *o = HTML_CLUE (self)->head;
111 guint len = 0;
112
113 while (o) {
114 len += html_object_get_recursive_length (o);
115 o = o->next;
116 }
117
118 return len;
119 }
120
121 static void
copy(HTMLObject * self,HTMLObject * dest)122 copy (HTMLObject *self,
123 HTMLObject *dest)
124 {
125 (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);
126
127 HTML_CLUE (dest)->head = NULL;
128 HTML_CLUE (dest)->tail = NULL;
129 HTML_CLUE (dest)->curr = NULL;
130
131 HTML_CLUE (dest)->valign = HTML_CLUE (self)->valign;
132 HTML_CLUE (dest)->halign = HTML_CLUE (self)->halign;
133 }
134
135 static HTMLObject *
op_helper(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len,gboolean cut)136 op_helper (HTMLObject *self,
137 HTMLEngine *e,
138 GList *from,
139 GList *to,
140 GList *left,
141 GList *right,
142 guint *len,
143 gboolean cut)
144 {
145 HTMLClue *clue = HTML_CLUE (self);
146 HTMLObject *cc;
147 HTMLObject *o, *last, *cnext, *child;
148
149 cc = html_object_dup (self);
150 o = (from) ? HTML_OBJECT (from->data) : clue->head;
151 last = (to) ? HTML_OBJECT (to->data) : clue->tail;
152
153 if ((o == NULL) || (last == NULL))
154 return cc;
155
156 if (HTML_IS_TEXT_SLAVE (last))
157 last = html_object_prev_not_slave (last);
158
159 g_assert (o->parent == self);
160 g_assert (last->parent == self);
161
162 while (o) {
163 cnext = html_object_next_not_slave (o);
164 child = cut ? html_object_op_cut (o, e,
165 html_object_get_bound_list (o, from),
166 html_object_get_bound_list (o, to),
167 left ? left->next : NULL, right ? right->next : NULL, len)
168 : html_object_op_copy (o, cc, e,
169 html_object_get_bound_list (o, from),
170 html_object_get_bound_list (o, to), len);
171 if (child)
172 html_clue_append (HTML_CLUE (cc), child);
173
174 if (o == last)
175 break;
176 o = cnext;
177 }
178
179 return cc;
180 }
181
182 static HTMLObject *
op_copy(HTMLObject * self,HTMLObject * parent,HTMLEngine * e,GList * from,GList * to,guint * len)183 op_copy (HTMLObject *self,
184 HTMLObject *parent,
185 HTMLEngine *e,
186 GList *from,
187 GList *to,
188 guint *len)
189 {
190 return op_helper (self, e, from, to, NULL, NULL, len, FALSE);
191 }
192
193 static HTMLObject *
op_cut(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len)194 op_cut (HTMLObject *self,
195 HTMLEngine *e,
196 GList *from,
197 GList *to,
198 GList *left,
199 GList *right,
200 guint *len)
201 {
202 HTMLObject *rv;
203 HTMLClue *clue;
204
205 clue = HTML_CLUE (self);
206 rv = op_helper (self, e, from, to, left, right, len, TRUE);
207 if (!clue->head) {
208 if (self->parent)
209 html_object_remove_child (self->parent, self);
210 html_object_destroy (self);
211 } else
212 html_object_change_set (self, HTML_CHANGE_ALL_CALC);
213
214 return rv;
215 }
216
217 static gboolean
merge(HTMLObject * self,HTMLObject * with,HTMLEngine * e,GList ** left,GList ** right,HTMLCursor * cursor)218 merge (HTMLObject *self,
219 HTMLObject *with,
220 HTMLEngine *e,
221 GList **left,
222 GList **right,
223 HTMLCursor *cursor)
224 {
225 HTMLClue *clue1, *clue2;
226
227 clue1 = HTML_CLUE (self);
228 clue2 = HTML_CLUE (with);
229
230 html_clue_append (clue1, clue2->head);
231 clue2->head = NULL;
232 clue2->tail = NULL;
233
234 html_object_change_set (self, HTML_CHANGE_ALL_CALC);
235 return TRUE;
236 }
237
238 static void
remove_child(HTMLObject * self,HTMLObject * child)239 remove_child (HTMLObject *self,
240 HTMLObject *child)
241 {
242 html_clue_remove (HTML_CLUE (self), child);
243 }
244
245 static void
split(HTMLObject * self,HTMLEngine * e,HTMLObject * child,gint offset,gint level,GList ** left,GList ** right)246 split (HTMLObject *self,
247 HTMLEngine *e,
248 HTMLObject *child,
249 gint offset,
250 gint level,
251 GList **left,
252 GList **right)
253 {
254 HTMLObject *dup;
255
256 dup = html_object_dup (self);
257
258 HTML_CLUE (dup)->tail = HTML_CLUE (self)->tail;
259 HTML_CLUE (self)->tail = child->prev;
260 if (child->prev)
261 child->prev->next = NULL;
262 child->prev = NULL;
263 if (child == HTML_CLUE (self)->head)
264 HTML_CLUE (self)->head = NULL;
265 HTML_CLUE (dup)->head = child;
266 set_parent (child, NULL, dup);
267
268 if (self->parent && HTML_OBJECT_TYPE (self->parent) != HTML_TYPE_TABLE)
269 html_clue_append_after (HTML_CLUE (self->parent), dup, self);
270
271 self->x = 0;
272 self->y = 0;
273
274 *left = g_list_prepend (*left, self);
275 *right = g_list_prepend (*right, dup);
276
277 level--;
278 if (level > 0)
279 html_object_split (self->parent, e, dup, 0, level, left, right);
280 }
281
282 static void
draw(HTMLObject * o,HTMLPainter * p,gint x,gint y,gint width,gint height,gint tx,gint ty)283 draw (HTMLObject *o,
284 HTMLPainter *p,
285 gint x,
286 gint y,
287 gint width,
288 gint height,
289 gint tx,
290 gint ty)
291 {
292 HTMLObject *obj;
293
294 if (y + height < o->y - o->ascent || y > o->y + o->descent)
295 return;
296
297 tx += o->x;
298 ty += o->y - o->ascent;
299
300 for (obj = HTML_CLUE (o)->head; obj != 0; obj = obj->next) {
301 if (!(obj->flags & HTML_OBJECT_FLAG_ALIGNED)) {
302 html_object_draw (obj,
303 p,
304 x - o->x, y - (o->y - o->ascent),
305 width, height,
306 tx, ty);
307 }
308 }
309 }
310
311 static void
set_max_height(HTMLObject * o,HTMLPainter * painter,gint height)312 set_max_height (HTMLObject *o,
313 HTMLPainter *painter,
314 gint height)
315 {
316 HTMLClue *clue = HTML_CLUE (o);
317 HTMLObject *obj;
318
319 if (o->ascent < height) {
320 for (obj = HTML_CLUE (o)->head; obj != 0; obj = obj->next) {
321 html_object_set_max_height (obj, painter, height);
322 if (clue->valign == HTML_VALIGN_MIDDLE)
323 obj->y += (height - o->ascent) / 2;
324 else if (clue->valign == HTML_VALIGN_BOTTOM)
325 obj->y += height - o->ascent;
326 }
327
328 o->ascent = height;
329 }
330 }
331
332 static void
reset(HTMLObject * clue)333 reset (HTMLObject *clue)
334 {
335 HTMLObject *obj;
336
337 for (obj = HTML_CLUE (clue)->head; obj != NULL; obj = obj->next)
338 html_object_reset (obj);
339
340 HTML_CLUE (clue)->curr = NULL;
341
342 (* HTML_OBJECT_CLASS (parent_class)->reset) (HTML_OBJECT (clue));
343 }
344
345 static gboolean
html_clue_real_calc_size(HTMLObject * o,HTMLPainter * painter,GList ** changed_objs)346 html_clue_real_calc_size (HTMLObject *o,
347 HTMLPainter *painter,
348 GList **changed_objs)
349 {
350 gboolean changed;
351
352 /* If we have already called calc_size for the children, then just
353 * continue from the last object done in previous call. */
354 if (HTML_CLUE (o)->curr == NULL) {
355 o->ascent = 0;
356 HTML_CLUE (o)->curr = HTML_CLUE (o)->head;
357 }
358
359 changed = FALSE;
360
361 while (HTML_CLUE (o)->curr != NULL) {
362 changed |= html_object_calc_size (HTML_CLUE (o)->curr, painter, changed_objs);
363 HTML_CLUE (o)->curr = HTML_CLUE (o)->curr->next;
364 }
365
366 /* Remember the last object so that we can start from here next time
367 * we are called */
368 HTML_CLUE (o)->curr = HTML_CLUE (o)->tail;
369
370 return changed;
371 }
372
373 static gint
calc_preferred_width(HTMLObject * o,HTMLPainter * painter)374 calc_preferred_width (HTMLObject *o,
375 HTMLPainter *painter)
376 {
377 gint prefWidth = 0;
378 HTMLObject *obj;
379
380 for (obj = HTML_CLUE (o)->head; obj != 0; obj = obj->next) {
381 gint w;
382
383 w = html_object_calc_preferred_width (obj, painter);
384 if (w > prefWidth)
385 prefWidth = w;
386 }
387
388 return prefWidth;
389 }
390
391 /* FIXME: This should be in HTMLClueV. */
392 static gint
calc_min_width(HTMLObject * o,HTMLPainter * painter)393 calc_min_width (HTMLObject *o,
394 HTMLPainter *painter)
395 {
396 HTMLObject *obj;
397 gint minWidth = 0;
398
399 for (obj = HTML_CLUE (o)->head; obj != 0; obj = obj->next) {
400 gint w;
401
402 w = html_object_calc_min_width (obj, painter);
403 if (w > minWidth)
404 minWidth = w;
405 }
406
407 return minWidth;
408 }
409
410 static HTMLAnchor *
find_anchor(HTMLObject * self,const gchar * name,gint * x,gint * y)411 find_anchor (HTMLObject *self,
412 const gchar *name,
413 gint *x,
414 gint *y)
415 {
416 HTMLClue *clue;
417 HTMLObject *obj;
418 HTMLAnchor *anchor;
419
420 *x += self->x;
421 *y += self->y - self->ascent;
422
423 clue = HTML_CLUE (self);
424
425 for (obj = clue->head; obj != NULL; obj = obj->next) {
426 if ((anchor = html_object_find_anchor (obj, name, x, y)) != 0 )
427 return anchor;
428 }
429
430 *x -= self->x;
431 *y -= self->y - self->ascent;
432
433 return 0;
434 }
435
436 static HTMLObject *
check_point(HTMLObject * o,HTMLPainter * painter,gint x,gint y,guint * offset_return,gboolean for_cursor)437 check_point (HTMLObject *o,
438 HTMLPainter *painter,
439 gint x,
440 gint y,
441 guint *offset_return,
442 gboolean for_cursor)
443 {
444 HTMLObject *obj;
445 HTMLObject *obj2;
446
447 if (x < o->x || x >= o->x + o->width
448 || y >= o->y + o->descent || y < o->y - o->ascent)
449 return NULL;
450
451 x = x - o->x;
452 y = y - o->y + o->ascent;
453
454 for (obj = HTML_CLUE (o)->head; obj != 0; obj = obj->next) {
455 obj2 = html_object_check_point (obj, painter,
456 x, y, offset_return,
457 for_cursor);
458 if (obj2 != NULL)
459 return obj2;
460 }
461
462 return NULL;
463 }
464
465 static gint
check_page_split(HTMLObject * self,HTMLPainter * painter,gint y)466 check_page_split (HTMLObject *self,
467 HTMLPainter *painter,
468 gint y)
469 {
470 HTMLClue *clue;
471 HTMLObject *p;
472 gint last_under = 0;
473
474 clue = HTML_CLUE (self);
475 for (p = clue->head; p != NULL; p = p->next) {
476 gint y1, y2;
477
478 y1 = p->y - p->ascent;
479 y2 = p->y + p->descent;
480
481 if (y1 > y)
482 return last_under;
483
484 if (y >= y1 && y < y2)
485 return html_object_check_page_split (p, painter, y - y1) + y1;
486 last_under = y2;
487 }
488
489 return y;
490 }
491
492 static void
forall(HTMLObject * self,HTMLEngine * e,HTMLObjectForallFunc func,gpointer data)493 forall (HTMLObject *self,
494 HTMLEngine *e,
495 HTMLObjectForallFunc func,
496 gpointer data)
497 {
498 HTMLObject *p, *pnext;
499
500 for (p = HTML_CLUE (self)->head; p != NULL; p = pnext) {
501 pnext = p->next;
502 html_object_forall (p, e, func, data);
503 }
504
505 html_object_class.forall (self, e, func, data);
506 }
507
508 static gboolean
is_container(HTMLObject * self)509 is_container (HTMLObject *self)
510 {
511 return TRUE;
512 }
513
514 static gboolean
save(HTMLObject * self,HTMLEngineSaveState * state)515 save (HTMLObject *self,
516 HTMLEngineSaveState *state)
517 {
518 HTMLObject *p;
519 HTMLClue *clue;
520
521 clue = HTML_CLUE (self);
522
523 for (p = clue->head; p != NULL; p = p->next) {
524 if (!html_object_save (p, state))
525 return FALSE;
526 }
527
528 return TRUE;
529 }
530
531 static gboolean
save_plain(HTMLObject * self,HTMLEngineSaveState * state,gint requested_width)532 save_plain (HTMLObject *self,
533 HTMLEngineSaveState *state,
534 gint requested_width)
535 {
536 HTMLObject *p;
537 HTMLClue *clue;
538
539 clue = HTML_CLUE (self);
540
541 for (p = clue->head; p != NULL; p = p->next) {
542 if (!html_object_save_plain (p, state, requested_width))
543 return FALSE;
544 }
545
546 return TRUE;
547 }
548
549 /* HTMLClue methods. */
550
551 static gint
get_left_clear(HTMLClue * o,gint y)552 get_left_clear (HTMLClue *o,
553 gint y)
554 {
555 return y;
556 }
557
558 static gint
get_right_clear(HTMLClue * o,gint y)559 get_right_clear (HTMLClue *o,
560 gint y)
561 {
562 return y;
563 }
564
565 static void
find_free_area(HTMLClue * clue,HTMLPainter * painter,gint y,gint width,gint height,gint indent,gint * y_pos,gint * lmargin,gint * rmargin)566 find_free_area (HTMLClue *clue,
567 HTMLPainter *painter,
568 gint y,
569 gint width,
570 gint height,
571 gint indent,
572 gint *y_pos,
573 gint *lmargin,
574 gint *rmargin)
575 {
576 *y_pos = y;
577 *lmargin = 0;
578 *rmargin = MAX (HTML_OBJECT (clue)->max_width, HTML_OBJECT (clue)->width);
579 }
580
581 static void
append_right_aligned(HTMLClue * clue,HTMLPainter * painter,HTMLClue * aclue,gint * lmargin,gint * rmargin,gint indent)582 append_right_aligned (HTMLClue *clue,
583 HTMLPainter *painter,
584 HTMLClue *aclue,
585 gint *lmargin,
586 gint *rmargin,
587 gint indent)
588 {
589 /* This needs to be implemented in the subclasses. */
590 g_warning ("`%s' does not implement `append_right_aligned()'.",
591 html_type_name (HTML_OBJECT_TYPE (clue)));
592 }
593
594 static gboolean
appended(HTMLClue * clue,HTMLClue * aclue)595 appended (HTMLClue *clue,
596 HTMLClue *aclue)
597 {
598 return FALSE;
599 }
600
601 static gboolean
search(HTMLObject * obj,HTMLSearch * info)602 search (HTMLObject *obj,
603 HTMLSearch *info)
604 {
605 HTMLObject *cur;
606 HTMLClue *clue = HTML_CLUE (obj);
607 gboolean next = FALSE;
608
609 /* search_next? */
610 if (html_search_child_on_stack (info, obj)) {
611 cur = html_search_pop (info);
612 cur = (info->forward) ? cur->next : cur->prev;
613 next = TRUE;
614 } else
615 cur = (info->forward) ? clue->head : clue->tail;
616
617 while (cur) {
618 html_search_push (info, cur);
619 if (html_object_search (cur, info))
620 return TRUE;
621
622 html_search_pop (info);
623 cur = (info->forward) ? cur->next : cur->prev;
624 }
625
626 if (next)
627 return html_search_next_parent (info);
628
629 return FALSE;
630 }
631
632 static void
append_selection_string(HTMLObject * self,GString * buffer)633 append_selection_string (HTMLObject *self,
634 GString *buffer)
635 {
636 HTMLObject *o = HTML_CLUE (self)->head;
637
638 while (o) {
639 html_object_append_selection_string (o, buffer);
640 o = o->next;
641 }
642 }
643
644 static HTMLObject *
clue_head(HTMLObject * self)645 clue_head (HTMLObject *self)
646 {
647 return HTML_CLUE (self)->head;
648 }
649
650 static HTMLObject *
clue_tail(HTMLObject * self)651 clue_tail (HTMLObject *self)
652 {
653 HTMLObject *obj;
654
655 obj = HTML_CLUE (self)->tail;
656 return (obj && HTML_OBJECT_TYPE (obj) == HTML_TYPE_TEXTSLAVE) ? html_object_prev_not_slave (obj) : obj;
657 }
658
659
660 void
html_clue_type_init(void)661 html_clue_type_init (void)
662 {
663 html_clue_class_init (&html_clue_class, HTML_TYPE_CLUE, sizeof (HTMLClue));
664 }
665
666 void
html_clue_class_init(HTMLClueClass * klass,HTMLType type,guint size)667 html_clue_class_init (HTMLClueClass *klass,
668 HTMLType type,
669 guint size)
670 {
671 HTMLObjectClass *object_class;
672
673 g_return_if_fail (klass != NULL);
674
675 object_class = HTML_OBJECT_CLASS (klass);
676 html_object_class_init (object_class, type, size);
677
678 /* HTMLObject functions */
679 object_class->destroy = destroy;
680 object_class->copy = copy;
681 object_class->op_copy = op_copy;
682 object_class->op_cut = op_cut;
683 object_class->merge = merge;
684 object_class->remove_child = remove_child;
685 object_class->split = split;
686 object_class->draw = draw;
687 object_class->set_max_height = set_max_height;
688 object_class->reset = reset;
689 object_class->calc_size = html_clue_real_calc_size;
690 object_class->calc_preferred_width = calc_preferred_width;
691 object_class->calc_min_width = calc_min_width;
692 object_class->check_point = check_point;
693 object_class->check_page_split = check_page_split;
694 object_class->find_anchor = find_anchor;
695 object_class->forall = forall;
696 object_class->is_container = is_container;
697 object_class->save = save;
698 object_class->save_plain = save_plain;
699 object_class->search = search;
700 object_class->append_selection_string = append_selection_string;
701 object_class->head = clue_head;
702 object_class->tail = clue_tail;
703 object_class->get_recursive_length = get_recursive_length;
704 object_class->get_n_children = get_n_children;
705 object_class->get_child = get_child;
706 object_class->get_child_index = get_child_index;
707
708 /* HTMLClue methods. */
709 klass->get_left_clear = get_left_clear;
710 klass->get_right_clear = get_right_clear;
711 klass->find_free_area = find_free_area;
712 klass->append_right_aligned = append_right_aligned;
713 klass->appended = appended;
714
715 parent_class = &html_object_class;
716 }
717
718 void
html_clue_init(HTMLClue * clue,HTMLClueClass * klass)719 html_clue_init (HTMLClue *clue,
720 HTMLClueClass *klass)
721 {
722 HTMLObject *object;
723
724 object = HTML_OBJECT (clue);
725 html_object_init (object, HTML_OBJECT_CLASS (klass));
726
727 clue->head = NULL;
728 clue->tail = NULL;
729 clue->curr = NULL;
730
731 clue->valign = HTML_VALIGN_TOP;
732 clue->halign = HTML_HALIGN_LEFT;
733 }
734
735
736 gint
html_clue_get_left_clear(HTMLClue * clue,gint y)737 html_clue_get_left_clear (HTMLClue *clue,
738 gint y)
739 {
740 return (* HC_CLASS (clue)->get_left_clear) (clue, y);
741 }
742
743 gint
html_clue_get_right_clear(HTMLClue * clue,gint y)744 html_clue_get_right_clear (HTMLClue *clue,
745 gint y)
746 {
747 return (* HC_CLASS (clue)->get_right_clear) (clue, y);
748 }
749
750 void
html_clue_find_free_area(HTMLClue * clue,HTMLPainter * painter,gint y,gint width,gint height,gint indent,gint * y_pos,gint * lmargin,gint * rmargin)751 html_clue_find_free_area (HTMLClue *clue,
752 HTMLPainter *painter,
753 gint y,
754 gint width,
755 gint height,
756 gint indent,
757 gint *y_pos,
758 gint *lmargin,
759 gint *rmargin)
760 {
761 (* HC_CLASS (clue)->find_free_area) (clue, painter, y, width, height, indent, y_pos, lmargin, rmargin);
762 }
763
764 void
html_clue_append_right_aligned(HTMLClue * clue,HTMLPainter * painter,HTMLClue * aclue,gint * lmargin,gint * rmargin,gint indent)765 html_clue_append_right_aligned (HTMLClue *clue,
766 HTMLPainter *painter,
767 HTMLClue *aclue,
768 gint *lmargin,
769 gint *rmargin,
770 gint indent)
771 {
772 g_assert (clue != NULL);
773 g_assert (aclue != NULL);
774
775 html_object_change_set (HTML_OBJECT (clue), HTML_OBJECT (aclue)->change);
776
777 (* HC_CLASS (clue)->append_right_aligned) (clue, painter, aclue, lmargin, rmargin, indent);
778 }
779
780 void
html_clue_append_left_aligned(HTMLClue * clue,HTMLPainter * painter,HTMLClue * aclue,gint * lmargin,gint * rmargin,gint indent)781 html_clue_append_left_aligned (HTMLClue *clue,
782 HTMLPainter *painter,
783 HTMLClue *aclue,
784 gint *lmargin,
785 gint *rmargin,
786 gint indent)
787 {
788 g_assert (clue != NULL);
789 g_assert (aclue != NULL);
790
791 html_object_change_set (HTML_OBJECT (clue), HTML_OBJECT (aclue)->change);
792
793 (* HC_CLASS (clue)->append_left_aligned) (clue, painter, aclue, lmargin, rmargin, indent);
794 }
795
796 gboolean
html_clue_appended(HTMLClue * clue,HTMLClue * aclue)797 html_clue_appended (HTMLClue *clue,
798 HTMLClue *aclue)
799 {
800 return (* HC_CLASS (clue)->appended) (clue, aclue);
801 }
802
803
804 /* Utility functions. */
805
806 static HTMLObject *
get_tail(HTMLObject * p)807 get_tail (HTMLObject *p)
808 {
809 if (p == NULL)
810 return NULL;
811
812 while (p->next != NULL)
813 p = p->next;
814
815 return p;
816 }
817
818 static void
set_parent(HTMLObject * o,HTMLObject * tail,HTMLObject * parent)819 set_parent (HTMLObject *o,
820 HTMLObject *tail,
821 HTMLObject *parent)
822 {
823 while (o) {
824 html_object_set_parent (o, parent);
825 if (o == tail)
826 break;
827 o = o->next;
828 }
829 }
830
831 /**
832 * html_clue_append_after:
833 * @clue: An HTMLClue.
834 * @o: An HTMLObject.
835 * @where: A child of @clue.
836 *
837 * Insert @o and its successors in @clue after @clue's element @where.
838 **/
839 void
html_clue_append_after(HTMLClue * clue,HTMLObject * o,HTMLObject * where)840 html_clue_append_after (HTMLClue *clue,
841 HTMLObject *o,
842 HTMLObject *where)
843 {
844 HTMLObject *tail;
845
846 g_return_if_fail (o != NULL);
847 g_return_if_fail (html_object_is_clue (HTML_OBJECT (clue)));
848
849 if (where == NULL) {
850 html_clue_prepend (clue, o);
851 return;
852 }
853 g_return_if_fail (where->parent == HTML_OBJECT (clue));
854
855 html_object_change_set (HTML_OBJECT (clue), o->change);
856
857 tail = get_tail (o);
858
859 if (where->next != NULL)
860 where->next->prev = tail;
861 tail->next = where->next;
862
863 where->next = o;
864 o->prev = where;
865
866 if (where == clue->tail)
867 clue->tail = tail;
868
869 set_parent (o, tail, HTML_OBJECT (clue));
870 }
871
872 /**
873 * html_clue_append:
874 * @clue: An HTMLClue.
875 * @o: An HTMLObject.
876 *
877 * Append @o and its successors to @clue.
878 **/
879 void
html_clue_append(HTMLClue * clue,HTMLObject * o)880 html_clue_append (HTMLClue *clue,
881 HTMLObject *o)
882 {
883 HTMLObject *tail;
884
885 g_return_if_fail (clue != NULL);
886 g_return_if_fail (html_object_is_clue (HTML_OBJECT (clue)));
887 g_return_if_fail (o != NULL);
888
889 html_object_change_set (HTML_OBJECT (clue), o->change);
890
891 tail = get_tail (o);
892
893 if (!clue->head) {
894 clue->head = o;
895 o->prev = NULL;
896 } else {
897 clue->tail->next = o;
898 o->prev = clue->tail;
899 }
900
901 clue->tail = tail;
902 tail->next = NULL;
903
904 html_object_set_parent (o, HTML_OBJECT (clue));
905
906 set_parent (o, tail, HTML_OBJECT (clue));
907 }
908
909 /**
910 * html_clue_prepend:
911 * @clue: An HTMLClue.
912 * @o: An HTMLObject.
913 *
914 * Prepend @o and its successors to @clue.
915 **/
916 void
html_clue_prepend(HTMLClue * clue,HTMLObject * o)917 html_clue_prepend (HTMLClue *clue,
918 HTMLObject *o)
919 {
920 HTMLObject *tail;
921
922 g_return_if_fail (clue != NULL);
923 g_return_if_fail (o != NULL);
924
925 html_object_change_set (HTML_OBJECT (clue), o->change);
926
927 tail = get_tail (o);
928
929 if (!clue->head) {
930 clue->head = o;
931 clue->tail = tail;
932 o->prev = NULL;
933 } else {
934 o->next = clue->head;
935 clue->head->prev = o;
936 clue->head = o;
937 }
938
939 o->prev = NULL;
940
941 set_parent (o, tail, HTML_OBJECT (clue));
942 }
943
944 /**
945 * html_clue_remove:
946 * @clue: An HTMLClue.
947 * @o: An HTMLObject.
948 *
949 * Remove object @o from the clue.
950 **/
951 void
html_clue_remove(HTMLClue * clue,HTMLObject * o)952 html_clue_remove (HTMLClue *clue,
953 HTMLObject *o)
954 {
955 g_return_if_fail (clue != NULL);
956 g_return_if_fail (o != NULL);
957 g_return_if_fail (clue == HTML_CLUE (o->parent));
958
959 if (o == clue->head)
960 clue->head = o->next;
961 if (o == clue->tail)
962 clue->tail = o->prev;
963
964 if (o->next != NULL)
965 o->next->prev = o->prev;
966 if (o->prev != NULL)
967 o->prev->next = o->next;
968
969 o->parent = NULL;
970 o->prev = NULL;
971 o->next = NULL;
972 }
973
974 void
html_clue_remove_text_slaves(HTMLClue * clue)975 html_clue_remove_text_slaves (HTMLClue *clue)
976 {
977 HTMLObject *p;
978 HTMLObject *pnext;
979
980 g_return_if_fail (clue != NULL);
981
982 for (p = clue->head; p != NULL; p = pnext) {
983 pnext = p->next;
984
985 if (HTML_OBJECT_TYPE (p) == HTML_TYPE_TEXTSLAVE) {
986 html_clue_remove (clue, p);
987 html_object_destroy (p);
988 }
989 }
990 }
991
992 gboolean
html_clue_is_empty(HTMLClue * clue)993 html_clue_is_empty (HTMLClue *clue)
994 {
995 if (clue->head == NULL)
996 return TRUE;
997 if (clue->head == clue->tail
998 && HTML_IS_CLUEFLOW (clue->head) && html_clueflow_is_empty (HTML_CLUEFLOW (clue->head)))
999 return TRUE;
1000 return FALSE;
1001 }
1002