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

Revision 21116, 31.6 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   
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public
8   License as published by the Free Software Foundation; either
9   version 2 of the License, or (at your option) any later version.
10   
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15   
16   You should have received a copy of the GNU Library General Public License
17   along with this library; see the file COPYING.LIB.  If not, write to
18   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20*/
21
22#include <config.h>
23#include "gtkhtml-compat.h"
24
25#include <string.h>
26#include <stdlib.h>
27
28#include <glib.h>
29#include <gdk/gdkx.h>
30#include <gdk/gdkgc.h>
31#include <gdk-pixbuf/gdk-pixbuf.h>
32#include <gtk/gtksignal.h>
33
34#include <libgnome/gnome-i18n.h>
35
36#include "htmlentity.h"
37#include "htmlgdkpainter.h"
38#include "htmlcolor.h"
39#include "htmlcolorset.h"
40#include "htmlembedded.h"
41#include "htmlengine.h"
42#include "htmltextslave.h"
43#include "htmlsettings.h"
44#include "gtkhtml-embedded.h"
45#include "gtkhtml.h"
46
47static HTMLPainterClass *parent_class = NULL;
48
49/* GObject methods.  */
50
51static void
52finalize (GObject *object)
53{
54        HTMLGdkPainter *painter;
55
56        painter = HTML_GDK_PAINTER (object);
57
58        if (painter->gc != NULL) {
59                g_object_unref (painter->gc);
60                painter->gc = NULL;
61        }
62
63        if (painter->pixmap != NULL) {
64                g_object_unref (painter->pixmap);
65                painter->pixmap = NULL;
66        }
67
68        if (painter->pc) {
69                g_object_unref (painter->pc);
70                painter->pc = NULL;
71        }
72
73        if (G_OBJECT_CLASS (parent_class)->finalize) {
74                (* G_OBJECT_CLASS (parent_class)->finalize) (object);
75        }
76}
77
78inline static void
79items_destroy (GList *items)
80{
81        GList *l;
82
83        for (l = items; l; l = l->next)
84                pango_item_free ((PangoItem *) l->data);
85        g_list_free (items);
86}
87
88static gint
89text_width (HTMLGdkPainter *painter, PangoFontDescription *desc, const gchar *text, gint bytes)
90{
91        HTMLTextPangoInfo *pi;
92        GList *glyphs;
93        gint width = 0;
94
95        pi = html_painter_text_itemize_and_prepare_glyphs (HTML_PAINTER (painter), desc, text, bytes, &glyphs, NULL);
96
97        if (pi && glyphs) {
98                GList *list;
99                int i;
100                for (list = glyphs, i = 0; list; list = list->next->next, i++) {
101                        PangoGlyphString *str = (PangoGlyphString *) list->data;
102                        for (i=0; i < str->num_glyphs; i ++)
103                                width += str->glyphs [i].geometry.width;
104                }
105        }
106        if (glyphs)
107                html_painter_glyphs_destroy (glyphs);
108        if (pi)
109                html_text_pango_info_destroy (pi);
110        /* printf ("text_width %d\n", PANGO_PIXELS (width)); */
111        return PANGO_PIXELS (width);
112}
113
114static void
115text_size (HTMLGdkPainter *painter, PangoFontDescription *desc, const gchar *text, gint bytes,
116           HTMLTextPangoInfo *pi, PangoAttrList *attrs, GList *glyphs, gint start_byte_offset, gint *width, gint *asc, gint *dsc)
117{
118        PangoFontMetrics *pfm;
119        gboolean temp_pi = FALSE;
120        if (!pi) {
121                pi = html_painter_text_itemize_and_prepare_glyphs (HTML_PAINTER (painter), desc, text, bytes, &glyphs, attrs);
122                temp_pi = TRUE;
123        }
124
125        *width = *asc = *dsc = 0;
126        if (pi && pi->n && glyphs) {
127                GList *gl;
128                PangoRectangle log_rect;
129                PangoItem *item;
130                PangoGlyphString *str;
131                const gchar *c_text = text;
132                gint c_bytes, ii;
133
134                c_bytes = 0;
135                for (gl = glyphs; gl && c_bytes < bytes; gl = gl->next) {
136                        str = (PangoGlyphString *) gl->data;
137                        gl = gl->next;
138                        ii = GPOINTER_TO_INT (gl->data);
139                        item = pi->entries [ii].item;
140                        pango_glyph_string_extents (str, item->analysis.font, NULL, &log_rect);
141                        *width += PANGO_PIXELS (log_rect.width);
142
143                        pfm = pango_font_get_metrics (item->analysis.font, item->analysis.language);
144                        if (asc)
145                                *asc = MAX (*asc, PANGO_PIXELS (pango_font_metrics_get_ascent (pfm)));
146                        if (dsc)
147                                *dsc = MAX (*dsc, PANGO_PIXELS (pango_font_metrics_get_descent (pfm)));
148                        pango_font_metrics_unref (pfm);
149
150                        c_text = g_utf8_offset_to_pointer (c_text, str->num_glyphs);
151                        if (*text == '\t')
152                                c_text ++;
153                        c_bytes = c_text - text;
154                }
155        }
156
157        if (temp_pi) {
158                if (glyphs)
159                        html_painter_glyphs_destroy (glyphs);
160                if (pi)
161                        html_text_pango_info_destroy (pi);
162        }
163}
164
165static HTMLFont *
166alloc_font (HTMLPainter *painter, gchar *face, gdouble size, gboolean points, GtkHTMLFontStyle style)
167{
168        PangoFontDescription *desc = NULL;
169        gint space_width, space_asc, space_dsc;
170
171        if (face) {
172                desc = pango_font_description_from_string (face);
173                pango_font_description_set_size (desc, (gint) size);
174        }
175
176        if (!desc || !pango_font_description_get_family (desc)) {
177                if (desc)
178                        pango_font_description_free (desc);
179
180                desc = pango_font_description_copy (gtk_widget_get_style (painter->widget)->font_desc);
181        }
182
183        pango_font_description_set_size (desc, size);
184        pango_font_description_set_style (desc, style & GTK_HTML_FONT_STYLE_ITALIC ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
185        pango_font_description_set_weight (desc, style & GTK_HTML_FONT_STYLE_BOLD ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
186
187        text_size (HTML_GDK_PAINTER (painter), desc, " ", 1, NULL, NULL, NULL, 0, &space_width, &space_asc, &space_dsc);
188
189        return html_font_new (desc,
190                              space_width,
191                              space_asc, space_dsc,
192                              text_width (HTML_GDK_PAINTER (painter), desc, "\xc2\xa0", 2),
193                              text_width (HTML_GDK_PAINTER (painter), desc, "\t", 1),
194                              text_width (HTML_GDK_PAINTER (painter), desc, "e", 1),
195                              text_width (HTML_GDK_PAINTER (painter), desc, HTML_BLOCK_INDENT, strlen (HTML_BLOCK_INDENT)),
196                              text_width (HTML_GDK_PAINTER (painter), desc, HTML_BLOCK_CITE, strlen (HTML_BLOCK_CITE)));
197}
198
199static void
200ref_font (HTMLPainter *painter, HTMLFont *font)
201{
202}
203
204static void
205unref_font (HTMLPainter *painter, HTMLFont *font)
206{
207        if (font->ref_count < 1) {
208                pango_font_description_free (font->data);
209                font->data = NULL;
210        }
211}
212
213
214static void
215alloc_color (HTMLPainter *painter,
216             GdkColor *color)
217{
218        HTMLGdkPainter *gdk_painter;
219        GdkColormap *colormap;
220
221        gdk_painter = HTML_GDK_PAINTER (painter);
222        g_return_if_fail (gdk_painter->window != NULL);
223
224        colormap = gdk_drawable_get_colormap (gdk_painter->window);
225        gdk_rgb_find_color (colormap, color);
226}
227
228static void
229free_color (HTMLPainter *painter,
230            GdkColor *color)
231{
232}
233
234
235static void
236begin (HTMLPainter *painter, int x1, int y1, int x2, int y2)
237{
238        HTMLGdkPainter *gdk_painter;
239
240        /* printf ("painter begin %d,%d %d,%d\n", x1, y1, x2, y2); */
241
242        gdk_painter = HTML_GDK_PAINTER (painter);
243        g_return_if_fail (gdk_painter->window != NULL);
244
245        if (gdk_painter->double_buffer){
246                const int width = x2 - x1 + 1;
247                const int height = y2 - y1 + 1;
248
249                g_assert (gdk_painter->pixmap == NULL);
250
251                gdk_painter->pixmap = gdk_pixmap_new (gdk_painter->window, width, height, -1);
252                gdk_painter->x1 = x1;
253                gdk_painter->y1 = y1;
254                gdk_painter->x2 = x2;
255                gdk_painter->y2 = y2;
256
257                if (gdk_painter->set_background){
258                        gdk_gc_set_background (gdk_painter->gc, &gdk_painter->background);
259                        gdk_painter->set_background = FALSE;
260                }
261
262                gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->background);
263                gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc,
264                                    TRUE, 0, 0, width, height);
265        } else {
266                gdk_painter->pixmap = gdk_painter->window;
267                gdk_painter->x1 = 0;
268                gdk_painter->y1 = 0;
269                gdk_painter->x2 = 0;
270                gdk_painter->y2 = 0;
271        }
272
273        g_return_if_fail (gdk_drawable_get_colormap (gdk_painter->pixmap) != NULL);
274}
275
276static void
277end (HTMLPainter *painter)
278{
279        HTMLGdkPainter *gdk_painter;
280
281        /* printf ("painter end\n"); */
282
283        gdk_painter = HTML_GDK_PAINTER (painter);
284       
285        if (! gdk_painter->double_buffer)
286                return;
287
288        gdk_draw_drawable (gdk_painter->window, gdk_painter->gc,
289                           gdk_painter->pixmap,
290                           0, 0,
291                           gdk_painter->x1, gdk_painter->y1,
292                           gdk_painter->x2 - gdk_painter->x1,
293                           gdk_painter->y2 - gdk_painter->y1);
294
295        g_object_unref (gdk_painter->pixmap);
296        gdk_painter->pixmap = NULL;
297}
298
299static void
300clear (HTMLPainter *painter)
301{
302        HTMLGdkPainter *gdk_painter;
303
304        gdk_painter = HTML_GDK_PAINTER (painter);
305
306        if (! gdk_painter->double_buffer){
307                gdk_window_clear (gdk_painter->window);
308        } else {
309                if (gdk_painter->pixmap != NULL)
310                        gdk_window_clear (gdk_painter->pixmap);
311                else
312                        gdk_painter->do_clear = TRUE;
313        }
314}
315
316
317static void
318set_clip_rectangle (HTMLPainter *painter,
319                    gint x, gint y,
320                    gint width, gint height)
321{
322        HTMLGdkPainter *gdk_painter;
323        GdkRectangle rect;
324
325        gdk_painter = HTML_GDK_PAINTER (painter);
326
327        if (width == 0 || height == 0) {
328                gdk_gc_set_clip_rectangle (gdk_painter->gc, NULL);
329                return;
330        }
331
332        rect.x = x;
333        rect.y = y;
334        rect.width = width;
335        rect.height = height;
336       
337        gdk_gc_set_clip_rectangle (gdk_painter->gc, &rect);
338}
339
340static void
341set_background_color (HTMLPainter *painter,
342                      const GdkColor *color)
343{
344        g_warning ("HTMLGdkPainter::set_background_color() needs to be implemented.");
345}
346
347static void
348set_pen (HTMLPainter *painter,
349         const GdkColor *color)
350{
351        HTMLGdkPainter *gdk_painter;
352
353        gdk_painter = HTML_GDK_PAINTER (painter);
354
355        /* GdkColor API not const-safe!  */
356        gdk_gc_set_foreground (gdk_painter->gc, (GdkColor *) color);
357}
358
359static const GdkColor *
360get_black (const HTMLPainter *painter)
361{
362        HTMLGdkPainter *gdk_painter;
363
364        gdk_painter = HTML_GDK_PAINTER (painter);
365        return &gdk_painter->black;
366}
367
368
369/* HTMLPainter drawing functions.  */
370
371static void
372draw_line (HTMLPainter *painter,
373           gint x1, gint y1,
374           gint x2, gint y2)
375 {
376        HTMLGdkPainter *gdk_painter;
377
378        gdk_painter = HTML_GDK_PAINTER (painter);
379
380        x1 -= gdk_painter->x1;
381        y1 -= gdk_painter->y1;
382        x2 -= gdk_painter->x1;
383        y2 -= gdk_painter->y1;
384
385        gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x1, y1, x2, y2);
386}
387
388static void
389draw_ellipse (HTMLPainter *painter,
390              gint x, gint y,
391              gint width, gint height)
392{
393        HTMLGdkPainter *gdk_painter;
394
395        gdk_painter = HTML_GDK_PAINTER (painter);
396
397        gdk_draw_arc (gdk_painter->pixmap, gdk_painter->gc, TRUE,
398                      x - gdk_painter->x1, y - gdk_painter->y1,
399                      width, height,
400                      0, 360 * 64);
401}
402
403static void
404draw_rect (HTMLPainter *painter,
405           gint x, gint y,
406           gint width, gint height)
407{
408        HTMLGdkPainter *gdk_painter;
409
410        gdk_painter = HTML_GDK_PAINTER (painter);
411
412        gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, FALSE,
413                            x - gdk_painter->x1, y - gdk_painter->y1,
414                            width, height);
415}
416
417static void
418draw_panel (HTMLPainter *painter,
419            GdkColor *bg,
420            gint x, gint y,
421            gint width, gint height,
422            GtkHTMLEtchStyle inset,
423            gint bordersize)
424{
425        HTMLGdkPainter *gdk_painter;
426        GdkColor *col1 = NULL, *col2 = NULL;
427        GdkColor dark, light;
428
429        #define INC 0x8000
430        #define DARK(c)  dark.c = MAX (((gint) bg->c) - INC, 0)
431        #define LIGHT(c) light.c = MIN (((gint) bg->c) + INC, 0xffff)
432
433        DARK(red);
434        DARK(green);
435        DARK(blue);
436        LIGHT(red);
437        LIGHT(green);
438        LIGHT(blue);
439
440        alloc_color (painter, &dark);
441        alloc_color (painter, &light);
442
443        gdk_painter = HTML_GDK_PAINTER (painter);
444
445        switch (inset) {
446        case GTK_HTML_ETCH_NONE:
447                /* use the current pen color */
448                col1 = NULL;
449                col2 = NULL;
450                break;
451        case GTK_HTML_ETCH_OUT:
452                col1 = &light;
453                col2 = &dark;
454                break;
455        default:
456        case GTK_HTML_ETCH_IN:
457                col1 = &dark;
458                col2 = &light;
459                break;
460        }
461       
462        x -= gdk_painter->x1;
463        y -= gdk_painter->y1;
464       
465        while (bordersize > 0) {
466                if (col2) {
467                        gdk_gc_set_foreground (gdk_painter->gc, col2);
468                }
469
470                gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc,
471                               x + width - 1, y, x + width - 1, y + height - 1);
472                gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc,
473                               x + 1, y + height - 1, x + width - 1, y + height - 1);
474                if (col1) {
475                        gdk_gc_set_foreground (gdk_painter->gc, col1);
476                }
477
478                gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc,
479                               x, y, x + width - 2, y);
480                gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc,
481                               x, y, x, y + height - 1);
482                bordersize--;
483                x++;
484                y++;
485                width-=2;
486                height-=2;
487        }
488
489        free_color (painter, &dark);
490        free_color (painter, &light);
491}
492
493static void
494draw_background (HTMLPainter *painter,
495                 GdkColor *color,
496                 GdkPixbuf *pixbuf,
497                 gint x, gint y,
498                 gint width, gint height,
499                 gint tile_x, gint tile_y)
500{
501        HTMLGdkPainter *gdk_painter;
502        gint pw;
503        gint ph;
504        gint tile_width, tile_height;
505        gint w, h;
506        GdkRectangle expose, paint, clip;
507
508        gdk_painter = HTML_GDK_PAINTER (painter);
509
510        expose.x = x;
511        expose.y = y;
512        expose.width  = width;
513        expose.height = height;
514
515        clip.x = gdk_painter->x1;
516        clip.width = gdk_painter->x2 - gdk_painter->x1;
517        clip.y = gdk_painter->y1;
518        clip.height = gdk_painter->y2 - gdk_painter->y1;
519
520        if (!gdk_rectangle_intersect (&clip, &expose, &paint))
521                return;
522
523        tile_x += paint.x - expose.x;
524        tile_y += paint.y - expose.y;
525       
526        if (!color && !pixbuf)
527                return;
528
529        if (color && !pixbuf) {
530                gdk_gc_set_foreground (gdk_painter->gc, color);
531                gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc,
532                                    TRUE, paint.x - clip.x, paint.y - clip.y,
533                                    paint.width, paint.height);
534               
535        }
536
537        if (!pixbuf)
538                return;
539
540        pw = gdk_pixbuf_get_width (pixbuf);
541        ph = gdk_pixbuf_get_height (pixbuf);
542
543        /* optimize out some special cases */
544        if (pw == 1 && ph == 1) {
545                GdkColor pixcol;
546                guchar *p;
547
548                p = gdk_pixbuf_get_pixels (pixbuf);
549               
550                if (!(gdk_pixbuf_get_has_alpha (pixbuf) && (p[3] < 0x80))) {
551                        pixcol.red = p[0] * 0xff;
552                        pixcol.green = p[1] * 0xff;
553                        pixcol.blue = p[2] * 0xff;
554                       
555                        html_painter_alloc_color (painter, &pixcol);
556                        color = &pixcol;
557                }
558
559                if (color) {
560                        gdk_gc_set_foreground (gdk_painter->gc, color);
561                        gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc,
562                                            TRUE, paint.x - clip.x, paint.y - clip.y,
563                                            paint.width, paint.height);
564                }       
565               
566                return;
567        }
568
569        tile_width = (tile_x % pw) + paint.width;
570        tile_height = (tile_y % ph) + paint.height;
571
572        /* do tiling */
573        if (tile_width > pw || tile_height > ph) {
574                GdkPixmap *pixmap = NULL;
575                gint cw, ch, cx, cy;
576                gint dw, dh;
577                GdkGC *gc;
578               
579                dw = MIN (pw, tile_width);
580                dh = MIN (ph, tile_height);
581
582                gc = gdk_gc_new (gdk_painter->window);
583
584                if (color || !gdk_pixbuf_get_has_alpha (pixbuf)) {
585                        pixmap = gdk_pixmap_new (gdk_painter->window, dw, dh, -1);             
586                       
587                        if (color) {
588                                gdk_gc_set_foreground (gc, color);
589                                gdk_draw_rectangle (pixmap, gc,
590                                                    TRUE, 0, 0,
591                                                    dw, dh);
592                        }       
593
594                        gdk_draw_pixbuf (pixmap, NULL, pixbuf,
595                                         0, 0,
596                                         0, 0,
597                                         dw, dh,
598                                         GDK_RGB_DITHER_NORMAL,
599                                         paint.x, paint.y);
600       
601                        gdk_gc_set_tile (gc, pixmap);
602                        gdk_gc_set_fill (gc, GDK_TILED);
603                        gdk_gc_set_ts_origin (gc,
604                                              paint.x - (tile_x % pw) - clip.x, 
605                                              paint.y - (tile_y % ph) - clip.y);
606
607                        gdk_draw_rectangle (gdk_painter->pixmap, gc, TRUE,
608                                            paint.x - clip.x, paint.y - clip.y,
609                                            paint.width, paint.height);
610                       
611                        g_object_unref (pixmap);                       
612                        g_object_unref (gc);                   
613                } else {
614                        int incr_x = 0;
615                        int incr_y = 0;
616
617                        cy = paint.y;
618                        ch = paint.height;
619                        h = tile_y % ph;
620                        while (ch > 0) {
621                                incr_y = dh - h;
622
623                                cx = paint.x;
624                                cw = paint.width;
625                                w = tile_x % pw;
626                                while (cw > 0) {
627                                        incr_x = dw - w;
628
629                                        gdk_draw_pixbuf (gdk_painter->pixmap, NULL, pixbuf,
630                                                         w, h,
631                                                         cx - clip.x, cy - clip.y,
632                                                         (cw >= incr_x) ? incr_x : cw,
633                                                         (ch >= incr_y) ? incr_y : ch,
634                                                         GDK_RGB_DITHER_NORMAL,
635                                                         cx, cy);
636
637                                        cw -= incr_x;
638                                        cx += incr_x;
639                                        w = 0;
640                                }
641                                ch -= incr_y;
642                                cy += incr_y;
643                                h = 0;
644                        }
645
646                        g_object_unref (gc);                   
647                }
648        } else {
649                if (color && gdk_pixbuf_get_has_alpha (pixbuf)) {
650                        gdk_gc_set_foreground (gdk_painter->gc, color);
651                        gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, TRUE,
652                                            paint.x - clip.x, paint.y - clip.y,
653                                            paint.width, paint.height);
654                }
655               
656                gdk_draw_pixbuf (gdk_painter->pixmap, NULL, pixbuf,
657                                 tile_x % pw, tile_y % ph,
658                                 paint.x - clip.x, paint.y - clip.y,
659                                 paint.width, paint.height,
660                                 GDK_RGB_DITHER_NORMAL,
661                                 paint.x, paint.y);
662        }
663}
664
665static void
666draw_pixmap (HTMLPainter *painter,
667             GdkPixbuf *pixbuf,
668             gint x, gint y,
669             gint scale_width, gint scale_height,
670             const GdkColor *color)
671{
672        GdkRectangle clip, image, paint;
673        HTMLGdkPainter *gdk_painter;
674        GdkPixbuf *tmp_pixbuf;
675        guint n_channels;
676        gint orig_width;
677        gint orig_height;
678        gint bilinear;
679
680        gdk_painter = HTML_GDK_PAINTER (painter);
681
682        orig_width = gdk_pixbuf_get_width (pixbuf);
683        orig_height = gdk_pixbuf_get_height (pixbuf);
684
685        if (scale_width < 0)
686                scale_width = orig_width;
687        if (scale_height < 0)
688                scale_height = orig_height;
689
690        image.x = x;
691        image.y = y;
692        image.width  = scale_width;
693        image.height = scale_height;
694
695        clip.x = gdk_painter->x1;
696        clip.width = gdk_painter->x2 - gdk_painter->x1;
697        clip.y = gdk_painter->y1;
698        clip.height = gdk_painter->y2 - gdk_painter->y1;
699
700        if (!gdk_rectangle_intersect (&clip, &image, &paint))
701            return;
702
703        if (scale_width == orig_width && scale_height == orig_height && color == NULL) {
704                gdk_draw_pixbuf (gdk_painter->pixmap, NULL, pixbuf,
705                                 paint.x - image.x,
706                                 paint.y - image.y,
707                                 paint.x - clip.x,
708                                 paint.y - clip.y,
709                                 paint.width,
710                                 paint.height,
711                                 GDK_RGB_DITHER_NORMAL,
712                                 paint.x, paint.y);
713                return;
714        }
715
716
717        tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
718                                     gdk_pixbuf_get_has_alpha (pixbuf),
719                                     gdk_pixbuf_get_bits_per_sample (pixbuf),
720                                     paint.width, paint.height);
721
722        gdk_pixbuf_fill (tmp_pixbuf, 0xff000000);
723
724        if (tmp_pixbuf == NULL)
725                return;
726
727        /*
728         * FIXME this is a hack to work around a gdk-pixbuf bug
729         * it could be removed when
730         * http://bugzilla.ximian.com/show_bug.cgi?id=12968
731         * is fixed.
732         */
733        bilinear = !((scale_width == 1) && (scale_height == 1));
734
735        gdk_pixbuf_composite (pixbuf, tmp_pixbuf,
736                              0,
737                              0,
738                              paint.width, paint.height,
739                              (double)-(paint.x - image.x),
740                              (double)-(paint.y - image.y),
741                              (gdouble) scale_width/ (gdouble) orig_width,
742                              (gdouble) scale_height/ (gdouble) orig_height,
743                              bilinear ? GDK_INTERP_BILINEAR : GDK_INTERP_NEAREST,
744                              255);
745
746        if (color != NULL) {
747                guchar *p, *q;
748                guint i, j;
749
750                n_channels = gdk_pixbuf_get_n_channels (tmp_pixbuf);
751                p = q = gdk_pixbuf_get_pixels (tmp_pixbuf);
752                for (i = 0; i < paint.height; i++) {
753                        p = q;
754
755                        for (j = 0; j < paint.width; j++) {
756                                gint r, g, b, a;
757
758                                if (n_channels > 3)
759                                        a = p[3];
760                                else
761                                        a = 0xff;
762
763                                r = (a * p[0] + color->red) >> 9;
764                                g = (a * p[1] + color->green) >> 9;
765                                b = (a * p[2] + color->blue) >> 9;
766
767                                p[0] = r;
768                                p[1] = g;
769                                p[2] = b;
770
771                                if (n_channels > 3)
772                                        p[3] = (a + 127) / 2;
773
774                                p += n_channels;
775                        }
776
777                        q += gdk_pixbuf_get_rowstride (tmp_pixbuf);
778                }
779        }
780
781        gdk_draw_pixbuf (gdk_painter->pixmap, NULL, tmp_pixbuf,
782                         0,
783                         0,
784                         paint.x - clip.x,
785                         paint.y - clip.y,
786                         paint.width,
787                         paint.height,
788                         GDK_RGB_DITHER_NORMAL,
789                         paint.x, paint.y);
790        gdk_pixbuf_unref (tmp_pixbuf);
791}
792
793static void
794fill_rect (HTMLPainter *painter,
795           gint x, gint y,
796           gint width, gint height)
797{
798        HTMLGdkPainter *gdk_painter;
799
800        gdk_painter = HTML_GDK_PAINTER (painter);
801
802        gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc,
803                            TRUE, x - gdk_painter->x1, y - gdk_painter->y1,
804                            width, height);
805}
806
807static gint
808draw_spell_error (HTMLPainter *painter, gint x, gint y, const gchar *text, gint len, HTMLTextPangoInfo *pi, GList *glyphs, gint start_byte_offset)
809{
810        HTMLGdkPainter *gdk_painter;
811        GdkGCValues values;
812        gchar dash [2];
813        GList *gl;
814        PangoRectangle log_rect;
815        PangoGlyphString *str;
816        gint width, ii;
817        const gchar *c_text = text;
818
819        if (!pi || !glyphs)
820                return 0;
821
822        gdk_painter = HTML_GDK_PAINTER (painter);
823
824        x -= gdk_painter->x1;
825        y -= gdk_painter->y1;
826
827        width = 0;
828        for (gl = glyphs; gl; gl = gl->next) {
829                str = (PangoGlyphString *) gl->data;
830                gl = gl->next;
831                ii = GPOINTER_TO_INT (gl->data);
832                pango_glyph_string_extents (str, pi->entries [ii].item->analysis.font, NULL, &log_rect);
833                c_text = g_utf8_offset_to_pointer (c_text, str->num_glyphs);
834                width += PANGO_PIXELS (log_rect.width);
835        }
836
837        gdk_gc_get_values (gdk_painter->gc, &values);
838        gdk_gc_set_fill (gdk_painter->gc, GDK_OPAQUE_STIPPLED);
839        dash [0] = 2;
840        dash [1] = 2;
841        gdk_gc_set_line_attributes (gdk_painter->gc, 1, GDK_LINE_ON_OFF_DASH, values.cap_style, values.join_style);
842        gdk_gc_set_dashes (gdk_painter->gc, 2, dash, 2);
843        gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y, x + width, y);
844        gdk_gc_set_dashes (gdk_painter->gc, 0, dash, 2);
845        gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y + 1, x + width, y + 1);
846        gdk_gc_set_line_attributes (gdk_painter->gc, values.line_width,
847                                    values.line_style, values.cap_style, values.join_style);
848
849        return width;
850}
851
852static void
853draw_embedded (HTMLPainter * p, HTMLEmbedded *o, gint x, gint y)
854{
855        HTMLGdkPainter *gdk_painter = HTML_GDK_PAINTER(p);
856        GtkWidget *embedded_widget;
857
858        embedded_widget = html_embedded_get_widget (o);
859        if (embedded_widget && GTK_IS_HTML_EMBEDDED (embedded_widget)) {
860                g_signal_emit_by_name (embedded_widget,
861                                       "draw_gdk", 0,
862                                       gdk_painter->pixmap,
863                                       gdk_painter->gc,
864                                       x, y);
865        }
866}
867
868static GdkGC *
869item_gc (HTMLPainter *p, PangoItem *item, GdkDrawable *drawable, GdkGC *orig_gc, gboolean *underline, gboolean *strikethrough, gboolean *bgcolor, GdkGC **bg_gc)
870{
871        GdkGC *new_gc = NULL;
872        GSList *tmp_list = item->analysis.extra_attrs;
873        HTMLEngine *e = GTK_HTML (p->widget)->engine;
874
875        *bgcolor = *underline = *strikethrough = FALSE;
876        new_gc = gdk_gc_new (drawable);
877        gdk_gc_copy (new_gc, orig_gc);
878        gdk_gc_set_foreground (new_gc,
879                               &html_colorset_get_color_allocated (e->settings->color_set,
880                                                                   e->painter, HTMLTextColor)->color);
881
882        while (tmp_list) {
883                PangoAttribute *attr = tmp_list->data;
884
885                switch (attr->klass->type) {
886                case PANGO_ATTR_FOREGROUND:
887                case PANGO_ATTR_BACKGROUND: {
888                        PangoColor pc;
889                        GdkColor color;
890     
891                        pc = ((PangoAttrColor *) attr)->color;
892                        color.red = pc.red;
893                        color.green = pc.green;
894                        color.blue = pc.blue;
895
896                        gdk_rgb_find_color (gdk_drawable_get_colormap (drawable), &color);
897                        if (attr->klass->type == PANGO_ATTR_FOREGROUND)
898                                gdk_gc_set_foreground (new_gc, &color);
899                        else {
900                                if (*bg_gc)
901                                        g_object_unref (*bg_gc);
902                                *bg_gc = gdk_gc_new (drawable);
903                                gdk_gc_copy (*bg_gc, orig_gc);
904                                gdk_gc_set_foreground (*bg_gc, &color);
905                                *bgcolor = TRUE;
906                        }
907                }
908                break;
909                case PANGO_ATTR_UNDERLINE:
910                        *underline = TRUE;
911                        break;
912                case PANGO_ATTR_STRIKETHROUGH:
913                        *strikethrough = TRUE;
914                        break;
915                default:
916                        break;
917                }
918                tmp_list = tmp_list->next;
919        }
920
921        return new_gc;
922}
923
924static gint
925draw_lines (PangoGlyphString *str, gint x, gint y, GdkDrawable *drawable, GdkGC *gc, HTMLTextPangoInfo *pi, gint ii, gboolean underline, gboolean strikethrough)
926{
927        PangoRectangle log_rect;
928        gint width, dsc, asc;
929
930        pango_glyph_string_extents (str, pi->entries [ii].item->analysis.font, NULL, &log_rect);
931
932        width = PANGO_PIXELS (log_rect.width);
933        dsc = PANGO_PIXELS (PANGO_DESCENT (log_rect));
934        asc = PANGO_PIXELS (PANGO_ASCENT (log_rect));
935
936        if (underline)
937                gdk_draw_line (drawable, gc, x, y + dsc - 2, x + width, y + dsc - 2);
938
939        if (strikethrough)
940                gdk_draw_line (drawable, gc, x, y - asc + (asc + dsc)/2, x + width, y - asc + (asc + dsc)/2);
941
942        return width;
943}
944
945static gint
946draw_text (HTMLPainter *painter, gint x, gint y, const gchar *text, gint len, HTMLTextPangoInfo *pi, PangoAttrList *attrs, GList *glyphs, gint start_byte_offset)
947{
948        HTMLGdkPainter *gdk_painter;
949        PangoGlyphString *str;
950        gboolean temp_pi = FALSE;
951        gint blen, width = 0, ii;
952        const gchar *c_text;
953
954        if (len == -1)
955                len = g_utf8_strlen (text, -1);
956
957        gdk_painter = HTML_GDK_PAINTER (painter);
958
959        x -= gdk_painter->x1;
960        y -= gdk_painter->y1;
961
962        blen = g_utf8_offset_to_pointer (text, len) - text;
963        if (!pi) {
964                pi = html_painter_text_itemize_and_prepare_glyphs (painter, html_painter_get_font (painter, painter->font_face, painter->font_style),
965                                                                   text, blen, &glyphs, attrs);
966                start_byte_offset = 0;
967                temp_pi = TRUE;
968        }
969        if (pi && pi->n) {
970                GList *gl;
971                guint i, char_offset = 0;
972
973                c_text = text;
974                for (gl = glyphs; gl && char_offset < len; gl = gl->next) {
975                        GdkGC *gc, *bg_gc;
976                        gboolean underline, strikethrough, bgcolor;
977                        gint cw = 0;
978
979                        str = (PangoGlyphString *) gl->data;
980                        gl = gl->next;
981                        ii = GPOINTER_TO_INT (gl->data);
982                        bg_gc = NULL;
983                        gc = item_gc (painter, pi->entries [ii].item, gdk_painter->pixmap, painter->widget->style->text_gc [painter->widget->state],
984                                      &underline, &strikethrough, &bgcolor, &bg_gc);
985                        if (bgcolor) {
986                                PangoRectangle log_rect;
987
988                                pango_glyph_string_extents (str, pi->entries [ii].item->analysis.font, NULL, &log_rect);
989                                gdk_draw_rectangle (gdk_painter->pixmap, bg_gc, TRUE, x + width, y - PANGO_PIXELS (PANGO_ASCENT (log_rect)),
990                                                    PANGO_PIXELS (log_rect.width), PANGO_PIXELS (log_rect.height));
991                                g_object_unref (bg_gc);
992                        }
993                        gdk_draw_glyphs (gdk_painter->pixmap, gc,
994                                         pi->entries [ii].item->analysis.font, x + width, y, str);
995                        if (strikethrough || underline)
996                                cw = draw_lines (str, x + width, y, gdk_painter->pixmap, gc, pi, ii, underline, strikethrough);
997                        else
998                                for (i=0; i < str->num_glyphs; i ++)
999                                        cw += PANGO_PIXELS (str->glyphs [i].geometry.width);
1000                        g_object_unref (gc);
1001                        width += cw;
1002                        c_text = g_utf8_offset_to_pointer (c_text, str->num_glyphs);
1003                        char_offset += str->num_glyphs;
1004                }
1005        }
1006
1007        if (temp_pi) {
1008                if (glyphs)
1009                        html_painter_glyphs_destroy (glyphs);
1010                if (pi)
1011                        html_text_pango_info_destroy (pi);
1012        }
1013
1014        return width;
1015}
1016
1017static void
1018draw_shade_line (HTMLPainter *painter,
1019                 gint x, gint y,
1020                 gint width)
1021{
1022        HTMLGdkPainter *gdk_painter;
1023
1024        gdk_painter = HTML_GDK_PAINTER (painter);
1025       
1026        x -= gdk_painter->x1;
1027        y -= gdk_painter->y1;
1028       
1029        gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->dark);
1030        gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y, x+width, y);
1031        gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->light);
1032        gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y + 1, x + width, y + 1);
1033}
1034
1035static void
1036calc_text_size (HTMLPainter *painter,
1037                const gchar *text,
1038                guint len,
1039                HTMLTextPangoInfo *pi, PangoAttrList *attrs, GList *glyphs, gint start_byte_offset,
1040                GtkHTMLFontStyle style,
1041                HTMLFontFace *face,
1042                gint *width, gint *asc, gint *dsc)
1043{
1044        HTMLFont *font;
1045        HTMLGdkPainter *gdk_painter;
1046
1047        gdk_painter = HTML_GDK_PAINTER (painter);
1048        font = html_font_manager_get_font (&painter->font_manager, face, style);
1049
1050        text_size (gdk_painter, (PangoFontDescription *) font->data, text, g_utf8_offset_to_pointer (text, len) - text,
1051                   pi, attrs, glyphs, start_byte_offset, width, asc, dsc);
1052        /* printf ("calc_text_size %d %d %d\n", *width, *asc, *dsc); */
1053}
1054
1055static void
1056calc_text_size_bytes (HTMLPainter *painter, const gchar *text,
1057                      guint bytes_len,
1058                      HTMLTextPangoInfo *pi, PangoAttrList *attrs, GList *glyphs, gint start_byte_offset,
1059                      HTMLFont *font, GtkHTMLFontStyle style,
1060                      gint *width, gint *asc, gint *dsc)
1061{
1062        HTMLGdkPainter *gdk_painter;
1063
1064        gdk_painter = HTML_GDK_PAINTER (painter);
1065
1066        text_size (gdk_painter, (PangoFontDescription *) font->data, text, bytes_len, pi, attrs, glyphs, start_byte_offset, width, asc, dsc);
1067
1068        /* printf ("calc_text_size_bytes %d %d %d\n", *width, *asc, *dsc); */
1069}
1070
1071static guint
1072get_pixel_size (HTMLPainter *painter)
1073{
1074        return 1;
1075}
1076
1077static guint
1078get_page_width (HTMLPainter *painter, HTMLEngine *e)
1079{
1080        return html_engine_get_view_width (e) + html_engine_get_left_border (e) + html_engine_get_right_border (e);
1081}
1082
1083static guint
1084get_page_height (HTMLPainter *painter, HTMLEngine *e)
1085{
1086        return html_engine_get_view_height (e) + html_engine_get_top_border (e) + html_engine_get_bottom_border (e);
1087}
1088
1089static void
1090init_color (GdkColor *color, gushort red, gushort green, gushort blue)
1091{
1092        color->pixel = 0;
1093        color->red = red;
1094        color->green = green;
1095        color->blue = blue;
1096}
1097
1098static void
1099html_gdk_painter_init (GObject *object)
1100{
1101        HTMLGdkPainter *gdk_painter;
1102
1103        gdk_painter = HTML_GDK_PAINTER (object);
1104
1105        gdk_painter->window = NULL;
1106
1107        gdk_painter->gc = NULL;
1108
1109        gdk_painter->double_buffer = TRUE;
1110        gdk_painter->pixmap = NULL;
1111        gdk_painter->x1 = gdk_painter->y1 = 0;
1112        gdk_painter->x2 = gdk_painter->y2 = 0;
1113        gdk_painter->set_background = FALSE;
1114        gdk_painter->do_clear = FALSE;
1115
1116        init_color (& gdk_painter->background, 0xffff, 0xffff, 0xffff);
1117        init_color (& gdk_painter->dark, 0, 0, 0);
1118        init_color (& gdk_painter->light, 0, 0, 0);
1119}
1120
1121static void
1122html_gdk_painter_real_set_widget (HTMLPainter *painter, GtkWidget *widget)
1123{
1124        HTMLGdkPainter *gdk_painter = HTML_GDK_PAINTER (painter);
1125
1126        parent_class->set_widget (painter, widget);
1127
1128        if (gdk_painter->pc)
1129                g_object_unref (gdk_painter->pc);
1130        gdk_painter->pc = gtk_widget_get_pango_context (widget);
1131        g_object_ref (gdk_painter->pc);
1132}
1133
1134static void
1135html_gdk_painter_class_init (GObjectClass *object_class)
1136{
1137        HTMLPainterClass *painter_class;
1138
1139        painter_class = HTML_PAINTER_CLASS (object_class);
1140
1141        object_class->finalize = finalize;
1142        parent_class = g_type_class_ref (HTML_TYPE_PAINTER);
1143
1144        painter_class->set_widget = html_gdk_painter_real_set_widget;
1145        painter_class->begin = begin;
1146        painter_class->end = end;
1147        painter_class->alloc_font = alloc_font;
1148        painter_class->ref_font   = ref_font;
1149        painter_class->unref_font = unref_font;
1150        painter_class->alloc_color = alloc_color;
1151        painter_class->free_color = free_color;
1152        painter_class->calc_text_size = calc_text_size;
1153        painter_class->calc_text_size_bytes = calc_text_size_bytes;
1154        painter_class->set_pen = set_pen;
1155        painter_class->get_black = get_black;
1156        painter_class->draw_line = draw_line;
1157        painter_class->draw_rect = draw_rect;
1158        painter_class->draw_text = draw_text;
1159        painter_class->draw_spell_error = draw_spell_error;
1160        painter_class->fill_rect = fill_rect;
1161        painter_class->draw_pixmap = draw_pixmap;
1162        painter_class->draw_ellipse = draw_ellipse;
1163        painter_class->clear = clear;
1164        painter_class->set_background_color = set_background_color;
1165        painter_class->draw_shade_line = draw_shade_line;
1166        painter_class->draw_panel = draw_panel;
1167        painter_class->set_clip_rectangle = set_clip_rectangle;
1168        painter_class->draw_background = draw_background;
1169        painter_class->get_pixel_size = get_pixel_size;
1170        painter_class->draw_embedded = draw_embedded;
1171        painter_class->get_page_width = get_page_width;
1172        painter_class->get_page_height = get_page_height;
1173}
1174
1175GType
1176html_gdk_painter_get_type (void)
1177{
1178        static GType html_gdk_painter_type = 0;
1179
1180        if (html_gdk_painter_type == 0) {
1181                static const GTypeInfo html_gdk_painter_info = {
1182                        sizeof (HTMLGdkPainterClass),
1183                        NULL,
1184                        NULL,
1185                        (GClassInitFunc) html_gdk_painter_class_init,
1186                        NULL,
1187                        NULL,
1188                        sizeof (HTMLGdkPainter),
1189                        1,
1190                        (GInstanceInitFunc) html_gdk_painter_init,
1191                };
1192                html_gdk_painter_type = g_type_register_static (HTML_TYPE_PAINTER, "HTMLGdkPainter",
1193                                                                &html_gdk_painter_info, 0);
1194        }
1195
1196        return html_gdk_painter_type;
1197}
1198
1199HTMLPainter *
1200html_gdk_painter_new (GtkWidget *widget, gboolean double_buffer)
1201{
1202        HTMLGdkPainter *new;
1203
1204        new = g_object_new (HTML_TYPE_GDK_PAINTER, NULL);
1205
1206        new->double_buffer = double_buffer;
1207        html_painter_set_widget (HTML_PAINTER (new), widget);
1208
1209        return HTML_PAINTER (new);
1210}
1211
1212void
1213html_gdk_painter_realize (HTMLGdkPainter *gdk_painter,
1214                          GdkWindow *window)
1215{
1216        g_return_if_fail (gdk_painter != NULL);
1217        g_return_if_fail (window != NULL);
1218
1219        gdk_painter->gc = gdk_gc_new (window);
1220        gdk_painter->window = window;
1221
1222        gdk_painter->light.red = 0xffff;
1223        gdk_painter->light.green = 0xffff;
1224        gdk_painter->light.blue = 0xffff;
1225        html_painter_alloc_color (HTML_PAINTER (gdk_painter), &gdk_painter->light);
1226
1227        gdk_painter->dark.red = 0x7fff;
1228        gdk_painter->dark.green = 0x7fff;
1229        gdk_painter->dark.blue = 0x7fff;
1230        html_painter_alloc_color (HTML_PAINTER (gdk_painter), &gdk_painter->dark);
1231
1232        gdk_painter->black.red = 0x0000;
1233        gdk_painter->black.green = 0x0000;
1234        gdk_painter->black.blue = 0x0000;
1235        html_painter_alloc_color (HTML_PAINTER (gdk_painter), &gdk_painter->black);
1236}
1237
1238void
1239html_gdk_painter_unrealize (HTMLGdkPainter *painter)
1240{
1241        g_return_if_fail (painter != NULL);
1242        g_return_if_fail (HTML_IS_GDK_PAINTER (painter));
1243
1244        if (html_gdk_painter_realized (painter)) {
1245                g_object_unref (painter->gc);
1246                painter->gc = NULL;
1247
1248                painter->window = NULL;
1249        }
1250}
1251
1252gboolean
1253html_gdk_painter_realized (HTMLGdkPainter *painter)
1254{
1255        g_return_val_if_fail (painter != NULL, FALSE);
1256        g_return_val_if_fail (HTML_IS_GDK_PAINTER (painter), FALSE);
1257
1258        if (painter->window == NULL)
1259                return FALSE;
1260        else
1261                return TRUE;
1262}
Note: See TracBrowser for help on using the repository browser.