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 <string.h>
26
27 #include "htmlclue.h"
28 #include "htmlclueflow.h"
29 #include "htmlcluealigned.h"
30 #include "htmlcluev.h"
31 #include "htmlcolor.h"
32 #include "htmlcolorset.h"
33 #include "htmlcursor.h"
34 #include "htmlengine.h"
35 #include "htmlengine-edit.h"
36 #include "htmlengine-edit-cut-and-paste.h"
37 #include "htmlengine-save.h"
38 #include "htmlframe.h"
39 #include "htmlinterval.h"
40 #include "htmlobject.h"
41 #include "htmlpainter.h"
42 #include "htmltable.h"
43 #include "htmltablecell.h"
44 #include "htmltext.h"
45 #include "htmlrule.h"
46 #include "htmltype.h"
47 #include "htmlsettings.h"
48
49 #include "gtkhtmldebug.h"
50
51
52 HTMLObjectClass html_object_class;
53
54 #define HO_CLASS(x) HTML_OBJECT_CLASS (HTML_OBJECT (x)->klass)
55
56 static void remove_child (HTMLObject *self, HTMLObject *child) G_GNUC_NORETURN;
57
58 static void
destroy(HTMLObject * self)59 destroy (HTMLObject *self)
60 {
61 #define GTKHTML_MEM_DEBUG 1
62 #if GTKHTML_MEM_DEBUG
63 self->parent = HTML_OBJECT (0xdeadbeef);
64 self->next = HTML_OBJECT (0xdeadbeef);
65 self->prev = HTML_OBJECT (0xdeadbeef);
66 #else
67 self->next = NULL;
68 self->prev = NULL;
69 #endif
70
71 g_datalist_clear (&self->object_data);
72 g_datalist_clear (&self->object_data_nocp);
73
74 g_free (self->id);
75 self->id = NULL;
76
77 if (self->redraw_pending) {
78 self->free_pending = TRUE;
79 } else {
80 g_free (self);
81 }
82 }
83
84 static void
copy(HTMLObject * self,HTMLObject * dest)85 copy (HTMLObject *self,
86 HTMLObject *dest)
87 {
88 dest->klass = self->klass;
89 dest->parent = NULL;
90 dest->prev = NULL;
91 dest->next = NULL;
92 dest->x = 0;
93 dest->y = 0;
94 dest->ascent = self->ascent;
95 dest->descent = self->descent;
96 dest->width = self->width;
97 dest->min_width = self->min_width;
98 dest->max_width = self->max_width;
99 dest->pref_width = self->pref_width;
100 dest->percent = self->percent;
101 dest->flags = self->flags;
102 dest->redraw_pending = FALSE;
103 dest->selected = FALSE;
104 dest->free_pending = FALSE;
105 dest->change = self->change;
106 dest->draw_focused = FALSE;
107 dest->id = g_strdup (self->id);
108
109 g_datalist_init (&dest->object_data);
110 html_object_copy_data_from_object (dest, self);
111
112 g_datalist_init (&dest->object_data_nocp);
113 }
114
115 static HTMLObject *
op_copy(HTMLObject * self,HTMLObject * parent,HTMLEngine * e,GList * from,GList * to,guint * len)116 op_copy (HTMLObject *self,
117 HTMLObject *parent,
118 HTMLEngine *e,
119 GList *from,
120 GList *to,
121 guint *len)
122 {
123 if ((!from || GPOINTER_TO_INT (from->data) == 0)
124 && (!to || GPOINTER_TO_INT (to->data) == html_object_get_length (self))) {
125 *len += html_object_get_recursive_length (self);
126
127 return html_object_dup (self);
128 } else
129 return html_engine_new_text_empty (e);
130 }
131
132 static HTMLObject *
op_cut(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len)133 op_cut (HTMLObject *self,
134 HTMLEngine *e,
135 GList *from,
136 GList *to,
137 GList *left,
138 GList *right,
139 guint *len)
140 {
141 if ((!from || GPOINTER_TO_INT (from->data) == 0)
142 && (!to || GPOINTER_TO_INT (to->data) == html_object_get_length (self))) {
143 if (!html_object_could_remove_whole (self, from, to, left, right)) {
144 HTMLObject *empty = html_engine_new_text_empty (e);
145
146 if (e->cursor->object == self)
147 e->cursor->object = empty;
148 html_clue_append_after (HTML_CLUE (self->parent), empty, self);
149 html_object_change_set (empty, HTML_CHANGE_ALL_CALC);
150 html_object_check_cut_lists (self, empty, left, right);
151 } else
152 html_object_move_cursor_before_remove (self, e);
153
154 html_object_change_set (self, HTML_CHANGE_ALL_CALC);
155 html_object_change_set (self->parent, HTML_CHANGE_ALL_CALC);
156 /* force parent redraw */
157 self->parent->width = 0;
158 html_object_remove_child (self->parent, self);
159 *len += html_object_get_recursive_length (self);
160
161 return self;
162 } else
163 return html_engine_new_text_empty (e);
164 }
165
166 static gboolean
merge(HTMLObject * self,HTMLObject * with,HTMLEngine * e,GList ** left,GList ** right,HTMLCursor * cursor)167 merge (HTMLObject *self,
168 HTMLObject *with,
169 HTMLEngine *e,
170 GList **left,
171 GList **right,
172 HTMLCursor *cursor)
173 {
174 if (self->parent) {
175 html_object_change_set (self->parent, HTML_CHANGE_ALL_CALC);
176 self->parent->width = 0;
177 }
178
179 return FALSE;
180 }
181
182 static void
remove_child(HTMLObject * self,HTMLObject * child)183 remove_child (HTMLObject *self,
184 HTMLObject *child)
185 {
186 g_warning ("REMOVE CHILD unimplemented for ");
187 gtk_html_debug_dump_object_type (self);
188 g_assert_not_reached ();
189 }
190
191 static void
split(HTMLObject * self,HTMLEngine * e,HTMLObject * child,gint offset,gint level,GList ** left,GList ** right)192 split (HTMLObject *self,
193 HTMLEngine *e,
194 HTMLObject *child,
195 gint offset,
196 gint level,
197 GList **left,
198 GList **right)
199 {
200 if (child || (offset && html_object_get_length (self) != offset)) {
201 g_warning ("don't know how to SPLIT ");
202 gtk_html_debug_dump_object_type (self);
203 return;
204 }
205
206 if (offset) {
207 if (!self->next) {
208 html_clue_append (HTML_CLUE (self->parent), html_engine_new_text_empty (e));
209 }
210 *left = g_list_prepend (*left, self);
211 *right = g_list_prepend (*right, self->next);
212 } else {
213 if (!self->prev) {
214 e->cursor->object = html_engine_new_text_empty (e);
215 e->cursor->offset = 0;
216 html_clue_prepend (HTML_CLUE (self->parent), e->cursor->object);
217 }
218 *left = g_list_prepend (*left, self->prev);
219 *right = g_list_prepend (*right, self);
220 }
221 level--;
222
223 if (level && self->parent)
224 html_object_split (self->parent, e, offset ? self->next : self, 0, level, left, right);
225 }
226
227 static void
draw(HTMLObject * o,HTMLPainter * p,gint x,gint y,gint width,gint height,gint tx,gint ty)228 draw (HTMLObject *o,
229 HTMLPainter *p,
230 gint x,
231 gint y,
232 gint width,
233 gint height,
234 gint tx,
235 gint ty)
236 {
237 /* Do nothing by default. We don't know how to paint ourselves. */
238 }
239
240 static gboolean
is_transparent(HTMLObject * self)241 is_transparent (HTMLObject *self)
242 {
243 return TRUE;
244 }
245
246 static HTMLFitType
fit_line(HTMLObject * o,HTMLPainter * painter,gboolean start_of_line,gboolean first_run,gboolean next_to_floating,gint width_left)247 fit_line (HTMLObject *o,
248 HTMLPainter *painter,
249 gboolean start_of_line,
250 gboolean first_run,
251 gboolean next_to_floating,
252 gint width_left)
253 {
254 return (o->width <= width_left || (first_run && !next_to_floating)) ? HTML_FIT_COMPLETE : HTML_FIT_NONE;
255 }
256
257 static gboolean
html_object_real_calc_size(HTMLObject * o,HTMLPainter * painter,GList ** changed_objs)258 html_object_real_calc_size (HTMLObject *o,
259 HTMLPainter *painter,
260 GList **changed_objs)
261 {
262 return FALSE;
263 }
264
265 static gint
calc_min_width(HTMLObject * o,HTMLPainter * painter)266 calc_min_width (HTMLObject *o,
267 HTMLPainter *painter)
268 {
269 html_object_calc_size (o, painter, NULL);
270 return o->width;
271 }
272
273 static gint
calc_preferred_width(HTMLObject * o,HTMLPainter * painter)274 calc_preferred_width (HTMLObject *o,
275 HTMLPainter *painter)
276 {
277 html_object_calc_size (o, painter, NULL);
278 return o->width;
279 }
280
281 static void
set_max_width(HTMLObject * o,HTMLPainter * painter,gint max_width)282 set_max_width (HTMLObject *o,
283 HTMLPainter *painter,
284 gint max_width)
285 {
286 o->max_width = max_width;
287 }
288
289 static void
set_max_height(HTMLObject * o,HTMLPainter * painter,gint max_height)290 set_max_height (HTMLObject *o,
291 HTMLPainter *painter,
292 gint max_height)
293 {
294 }
295
296 static gint
get_left_margin(HTMLObject * self,HTMLPainter * painter,gint y,gboolean with_aligned)297 get_left_margin (HTMLObject *self,
298 HTMLPainter *painter,
299 gint y,
300 gboolean with_aligned)
301 {
302 return 0;
303 }
304
305 static gint
get_right_margin(HTMLObject * self,HTMLPainter * painter,gint y,gboolean with_aligned)306 get_right_margin (HTMLObject *self,
307 HTMLPainter *painter,
308 gint y,
309 gboolean with_aligned)
310 {
311 return MAX (self->max_width, self->width);
312 }
313
314 static void
set_painter(HTMLObject * o,HTMLPainter * painter)315 set_painter (HTMLObject *o,
316 HTMLPainter *painter)
317 {
318 }
319
320 static void
reset(HTMLObject * o)321 reset (HTMLObject *o)
322 {
323 /* o->width = 0;
324 * o->ascent = 0;
325 * o->descent = 0; */
326 }
327
328 static const gchar *
get_url(HTMLObject * o,gint offset)329 get_url (HTMLObject *o,
330 gint offset)
331 {
332 return NULL;
333 }
334
335 static const gchar *
get_target(HTMLObject * o,gint offset)336 get_target (HTMLObject *o,
337 gint offset)
338 {
339 return NULL;
340 }
341
342 static const gchar *
get_src(HTMLObject * o)343 get_src (HTMLObject *o)
344 {
345 return NULL;
346 }
347
348 static HTMLAnchor *
find_anchor(HTMLObject * o,const gchar * name,gint * x,gint * y)349 find_anchor (HTMLObject *o,
350 const gchar *name,
351 gint *x,
352 gint *y)
353 {
354 return NULL;
355 }
356
357 static void
set_bg_color(HTMLObject * o,GdkColor * color)358 set_bg_color (HTMLObject *o,
359 GdkColor *color)
360 {
361 }
362
363 static GdkColor *
get_bg_color(HTMLObject * o,HTMLPainter * p)364 get_bg_color (HTMLObject *o,
365 HTMLPainter *p)
366 {
367 if (o->parent)
368 return html_object_get_bg_color (o->parent, p);
369
370 if (p->widget && GTK_IS_HTML (p->widget)) {
371 HTMLEngine *e = html_object_engine (o, GTK_HTML (p->widget)->engine);
372 return &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color);
373 }
374
375 return NULL;
376 }
377
378 static HTMLObject *
check_point(HTMLObject * self,HTMLPainter * painter,gint x,gint y,guint * offset_return,gboolean for_cursor)379 check_point (HTMLObject *self,
380 HTMLPainter *painter,
381 gint x,
382 gint y,
383 guint *offset_return,
384 gboolean for_cursor)
385 {
386 if (x >= self->x
387 && x < self->x + self->width
388 && y >= self->y - self->ascent
389 && y < self->y + self->descent) {
390 if (offset_return != NULL)
391 *offset_return = 0;
392 return self;
393 }
394
395 return NULL;
396 }
397
398 static gboolean
relayout(HTMLObject * self,HTMLEngine * engine,HTMLObject * child)399 relayout (HTMLObject *self,
400 HTMLEngine *engine,
401 HTMLObject *child)
402 {
403 /* FIXME gint types of this stuff might change in `htmlobject.h',
404 * remember to sync. */
405 guint prev_width;
406 guint prev_ascent, prev_descent;
407 gboolean changed;
408
409 if (html_engine_frozen (engine))
410 return FALSE;
411
412 prev_width = self->width;
413 prev_ascent = self->ascent;
414 prev_descent = self->descent;
415
416 /* Notice that this will reset ascent and descent which we
417 * need afterwards. Yeah, yuck, bleargh. */
418 html_object_reset (self);
419
420 /* Crappy hack to make crappy htmlclueflow.c happy. */
421 if (self->y < self->ascent + self->descent) {
422 g_warning ("htmlobject.c:relayout -- Eeek! This should not happen! "
423 "Y value < height of object!\n");
424 self->y = 0;
425 } else {
426 self->y -= prev_ascent + prev_descent;
427 }
428
429 changed = html_object_calc_size (self, engine->painter, NULL);
430
431 if (prev_width == self->width
432 && prev_ascent == self->ascent
433 && prev_descent == self->descent) {
434 gtk_html_debug_log (engine->widget,
435 "relayout: %s %p did not change.\n",
436 html_type_name (HTML_OBJECT_TYPE (self)),
437 self);
438 if (changed)
439 html_engine_queue_draw (engine, self);
440
441 return FALSE;
442 }
443
444 gtk_html_debug_log (engine->widget, "relayout: %s %p changed.\n",
445 html_type_name (HTML_OBJECT_TYPE (self)), self);
446
447 if (self->parent == NULL) {
448 /* FIXME resize the widget, e.g. scrollbars and such. */
449 html_engine_queue_draw (engine, self);
450
451 /* FIXME extreme ugliness. */
452 self->x = 0;
453 self->y = self->ascent;
454 } else {
455 /* Relayout our parent starting from us. */
456 if (!html_object_relayout (self->parent, engine, self))
457 html_engine_queue_draw (engine, self);
458 }
459
460 /* If the object has shrunk, we have to clean the areas around
461 * it so that we don't leave garbage on the screen. FIXME:
462 * this wastes some time if there is an object on the right of
463 * or under this one. */
464
465 if (prev_ascent + prev_descent > self->ascent + self->descent)
466 html_engine_queue_clear (engine,
467 self->x,
468 self->y + self->descent,
469 self->width,
470 (prev_ascent + prev_descent
471 - (self->ascent + self->descent)));
472
473 if (prev_width > self->width)
474 html_engine_queue_clear (engine,
475 self->x + self->width,
476 self->y - self->ascent,
477 prev_width - self->width,
478 self->ascent + self->descent);
479
480 return TRUE;
481 }
482
483 static HTMLVAlignType
get_valign(HTMLObject * self)484 get_valign (HTMLObject *self)
485 {
486 return HTML_VALIGN_BOTTOM;
487 }
488
489 static gboolean
accepts_cursor(HTMLObject * self)490 accepts_cursor (HTMLObject *self)
491 {
492 return FALSE;
493 }
494
495 static void
get_cursor(HTMLObject * self,HTMLPainter * painter,guint offset,gint * x1,gint * y1,gint * x2,gint * y2)496 get_cursor (HTMLObject *self,
497 HTMLPainter *painter,
498 guint offset,
499 gint *x1,
500 gint *y1,
501 gint *x2,
502 gint *y2)
503 {
504 html_object_get_cursor_base (self, painter, offset, x2, y2);
505
506 *x1 = *x2;
507 *y1 = *y2 - self->ascent;
508 *y2 += self->descent - 1;
509 }
510
511 static void
get_cursor_base(HTMLObject * self,HTMLPainter * painter,guint offset,gint * x,gint * y)512 get_cursor_base (HTMLObject *self,
513 HTMLPainter *painter,
514 guint offset,
515 gint *x,
516 gint *y)
517 {
518 html_object_calc_abs_position (self, x, y);
519
520 if (offset > 0)
521 *x += self->width;
522 }
523
524 static guint
get_length(HTMLObject * self)525 get_length (HTMLObject *self)
526 {
527 return html_object_accepts_cursor (self) ? 1 : 0;
528 }
529
530 static guint
get_line_length(HTMLObject * self,HTMLPainter * p,gint line_offset)531 get_line_length (HTMLObject *self,
532 HTMLPainter *p,
533 gint line_offset)
534 {
535 return html_object_get_length (self);
536 }
537
538 static guint
get_recursive_length(HTMLObject * self)539 get_recursive_length (HTMLObject *self)
540 {
541 return html_object_get_length (self);
542 }
543
544 static gboolean
select_range(HTMLObject * self,HTMLEngine * engine,guint start,gint length,gboolean queue_draw)545 select_range (HTMLObject *self,
546 HTMLEngine *engine,
547 guint start,
548 gint length,
549 gboolean queue_draw)
550 {
551 gboolean selected;
552 gboolean changed;
553
554 selected = length > 0 || (length == -1 && start < html_object_get_length (self)) || html_object_is_container (self) ? TRUE : FALSE;
555 changed = (!selected && self->selected) || (selected && !self->selected) ? TRUE : FALSE;
556
557 self->selected = selected;
558
559 return changed;
560 }
561
562 static void
append_selection_string(HTMLObject * self,GString * buffer)563 append_selection_string (HTMLObject *self,
564 GString *buffer)
565 {
566 }
567
568 static void
forall(HTMLObject * self,HTMLEngine * e,HTMLObjectForallFunc func,gpointer data)569 forall (HTMLObject *self,
570 HTMLEngine *e,
571 HTMLObjectForallFunc func,
572 gpointer data)
573 {
574 (* func) (self, e, data);
575 }
576
577 static HTMLEngine *
get_engine(HTMLObject * self,HTMLEngine * e)578 get_engine (HTMLObject *self,
579 HTMLEngine *e)
580 {
581 return e;
582 }
583
584 static gboolean
is_container(HTMLObject * self)585 is_container (HTMLObject *self)
586 {
587 return FALSE;
588 }
589
590 static gboolean
save(HTMLObject * self,HTMLEngineSaveState * state)591 save (HTMLObject *self,
592 HTMLEngineSaveState *state)
593 {
594 return TRUE;
595 }
596
597 static gboolean
save_plain(HTMLObject * self,HTMLEngineSaveState * state,gint requested_width)598 save_plain (HTMLObject *self,
599 HTMLEngineSaveState *state,
600 gint requested_width)
601 {
602 return TRUE;
603 }
604
605 static gint
check_page_split(HTMLObject * self,HTMLPainter * p,gint y)606 check_page_split (HTMLObject *self,
607 HTMLPainter *p,
608 gint y)
609 {
610 return 0;
611 }
612
613 static gboolean
search(HTMLObject * self,HTMLSearch * info)614 search (HTMLObject *self,
615 HTMLSearch *info)
616 {
617 /* not found by default */
618 return FALSE;
619 }
620
621 static HTMLObject *
next(HTMLObject * self,HTMLObject * child)622 next (HTMLObject *self,
623 HTMLObject *child)
624 {
625 return child->next;
626 }
627
628 static HTMLObject *
prev(HTMLObject * self,HTMLObject * child)629 prev (HTMLObject *self,
630 HTMLObject *child)
631 {
632 return child->prev;
633 }
634
635 static HTMLObject *
head(HTMLObject * self)636 head (HTMLObject *self)
637 {
638 return NULL;
639 }
640
641 static HTMLObject *
tail(HTMLObject * self)642 tail (HTMLObject *self)
643 {
644 return NULL;
645 }
646
647 static HTMLClearType
get_clear(HTMLObject * self)648 get_clear (HTMLObject *self)
649 {
650 return HTML_CLEAR_NONE;
651 }
652
653 static HTMLDirection
html_object_real_get_direction(HTMLObject * o)654 html_object_real_get_direction (HTMLObject *o)
655 {
656 if (o->parent)
657 return html_object_get_direction (o->parent);
658
659 return HTML_DIRECTION_DERIVED;
660 }
661
662 static gboolean
html_object_real_cursor_forward(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)663 html_object_real_cursor_forward (HTMLObject *self,
664 HTMLCursor *cursor,
665 HTMLEngine *engine)
666 {
667 gint len;
668
669 g_assert (self);
670 g_assert (cursor->object == self);
671
672 if (html_object_is_container (self))
673 return FALSE;
674
675 len = html_object_get_length (self);
676 if (cursor->offset < len) {
677 cursor->offset++;
678 cursor->position++;
679 return TRUE;
680 } else
681 return FALSE;
682 }
683
684 static gboolean
html_cursor_allow_zero_offset(HTMLCursor * cursor,HTMLObject * o)685 html_cursor_allow_zero_offset (HTMLCursor *cursor,
686 HTMLObject *o)
687 {
688 if (cursor->offset == 1) {
689 HTMLObject *prev;
690
691 prev = html_object_prev_not_slave (o);
692 if (!prev || HTML_IS_CLUEALIGNED (prev))
693 return TRUE;
694 else {
695 while (prev && !html_object_accepts_cursor (prev))
696 prev = html_object_prev_not_slave (prev);
697
698 if (!prev)
699 return TRUE;
700 }
701 }
702
703 return FALSE;
704 }
705
706 static gboolean
html_object_real_cursor_backward(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)707 html_object_real_cursor_backward (HTMLObject *self,
708 HTMLCursor *cursor,
709 HTMLEngine *engine)
710 {
711 g_assert (self);
712 g_assert (cursor->object == self);
713
714 if (html_object_is_container (self))
715 return FALSE;
716
717 if (cursor->offset > 1 || html_cursor_allow_zero_offset (cursor, self)) {
718 cursor->offset--;
719 cursor->position--;
720 return TRUE;
721 }
722
723 return FALSE;
724 }
725
726 static gboolean
html_object_real_cursor_right(HTMLObject * self,HTMLPainter * painter,HTMLCursor * cursor)727 html_object_real_cursor_right (HTMLObject *self,
728 HTMLPainter *painter,
729 HTMLCursor *cursor)
730 {
731 HTMLDirection dir = html_object_get_direction (self);
732
733 g_assert (self);
734 g_assert (cursor->object == self);
735
736 if (html_object_is_container (self))
737 return FALSE;
738
739 if (dir != HTML_DIRECTION_RTL) {
740 gint len;
741
742 len = html_object_get_length (self);
743
744 if (cursor->offset < len) {
745 cursor->offset++;
746 cursor->position++;
747 return TRUE;
748 }
749 } else {
750 if (cursor->offset > 1 || html_cursor_allow_zero_offset (cursor, self)) {
751 cursor->offset--;
752 cursor->position--;
753 return TRUE;
754 }
755 }
756
757 return FALSE;
758 }
759
760 static gboolean
html_object_real_cursor_left(HTMLObject * self,HTMLPainter * painter,HTMLCursor * cursor)761 html_object_real_cursor_left (HTMLObject *self,
762 HTMLPainter *painter,
763 HTMLCursor *cursor)
764 {
765 HTMLDirection dir = html_object_get_direction (self);
766
767 g_assert (self);
768 g_assert (cursor->object == self);
769
770 if (html_object_is_container (self))
771 return FALSE;
772
773 if (dir != HTML_DIRECTION_RTL) {
774 if (cursor->offset > 1 || html_cursor_allow_zero_offset (cursor, self)) {
775 cursor->offset--;
776 cursor->position--;
777 return TRUE;
778 }
779 } else {
780 gint len;
781
782 len = html_object_get_length (self);
783
784 if (cursor->offset < len) {
785 cursor->offset++;
786 cursor->position++;
787 return TRUE;
788 }
789 }
790
791 return FALSE;
792 }
793
794 static gboolean
html_object_real_backspace(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)795 html_object_real_backspace (HTMLObject *self,
796 HTMLCursor *cursor,
797 HTMLEngine *engine)
798 {
799 html_cursor_backward (cursor, engine);
800 html_engine_delete (engine);
801
802 return TRUE;
803 }
804
805 static gint
html_object_real_get_right_edge_offset(HTMLObject * o,HTMLPainter * painter,gint offset)806 html_object_real_get_right_edge_offset (HTMLObject *o,
807 HTMLPainter *painter,
808 gint offset)
809 {
810 return html_object_get_length (o);
811 }
812
813 static gint
html_object_real_get_left_edge_offset(HTMLObject * o,HTMLPainter * painter,gint offset)814 html_object_real_get_left_edge_offset (HTMLObject *o,
815 HTMLPainter *painter,
816 gint offset)
817 {
818 return 0;
819 }
820
821 /* Class initialization. */
822
823 void
html_object_type_init(void)824 html_object_type_init (void)
825 {
826 html_object_class_init (&html_object_class, HTML_TYPE_OBJECT, sizeof (HTMLObject));
827 }
828
829 void
html_object_class_init(HTMLObjectClass * klass,HTMLType type,guint object_size)830 html_object_class_init (HTMLObjectClass *klass,
831 HTMLType type,
832 guint object_size)
833 {
834 g_return_if_fail (klass != NULL);
835
836 /* Set type. */
837 klass->type = type;
838 klass->object_size = object_size;
839
840 /* Install virtual methods. */
841 klass->destroy = destroy;
842 klass->copy = copy;
843 klass->op_copy = op_copy;
844 klass->op_cut = op_cut;
845 klass->merge = merge;
846 klass->remove_child = remove_child;
847 klass->split = split;
848 klass->draw = draw;
849 klass->is_transparent = is_transparent;
850 klass->fit_line = fit_line;
851 klass->calc_size = html_object_real_calc_size;
852 klass->set_max_width = set_max_width;
853 klass->set_max_height = set_max_height;
854 klass->get_left_margin = get_left_margin;
855 klass->get_right_margin = get_right_margin;
856 klass->set_painter = set_painter;
857 klass->reset = reset;
858 klass->calc_min_width = calc_min_width;
859 klass->calc_preferred_width = calc_preferred_width;
860 klass->get_url = get_url;
861 klass->get_target = get_target;
862 klass->get_src = get_src;
863 klass->find_anchor = find_anchor;
864 klass->set_link = NULL;
865 klass->set_bg_color = set_bg_color;
866 klass->get_bg_color = get_bg_color;
867 klass->check_point = check_point;
868 klass->relayout = relayout;
869 klass->get_valign = get_valign;
870 klass->accepts_cursor = accepts_cursor;
871 klass->get_cursor = get_cursor;
872 klass->get_cursor_base = get_cursor_base;
873 klass->select_range = select_range;
874 klass->append_selection_string = append_selection_string;
875 klass->forall = forall;
876 klass->is_container = is_container;
877 klass->save = save;
878 klass->save_plain = save_plain;
879 klass->check_page_split = check_page_split;
880 klass->search = search;
881 klass->search_next = search;
882 klass->get_length = get_length;
883 klass->get_line_length = get_line_length;
884 klass->get_recursive_length = get_recursive_length;
885 klass->next = next;
886 klass->prev = prev;
887 klass->head = head;
888 klass->tail = tail;
889 klass->get_engine = get_engine;
890 klass->get_clear = get_clear;
891 klass->get_direction = html_object_real_get_direction;
892 klass->cursor_forward = html_object_real_cursor_forward;
893 klass->cursor_forward_one = html_object_real_cursor_forward;
894 klass->cursor_backward = html_object_real_cursor_backward;
895 klass->cursor_backward_one = html_object_real_cursor_backward;
896 klass->cursor_left = html_object_real_cursor_left;
897 klass->cursor_right = html_object_real_cursor_right;
898 klass->backspace = html_object_real_backspace;
899 klass->get_right_edge_offset = html_object_real_get_right_edge_offset;
900 klass->get_left_edge_offset = html_object_real_get_left_edge_offset;
901 }
902
903 void
html_object_init(HTMLObject * o,HTMLObjectClass * klass)904 html_object_init (HTMLObject *o,
905 HTMLObjectClass *klass)
906 {
907 o->klass = klass;
908
909 o->parent = NULL;
910 o->prev = NULL;
911 o->next = NULL;
912
913 /* we don't have any info cached in the beginning */
914 o->change = HTML_CHANGE_ALL;
915
916 o->x = 0;
917 o->y = 0;
918
919 o->ascent = 0;
920 o->descent = 0;
921
922 o->width = 0;
923 o->max_width = 0;
924 o->min_width = 0;
925 o->pref_width = 0;
926 o->percent = 0;
927
928 o->flags = HTML_OBJECT_FLAG_FIXEDWIDTH; /* FIXME Why? */
929
930 o->redraw_pending = FALSE;
931 o->free_pending = FALSE;
932 o->selected = FALSE;
933 o->draw_focused = FALSE;
934
935 g_datalist_init (&o->object_data);
936 g_datalist_init (&o->object_data_nocp);
937
938 o->id = NULL;
939 }
940
941 HTMLObject *
html_object_new(HTMLObject * parent)942 html_object_new (HTMLObject *parent)
943 {
944 HTMLObject *o;
945
946 o = g_new0 (HTMLObject, 1);
947 html_object_init (o, &html_object_class);
948
949 return o;
950 }
951
952
953 /* Object duplication. */
954
955 HTMLObject *
html_object_dup(HTMLObject * object)956 html_object_dup (HTMLObject *object)
957 {
958 HTMLObject *new;
959
960 g_return_val_if_fail (object != NULL, NULL);
961
962 new = g_malloc (object->klass->object_size);
963 html_object_copy (object, new);
964
965 return new;
966 }
967
968 HTMLObject *
html_object_op_copy(HTMLObject * self,HTMLObject * parent,HTMLEngine * e,GList * from,GList * to,guint * len)969 html_object_op_copy (HTMLObject *self,
970 HTMLObject *parent,
971 HTMLEngine *e,
972 GList *from,
973 GList *to,
974 guint *len)
975 {
976 return (* HO_CLASS (self)->op_copy) (self, parent, e, from, to, len);
977 }
978
979 HTMLObject *
html_object_op_cut(HTMLObject * self,HTMLEngine * e,GList * from,GList * to,GList * left,GList * right,guint * len)980 html_object_op_cut (HTMLObject *self,
981 HTMLEngine *e,
982 GList *from,
983 GList *to,
984 GList *left,
985 GList *right,
986 guint *len)
987 {
988 return (* HO_CLASS (self)->op_cut) (self, e, from, to, left, right, len);
989 }
990
991 gboolean
html_object_merge(HTMLObject * self,HTMLObject * with,HTMLEngine * e,GList ** left,GList ** right,HTMLCursor * cursor)992 html_object_merge (HTMLObject *self,
993 HTMLObject *with,
994 HTMLEngine *e,
995 GList **left,
996 GList **right,
997 HTMLCursor *cursor)
998 {
999 if ((HTML_OBJECT_TYPE (self) == HTML_OBJECT_TYPE (with)
1000 /* FIXME */
1001 || (HTML_OBJECT_TYPE (self) == HTML_TYPE_TABLECELL && HTML_OBJECT_TYPE (with) == HTML_TYPE_CLUEV)
1002 || (HTML_OBJECT_TYPE (with) == HTML_TYPE_TABLECELL && HTML_OBJECT_TYPE (self) == HTML_TYPE_CLUEV))
1003 && (* HO_CLASS (self)->merge) (self, with, e, left, right, cursor)) {
1004 if (with->parent)
1005 html_object_remove_child (with->parent, with);
1006 html_object_destroy (with);
1007 return TRUE;
1008 }
1009 return FALSE;
1010 }
1011
1012 void
html_object_remove_child(HTMLObject * self,HTMLObject * child)1013 html_object_remove_child (HTMLObject *self,
1014 HTMLObject *child)
1015 {
1016 g_assert (self);
1017 g_assert (child);
1018
1019 (* HO_CLASS (self)->remove_child) (self, child);
1020 }
1021
1022 void
html_object_split(HTMLObject * self,HTMLEngine * e,HTMLObject * child,gint offset,gint level,GList ** left,GList ** right)1023 html_object_split (HTMLObject *self,
1024 HTMLEngine *e,
1025 HTMLObject *child,
1026 gint offset,
1027 gint level,
1028 GList **left,
1029 GList **right)
1030 {
1031 g_assert (self);
1032
1033 (* HO_CLASS (self)->split) (self, e, child, offset, level, left, right);
1034 }
1035
1036
1037 void
html_object_set_parent(HTMLObject * o,HTMLObject * parent)1038 html_object_set_parent (HTMLObject *o,
1039 HTMLObject *parent)
1040 {
1041 o->parent = parent;
1042
1043 /* parent change requires recalc of everything */
1044 o->change = HTML_CHANGE_ALL;
1045 }
1046
1047 static void
frame_offset(HTMLObject * o,gint * x_return,gint * y_return)1048 frame_offset (HTMLObject *o,
1049 gint *x_return,
1050 gint *y_return)
1051 {
1052 if (html_object_is_frame (o)) {
1053 HTMLEngine *e = html_object_get_engine (o, NULL);
1054 *x_return -= e->x_offset;
1055 *y_return -= e->y_offset;
1056 }
1057 }
1058
1059 void
html_object_calc_abs_position(HTMLObject * o,gint * x_return,gint * y_return)1060 html_object_calc_abs_position (HTMLObject *o,
1061 gint *x_return,
1062 gint *y_return)
1063 {
1064 HTMLObject *p;
1065
1066 g_return_if_fail (o != NULL);
1067
1068 *x_return = o->x;
1069 *y_return = o->y;
1070
1071 frame_offset (o, x_return, y_return);
1072
1073 for (p = o->parent; p != NULL; p = p->parent) {
1074 *x_return += p->x;
1075 *y_return += p->y - p->ascent;
1076
1077 frame_offset (p, x_return, y_return);
1078 }
1079 }
1080
1081 void
html_object_calc_abs_position_in_frame(HTMLObject * o,gint * x_return,gint * y_return)1082 html_object_calc_abs_position_in_frame (HTMLObject *o,
1083 gint *x_return,
1084 gint *y_return)
1085 {
1086 HTMLObject *p;
1087
1088 g_return_if_fail (o != NULL);
1089
1090 *x_return = o->x;
1091 *y_return = o->y;
1092
1093 frame_offset (o, x_return, y_return);
1094
1095 for (p = o->parent; p != NULL && !html_object_is_frame (p); p = p->parent) {
1096 *x_return += p->x;
1097 *y_return += p->y - p->ascent;
1098
1099 frame_offset (p, x_return, y_return);
1100 }
1101 }
1102
1103 GdkRectangle *
html_object_get_bounds(HTMLObject * o,GdkRectangle * bounds)1104 html_object_get_bounds (HTMLObject *o,
1105 GdkRectangle *bounds)
1106 {
1107 if (!bounds)
1108 bounds = g_new (GdkRectangle, 1);
1109
1110 bounds->x = o->x;
1111 bounds->y = o->y - o->ascent;
1112 bounds->width = o->width;
1113 bounds->height = o->ascent + o->descent;
1114
1115 return bounds;
1116 }
1117
1118 gboolean
html_object_intersect(HTMLObject * o,GdkRectangle * result,gint x,gint y,gint width,gint height)1119 html_object_intersect (HTMLObject *o,
1120 GdkRectangle *result,
1121 gint x,
1122 gint y,
1123 gint width,
1124 gint height)
1125 {
1126 GdkRectangle b;
1127 GdkRectangle a;
1128
1129 a.x = x;
1130 a.y = y;
1131 a.width = width;
1132 a.height = height;
1133
1134 return gdk_rectangle_intersect (html_object_get_bounds (o, &b), &a, result);
1135 }
1136
1137
1138 /* Virtual methods. */
1139
1140 void
html_object_destroy(HTMLObject * self)1141 html_object_destroy (HTMLObject *self)
1142 {
1143 (* HO_CLASS (self)->destroy) (self);
1144 }
1145
1146 void
html_object_copy(HTMLObject * self,HTMLObject * dest)1147 html_object_copy (HTMLObject *self,
1148 HTMLObject *dest)
1149 {
1150 (* HO_CLASS (self)->copy) (self, dest);
1151 }
1152
1153 void
html_object_draw(HTMLObject * o,HTMLPainter * p,gint x,gint y,gint width,gint height,gint tx,gint ty)1154 html_object_draw (HTMLObject *o,
1155 HTMLPainter *p,
1156 gint x,
1157 gint y,
1158 gint width,
1159 gint height,
1160 gint tx,
1161 gint ty)
1162 {
1163 (* HO_CLASS (o)->draw) (o, p, x, y, width, height, tx, ty);
1164 }
1165
1166 gboolean
html_object_is_transparent(HTMLObject * self)1167 html_object_is_transparent (HTMLObject *self)
1168 {
1169 g_return_val_if_fail (self != NULL, TRUE);
1170
1171 return (* HO_CLASS (self)->is_transparent) (self);
1172 }
1173
1174 HTMLFitType
html_object_fit_line(HTMLObject * o,HTMLPainter * painter,gboolean start_of_line,gboolean first_run,gboolean next_to_floating,gint width_left)1175 html_object_fit_line (HTMLObject *o,
1176 HTMLPainter *painter,
1177 gboolean start_of_line,
1178 gboolean first_run,
1179 gboolean next_to_floating,
1180 gint width_left)
1181 {
1182 return (* HO_CLASS (o)->fit_line) (o, painter, start_of_line, first_run, next_to_floating, width_left);
1183 }
1184
1185 gboolean
html_object_calc_size(HTMLObject * o,HTMLPainter * painter,GList ** changed_objs)1186 html_object_calc_size (HTMLObject *o,
1187 HTMLPainter *painter,
1188 GList **changed_objs)
1189 {
1190 gboolean rv;
1191
1192 rv = (* HO_CLASS (o)->calc_size) (o, painter, changed_objs);
1193 o->change &= ~HTML_CHANGE_SIZE;
1194
1195 return rv;
1196 }
1197
1198 void
html_object_set_max_width(HTMLObject * o,HTMLPainter * painter,gint max_width)1199 html_object_set_max_width (HTMLObject *o,
1200 HTMLPainter *painter,
1201 gint max_width)
1202 {
1203 (* HO_CLASS (o)->set_max_width) (o, painter, max_width);
1204 }
1205
1206 void
html_object_set_max_height(HTMLObject * o,HTMLPainter * painter,gint max_height)1207 html_object_set_max_height (HTMLObject *o,
1208 HTMLPainter *painter,
1209 gint max_height)
1210 {
1211 (* HO_CLASS (o)->set_max_height) (o, painter, max_height);
1212 }
1213
1214 gint
html_object_get_left_margin(HTMLObject * self,HTMLPainter * painter,gint y,gboolean with_aligned)1215 html_object_get_left_margin (HTMLObject *self,
1216 HTMLPainter *painter,
1217 gint y,
1218 gboolean with_aligned)
1219 {
1220 return (* HO_CLASS (self)->get_left_margin) (self, painter, y, with_aligned);
1221 }
1222
1223 gint
html_object_get_right_margin(HTMLObject * self,HTMLPainter * painter,gint y,gboolean with_aligned)1224 html_object_get_right_margin (HTMLObject *self,
1225 HTMLPainter *painter,
1226 gint y,
1227 gboolean with_aligned)
1228 {
1229 return (* HO_CLASS (self)->get_right_margin) (self, painter, y, with_aligned);
1230 }
1231
1232 static void
set_painter_forall(HTMLObject * o,HTMLEngine * e,gpointer data)1233 set_painter_forall (HTMLObject *o,
1234 HTMLEngine *e,
1235 gpointer data)
1236 {
1237 (* HO_CLASS (o)->set_painter) (o, HTML_PAINTER (data));
1238 }
1239
1240 void
html_object_set_painter(HTMLObject * o,HTMLPainter * painter)1241 html_object_set_painter (HTMLObject *o,
1242 HTMLPainter *painter)
1243 {
1244 html_object_forall (o, NULL, set_painter_forall, painter);
1245 }
1246
1247 void
html_object_reset(HTMLObject * o)1248 html_object_reset (HTMLObject *o)
1249 {
1250 (* HO_CLASS (o)->reset) (o);
1251 }
1252
1253 gint
html_object_calc_min_width(HTMLObject * o,HTMLPainter * painter)1254 html_object_calc_min_width (HTMLObject *o,
1255 HTMLPainter *painter)
1256 {
1257 if (o->change & HTML_CHANGE_MIN_WIDTH) {
1258 o->min_width = (* HO_CLASS (o)->calc_min_width) (o, painter);
1259 o->change &= ~HTML_CHANGE_MIN_WIDTH;
1260 }
1261 return o->min_width;
1262 }
1263
1264 gint
html_object_calc_preferred_width(HTMLObject * o,HTMLPainter * painter)1265 html_object_calc_preferred_width (HTMLObject *o,
1266 HTMLPainter *painter)
1267 {
1268 if (o->change & HTML_CHANGE_PREF_WIDTH) {
1269 o->pref_width = (* HO_CLASS (o)->calc_preferred_width) (o, painter);
1270 o->change &= ~HTML_CHANGE_PREF_WIDTH;
1271 }
1272 return o->pref_width;
1273 }
1274
1275 #if 0
1276 gint
1277 html_object_get_uris (HTMLObject *o,
1278 gchar **link,
1279 gchar **target,
1280 gchar **src)
1281 {
1282 return TRUE;
1283 }
1284 #endif
1285
1286 const gchar *
html_object_get_url(HTMLObject * o,gint offset)1287 html_object_get_url (HTMLObject *o,
1288 gint offset)
1289 {
1290 return (* HO_CLASS (o)->get_url) (o, offset);
1291 }
1292
1293 const gchar *
html_object_get_target(HTMLObject * o,gint offset)1294 html_object_get_target (HTMLObject *o,
1295 gint offset)
1296 {
1297 return (* HO_CLASS (o)->get_target) (o, offset);
1298 }
1299
1300 gchar *
html_object_get_complete_url(HTMLObject * o,gint offset)1301 html_object_get_complete_url (HTMLObject *o,
1302 gint offset)
1303 {
1304 const gchar *url, *target;
1305
1306 url = html_object_get_url (o, offset);
1307 target = html_object_get_target (o, offset);
1308 return url || target ? g_strconcat (url ? url : "#", url ? (target && *target ? "#" : NULL) : target,
1309 url ? target : NULL, NULL) : NULL;
1310 }
1311
1312 const gchar *
html_object_get_src(HTMLObject * o)1313 html_object_get_src (HTMLObject *o)
1314 {
1315 return (* HO_CLASS (o)->get_src) (o);
1316 }
1317
1318 HTMLAnchor *
html_object_find_anchor(HTMLObject * o,const gchar * name,gint * x,gint * y)1319 html_object_find_anchor (HTMLObject *o,
1320 const gchar *name,
1321 gint *x,
1322 gint *y)
1323 {
1324 return (* HO_CLASS (o)->find_anchor) (o, name, x, y);
1325 }
1326
1327 void
html_object_set_bg_color(HTMLObject * o,GdkColor * color)1328 html_object_set_bg_color (HTMLObject *o,
1329 GdkColor *color)
1330 {
1331 (* HO_CLASS (o)->set_bg_color) (o, color);
1332 }
1333
1334 GdkColor *
html_object_get_bg_color(HTMLObject * o,HTMLPainter * p)1335 html_object_get_bg_color (HTMLObject *o,
1336 HTMLPainter *p)
1337 {
1338 return (* HO_CLASS (o)->get_bg_color) (o, p);
1339 }
1340
1341 HTMLObject *
html_object_check_point(HTMLObject * self,HTMLPainter * painter,gint x,gint y,guint * offset_return,gboolean for_cursor)1342 html_object_check_point (HTMLObject *self,
1343 HTMLPainter *painter,
1344 gint x,
1345 gint y,
1346 guint *offset_return,
1347 gboolean for_cursor)
1348 {
1349 if (self->width == 0 || self->ascent + self->descent == 0)
1350 return NULL;
1351
1352 return (* HO_CLASS (self)->check_point) (self, painter, x, y, offset_return, for_cursor);
1353 }
1354
1355 gboolean
html_object_relayout(HTMLObject * self,HTMLEngine * engine,HTMLObject * child)1356 html_object_relayout (HTMLObject *self,
1357 HTMLEngine *engine,
1358 HTMLObject *child)
1359 {
1360 g_return_val_if_fail (self != NULL, TRUE);
1361 return (* HO_CLASS (self)->relayout) (self, engine, child);
1362 }
1363
1364 HTMLVAlignType
html_object_get_valign(HTMLObject * self)1365 html_object_get_valign (HTMLObject *self)
1366 {
1367 g_return_val_if_fail (self != NULL, HTML_VALIGN_BOTTOM);
1368
1369 return (* HO_CLASS (self)->get_valign) (self);
1370 }
1371
1372 gboolean
html_object_accepts_cursor(HTMLObject * self)1373 html_object_accepts_cursor (HTMLObject *self)
1374 {
1375 return (* HO_CLASS (self)->accepts_cursor) (self);
1376 }
1377
1378 /* Warning: `calc_size()' must have been called on `self' before this so that
1379 * this works correctly. */
1380 void
html_object_get_cursor(HTMLObject * self,HTMLPainter * painter,guint offset,gint * x1,gint * y1,gint * x2,gint * y2)1381 html_object_get_cursor (HTMLObject *self,
1382 HTMLPainter *painter,
1383 guint offset,
1384 gint *x1,
1385 gint *y1,
1386 gint *x2,
1387 gint *y2)
1388 {
1389 (* HO_CLASS (self)->get_cursor) (self, painter, offset, x1, y1, x2, y2);
1390
1391 if (*y2 - *y1 > *y2 - self->ascent)
1392 *y2 = *y1 + 20;
1393
1394 if (!html_object_is_text (self) && *y2 - *y1 < 10) {
1395 gint missing = 10 - (*y2 - *y1);
1396
1397 *y1 -= (missing >> 1) + ((missing >> 1) & 1);
1398 *y2 += missing >> 1;
1399 }
1400 }
1401
1402 /* Warning: `calc_size()' must have been called on `self' before this so that
1403 * this works correctly. */
1404 void
html_object_get_cursor_base(HTMLObject * self,HTMLPainter * painter,guint offset,gint * x,gint * y)1405 html_object_get_cursor_base (HTMLObject *self,
1406 HTMLPainter *painter,
1407 guint offset,
1408 gint *x,
1409 gint *y)
1410 {
1411 (* HO_CLASS (self)->get_cursor_base) (self, painter, offset, x, y);
1412 }
1413
1414
1415 gboolean
html_object_select_range(HTMLObject * self,HTMLEngine * engine,guint start,gint length,gboolean queue_draw)1416 html_object_select_range (HTMLObject *self,
1417 HTMLEngine *engine,
1418 guint start,
1419 gint length,
1420 gboolean queue_draw)
1421 {
1422 return (* HO_CLASS (self)->select_range) (self, engine, start, length, queue_draw);
1423 }
1424
1425 void
html_object_append_selection_string(HTMLObject * self,GString * buffer)1426 html_object_append_selection_string (HTMLObject *self,
1427 GString *buffer)
1428 {
1429 g_return_if_fail (self != NULL);
1430 g_return_if_fail (buffer != NULL);
1431
1432 (* HO_CLASS (self)->append_selection_string) (self, buffer);
1433 }
1434
1435 HTMLEngine *
html_object_get_engine(HTMLObject * self,HTMLEngine * e)1436 html_object_get_engine (HTMLObject *self,
1437 HTMLEngine *e)
1438 {
1439 return (* HO_CLASS (self)->get_engine) (self, e);
1440 }
1441
1442 HTMLEngine *
html_object_engine(HTMLObject * o,HTMLEngine * e)1443 html_object_engine (HTMLObject *o,
1444 HTMLEngine *e)
1445 {
1446 while (o) {
1447 e = html_object_get_engine (o, e);
1448 if (html_object_is_frame (o))
1449 break;
1450 o = o->parent;
1451 }
1452
1453 return e;
1454 }
1455
1456 void
html_object_forall(HTMLObject * self,HTMLEngine * e,HTMLObjectForallFunc func,gpointer data)1457 html_object_forall (HTMLObject *self,
1458 HTMLEngine *e,
1459 HTMLObjectForallFunc func,
1460 gpointer data)
1461 {
1462 (* HO_CLASS (self)->forall) (self, e, func, data);
1463 }
1464
1465 /* Ugly. We should have an `is_a' implementation. */
1466 gboolean
html_object_is_container(HTMLObject * self)1467 html_object_is_container (HTMLObject *self)
1468 {
1469 return (* HO_CLASS (self)->is_container) (self);
1470 }
1471
1472
1473 /* Ugly. We should have an `is_a' implementation. */
1474
1475 gboolean
html_object_is_text(HTMLObject * object)1476 html_object_is_text (HTMLObject *object)
1477 {
1478 HTMLType type;
1479
1480 g_return_val_if_fail (object != NULL, FALSE);
1481
1482 type = HTML_OBJECT_TYPE (object);
1483
1484 return (type == HTML_TYPE_TEXT || type == HTML_TYPE_LINKTEXT);
1485 }
1486
1487 gboolean
html_object_is_clue(HTMLObject * object)1488 html_object_is_clue (HTMLObject *object)
1489 {
1490 HTMLType type;
1491
1492 g_return_val_if_fail (object != NULL, FALSE);
1493
1494 type = HTML_OBJECT_TYPE (object);
1495
1496 return (type == HTML_TYPE_CLUE || type == HTML_TYPE_CLUEV || type == HTML_TYPE_TABLECELL
1497 || type == HTML_TYPE_CLUEFLOW || type == HTML_TYPE_CLUEALIGNED);
1498 }
1499
1500 HTMLObject *
html_object_next_not_type(HTMLObject * object,HTMLType t)1501 html_object_next_not_type (HTMLObject *object,
1502 HTMLType t)
1503 {
1504 HTMLObject *p;
1505
1506 g_return_val_if_fail (object != NULL, NULL);
1507 g_return_val_if_fail (object->parent, NULL);
1508
1509 p = html_object_next (object->parent, object);
1510 while (p && HTML_OBJECT_TYPE (p) == t)
1511 p = html_object_next (p->parent, p);
1512
1513 return p;
1514 }
1515
1516 HTMLObject *
html_object_prev_not_type(HTMLObject * object,HTMLType t)1517 html_object_prev_not_type (HTMLObject *object,
1518 HTMLType t)
1519 {
1520 HTMLObject *p;
1521
1522 g_return_val_if_fail (object != NULL, NULL);
1523 g_return_val_if_fail (object->parent, NULL);
1524
1525 p = html_object_prev (object->parent, object);
1526 while (p && HTML_OBJECT_TYPE (p) == t)
1527 p = html_object_prev (p->parent, p);
1528
1529 return p;
1530 }
1531
1532 HTMLObject *
html_object_next_not_slave(HTMLObject * object)1533 html_object_next_not_slave (HTMLObject *object)
1534 {
1535 return html_object_next_not_type (object, HTML_TYPE_TEXTSLAVE);
1536 }
1537
1538 HTMLObject *
html_object_prev_not_slave(HTMLObject * object)1539 html_object_prev_not_slave (HTMLObject *object)
1540 {
1541 return html_object_prev_not_type (object, HTML_TYPE_TEXTSLAVE);
1542 }
1543
1544
1545 gboolean
html_object_save(HTMLObject * self,HTMLEngineSaveState * state)1546 html_object_save (HTMLObject *self,
1547 HTMLEngineSaveState *state)
1548 {
1549 return (* HO_CLASS (self)->save) (self, state);
1550 }
1551
1552 gboolean
html_object_save_plain(HTMLObject * self,HTMLEngineSaveState * state,gint requested_width)1553 html_object_save_plain (HTMLObject *self,
1554 HTMLEngineSaveState *state,
1555 gint requested_width)
1556 {
1557 return (* HO_CLASS (self)->save_plain) (self, state, requested_width);
1558 }
1559
1560 gint
html_object_check_page_split(HTMLObject * self,HTMLPainter * p,gint y)1561 html_object_check_page_split (HTMLObject *self,
1562 HTMLPainter *p,
1563 gint y)
1564 {
1565 g_return_val_if_fail (self != NULL, 0);
1566
1567 return (* HO_CLASS (self)->check_page_split) (self, p, y);
1568 }
1569
1570 void
html_object_change_set(HTMLObject * self,HTMLChangeFlags f)1571 html_object_change_set (HTMLObject *self,
1572 HTMLChangeFlags f)
1573 {
1574 HTMLObject *obj = self;
1575
1576 g_assert (self != NULL);
1577
1578 if (f != HTML_CHANGE_NONE) {
1579 while (obj) {
1580 obj->change |= f;
1581 obj = obj->parent;
1582 }
1583 }
1584 }
1585
1586 static void
change(HTMLObject * o,HTMLEngine * e,gpointer data)1587 change (HTMLObject *o,
1588 HTMLEngine *e,
1589 gpointer data)
1590 {
1591 o->change |= GPOINTER_TO_INT (data);
1592 }
1593
1594 void
html_object_change_set_down(HTMLObject * self,HTMLChangeFlags f)1595 html_object_change_set_down (HTMLObject *self,
1596 HTMLChangeFlags f)
1597 {
1598 html_object_forall (self, NULL, (HTMLObjectForallFunc) change, GINT_TO_POINTER (f));
1599 }
1600
1601 gboolean
html_object_search(HTMLObject * self,HTMLSearch * info)1602 html_object_search (HTMLObject *self,
1603 HTMLSearch *info)
1604 {
1605 return (* HO_CLASS (self)->search) (self, info);
1606 }
1607
1608 gboolean
html_object_search_next(HTMLObject * self,HTMLSearch * info)1609 html_object_search_next (HTMLObject *self,
1610 HTMLSearch *info)
1611 {
1612 return (* HO_CLASS (self)->search_next) (self, info);
1613 }
1614
1615 HTMLObject *
html_object_set_link(HTMLObject * self,HTMLColor * color,const gchar * url,const gchar * target)1616 html_object_set_link (HTMLObject *self,
1617 HTMLColor *color,
1618 const gchar *url,
1619 const gchar *target)
1620 {
1621 return (HO_CLASS (self)->set_link) ? (* HO_CLASS (self)->set_link) (self, color, url, target) : NULL;
1622 }
1623
1624 HTMLObject *
html_object_remove_link(HTMLObject * self,HTMLColor * color)1625 html_object_remove_link (HTMLObject *self,
1626 HTMLColor *color)
1627 {
1628 return (HO_CLASS (self)->set_link) ? (* HO_CLASS (self)->set_link) (self, color, NULL, NULL) : NULL;
1629 }
1630
1631 guint
html_object_get_length(HTMLObject * self)1632 html_object_get_length (HTMLObject *self)
1633 {
1634 return (* HO_CLASS (self)->get_length) (self);
1635 }
1636
1637 guint
html_object_get_line_length(HTMLObject * self,HTMLPainter * p,gint line_offset)1638 html_object_get_line_length (HTMLObject *self,
1639 HTMLPainter *p,
1640 gint line_offset)
1641 {
1642 return (* HO_CLASS (self)->get_line_length) (self, p, line_offset);
1643 }
1644
1645 guint
html_object_get_recursive_length(HTMLObject * self)1646 html_object_get_recursive_length (HTMLObject *self)
1647 {
1648 return (* HO_CLASS (self)->get_recursive_length) (self);
1649 }
1650
1651 HTMLObject *
html_object_next_by_type(HTMLObject * self,HTMLType t)1652 html_object_next_by_type (HTMLObject *self,
1653 HTMLType t)
1654 {
1655 HTMLObject *next;
1656
1657 g_assert (self);
1658
1659 next = self->next;
1660 while (next && HTML_OBJECT_TYPE (next) != t)
1661 next = next->next;
1662
1663 return next;
1664 }
1665
1666 HTMLObject *
html_object_prev_by_type(HTMLObject * self,HTMLType t)1667 html_object_prev_by_type (HTMLObject *self,
1668 HTMLType t)
1669 {
1670 HTMLObject *prev;
1671
1672 g_assert (self);
1673
1674 prev = self->prev;
1675 while (prev && HTML_OBJECT_TYPE (prev) != t)
1676 prev = prev->prev;
1677
1678 return prev;
1679 }
1680
1681 /* Movement functions */
1682
1683 HTMLObject *
html_object_next(HTMLObject * self,HTMLObject * child)1684 html_object_next (HTMLObject *self,
1685 HTMLObject *child)
1686 {
1687 return (* HO_CLASS (self)->next) (self, child);
1688 }
1689
1690 HTMLObject *
html_object_prev(HTMLObject * self,HTMLObject * child)1691 html_object_prev (HTMLObject *self,
1692 HTMLObject *child)
1693 {
1694 return (* HO_CLASS (self)->prev) (self, child);
1695 }
1696
1697 HTMLObject *
html_object_head(HTMLObject * self)1698 html_object_head (HTMLObject *self)
1699 {
1700 return (* HO_CLASS (self)->head) (self);
1701 }
1702
1703 HTMLObject *
html_object_tail(HTMLObject * self)1704 html_object_tail (HTMLObject *self)
1705 {
1706 return (* HO_CLASS (self)->tail) (self);
1707 }
1708
1709 HTMLObject *
html_object_tail_not_slave(HTMLObject * self)1710 html_object_tail_not_slave (HTMLObject *self)
1711 {
1712 HTMLObject *o = html_object_tail (self);
1713
1714 if (o && HTML_OBJECT_TYPE (o) == HTML_TYPE_TEXTSLAVE)
1715 o = html_object_prev_not_slave (o);
1716 return o;
1717 }
1718
1719 gboolean
html_object_cursor_forward(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)1720 html_object_cursor_forward (HTMLObject *self,
1721 HTMLCursor *cursor,
1722 HTMLEngine *engine)
1723 {
1724 return (* HO_CLASS (self)->cursor_forward) (self, cursor, engine);
1725 }
1726
1727 gboolean
html_object_cursor_forward_one(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)1728 html_object_cursor_forward_one (HTMLObject *self,
1729 HTMLCursor *cursor,
1730 HTMLEngine *engine)
1731 {
1732 return (* HO_CLASS (self)->cursor_forward_one) (self, cursor, engine);
1733 }
1734
1735 gboolean
html_object_cursor_backward(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)1736 html_object_cursor_backward (HTMLObject *self,
1737 HTMLCursor *cursor,
1738 HTMLEngine *engine)
1739 {
1740 return (* HO_CLASS (self)->cursor_backward) (self, cursor, engine);
1741 }
1742
1743 gboolean
html_object_cursor_backward_one(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)1744 html_object_cursor_backward_one (HTMLObject *self,
1745 HTMLCursor *cursor,
1746 HTMLEngine *engine)
1747 {
1748 return (* HO_CLASS (self)->cursor_backward_one) (self, cursor, engine);
1749 }
1750
1751 gboolean
html_object_cursor_right(HTMLObject * self,HTMLPainter * painter,HTMLCursor * cursor)1752 html_object_cursor_right (HTMLObject *self,
1753 HTMLPainter *painter,
1754 HTMLCursor *cursor)
1755 {
1756 return (* HO_CLASS (self)->cursor_right) (self, painter, cursor);
1757 }
1758
1759 gboolean
html_object_cursor_left(HTMLObject * self,HTMLPainter * painter,HTMLCursor * cursor)1760 html_object_cursor_left (HTMLObject *self,
1761 HTMLPainter *painter,
1762 HTMLCursor *cursor)
1763 {
1764 return (* HO_CLASS (self)->cursor_left) (self, painter, cursor);
1765 }
1766
1767 gboolean
html_object_backspace(HTMLObject * self,HTMLCursor * cursor,HTMLEngine * engine)1768 html_object_backspace (HTMLObject *self,
1769 HTMLCursor *cursor,
1770 HTMLEngine *engine)
1771 {
1772 return (* HO_CLASS (self)->backspace) (self, cursor, engine);
1773 }
1774
1775 /*********************
1776 * movement on leafs
1777 */
1778
1779 /* go up in tree so long as we can get object in neighborhood given by function next_fn */
1780
1781 static HTMLObject *
next_object_uptree(HTMLObject * obj,HTMLObject * (* next_fn)(HTMLObject *,HTMLObject *))1782 next_object_uptree (HTMLObject *obj,
1783 HTMLObject * (*next_fn) (HTMLObject *,
1784 HTMLObject *))
1785 {
1786 HTMLObject *next = NULL;
1787
1788 while (obj->parent && !(next = (*next_fn) (obj->parent, obj)))
1789 obj = obj->parent;
1790
1791 return next;
1792 }
1793
1794 /* go down in tree to leaf in way given by down_fn children */
1795
1796 static HTMLObject *
move_object_downtree(HTMLObject * obj,HTMLObject * (* down_fn)(HTMLObject *))1797 move_object_downtree (HTMLObject *obj,
1798 HTMLObject * (*down_fn) (HTMLObject *))
1799 {
1800 HTMLObject *down;
1801
1802 while ((down = (*down_fn) (obj)))
1803 obj = down;
1804
1805 return obj;
1806 }
1807
1808 static HTMLObject *
move_object(HTMLObject * obj,HTMLObject * (* next_fn)(HTMLObject *,HTMLObject *),HTMLObject * (* down_fn)(HTMLObject *))1809 move_object (HTMLObject *obj,
1810 HTMLObject * (*next_fn) (HTMLObject *,
1811 HTMLObject *),
1812 HTMLObject * (*down_fn) (HTMLObject *))
1813 {
1814 obj = next_object_uptree (obj, next_fn);
1815 if (obj)
1816 obj = move_object_downtree (obj, down_fn);
1817 return obj;
1818 }
1819
1820 HTMLObject *
html_object_next_leaf(HTMLObject * self)1821 html_object_next_leaf (HTMLObject *self)
1822 {
1823 return move_object (self, html_object_next, html_object_head);
1824 }
1825
1826 HTMLObject *
html_object_next_leaf_not_type(HTMLObject * self,HTMLType t)1827 html_object_next_leaf_not_type (HTMLObject *self,
1828 HTMLType t)
1829 {
1830 HTMLObject *rv = self;
1831 while ((rv = html_object_next_leaf (rv)) && HTML_OBJECT_TYPE (rv) == t);
1832
1833 return rv;
1834 }
1835
1836 HTMLObject *
html_object_prev_leaf(HTMLObject * self)1837 html_object_prev_leaf (HTMLObject *self)
1838 {
1839 return move_object (self, html_object_prev, html_object_tail);
1840 }
1841
1842 HTMLObject *
html_object_prev_leaf_not_type(HTMLObject * self,HTMLType t)1843 html_object_prev_leaf_not_type (HTMLObject *self,
1844 HTMLType t)
1845 {
1846 HTMLObject *rv = self;
1847 while ((rv = html_object_prev_leaf (rv)) && HTML_OBJECT_TYPE (rv) == t);
1848
1849 return rv;
1850 }
1851
1852 /* movement on cursor accepting objects */
1853
1854 /* go up in tree so long as we can get object in neighborhood given by function next_fn */
1855
1856 static HTMLObject *
next_object_uptree_cursor(HTMLObject * obj,HTMLObject * (* next_fn)(HTMLObject *))1857 next_object_uptree_cursor (HTMLObject *obj,
1858 HTMLObject * (*next_fn) (HTMLObject *))
1859 {
1860 HTMLObject *next = NULL;
1861
1862 while (obj->parent && !(next = (*next_fn) (obj))) {
1863 obj = obj->parent;
1864 if (html_object_accepts_cursor (obj))
1865 return obj;
1866 }
1867
1868 return next;
1869 }
1870
1871 /* go down in tree to leaf in way given by down_fn children */
1872
1873 static HTMLObject *
move_object_downtree_cursor(HTMLObject * obj,HTMLObject * (* down_fn)(HTMLObject *),HTMLObject * (* next_fn)(HTMLObject *))1874 move_object_downtree_cursor (HTMLObject *obj,
1875 HTMLObject * (*down_fn) (HTMLObject *),
1876 HTMLObject * (*next_fn) (HTMLObject *))
1877 {
1878 HTMLObject *last_obj = obj;
1879
1880 while ((obj = (*down_fn) (obj))) {
1881 if (html_object_accepts_cursor (obj))
1882 break;
1883 last_obj = obj;
1884 }
1885
1886 if (!obj && last_obj) {
1887 obj = last_obj;
1888
1889 while ((obj = (*next_fn) (obj))) {
1890 if (html_object_accepts_cursor (obj))
1891 break;
1892 last_obj = obj;
1893 if ((obj = move_object_downtree_cursor (obj, down_fn, next_fn)))
1894 break;
1895 obj = last_obj;
1896 }
1897 }
1898
1899 return obj;
1900 }
1901
1902 static HTMLObject *
move_object_cursor(HTMLObject * obj,gint * offset,gboolean forward,HTMLObject * (* next_fn)(HTMLObject *),HTMLObject * (* down_fn)(HTMLObject *))1903 move_object_cursor (HTMLObject *obj,
1904 gint *offset,
1905 gboolean forward,
1906 HTMLObject * (*next_fn) (HTMLObject *), HTMLObject * (*down_fn) (HTMLObject *))
1907 {
1908 HTMLObject *down, *before;
1909
1910 do {
1911 gboolean found = FALSE;
1912 if (((*offset == 0 && forward) || (*offset && !forward)) && html_object_is_container (obj))
1913 if ((down = (*down_fn) (obj))) {
1914 down = move_object_downtree_cursor (down, down_fn, next_fn);
1915 if (down) {
1916 if (html_object_is_container (down))
1917 *offset = forward ? 0 : 1;
1918 return down;
1919 }
1920 }
1921
1922 before = obj;
1923 do {
1924 obj = next_object_uptree_cursor (obj, next_fn);
1925 if (obj) {
1926 if (html_object_accepts_cursor (obj)) {
1927 if (html_object_is_container (obj))
1928 *offset = before->parent == obj->parent
1929 ? forward ? 0 : 1
1930 : forward ? 1 : 0;
1931 found = TRUE;
1932 } else {
1933 HTMLObject *down;
1934 down = move_object_downtree_cursor (obj, down_fn, next_fn);
1935 if (down) {
1936 if (html_object_is_container (down))
1937 *offset = forward ? 0 : 1;
1938 obj = down;
1939 found = TRUE;
1940 }
1941 }
1942 }
1943 } while (obj && !found);
1944 } while (obj && !html_object_accepts_cursor (obj));
1945
1946 return obj;
1947 }
1948
1949 HTMLObject *
html_object_next_cursor(HTMLObject * self,gint * offset)1950 html_object_next_cursor (HTMLObject *self,
1951 gint *offset)
1952 {
1953 return move_object_cursor (self, offset, TRUE, html_object_next_not_slave, html_object_head);
1954 }
1955
1956 HTMLObject *
html_object_prev_cursor(HTMLObject * self,gint * offset)1957 html_object_prev_cursor (HTMLObject *self,
1958 gint *offset)
1959 {
1960 return move_object_cursor (self, offset, FALSE, html_object_prev_not_slave, html_object_tail_not_slave);
1961 }
1962
1963 /***/
1964
1965 guint
html_object_get_bytes(HTMLObject * self)1966 html_object_get_bytes (HTMLObject *self)
1967 {
1968 return html_object_is_text (self) ? html_text_get_bytes (HTML_TEXT (self)) : html_object_get_length (self);
1969 }
1970
1971 guint
html_object_get_index(HTMLObject * self,guint offset)1972 html_object_get_index (HTMLObject *self,
1973 guint offset)
1974 {
1975 return html_object_is_text (self) ? html_text_get_index (HTML_TEXT (self), offset) : offset;
1976 }
1977
1978 void
html_object_set_data_nocp(HTMLObject * object,const gchar * key,const gchar * value)1979 html_object_set_data_nocp (HTMLObject *object,
1980 const gchar *key,
1981 const gchar *value)
1982 {
1983 g_datalist_set_data_full (&object->object_data_nocp, key, g_strdup (value), g_free);
1984 }
1985
1986 void
html_object_set_data_full_nocp(HTMLObject * object,const gchar * key,gconstpointer value,GDestroyNotify func)1987 html_object_set_data_full_nocp (HTMLObject *object,
1988 const gchar *key,
1989 gconstpointer value,
1990 GDestroyNotify func)
1991 {
1992 g_datalist_set_data_full (&object->object_data_nocp, key, (gpointer) value, func);
1993 }
1994
1995 gpointer
html_object_get_data_nocp(HTMLObject * object,const gchar * key)1996 html_object_get_data_nocp (HTMLObject *object,
1997 const gchar *key)
1998 {
1999 return g_datalist_get_data (&object->object_data_nocp, key);
2000 }
2001
2002 void
html_object_set_data(HTMLObject * object,const gchar * key,const gchar * value)2003 html_object_set_data (HTMLObject *object,
2004 const gchar *key,
2005 const gchar *value)
2006 {
2007 g_datalist_set_data_full (&object->object_data, key, g_strdup (value), g_free);
2008 }
2009
2010 void
html_object_set_data_full(HTMLObject * object,const gchar * key,gconstpointer value,GDestroyNotify func)2011 html_object_set_data_full (HTMLObject *object,
2012 const gchar *key,
2013 gconstpointer value,
2014 GDestroyNotify func)
2015 {
2016 g_datalist_set_data_full (&object->object_data, key, (gpointer) value, func);
2017 }
2018
2019 gpointer
html_object_get_data(HTMLObject * object,const gchar * key)2020 html_object_get_data (HTMLObject *object,
2021 const gchar *key)
2022 {
2023 return g_datalist_get_data (&object->object_data, key);
2024 }
2025
2026 static void
copy_data(GQuark key_id,gpointer data,gpointer user_data)2027 copy_data (GQuark key_id,
2028 gpointer data,
2029 gpointer user_data)
2030 {
2031 HTMLObject *o = HTML_OBJECT (user_data);
2032
2033 g_datalist_id_set_data_full (&o->object_data,
2034 key_id,
2035 g_strdup ((gchar *) data), g_free);
2036 }
2037
2038 void
html_object_copy_data_from_object(HTMLObject * dst,HTMLObject * src)2039 html_object_copy_data_from_object (HTMLObject *dst,
2040 HTMLObject *src)
2041 {
2042 g_datalist_foreach (&src->object_data, copy_data, dst);
2043 }
2044
2045 static void
object_save_data(GQuark key_id,gpointer data,gpointer user_data)2046 object_save_data (GQuark key_id,
2047 gpointer data,
2048 gpointer user_data)
2049 {
2050 HTMLEngineSaveState *state = (HTMLEngineSaveState *) user_data;
2051 const gchar *str;
2052
2053 str = html_engine_get_class_data (state->engine, state->save_data_class_name, g_quark_to_string (key_id));
2054 /* printf ("object %s %s\n", g_quark_to_string (key_id), str); */
2055 if (!str) {
2056 /* printf ("save %s %s -> %s\n", state->save_data_class_name, g_quark_to_string (key_id), (gchar *) data); */
2057 html_engine_save_delims_and_vals (state,
2058 "<!--+GtkHTML:<DATA class=\"", state->save_data_class_name,
2059 "\" key=\"", g_quark_to_string (key_id),
2060 "\" value=\"", (gchar *) data,
2061 "\">-->", NULL);
2062 html_engine_set_class_data (state->engine, state->save_data_class_name, g_quark_to_string (key_id), data);
2063 }
2064 }
2065
2066 static void
handle_object_data(gpointer key,gpointer value,gpointer data)2067 handle_object_data (gpointer key,
2068 gpointer value,
2069 gpointer data)
2070 {
2071 HTMLEngineSaveState *state = (HTMLEngineSaveState *) data;
2072 gchar *str;
2073
2074 str = html_object_get_data (HTML_OBJECT (state->save_data_object), key);
2075 /* printf ("handle: %s %s %s %s\n", state->save_data_class_name, key, value, str); */
2076 if (!str) {
2077 /* printf ("clear\n"); */
2078 html_engine_save_delims_and_vals (state,
2079 "<!--+GtkHTML:<DATA class=\"", state->save_data_class_name,
2080 "\" clear=\"", (gchar *) key,
2081 "\">-->", NULL);
2082 state->data_to_remove = g_slist_prepend (state->data_to_remove, key);
2083 } else if (strcmp (value, str)) {
2084 /* printf ("change\n"); */
2085 html_engine_save_delims_and_vals (state,
2086 "<!--+GtkHTML:<DATA class=\"", state->save_data_class_name,
2087 "\" key=\"", (gchar *) key,
2088 "\" value=\"", str,
2089 "\">-->", NULL);
2090 html_engine_set_class_data (state->engine, state->save_data_class_name, key, value);
2091 }
2092 }
2093
2094 static void
clear_data(gchar * key,HTMLEngineSaveState * state)2095 clear_data (gchar *key,
2096 HTMLEngineSaveState *state)
2097 {
2098 html_engine_clear_class_data (state->engine, state->save_data_class_name, key);
2099 }
2100
2101 gboolean
html_object_save_data(HTMLObject * self,HTMLEngineSaveState * state)2102 html_object_save_data (HTMLObject *self,
2103 HTMLEngineSaveState *state)
2104 {
2105 if (state->engine->save_data) {
2106 GHashTable *t;
2107 state->save_data_class_name = html_type_name (self->klass->type);
2108 state->save_data_object = self;
2109 t = html_engine_get_class_table (state->engine, state->save_data_class_name);
2110 if (t) {
2111 state->data_to_remove = NULL;
2112 g_hash_table_foreach (t, handle_object_data, state);
2113 g_slist_foreach (state->data_to_remove, (GFunc) clear_data, state);
2114 g_slist_free (state->data_to_remove);
2115 state->data_to_remove = NULL;
2116 }
2117 g_datalist_foreach (&self->object_data, object_save_data, state);
2118 }
2119
2120 return TRUE;
2121 }
2122
2123 GList *
html_object_get_bound_list(HTMLObject * self,GList * list)2124 html_object_get_bound_list (HTMLObject *self,
2125 GList *list)
2126 {
2127 return list && list->next
2128 ? (HTML_OBJECT (list->data) == self ? list->next : NULL)
2129 : NULL;
2130 }
2131
2132 void
html_object_move_cursor_before_remove(HTMLObject * o,HTMLEngine * e)2133 html_object_move_cursor_before_remove (HTMLObject *o,
2134 HTMLEngine *e)
2135 {
2136 if (e->cursor->object == o) {
2137 if (html_object_next_not_slave (o))
2138 e->cursor->object = html_object_next_not_slave (o);
2139 else
2140 e->cursor->object = html_object_prev_not_slave (o);
2141 }
2142 }
2143
2144 gboolean
html_object_could_remove_whole(HTMLObject * o,GList * from,GList * to,GList * left,GList * right)2145 html_object_could_remove_whole (HTMLObject *o,
2146 GList *from,
2147 GList *to,
2148 GList *left,
2149 GList *right)
2150 {
2151 return ((!from && !to)
2152 || html_object_next_not_slave (HTML_OBJECT (o))
2153 || html_object_prev_not_slave (HTML_OBJECT (o)))
2154 && ((!left || o != left->data) && (!right || o != right->data));
2155
2156 }
2157
2158 void
html_object_check_cut_lists(HTMLObject * self,HTMLObject * replacement,GList * left,GList * right)2159 html_object_check_cut_lists (HTMLObject *self,
2160 HTMLObject *replacement,
2161 GList *left,
2162 GList *right)
2163 {
2164 if (left && left->data == self)
2165 left->data = replacement;
2166 if (right && right->data == self)
2167 right->data = replacement;
2168 }
2169
2170 typedef struct {
2171 HTMLInterval *i;
2172 GString *buffer;
2173 gboolean in;
2174 } tmpSelData;
2175
2176 static void
select_object(HTMLObject * o,HTMLEngine * e,gpointer data)2177 select_object (HTMLObject *o,
2178 HTMLEngine *e,
2179 gpointer data)
2180 {
2181 tmpSelData *d = (tmpSelData *) data;
2182
2183 if (o == d->i->from.object)
2184 d->in = TRUE;
2185 if (d->in)
2186 html_object_select_range (o, e,
2187 html_interval_get_start (d->i, o),
2188 html_interval_get_length (d->i, o), FALSE);
2189
2190 if (o == d->i->to.object)
2191 d->in = FALSE;
2192 }
2193
2194 static void
unselect_object(HTMLObject * o,HTMLEngine * e,gpointer data)2195 unselect_object (HTMLObject *o,
2196 HTMLEngine *e,
2197 gpointer data)
2198 {
2199 o->selected = FALSE;
2200 }
2201
2202 gchar *
html_object_get_selection_string(HTMLObject * o,HTMLEngine * e)2203 html_object_get_selection_string (HTMLObject *o,
2204 HTMLEngine *e)
2205 {
2206 HTMLObject *tail;
2207 tmpSelData data;
2208 gchar *string;
2209
2210 g_assert (o);
2211
2212 tail = html_object_get_tail_leaf (o);
2213 data.buffer = g_string_new (NULL);
2214 data.in = FALSE;
2215 data.i = html_interval_new (html_object_get_head_leaf (o), tail, 0, html_object_get_length (tail));
2216
2217 html_interval_forall (data.i, e, select_object, &data);
2218 html_object_append_selection_string (o, data.buffer);
2219 html_interval_forall (data.i, e, unselect_object, NULL);
2220
2221 html_interval_destroy (data.i);
2222 string = data.buffer->str;
2223 g_string_free (data.buffer, FALSE);
2224
2225 return string;
2226 }
2227
2228 HTMLObject *
html_object_get_tail_leaf(HTMLObject * o)2229 html_object_get_tail_leaf (HTMLObject *o)
2230 {
2231 HTMLObject *tail, *rv = o;
2232
2233 do {
2234 tail = html_object_tail_not_slave (rv);
2235 if (tail)
2236 rv = tail;
2237 } while (tail);
2238
2239 return rv;
2240 }
2241
2242 HTMLObject *
html_object_get_head_leaf(HTMLObject * o)2243 html_object_get_head_leaf (HTMLObject *o)
2244 {
2245 HTMLObject *head, *rv = o;
2246
2247 do {
2248 head = html_object_head (rv);
2249 if (head)
2250 rv = head;
2251 } while (head);
2252
2253 return rv;
2254 }
2255
2256 HTMLObject *
html_object_nth_parent(HTMLObject * self,gint n)2257 html_object_nth_parent (HTMLObject *self,
2258 gint n)
2259 {
2260 while (self && n > 0) {
2261 self = self->parent;
2262 n--;
2263 }
2264
2265 return self;
2266 }
2267
2268 gint
html_object_get_parent_level(HTMLObject * self)2269 html_object_get_parent_level (HTMLObject *self)
2270 {
2271 gint level = 0;
2272
2273 while (self) {
2274 level++;
2275 self = self->parent;
2276 }
2277
2278 return level;
2279 }
2280
2281 GList *
html_object_heads_list(HTMLObject * o)2282 html_object_heads_list (HTMLObject *o)
2283 {
2284 GList *list = NULL;
2285
2286 g_return_val_if_fail (o, NULL);
2287
2288 while (o) {
2289 list = g_list_append (list, o);
2290 o = html_object_head (o);
2291 }
2292
2293 return list;
2294 }
2295
2296 GList *
html_object_tails_list(HTMLObject * o)2297 html_object_tails_list (HTMLObject *o)
2298 {
2299 GList *list = NULL;
2300
2301 g_return_val_if_fail (o, NULL);
2302
2303 while (o) {
2304 list = g_list_append (list, o);
2305 o = html_object_tail_not_slave (o);
2306 }
2307
2308 return list;
2309 }
2310
2311 static void
merge_down(HTMLEngine * e,GList * left,GList * right)2312 merge_down (HTMLEngine *e,
2313 GList *left,
2314 GList *right)
2315 {
2316 HTMLObject *lo;
2317 HTMLObject *ro;
2318
2319 while (left && right) {
2320 lo = HTML_OBJECT (left->data);
2321 ro = HTML_OBJECT (right->data);
2322 left = left->next;
2323 right = right->next;
2324 if (!html_object_merge (lo, ro, e, &left, &right, NULL))
2325 break;
2326 }
2327 }
2328
2329 void
html_object_merge_down(HTMLObject * o,HTMLObject * w,HTMLEngine * e)2330 html_object_merge_down (HTMLObject *o,
2331 HTMLObject *w,
2332 HTMLEngine *e)
2333 {
2334 merge_down (e, html_object_tails_list (o), html_object_heads_list (w));
2335 }
2336
2337 gboolean
html_object_is_parent(HTMLObject * parent,HTMLObject * child)2338 html_object_is_parent (HTMLObject *parent,
2339 HTMLObject *child)
2340 {
2341 g_assert (parent && child);
2342
2343 while (child) {
2344 if (child->parent == parent)
2345 return TRUE;
2346 child = child->parent;
2347 }
2348
2349 return FALSE;
2350 }
2351
2352 gint
html_object_get_insert_level(HTMLObject * o)2353 html_object_get_insert_level (HTMLObject *o)
2354 {
2355 switch (HTML_OBJECT_TYPE (o)) {
2356 case HTML_TYPE_TABLECELL:
2357 case HTML_TYPE_CLUEV: {
2358 gint level = 3;
2359
2360 while (o && (HTML_IS_CLUEV (o) || HTML_IS_TABLE_CELL (o))
2361 && HTML_CLUE (o)->head && (HTML_IS_CLUEV (HTML_CLUE (o)->head) || HTML_IS_TABLE_CELL (HTML_CLUE (o)->head))) {
2362 level++;
2363 o = HTML_CLUE (o)->head;
2364 }
2365
2366 return level;
2367 }
2368 case HTML_TYPE_CLUEFLOW:
2369 return 2;
2370 default:
2371 return 1;
2372 }
2373 }
2374
2375 void
html_object_engine_translation(HTMLObject * o,HTMLEngine * e,gint * tx,gint * ty)2376 html_object_engine_translation (HTMLObject *o,
2377 HTMLEngine *e,
2378 gint *tx,
2379 gint *ty)
2380 {
2381 HTMLObject *p;
2382
2383 *tx = 0;
2384 *ty = 0;
2385
2386 for (p = o->parent; p != NULL && HTML_OBJECT_TYPE (p) != HTML_TYPE_IFRAME; p = p->parent) {
2387 *tx += p->x;
2388 *ty += p->y - p->ascent;
2389 }
2390
2391 /* *tx += e->leftBorder; */
2392 /* *ty += e->topBorder; */
2393 }
2394
2395 gboolean
html_object_engine_intersection(HTMLObject * o,HTMLEngine * e,gint tx,gint ty,gint * x1,gint * y1,gint * x2,gint * y2)2396 html_object_engine_intersection (HTMLObject *o,
2397 HTMLEngine *e,
2398 gint tx,
2399 gint ty,
2400 gint *x1,
2401 gint *y1,
2402 gint *x2,
2403 gint *y2)
2404 {
2405 *x1 = o->x + tx;
2406 *y1 = o->y - o->ascent + ty;
2407 *x2 = o->x + o->width + tx;
2408 *y2 = o->y + o->descent + ty;
2409
2410 return html_engine_intersection (e, x1, y1, x2, y2);
2411 }
2412
2413 void
html_object_add_to_changed(GList ** changed_objs,HTMLObject * o)2414 html_object_add_to_changed (GList **changed_objs,
2415 HTMLObject *o)
2416 {
2417 GList *l, *next;
2418
2419 if (!changed_objs || (*changed_objs && (*changed_objs)->data == o))
2420 return;
2421
2422 for (l = *changed_objs; l; l = next) {
2423 if (l->data == NULL) {
2424 l = l->next;
2425 next = l->next;
2426 continue;
2427 }
2428 next = l->next;
2429 if (html_object_is_parent (o, HTML_OBJECT (l->data))) {
2430 *changed_objs = g_list_remove_link (*changed_objs, l);
2431 g_list_free (l);
2432 } else
2433 break;
2434 }
2435
2436 *changed_objs = g_list_prepend (*changed_objs, o);
2437 }
2438
2439 gint
html_object_get_n_children(HTMLObject * self)2440 html_object_get_n_children (HTMLObject *self)
2441 {
2442 return HO_CLASS (self)->get_n_children ? (* HO_CLASS (self)->get_n_children) (self) : 0;
2443 }
2444
2445 HTMLObject *
html_object_get_child(HTMLObject * self,gint index)2446 html_object_get_child (HTMLObject *self,
2447 gint index)
2448 {
2449 return HO_CLASS (self)->get_child ? (* HO_CLASS (self)->get_child) (self, index) : NULL;
2450 }
2451
2452 gint
html_object_get_child_index(HTMLObject * self,HTMLObject * child)2453 html_object_get_child_index (HTMLObject *self,
2454 HTMLObject *child)
2455 {
2456 return HO_CLASS (self)->get_child_index ? (* HO_CLASS (self)->get_child_index) (self, child) : -1;
2457 }
2458
2459 HTMLClearType
html_object_get_clear(HTMLObject * self)2460 html_object_get_clear (HTMLObject *self)
2461 {
2462 return (* HO_CLASS (self)->get_clear) (self);
2463 }
2464
2465 static HTMLObject *
next_prev_cursor_object(HTMLObject * o,HTMLEngine * e,gint * offset,gboolean forward)2466 next_prev_cursor_object (HTMLObject *o,
2467 HTMLEngine *e,
2468 gint *offset,
2469 gboolean forward)
2470 {
2471 HTMLCursor cursor;
2472 gboolean result;
2473
2474 html_cursor_init (&cursor, o, html_object_is_container (o) ? *offset : (forward ? html_object_get_length (o) : 0));
2475
2476 result = forward ? html_cursor_forward (&cursor, e) : html_cursor_backward (&cursor, e);
2477 *offset = cursor.offset;
2478
2479 return result ? cursor.object : NULL;
2480 }
2481
2482 HTMLObject *
html_object_next_cursor_object(HTMLObject * o,HTMLEngine * e,gint * offset)2483 html_object_next_cursor_object (HTMLObject *o,
2484 HTMLEngine *e,
2485 gint *offset)
2486 {
2487 return next_prev_cursor_object (o, e, offset, TRUE);
2488 }
2489
2490 HTMLObject *
html_object_prev_cursor_object(HTMLObject * o,HTMLEngine * e,gint * offset)2491 html_object_prev_cursor_object (HTMLObject *o,
2492 HTMLEngine *e,
2493 gint *offset)
2494 {
2495 return next_prev_cursor_object (o, e, offset, FALSE);
2496 }
2497
2498 HTMLObject *
html_object_next_cursor_leaf(HTMLObject * o,HTMLEngine * e)2499 html_object_next_cursor_leaf (HTMLObject *o,
2500 HTMLEngine *e)
2501 {
2502 gint offset = html_object_get_length (o);
2503
2504 o = html_object_next_cursor_object (o, e, &offset);
2505 while (o && html_object_is_container (o))
2506 o = html_object_next_cursor_object (o, e, &offset);
2507
2508 return o;
2509 }
2510
2511 HTMLObject *
html_object_prev_cursor_leaf(HTMLObject * o,HTMLEngine * e)2512 html_object_prev_cursor_leaf (HTMLObject *o,
2513 HTMLEngine *e)
2514 {
2515 gint offset = html_object_get_length (o);
2516
2517 o = html_object_prev_cursor_object (o, e, &offset);
2518 while (o && html_object_is_container (o))
2519 o = html_object_prev_cursor_object (o, e, &offset);
2520
2521 return o;
2522 }
2523
2524 HTMLDirection
html_object_get_direction(HTMLObject * o)2525 html_object_get_direction (HTMLObject *o)
2526 {
2527 return (* HO_CLASS (o)->get_direction) (o);
2528 }
2529
2530 const gchar *
html_object_get_id(HTMLObject * o)2531 html_object_get_id (HTMLObject *o)
2532 {
2533 return o->id;
2534 }
2535
2536 void
html_object_set_id(HTMLObject * o,const gchar * id)2537 html_object_set_id (HTMLObject *o,
2538 const gchar *id)
2539 {
2540 g_free (o->id);
2541 o->id = g_strdup (id);
2542 }
2543
2544 HTMLClueFlow *
html_object_get_flow(HTMLObject * o)2545 html_object_get_flow (HTMLObject *o)
2546 {
2547 while (o && !HTML_IS_CLUEFLOW (o))
2548 o = o->parent;
2549
2550 return HTML_CLUEFLOW (o);
2551 }
2552
2553 gint
html_object_get_right_edge_offset(HTMLObject * o,HTMLPainter * painter,gint offset)2554 html_object_get_right_edge_offset (HTMLObject *o,
2555 HTMLPainter *painter,
2556 gint offset)
2557 {
2558 return (* HO_CLASS (o)->get_right_edge_offset) (o, painter, offset);
2559 }
2560
2561 gint
html_object_get_left_edge_offset(HTMLObject * o,HTMLPainter * painter,gint offset)2562 html_object_get_left_edge_offset (HTMLObject *o,
2563 HTMLPainter *painter,
2564 gint offset)
2565 {
2566 return (* HO_CLASS (o)->get_left_edge_offset) (o, painter, offset);
2567 }
2568