source: trunk/third/gtkhtml3/src/htmlinterval.c @ 21116

Revision 21116, 10.3 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21115, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/* This file is part of the GtkHTML library
3
4   Copyright (C) 2000 Helix Code, Inc.
5   Authors:           Radek Doulik (rodo@helixcode.com)
6
7   This library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   This library is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with this library; see the file COPYING.LIB.  If not, write to
19   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.
21*/
22
23#include <config.h>
24#include "htmlcursor.h"
25#include "htmlengine.h"
26#include "htmlinterval.h"
27#include "htmlobject.h"
28#include "htmlselection.h"
29
30inline void
31html_point_construct (HTMLPoint *p, HTMLObject *o, guint off)
32{
33        p->object = o;
34        p->offset = off;
35}
36
37HTMLPoint *
38html_point_new (HTMLObject *o, guint off)
39{
40        HTMLPoint *np = g_new (HTMLPoint, 1);
41        html_point_construct (np, o, off);
42
43        return np;
44}
45
46inline void
47html_point_destroy (HTMLPoint *p)
48{
49        g_free (p);
50}
51
52gboolean
53html_point_cursor_object_eq (HTMLPoint *p, HTMLPoint *c)
54{
55        return p->object == c->object && (!html_object_is_container (p->object) || p->offset == c->offset);
56}
57
58inline void
59html_point_next_cursor (HTMLPoint *p)
60{
61        p->object = html_object_next_cursor (p->object, &p->offset);
62}
63
64HTMLInterval *
65html_interval_new (HTMLObject *from, HTMLObject *to, guint from_offset, guint to_offset)
66{
67        HTMLInterval *i = g_new (HTMLInterval, 1);
68
69        html_point_construct (&i->from, from, from_offset);
70        html_point_construct (&i->to,   to,   to_offset);
71
72        return i;
73}
74
75inline HTMLInterval *
76html_interval_new_from_cursor (HTMLCursor *a, HTMLCursor *b)
77{
78        HTMLCursor *begin, *end;
79
80        if (html_cursor_get_position (a) < html_cursor_get_position (b)) {
81                begin = a;
82                end   = b;
83        } else {
84                begin = b;
85                end   = a;
86        }
87
88        return html_interval_new (begin->object, end->object, begin->offset, end->offset);
89}
90
91inline HTMLInterval *
92html_interval_new_from_points (HTMLPoint *from, HTMLPoint *to)
93{
94        return html_interval_new (from->object, to->object, from->offset, to->offset);
95}
96
97void
98html_interval_destroy (HTMLInterval *i)
99{
100        g_free (i);
101}
102
103guint
104html_interval_get_length (HTMLInterval *i, HTMLObject *obj)
105{
106        if (obj != i->from.object && obj != i->to.object)
107                return html_object_get_length (obj);   
108        if (obj == i->from.object) {
109                if (obj == i->to.object)
110                        return i->to.offset - i->from.offset;
111                else
112                        return html_object_get_length (obj) - i->from.offset;
113        } else
114                return i->to.offset;
115}
116
117guint
118html_interval_get_bytes (HTMLInterval *i, HTMLObject *obj)
119{
120        if (obj != i->from.object && obj != i->to.object)
121                return html_object_get_bytes (obj);
122        if (obj == i->from.object) {
123                if (obj == i->to.object)
124                        return html_interval_get_to_index (i) - html_interval_get_from_index (i);
125                else
126                        return html_object_get_bytes (obj) - html_interval_get_from_index (i);
127        } else
128                return html_interval_get_to_index (i);
129}
130
131guint
132html_interval_get_start (HTMLInterval *i, HTMLObject *obj)
133{
134        return (obj != i->from.object) ? 0 : i->from.offset;
135}
136
137guint
138html_interval_get_start_index (HTMLInterval *i, HTMLObject *obj)
139{
140        return (obj != i->from.object) ? 0 : html_interval_get_from_index (i);
141}
142
143static void
144select_object (HTMLObject *o, HTMLEngine *e, gpointer data)
145{
146        HTMLInterval *i = (HTMLInterval *) data;
147        HTMLEngine *etop = html_engine_get_top_html_engine (e);
148
149        if (o == i->from.object)
150                etop->selected_in = TRUE;
151        if (etop->selected_in) {
152                gint len;
153
154                len = html_interval_get_length (i, o);
155                if (len || html_object_is_container (o))
156                        html_object_select_range (o, e,
157                                                  html_interval_get_start (i, o), len,
158                                                  !html_engine_frozen (e));
159        }
160
161        if (o == i->to.object)
162                etop->selected_in = FALSE;
163}
164
165void
166html_interval_select (HTMLInterval *i, HTMLEngine *e)
167{
168        html_engine_get_top_html_engine (e)->selected_in = FALSE;
169        i = html_interval_flat (i);
170        html_interval_forall (i, e, select_object, i);
171        html_interval_destroy (i);
172}
173
174static void
175unselect_object (HTMLObject *o, HTMLEngine *e, gpointer data)
176{
177        if (html_interval_get_length ((HTMLInterval *) data, o))
178                html_object_select_range (o, e, 0, 0, !html_engine_frozen (e));
179}
180
181void
182html_interval_unselect (HTMLInterval *i, HTMLEngine *e)
183{
184        i = html_interval_flat (i);
185        html_interval_forall (i, e, unselect_object, i);
186        html_interval_destroy (i);
187}
188
189gint
190html_interval_get_from_index (HTMLInterval *i)
191{
192        g_assert (i);
193
194        return html_object_get_index (i->from.object, i->from.offset);
195}
196
197gint
198html_interval_get_to_index (HTMLInterval *i)
199{
200        g_assert (i);
201
202        return html_object_get_index (i->to.object, i->to.offset);
203}
204
205static GSList *
206get_downtree_line (HTMLObject *o)
207{
208        GSList *list = NULL;
209
210        while (o) {
211                list = g_slist_prepend (list, o);
212                o = o->parent;
213        }
214
215        return list;
216}
217
218static HTMLEngine *
219do_downtree_lines_intersection (GSList **l1, GSList **l2, HTMLEngine *e)
220{
221        g_assert ((*l1)->data == (*l2)->data);
222
223        while (*l1 && *l2 && (*l1)->data == (*l2)->data) {
224                e = html_object_get_engine (HTML_OBJECT ((*l1)->data), e);
225                *l1 = g_slist_remove_link (*l1, *l1);
226                *l2 = g_slist_remove_link (*l2, *l2);
227        }
228
229        return e;
230}
231
232static void
233interval_forall (HTMLObject *parent, GSList *from_down, GSList *to_down, HTMLEngine *e, HTMLObjectForallFunc f, gpointer data)
234{
235        HTMLObject *o, *from, *to;
236
237        from = from_down ? HTML_OBJECT (from_down->data) : html_object_head (parent);
238        to   = to_down   ? HTML_OBJECT (to_down->data)   : NULL;
239
240        for (o = from; o; o = html_object_next_not_slave (o)) {
241                interval_forall (o,
242                                 (from_down && o == HTML_OBJECT (from_down->data)) ? from_down->next : NULL,
243                                 (to_down   && o == HTML_OBJECT (to_down->data))   ? to_down->next   : NULL,
244                                 html_object_get_engine (o, e), f, data);
245                if (o == to)
246                        break;
247        }
248        (*f) (parent, e, data);
249}
250
251static void
252html_point_to_leaf (HTMLPoint *p)
253{
254        if (html_object_is_container (p->object)) {
255                if (p->offset == 0)
256                        p->object = html_object_get_head_leaf (p->object);
257                else if (p->offset == html_object_get_length (p->object)) {
258                        p->object = html_object_get_tail_leaf (p->object);
259                        p->offset = html_object_get_length (p->object);
260                } else
261                        g_warning ("Can't transform point to leaf\n");
262        }
263}
264
265static inline HTMLInterval *
266html_interval_dup (HTMLInterval *i)
267{
268        return html_interval_new_from_points (&i->from, &i->to);
269}
270
271HTMLInterval *
272html_interval_flat (HTMLInterval *i)
273{
274        HTMLInterval *ni = html_interval_dup (i);
275
276        html_point_to_leaf (&ni->from);
277        html_point_to_leaf (&ni->to);
278
279        return ni;
280}
281
282void
283html_interval_forall (HTMLInterval *i, HTMLEngine *e, HTMLObjectForallFunc f, gpointer data)
284{
285        GSList *from_downline, *to_downline;
286        HTMLEngine *engine;
287
288        g_return_if_fail (i->from.object);
289        g_return_if_fail (i->to.object);
290
291        i = html_interval_flat (i);
292
293        from_downline = get_downtree_line (i->from.object);
294        to_downline   = get_downtree_line (i->to.object);
295        engine = do_downtree_lines_intersection  (&from_downline, &to_downline, e);
296
297        if (from_downline)
298                interval_forall    (HTML_OBJECT (from_downline->data)->parent, from_downline, to_downline,
299                                    html_object_get_engine (HTML_OBJECT (from_downline->data)->parent, engine), f, data);
300        else {
301                g_assert (i->from.object == i->to.object);
302                html_object_forall (i->from.object, html_object_get_engine (i->from.object, engine), f, data);
303        }
304
305        g_slist_free (from_downline);
306        g_slist_free (to_downline);
307        html_interval_destroy (i);
308}
309
310static HTMLObject *
311html_object_children_max (HTMLObject *a, HTMLObject *b)
312{
313        HTMLObject *o;
314
315        g_return_val_if_fail (a->parent, NULL);
316        g_return_val_if_fail (b->parent, NULL);
317        g_return_val_if_fail (a->parent == b->parent, NULL);
318
319        for (o=a; o; o = html_object_next_not_slave (o))
320                if (o == b)
321                        return b;
322        return a;
323}
324
325static inline HTMLObject *
326html_object_children_min (HTMLObject *a, HTMLObject *b)
327{
328        return a == html_object_children_max (b, a) ? b : a;
329}
330
331HTMLPoint *
332html_point_max (HTMLPoint *a, HTMLPoint *b)
333{
334        GSList *a_downline, *b_downline;
335        HTMLPoint *rv = NULL;
336
337        if (a->object == b->object)
338                return a->offset < b->offset ? b : a;
339
340        a_downline = get_downtree_line (a->object);
341        b_downline = get_downtree_line (b->object);
342        do_downtree_lines_intersection (&a_downline, &b_downline, NULL);
343
344        if (a_downline == NULL)
345                /* it means that a is parent (container) of b */
346                rv = a->offset ? a : b;
347        else if (b_downline == NULL)
348                /* it means that b is parent (container) of a */
349                rv = b->offset ? b : a;
350        else
351                rv = html_object_children_max (HTML_OBJECT (a_downline->data), HTML_OBJECT (b_downline->data))
352                        == HTML_OBJECT (a_downline->data) ? a : b;
353        g_slist_free (a_downline);
354        g_slist_free (b_downline);
355
356        return rv;
357}
358
359inline HTMLPoint *
360html_point_min (HTMLPoint *a, HTMLPoint *b)
361{
362        return a == html_point_max (a, b) ? b : a;
363}
364
365static HTMLPoint *
366max_from (HTMLInterval *a, HTMLInterval *b)
367{
368        if (!a->from.object)
369                return &b->from;
370        if (!b->from.object)
371                return &a->from;
372
373        return html_point_max (&a->from, &b->from);
374}
375
376static HTMLPoint *
377min_to (HTMLInterval *a, HTMLInterval *b)
378{
379        if (!a->to.object)
380                return &b->to;
381        if (!b->to.object)
382                return &a->to;
383
384        return html_point_min (&a->to, &b->to);
385}
386
387HTMLInterval *
388html_interval_intersection (HTMLInterval *a, HTMLInterval *b)
389{
390        HTMLPoint *from, *to;
391
392        from = max_from (a, b);
393        to   = min_to   (a, b);
394
395        return to == html_point_max (from, to) ?
396                html_interval_new_from_points (from, to) : NULL;
397}
398
399void *
400html_interval_substract (HTMLInterval *a, HTMLInterval *b, HTMLInterval **s1, HTMLInterval **s2)
401{
402        return NULL;
403}
404
405void
406html_interval_validate (HTMLInterval *i)
407{
408        if (&i->from == html_point_max (&i->from, &i->to)) {
409                HTMLPoint tmp;
410
411                tmp     = i->from;
412                i->from = i->to;
413                i->to   = tmp;
414        }
415}
416
417gboolean
418html_point_eq (const HTMLPoint *a, const HTMLPoint *b)
419{
420        return a->object == b->object && a->offset == b->offset;
421}
422
423gboolean
424html_interval_eq (const HTMLInterval *a, const HTMLInterval *b)
425{
426        return html_point_eq (&a->from, &b->from) && html_point_eq (&a->to, &b->to);
427}
428
429HTMLObject *
430html_interval_get_head (HTMLInterval *i, HTMLObject *o)
431{
432        return o == i->from.object->parent ? i->from.object : html_object_head (o);
433}
Note: See TracBrowser for help on using the repository browser.