source: trunk/third/gtkhtml3/src/htmltextslave.c @ 21460

Revision 21460, 23.7 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21459, 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) 1997 Martin Jones (mjones@kde.org)
5   Copyright (C) 1997 Torben Weis (weis@kde.org)
6   Copyright (C) 1999 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., 59 Temple Place - Suite 330,
21   Boston, MA 02111-1307, USA.
22*/
23
24#include <config.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "htmltextslave.h"
29#include "htmlclue.h"
30#include "htmlclueflow.h"
31#include "htmlcursor.h"
32#include "htmlcolor.h"
33#include "htmlcolorset.h"
34#include "htmlpainter.h"
35#include "htmlobject.h"
36#include "htmlprinter.h"
37#include "htmlplainpainter.h"
38#include "htmlgdkpainter.h"
39#include "htmlsettings.h"
40#include "gtkhtml.h"
41
42
43/* #define HTML_TEXT_SLAVE_DEBUG */
44
45HTMLTextSlaveClass html_text_slave_class;
46static HTMLObjectClass *parent_class = NULL;
47
48static GList * get_glyphs (HTMLTextSlave *slave, HTMLPainter *painter);
49static GList * get_glyphs_part (HTMLTextSlave *slave, HTMLPainter *painter, guint offset, guint len);
50static void    clear_glyphs (HTMLTextSlave *slave);
51
52char *
53html_text_slave_get_text (HTMLTextSlave *slave)
54{
55        if (!slave->charStart)
56                slave->charStart = html_text_get_text (slave->owner, slave->posStart);
57
58        return slave->charStart;
59}
60
61/* Split this TextSlave at the specified offset.  */
62static void
63split (HTMLTextSlave *slave, guint offset, char *start_pointer)
64{
65        HTMLObject *obj;
66        HTMLObject *new;
67
68        g_return_if_fail (offset >= 0);
69        g_return_if_fail (offset < slave->posLen);
70
71        obj = HTML_OBJECT (slave);
72
73        new = html_text_slave_new (slave->owner,
74                                   slave->posStart + offset,
75                                   slave->posLen - offset);
76
77        HTML_TEXT_SLAVE (new)->charStart = start_pointer;
78
79        html_clue_append_after (HTML_CLUE (obj->parent), new, obj);
80
81        slave->posLen = offset;
82}
83
84
85/* HTMLObject methods.  */
86
87static void
88copy (HTMLObject *self,
89      HTMLObject *dest)
90{
91        (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);
92
93        /* FIXME it does not make much sense to me to share the owner.  */
94        HTML_TEXT_SLAVE (dest)->owner = HTML_TEXT_SLAVE (self)->owner;
95        HTML_TEXT_SLAVE (dest)->posStart = HTML_TEXT_SLAVE (self)->posStart;
96        HTML_TEXT_SLAVE (dest)->posLen = HTML_TEXT_SLAVE (self)->posLen;
97}
98
99static inline gint
100html_text_slave_get_start_byte_offset (HTMLTextSlave *slave)
101{
102        return html_text_slave_get_text (slave) - slave->owner->text;
103}
104
105static guint
106hts_calc_width (HTMLTextSlave *slave, HTMLPainter *painter, gint *asc, gint *dsc)
107{
108        HTMLText *text = slave->owner;
109        gint line_offset, tabs = 0, width = 0;
110
111        line_offset = html_text_slave_get_line_offset (slave, 0, painter);
112        if (line_offset != -1)
113                width += (html_text_text_line_length (html_text_slave_get_text (slave), &line_offset, slave->posLen, &tabs) - slave->posLen)*
114                        html_painter_get_space_width (painter, html_text_get_font_style (text), text->face);
115
116        width += html_text_calc_part_width (text, painter, html_text_slave_get_text (slave), slave->posStart, slave->posLen, asc, dsc);
117
118        return width;
119}
120
121inline static void
122glyphs_destroy (GList *glyphs)
123{
124        GList *l;
125
126        for (l = glyphs; l; l = l->next->next)
127                pango_glyph_string_free ((PangoGlyphString *) l->data);
128        g_list_free (glyphs);
129}
130
131static gboolean
132html_text_slave_real_calc_size (HTMLObject *self, HTMLPainter *painter, GList **changed_objs)
133{
134        HTMLText *owner;
135        HTMLTextSlave *slave;
136        GtkHTMLFontStyle font_style;
137        gint new_ascent, new_descent, new_width;
138        gboolean changed;
139
140        slave = HTML_TEXT_SLAVE (self);
141        owner = HTML_TEXT (slave->owner);
142        font_style = html_text_get_font_style (owner);
143
144        new_width = MAX (1, hts_calc_width (slave, painter, &new_ascent, &new_descent));
145
146        /* handle sub & super script */
147        if (font_style & GTK_HTML_FONT_STYLE_SUBSCRIPT || font_style & GTK_HTML_FONT_STYLE_SUPERSCRIPT) {
148                gint shift = (new_ascent + new_descent) >> 1;
149
150                if (font_style & GTK_HTML_FONT_STYLE_SUBSCRIPT) {
151                        new_descent += shift;
152                        new_ascent  -= shift;
153                } else {
154                        new_descent -= shift;
155                        new_ascent  += shift;
156                }
157        }
158
159        changed = FALSE;
160
161        if (new_ascent != self->ascent) {
162                self->ascent = new_ascent;
163                changed = TRUE;
164        }
165
166        if (new_descent != self->descent) {
167                self->descent = new_descent;
168                changed = TRUE;
169        }
170
171        if (new_width != self->width) {
172                self->width = new_width;
173                changed = TRUE;
174        }
175
176        return changed;
177}
178
179#ifdef HTML_TEXT_SLAVE_DEBUG
180static void
181debug_print (HTMLFitType rv, gchar *text, gint len)
182{
183        gint i;
184
185        printf ("Split text");
186        switch (rv) {
187        case HTML_FIT_PARTIAL:
188                printf (" (Partial): `");
189                break;
190        case HTML_FIT_NONE:
191                printf (" (NoFit): `");
192                break;
193        case HTML_FIT_COMPLETE:
194                printf (" (Complete): `");
195                break;
196        }
197
198        for (i = 0; i < len; i++)
199                putchar (text [i]);
200
201        printf ("'\n");
202}
203#endif
204
205gint
206html_text_slave_get_line_offset (HTMLTextSlave *slave, gint offset, HTMLPainter *p)
207{
208        HTMLObject *head = HTML_OBJECT (slave->owner)->next;
209
210        g_assert (HTML_IS_TEXT_SLAVE (head));
211
212        if (!html_clueflow_tabs (HTML_CLUEFLOW (HTML_OBJECT (slave)->parent), p))
213                return -1;
214
215        if (head->y + head->descent - 1 < HTML_OBJECT (slave)->y - HTML_OBJECT (slave)->ascent) {
216                HTMLObject *prev;
217                HTMLTextSlave *bol;
218                gint line_offset = 0;
219
220                prev = html_object_prev (HTML_OBJECT (slave)->parent, HTML_OBJECT (slave));
221                while (prev->y + prev->descent - 1 >= HTML_OBJECT (slave)->y - HTML_OBJECT (slave)->ascent)
222                        prev = html_object_prev (HTML_OBJECT (slave)->parent, HTML_OBJECT (prev));
223
224                bol = HTML_TEXT_SLAVE (prev->next);
225                return html_text_text_line_length (html_text_slave_get_text (bol),
226                                                   &line_offset, slave->posStart + offset - bol->posStart, NULL);
227        } else
228                return html_text_get_line_offset (slave->owner, p, slave->posStart + offset);
229}
230
231static gboolean
232could_remove_leading_space (HTMLTextSlave *slave, gboolean lineBegin)
233{
234        HTMLObject *o = HTML_OBJECT (slave->owner);
235
236        if (lineBegin && (HTML_OBJECT (slave)->prev != o || o->prev))
237                return TRUE;
238
239        if (!o->prev)
240                return FALSE;
241
242        while (o->prev && HTML_OBJECT_TYPE (o->prev) == HTML_TYPE_CLUEALIGNED)
243                o = o->prev;
244
245        return o->prev ? FALSE : TRUE;
246}
247
248gchar *
249html_text_slave_remove_leading_space (HTMLTextSlave *slave, HTMLPainter *painter, gboolean lineBegin)
250{
251        gchar *begin;
252
253        begin = html_text_slave_get_text (slave);
254        if (*begin == ' ' && could_remove_leading_space (slave, lineBegin)) {
255                begin = g_utf8_next_char (begin);
256                slave->charStart = begin;
257                slave->posStart ++;
258                slave->posLen --;
259        }
260
261        return begin;
262}
263
264gint
265html_text_slave_get_nb_width (HTMLTextSlave *slave, HTMLPainter *painter, gboolean lineBegin)
266{
267        html_text_slave_remove_leading_space (slave, painter, lineBegin);
268
269        return html_object_calc_min_width (HTML_OBJECT (slave), painter);
270}
271
272static gboolean
273update_lb (HTMLTextSlave *slave, HTMLPainter *painter, gint widthLeft, gint offset, gchar *s, gint ii, gint io, gint line_offset,
274           gint *w, gint *ltw, gint *lwl, gint *lbw, gint *lbo, gchar **lbsp, gboolean *force_fit)
275{
276        gint new_ltw, new_lwl, aw;
277
278        new_ltw = html_text_tail_white_space (slave->owner, painter, offset, ii, io, &new_lwl, line_offset, s);
279        if (HTML_IS_GDK_PAINTER (painter) || HTML_IS_PLAIN_PAINTER (painter)) {
280                aw = *w - new_ltw;
281        } else {
282                gint lo = html_text_get_line_offset (slave->owner, painter, *lbo);
283                gint width;
284                                /* printf ("s: %s l: %d\n", html_text_get_text (slave->owner, lbo - lwl), offset - new_lwl - lbo + lwl); */
285                html_text_calc_text_size (slave->owner, painter, html_text_get_text (slave->owner, *lbo) - slave->owner->text,
286                                          offset - *lbo, NULL, NULL, &lo,
287                                          html_text_get_font_style (slave->owner), slave->owner->face,
288                                          &width, NULL, NULL);
289                *w += width;
290                aw = *w - new_ltw;
291        }
292        if (aw <= widthLeft || *force_fit) {
293                *ltw = new_ltw;
294                *lwl = new_lwl;
295                *lbw = aw;
296                *lbo = offset;
297                *lbsp = s;
298                if (*force_fit && *lbw >= widthLeft)
299                        return TRUE;
300                *force_fit = FALSE;
301        } else
302                return TRUE;
303
304        return FALSE;
305}
306
307static HTMLFitType
308hts_fit_line (HTMLObject *o, HTMLPainter *painter,
309              gboolean lineBegin, gboolean firstRun, gboolean next_to_floating, gint widthLeft)
310{
311        HTMLTextSlave *slave = HTML_TEXT_SLAVE (o);
312        gint lbw, w, lbo, ltw, lwl, offset;
313        gint ii, io, line_offset;
314        gchar *s, *lbsp;
315        HTMLFitType rv = HTML_FIT_NONE;
316        HTMLTextPangoInfo *pi = html_text_get_pango_info (slave->owner, painter);
317        gboolean force_fit = lineBegin;
318
319        if (rv == HTML_FIT_COMPLETE)
320                return rv;
321
322        lbw = ltw = lwl = w = 0;
323        offset = lbo = slave->posStart;
324        ii = html_text_get_item_index (slave->owner, painter, offset, &io);
325
326        line_offset = html_text_get_line_offset (slave->owner, painter, offset);
327        lbsp = s = html_text_slave_get_text (slave);
328
329        while ((force_fit || widthLeft > lbw) && offset < slave->posStart + slave->posLen) {
330                if (offset > slave->posStart && offset > lbo && html_text_is_line_break (pi->attrs [offset]))
331                        if (update_lb (slave, painter, widthLeft, offset, s, ii, io, line_offset, &w, &ltw, &lwl, &lbw, &lbo, &lbsp, &force_fit))
332                                break;
333
334                if (*s == '\t') {
335                        gint skip = 8 - (line_offset % 8);
336                        if (HTML_IS_GDK_PAINTER (painter) || HTML_IS_PLAIN_PAINTER (painter))
337                                w += skip*PANGO_PIXELS (pi->entries [ii].widths [io]);
338                        line_offset += skip;
339                } else {
340                        if (HTML_IS_GDK_PAINTER (painter) || HTML_IS_PLAIN_PAINTER (painter))
341                                w += PANGO_PIXELS (pi->entries [ii].widths [io]);
342                        line_offset ++;
343                }
344
345                s = g_utf8_next_char (s);
346                offset ++;
347
348                html_text_pi_forward (pi, &ii, &io);
349        }
350
351        if (!HTML_IS_GDK_PAINTER (painter) && !HTML_IS_PLAIN_PAINTER (painter)) {
352                gint aw;
353                gint lo = html_text_get_line_offset (slave->owner, painter, lbo);
354
355                /* printf ("s: %s l: %d\n", html_text_get_text (slave->owner, lbo - lwl), offset - lbo + lwl); */
356                html_text_calc_text_size (slave->owner, painter, html_text_get_text (slave->owner, lbo) - slave->owner->text,
357                                          offset - lbo, NULL, NULL, &lo,
358                                          html_text_get_font_style (slave->owner), slave->owner->face,
359                                          &aw, NULL, NULL);
360                w += aw;
361        }
362
363        if (offset == slave->posStart + slave->posLen && (widthLeft >= w || force_fit)) {
364                rv = HTML_FIT_COMPLETE;
365                if (slave->posLen)
366                        o->width = w;
367        } else if (lbo > slave->posStart) {
368                split (slave, lbo - slave->posStart, lbsp);
369                rv = HTML_FIT_PARTIAL;
370                o->width = lbw;
371                slave->posLen -= lwl;
372        }
373
374        return rv;
375}
376
377static gboolean
378select_range (HTMLObject *self,
379              HTMLEngine *engine,
380              guint start, gint length,
381              gboolean queue_draw)
382{
383        return FALSE;
384}
385
386static guint
387get_length (HTMLObject *self)
388{
389        return 0;
390}
391
392
393/* HTMLObject::draw() implementation.  */
394
395static gint
396get_ys (HTMLText *text, HTMLPainter *p)
397{
398        if (text->font_style & GTK_HTML_FONT_STYLE_SUBSCRIPT || text->font_style & GTK_HTML_FONT_STYLE_SUPERSCRIPT) {
399                gint height2;
400
401                height2 = (HTML_OBJECT (text)->ascent + HTML_OBJECT (text)->descent) / 2;
402                /* FIX2? (html_painter_calc_ascent (p, text->font_style, text->face)
403                   + html_painter_calc_descent (p, text->font_style, text->face)) >> 1; */
404                return (text->font_style & GTK_HTML_FONT_STYLE_SUBSCRIPT) ? height2 : -height2;
405                       
406        } else
407                return 0;
408}
409
410static void
411draw_spell_errors (HTMLTextSlave *slave, HTMLPainter *p, gint tx, gint ty)
412{
413        GList *cur = HTML_TEXT (slave->owner)->spell_errors;
414        HTMLObject *obj = HTML_OBJECT (slave);
415        SpellError *se;
416        guint ma, mi;
417        gint x_off = 0;
418        gint last_off = 0;
419        gint line_offset = html_text_slave_get_line_offset (slave, 0, p);
420        gchar *text = html_text_slave_get_text (slave);
421        HTMLEngine *e;
422
423        if (p->widget && GTK_IS_HTML (p->widget))
424                e = GTK_HTML (p->widget)->engine;
425        else
426                return;
427
428        while (cur) {
429
430                se = (SpellError *) cur->data;
431                ma = MAX (se->off, slave->posStart);
432                mi = MIN (se->off + se->len, slave->posStart + slave->posLen);
433                if (ma < mi) {
434                        GList *glyphs;
435                        guint off = ma - slave->posStart;
436                        guint len = mi - ma;
437                        gint lo, width, asc, dsc;
438
439                        html_painter_set_pen (p, &html_colorset_get_color_allocated (e->settings->color_set,
440                                                                                     p, HTMLSpellErrorColor)->color);
441                        /* printf ("spell error: %s\n", html_text_get_text (slave->owner, off)); */
442                        lo = line_offset;
443                       
444                        glyphs = get_glyphs_part (slave, p, last_off, off - last_off);
445                        html_text_calc_text_size (slave->owner, p, text - slave->owner->text,
446                                                  off - last_off, html_text_get_pango_info (slave->owner, p), glyphs,
447                                                  &line_offset,
448                                                  p->font_style,
449                                                  p->font_face, &width, &asc, &dsc);
450                        glyphs_destroy (glyphs);
451                        x_off += width;
452                        text = g_utf8_offset_to_pointer (text, off - last_off);
453                        glyphs = get_glyphs_part (slave, p, off, len);
454                        x_off += html_painter_draw_spell_error (p, obj->x + tx + x_off,
455                                                                obj->y + ty + get_ys (slave->owner, p),
456                                                                text, len, html_text_get_pango_info (slave->owner, p), glyphs, text - slave->owner->text);
457                        glyphs_destroy (glyphs);
458                        last_off = off + len;
459                        if (line_offset != -1)
460                                line_offset += len;
461                        text = g_utf8_offset_to_pointer (text, len);
462                }
463                if (se->off > slave->posStart + slave->posLen)
464                        break;
465                cur = cur->next;
466        }
467}
468
469static inline GList *
470get_glyphs_base_text (GList *glyphs, PangoItem *item, gint ii, const gchar *text, gint bytes)
471{
472        PangoGlyphString *str;
473
474        str = pango_glyph_string_new ();
475        pango_shape (text, bytes, &item->analysis, str);
476        glyphs = g_list_prepend (glyphs, str);
477        glyphs = g_list_prepend (glyphs, GINT_TO_POINTER (ii));
478
479        return glyphs;
480}
481
482GList *
483html_get_glyphs_non_tab (GList *glyphs, PangoItem *item, gint ii, const gchar *text, gint bytes, gint len)
484{
485        gchar *tab;
486
487        while ((tab = memchr (text, (unsigned char) '\t', bytes))) {
488                gint c_bytes = tab - text;
489                if (c_bytes > 0)
490                        glyphs = get_glyphs_base_text (glyphs, item, ii, text, c_bytes);
491                text += c_bytes + 1;
492                bytes -= c_bytes + 1;
493        }
494
495        if (bytes > 0)
496                glyphs = get_glyphs_base_text (glyphs, item, ii, text, bytes);
497
498        return glyphs;
499}
500
501static GList *
502get_glyphs_part (HTMLTextSlave *slave, HTMLPainter *painter, guint offset, guint len)
503{
504        GList *glyphs = NULL;
505        HTMLTextPangoInfo *pi;
506
507        pi = html_text_get_pango_info (slave->owner, painter);
508        if (pi) {
509                PangoItem *item;
510                gint index, c_len;
511                gint byte_offset, ii;
512                const gchar *text, *owner_text;
513                gchar *end;
514
515                owner_text = slave->owner->text;
516                text = g_utf8_offset_to_pointer (html_text_slave_get_text (slave), offset);
517                byte_offset = text - owner_text;
518
519                ii = html_text_pango_info_get_index (pi, byte_offset, 0);
520                index = 0;
521                while (index < len) {
522                        item = pi->entries [ii].item;
523                        c_len = MIN (item->num_chars - g_utf8_pointer_to_offset (owner_text + item->offset, text), len - index);
524
525                        end = g_utf8_offset_to_pointer (text, c_len);
526                        glyphs = html_get_glyphs_non_tab (glyphs, item, ii, text, end - text, c_len);
527                        text = end;
528                        index += c_len;
529                        ii ++;
530                }
531                glyphs = g_list_reverse (glyphs);
532        }
533
534        return glyphs;
535}
536
537static GList *
538get_glyphs (HTMLTextSlave *slave, HTMLPainter *painter)
539{
540        if (!slave->glyphs || (HTML_OBJECT (slave)->change & HTML_CHANGE_RECALC_PI)) {
541                clear_glyphs (slave);
542
543                HTML_OBJECT (slave)->change &= ~HTML_CHANGE_RECALC_PI;
544                slave->glyphs = get_glyphs_part (slave, painter, 0, slave->posLen);
545        }
546
547        return slave->glyphs;
548}
549
550
551static void
552draw_normal (HTMLTextSlave *self,
553             HTMLPainter *p,
554             GtkHTMLFontStyle font_style,
555             gint x, gint y,
556             gint width, gint height,
557             gint tx, gint ty)
558{
559        HTMLObject *obj;
560        HTMLText *text = self->owner;
561        gchar *str;
562
563        obj = HTML_OBJECT (self);
564
565        str = html_text_slave_get_text (self);
566        if (*str) {
567                GList *glyphs;
568                PangoAttrList *attrs = NULL;
569
570                if (self->posStart > 0)
571                        glyphs = get_glyphs_part (self, p, 0, self->posLen);
572                else
573                        glyphs = get_glyphs (self, p);
574
575                if (HTML_IS_PRINTER (p)) {
576                        HTMLClueFlow *flow = NULL;
577                        HTMLEngine *e = NULL;
578
579                        gchar *text = html_text_slave_get_text (self);
580                        gint start_index, end_index;
581
582                        start_index = text - self->owner->text;
583                        end_index = g_utf8_offset_to_pointer (text, self->posLen) - self->owner->text;
584
585                        attrs = html_text_get_attr_list (self->owner, start_index, end_index);
586
587                        if (p->widget && GTK_IS_HTML (p->widget))
588                                e = GTK_HTML (p->widget)->engine;
589
590                        if (HTML_OBJECT (self)->parent && HTML_IS_CLUEFLOW (HTML_OBJECT (self)->parent))
591                                flow = HTML_CLUEFLOW (HTML_OBJECT (self)->parent);
592
593                        if (flow && e)
594                                html_text_change_attrs (attrs, html_clueflow_get_default_font_style (flow), GTK_HTML (p->widget)->engine,
595                                                        start_index, end_index, TRUE);
596                }
597
598                html_painter_draw_text (p, obj->x + tx, obj->y + ty + get_ys (text, p),
599                                        str, self->posLen, html_text_get_pango_info (text, p), attrs, glyphs,
600                                        str - self->owner->text, html_text_slave_get_line_offset (self, 0, p));
601                if (attrs)
602                        pango_attr_list_unref (attrs);
603
604                if (self->posStart > 0)
605                        glyphs_destroy (glyphs);
606        }
607}
608
609static void
610draw_focus  (HTMLPainter *painter, GdkRectangle *box)
611{
612        HTMLGdkPainter *p;
613        GdkGCValues values;
614        gchar dash [2];
615        HTMLEngine *e;
616
617        if (painter->widget && GTK_IS_HTML (painter->widget))
618                e = GTK_HTML (painter->widget)->engine;
619        else
620                return;
621
622        if (HTML_IS_PRINTER (painter))
623                return;
624       
625        p = HTML_GDK_PAINTER (painter);
626        /* printf ("draw_text_focus\n"); */
627
628        gdk_gc_set_foreground (p->gc, &html_colorset_get_color_allocated (e->settings->color_set,
629                                                                          painter, HTMLTextColor)->color);
630        gdk_gc_get_values (p->gc, &values);
631
632        dash [0] = 1;
633        dash [1] = 1;
634        gdk_gc_set_line_attributes (p->gc, 1, GDK_LINE_ON_OFF_DASH, values.cap_style, values.join_style);
635        gdk_gc_set_dashes (p->gc, 2, dash, 2);
636        gdk_draw_rectangle (p->pixmap, p->gc, 0, box->x - p->x1, box->y - p->y1, box->width - 1, box->height - 1);
637        gdk_gc_set_line_attributes (p->gc, 1, values.line_style, values.cap_style, values.join_style);
638}
639
640static void
641draw (HTMLObject *o,
642      HTMLPainter *p,
643      gint x, gint y,
644      gint width, gint height,
645      gint tx, gint ty)
646{
647        HTMLTextSlave *textslave;
648        HTMLText *owner;
649        HTMLText *ownertext;
650        GtkHTMLFontStyle font_style;
651        guint end;
652        GdkRectangle paint;
653
654        /* printf ("slave draw %p\n", o); */
655
656        textslave = HTML_TEXT_SLAVE (o);
657        if (!html_object_intersect (o, &paint, x, y, width, height) || textslave->posLen == 0)
658                return;
659       
660        owner = textslave->owner;
661        ownertext = HTML_TEXT (owner);
662        font_style = html_text_get_font_style (ownertext);
663
664        end = textslave->posStart + textslave->posLen;
665        draw_normal (textslave, p, font_style, x, y, width, height, tx, ty);
666       
667        if (owner->spell_errors)
668                draw_spell_errors (textslave, p, tx ,ty);
669       
670        if (HTML_OBJECT (owner)->draw_focused) {
671                GdkRectangle rect;
672                Link *link = html_text_get_link_at_offset (owner, owner->focused_link_offset);
673
674                if (link && MAX (link->start_offset, textslave->posStart) < MIN (link->end_offset, textslave->posStart + textslave->posLen)) {
675                        gint bw = 0;
676                        html_object_get_bounds (o, &rect);
677                        if (textslave->posStart < link->start_offset)
678                                bw = html_text_calc_part_width (owner, p, html_text_slave_get_text (textslave), textslave->posStart, link->start_offset - textslave->posStart, NULL, NULL);
679                        rect.x += tx + bw;
680                        rect.width -= bw;
681                        if (textslave->posStart + textslave->posLen > link->end_offset)
682                                rect.width -= html_text_calc_part_width (owner, p, owner->text + link->end_index, link->end_offset,  textslave->posStart + textslave->posLen - link->end_offset, NULL, NULL);
683                        rect.y += ty;
684                        draw_focus (p, &rect);
685                }
686        }
687}
688
689static gint
690calc_min_width (HTMLObject *o,
691                HTMLPainter *painter)
692{
693        return 0;
694}
695
696static gint
697calc_preferred_width (HTMLObject *o,
698                      HTMLPainter *painter)
699{
700        return 0;
701}
702
703static const gchar *
704get_url (HTMLObject *o, gint offset)
705{
706        HTMLTextSlave *slave;
707
708        slave = HTML_TEXT_SLAVE (o);
709        return html_object_get_url (HTML_OBJECT (slave->owner), offset);
710}
711
712static gint
713calc_offset (HTMLTextSlave *slave, HTMLPainter *painter, gint x, gint y)
714{
715        HTMLText *owner;
716        GtkHTMLFontStyle font_style;
717        gint line_offset;
718        guint width, prev_width;
719        gchar *text;
720        guint upper;
721        guint len;
722        guint lower;
723        GList *glyphs;
724        gint lo;
725        gint asc, dsc;
726
727        g_assert (slave->posLen > 1);
728
729        width = 0;
730        prev_width  = 0;
731        lower = 0;
732        upper = slave->posLen;
733        len = 0;
734
735        text = html_text_slave_get_text (slave);
736        line_offset = html_text_slave_get_line_offset (slave, 0, painter);     
737        owner = HTML_TEXT (slave->owner);
738        font_style = html_text_get_font_style (owner);
739
740        while (upper - lower > 1) {
741                lo = line_offset;
742                prev_width = width;
743
744                if (width > x)
745                        upper = len;
746                else
747                        lower = len;
748       
749                len = (lower + upper + 1) / 2;
750
751                if (len) {
752                        glyphs = get_glyphs_part (slave, painter, 0, len);
753                        html_text_calc_text_size (slave->owner, painter, text - slave->owner->text, len, html_text_get_pango_info (owner, painter), glyphs,
754                                                  &lo, font_style, owner->face, &width, &asc, &dsc);
755                        glyphs_destroy (glyphs);
756                } else {
757                        width = 0;
758                }
759        }
760
761        if ((width + prev_width) / 2 >= x)
762                len--;
763
764        return len;
765}
766
767static guint
768get_offset_for_pointer (HTMLTextSlave *slave, HTMLPainter *painter, gint x, gint y)
769{
770        g_return_val_if_fail (slave != NULL, 0);
771
772        x -= HTML_OBJECT (slave)->x;
773
774        if (x <= 0)
775                return 0;
776
777        if (x >= HTML_OBJECT (slave)->width - 1)
778                return slave->posLen;
779
780        if (slave->posLen > 1)
781                return calc_offset (slave, painter, x, y);
782        else
783                return x > HTML_OBJECT (slave)->width / 2 ? 1 : 0;
784}
785
786static HTMLObject *
787check_point (HTMLObject *self,
788             HTMLPainter *painter,
789             gint x, gint y,
790             guint *offset_return,
791             gboolean for_cursor)
792{
793        if (x >= self->x
794            && x < self->x + MAX (1, self->width)
795            && y >= self->y - self->ascent
796            && y < self->y + self->descent) {
797                HTMLTextSlave *slave = HTML_TEXT_SLAVE (self);
798
799                if (offset_return != NULL)
800                        *offset_return = slave->posStart
801                                + get_offset_for_pointer (slave, painter, x, y);
802
803                return HTML_OBJECT (slave->owner);
804        }
805
806        return NULL;
807}
808
809static void
810clear_glyphs (HTMLTextSlave *slave)
811{
812        if (slave->glyphs) {
813                glyphs_destroy (slave->glyphs);
814                slave->glyphs = NULL;
815        }
816}
817
818static void
819destroy (HTMLObject *obj)
820{
821        HTMLTextSlave *slave = HTML_TEXT_SLAVE (obj);
822
823        clear_glyphs (slave);
824
825        HTML_OBJECT_CLASS (parent_class)->destroy (obj);
826}
827
828void
829html_text_slave_type_init (void)
830{
831        html_text_slave_class_init (&html_text_slave_class, HTML_TYPE_TEXTSLAVE, sizeof (HTMLTextSlave));
832}
833
834void
835html_text_slave_class_init (HTMLTextSlaveClass *klass,
836                            HTMLType type,
837                            guint object_size)
838{
839        HTMLObjectClass *object_class;
840
841        object_class = HTML_OBJECT_CLASS (klass);
842
843        html_object_class_init (object_class, type, object_size);
844
845        object_class->select_range = select_range;
846        object_class->copy = copy;
847        object_class->destroy = destroy;
848        object_class->draw = draw;
849        object_class->calc_size = html_text_slave_real_calc_size;
850        object_class->fit_line = hts_fit_line;
851        object_class->calc_min_width = calc_min_width;
852        object_class->calc_preferred_width = calc_preferred_width;
853        object_class->get_url = get_url;
854        object_class->get_length = get_length;
855        object_class->check_point = check_point;
856
857        parent_class = &html_object_class;
858}
859
860void
861html_text_slave_init (HTMLTextSlave *slave,
862                      HTMLTextSlaveClass *klass,
863                      HTMLText *owner,
864                      guint posStart,
865                      guint posLen)
866{
867        HTMLText *owner_text;
868        HTMLObject *object;
869
870        object = HTML_OBJECT (slave);
871        owner_text = HTML_TEXT (owner);
872
873        html_object_init (object, HTML_OBJECT_CLASS (klass));
874
875        object->ascent = HTML_OBJECT (owner)->ascent;
876        object->descent = HTML_OBJECT (owner)->descent;
877
878        slave->posStart   = posStart;
879        slave->posLen     = posLen;
880        slave->owner      = owner;
881        slave->charStart  = NULL;
882        slave->pi         = NULL;
883        slave->glyphs     = NULL;
884
885        /* text slaves have always min_width 0 */
886        object->min_width = 0;
887        object->change   &= ~HTML_CHANGE_MIN_WIDTH;
888}
889
890HTMLObject *
891html_text_slave_new (HTMLText *owner, guint posStart, guint posLen)
892{
893        HTMLTextSlave *slave;
894
895        slave = g_new (HTMLTextSlave, 1);
896        html_text_slave_init (slave, &html_text_slave_class, owner, posStart, posLen);
897
898        return HTML_OBJECT (slave);
899}
Note: See TracBrowser for help on using the repository browser.