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

Revision 21460, 41.0 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 Red Hat Software
7   Copyright (C) 1999, 2000 Helix Code, Inc.
8   
9   This library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Library General Public
11   License as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13   
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Library General Public License for more details.
18   
19   You should have received a copy of the GNU Library General Public License
20   along with this library; see the file COPYING.LIB.  If not, write to
21   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22   Boston, MA 02111-1307, USA.
23
24*/
25
26#include <config.h>
27#include <glib.h>
28#include <string.h>
29#include <gdk-pixbuf/gdk-pixbuf.h>
30#include <gtk/gtkmain.h>
31#include <gtk/gtksignal.h>
32#include <gtk/gtkstock.h>
33#include <gtk/gtk.h>
34
35#include "gtkhtml.h"
36#include "gtkhtml-properties.h"
37#include "gtkhtml-stream.h"
38
39#include "htmlclueflow.h"
40#include "htmlcolor.h"
41#include "htmlcolorset.h"
42#include "htmldrawqueue.h"
43#include "htmlengine.h"
44#include "htmlengine-save.h"
45#include "htmlenumutils.h"
46#include "htmlimage.h"
47#include "htmlobject.h"
48#include "htmlmap.h"
49#include "htmlprinter.h"
50#include "htmlgdkpainter.h"
51#include "htmlplainpainter.h"
52#include "htmlsettings.h"
53
54/* HTMLImageFactory stuff.  */
55
56struct _HTMLImageFactory {
57        HTMLEngine *engine;
58        GHashTable *loaded_images;
59        GdkPixbuf  *missing;
60        gboolean    animate;
61};
62
63
64#define DEFAULT_SIZE 48
65#define STRDUP_HELPER(i,j) if (i != j) {char *tmp = g_strdup (j); g_free(i); i = tmp;}
66
67#define DA(x)
68
69HTMLImageClass html_image_class;
70static HTMLObjectClass *parent_class = NULL;
71
72static HTMLImagePointer   *html_image_pointer_new               (const char *filename, HTMLImageFactory *factory);
73static void                html_image_pointer_ref               (HTMLImagePointer *ip);
74static void                html_image_pointer_unref             (HTMLImagePointer *ip);
75static gboolean            html_image_pointer_timeout           (HTMLImagePointer *ip);
76static gint                html_image_pointer_update            (HTMLImagePointer *ip);
77static void                html_image_pointer_start_animation   (HTMLImagePointer *ip);
78
79static GdkPixbuf *         html_image_factory_get_missing       (HTMLImageFactory *factory);
80
81guint
82html_image_get_actual_width (HTMLImage *image, HTMLPainter *painter)
83{
84        GdkPixbufAnimation *anim = image->image_ptr->animation;
85        gint pixel_size = painter ? html_painter_get_pixel_size (painter) : 1;
86        gint width;
87
88        if (image->percent_width) {
89                /* The cast to `gdouble' is to avoid overflow (eg. when
90                   printing).  */
91                width = ((gdouble) HTML_OBJECT (image)->max_width
92                         * image->specified_width) / 100;
93        } else if (image->specified_width > 0) {
94                width = image->specified_width * pixel_size;
95        } else if (image->image_ptr == NULL || anim == NULL) {
96                width = DEFAULT_SIZE * pixel_size;
97        } else {
98                width = gdk_pixbuf_animation_get_width (anim) * pixel_size;
99
100                if (image->specified_height > 0 || image->percent_height) {
101                        double scale;
102
103                        scale =  ((double) html_image_get_actual_height (image, painter))
104                                / (gdk_pixbuf_animation_get_height (anim) * pixel_size);
105                       
106                        width *= scale;
107                }
108
109        }
110
111        return width;
112}
113
114guint
115html_image_get_actual_height (HTMLImage *image, HTMLPainter *painter)
116{
117        GdkPixbufAnimation *anim = image->image_ptr->animation;
118        gint pixel_size = painter ? html_painter_get_pixel_size (painter) : 1;
119        gint height;
120               
121        if (image->percent_height) {
122                /* The cast to `gdouble' is to avoid overflow (eg. when
123                   printing).  */
124                height = ((gdouble) html_engine_get_view_height (image->image_ptr->factory->engine)
125                          * image->specified_height) / 100;
126        } else if (image->specified_height > 0) {
127                height = image->specified_height * pixel_size;
128        } else if (image->image_ptr == NULL || anim == NULL) {
129                height = DEFAULT_SIZE * pixel_size;
130        } else {
131                height = gdk_pixbuf_animation_get_height (anim) * pixel_size;
132
133                if (image->specified_width > 0 || image->percent_width) {
134                        double scale;
135                       
136                        scale = ((double) html_image_get_actual_width (image, painter))
137                                / (gdk_pixbuf_animation_get_width (anim) * pixel_size);
138                       
139                        height *= scale;
140                }
141        }
142
143        return height;
144}
145
146
147/* HTMLObject methods.  */
148
149/* FIXME: We should close the stream here, too.  But in practice we cannot
150   because the stream pointer might be invalid at this point, and there is no
151   way to set it to NULL when the stream is closed.  This clearly sucks and
152   must be fixed.  */
153static void
154destroy (HTMLObject *o)
155{
156        HTMLImage *image = HTML_IMAGE (o);
157
158        html_image_factory_unregister (image->image_ptr->factory,
159                                       image->image_ptr, HTML_IMAGE (image));
160
161        g_free (image->url);
162        g_free (image->target);
163        g_free (image->alt);
164        g_free (image->usemap);
165        g_free (image->final_url);
166
167        if (image->color)
168                html_color_unref (image->color);
169
170        HTML_OBJECT_CLASS (parent_class)->destroy (o);
171}
172
173static void
174copy (HTMLObject *self,
175      HTMLObject *dest)
176{
177        HTMLImage *dimg = HTML_IMAGE (dest);
178        HTMLImage *simg = HTML_IMAGE (self);
179
180        /* FIXME not sure this is all correct.  */
181
182        (* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);
183
184        dimg->image_ptr = simg->image_ptr;
185        dimg->color = simg->color;
186        if (simg->color)
187                html_color_ref (dimg->color);
188
189        dimg->have_color = simg->have_color;
190
191        dimg->border = simg->border;
192
193        dimg->specified_width = simg->specified_width;
194        dimg->specified_height = simg->specified_height;
195        dimg->percent_width = simg->percent_width;
196        dimg->percent_height = simg->percent_height;
197        dimg->ismap = simg->ismap;
198
199        dimg->hspace = simg->hspace;
200        dimg->vspace = simg->vspace;
201
202        dimg->valign = simg->valign;
203
204        dimg->url = g_strdup (simg->url);
205        dimg->target = g_strdup (simg->target);
206        dimg->alt = g_strdup (simg->alt);
207        dimg->usemap = g_strdup (simg->usemap);
208        dimg->final_url = NULL;
209        dimg->animation_active = FALSE;
210
211        /* add dest to image_ptr interests */
212        dimg->image_ptr->interests = g_slist_prepend (dimg->image_ptr->interests, dimg);
213        html_image_pointer_ref (dimg->image_ptr);
214}
215
216static void
217image_update_url (HTMLImage *image, gint x, gint y)
218{
219        HTMLMap *map;
220        HTMLObject *o = HTML_OBJECT (image);
221        char *url = NULL;
222
223        /*
224         * FIXME this is a huge hack waiting until we implement events for now we write
225         * over the image->url for every point since we always call point before get_url
226         * it is sick, I know.
227         */
228        if (image->usemap != NULL) {
229                map = html_engine_get_map (image->image_ptr->factory->engine,
230                                           image->usemap + 1);
231               
232                if (map) {
233                        url = html_map_calc_point (map, x - o->x , y - (o->y - o->ascent));
234                       
235                        if (url)
236                                url = g_strdup (url);
237                }
238        } else if (image->ismap) {
239                if (image->url)
240                        url = g_strdup_printf ("%s?%d,%d", image->url, x - o->x, y - (o->y - o->ascent));
241        } else {
242                return;
243        }
244       
245        g_free (image->final_url);
246        image->final_url = url;
247}
248
249static HTMLObject *
250check_point (HTMLObject *self,
251             HTMLPainter *painter,
252             gint x, gint y,
253             guint *offset_return,
254             gboolean for_cursor)
255{
256        if ((x >= self->x)
257            && (x < (self->x + self->width))
258            && (y >= (self->y - self->ascent))
259            && (y < (self->y + self->descent))) {
260                if (offset_return != NULL)
261                        *offset_return = x - self->x < self->width / 2 ? 0 : 1;
262               
263                image_update_url (HTML_IMAGE (self), x, y);
264                return self;
265        }
266       
267        return NULL;
268}
269
270static gint
271calc_min_width (HTMLObject *o,
272                HTMLPainter *painter)
273{
274        HTMLImage *image = HTML_IMAGE (o);
275        guint pixel_size;
276        guint min_width;
277
278        pixel_size = html_painter_get_pixel_size (painter);
279
280        if (image->percent_width || image->percent_height)
281                min_width = pixel_size;
282        else
283                min_width = html_image_get_actual_width (HTML_IMAGE (o), painter);
284
285        min_width += (image->border * 2 + 2 * image->hspace) * pixel_size;
286
287        return min_width;
288}
289
290static gint
291calc_preferred_width (HTMLObject *o,
292                      HTMLPainter *painter)
293{
294        HTMLImage *image = HTML_IMAGE (o);
295        guint width;
296
297        width = html_image_get_actual_width (HTML_IMAGE (o), painter)
298                + (image->border * 2 + 2 * image->hspace) * html_painter_get_pixel_size (painter);
299
300        return width;
301}
302
303static gboolean
304html_image_real_calc_size (HTMLObject *o, HTMLPainter *painter, GList **changed_objs)
305{
306        HTMLImage *image;
307        guint pixel_size;
308        guint width, height;
309        gint old_width, old_ascent, old_descent;
310
311        old_width = o->width;
312        old_ascent = o->ascent;
313        old_descent = o->descent;
314
315        image = HTML_IMAGE (o);
316
317        pixel_size = html_painter_get_pixel_size (painter);
318
319        if (o->parent && HTML_IS_PLAIN_PAINTER (painter) && image->alt && *image->alt) {
320                GtkHTMLFontStyle style = GTK_HTML_FONT_STYLE_DEFAULT;
321                HTMLClueFlow *cf = html_object_get_flow (o);
322                gint lo = 0;
323
324                if (cf)
325                        style = html_clueflow_get_default_font_style (cf);
326
327                /* FIXME: cache items and glyphs? */
328                html_painter_calc_text_size (painter, image->alt, g_utf8_strlen (image->alt, -1), NULL, NULL, NULL, 0, &lo,
329                                             style, NULL, &o->width, &o->ascent, &o->descent);
330        } else {
331                width = html_image_get_actual_width (image, painter);
332                height = html_image_get_actual_height (image, painter);
333
334                o->width  = width + (image->border + image->hspace) * 2 * pixel_size;
335                o->ascent = height + (image->border + image->vspace) * 2 * pixel_size;
336                o->descent = 0;
337        }
338
339        if (o->descent != old_descent
340            || o->ascent != old_ascent
341            || o->width != old_width)
342                return TRUE;
343
344        return FALSE;
345}
346
347static void
348draw_plain (HTMLObject *o, HTMLPainter *p, gint x, gint y, gint width, gint height, gint tx, gint ty)
349{
350        HTMLImage *img = HTML_IMAGE (o);
351        HTMLEngine *e;
352
353        if (p->widget && GTK_IS_HTML (p->widget))
354                e = GTK_HTML (p->widget)->engine;
355        else
356                return;
357
358        if (img->alt && *img->alt) {
359                HTMLClueFlow *cf = html_object_get_flow (o);
360
361                /* FIXME: cache items and glyphs? */
362                if (o->selected) {
363                        html_painter_set_pen (p, &html_colorset_get_color_allocated
364                                              (e->settings->color_set, p,
365                                               p->focus ? HTMLHighlightColor : HTMLHighlightNFColor)->color);
366                        html_painter_fill_rect (p, o->x + tx, o->y + ty - o->ascent, o->width, o->ascent + o->descent);
367                        html_painter_set_pen (p, &html_colorset_get_color_allocated
368                                              (e->settings->color_set, p,
369                                               p->focus ? HTMLHighlightTextColor : HTMLHighlightTextNFColor)->color);
370                } else {
371                        html_painter_set_pen (p, &html_colorset_get_color_allocated (e->settings->color_set, p,
372                                                                                     HTMLTextColor)->color);
373                }
374                if (cf)
375                        html_painter_set_font_style (p, html_clueflow_get_default_font_style (cf));
376
377                html_painter_set_font_face (p, NULL);
378                html_painter_draw_text (p, o->x + tx, o->y + ty, img->alt, g_utf8_strlen (img->alt, -1), NULL, NULL, NULL, 0, 0);
379        }
380}
381
382static void
383draw_focus  (HTMLPainter *painter, GdkRectangle *box)
384{
385        HTMLGdkPainter *p;
386        GdkGCValues values;
387        gchar dash [2];
388        HTMLEngine *e;
389
390        if (painter->widget && GTK_IS_HTML (painter->widget))
391                e = GTK_HTML (painter->widget)->engine;
392        else
393                return;
394
395        if (HTML_IS_PRINTER (painter))
396                return;
397       
398        p = HTML_GDK_PAINTER (painter);
399        /* printf ("draw_image_focus\n"); */
400
401        gdk_gc_set_foreground (p->gc, &html_colorset_get_color_allocated (e->settings->color_set,
402                                                                          painter, HTMLTextColor)->color);
403        gdk_gc_get_values (p->gc, &values);
404
405        dash [0] = 1;
406        dash [1] = 1;
407        gdk_gc_set_line_attributes (p->gc, 1, GDK_LINE_ON_OFF_DASH, values.cap_style, values.join_style);
408        gdk_gc_set_dashes (p->gc, 2, dash, 2);
409        gdk_draw_rectangle (p->pixmap, p->gc, 0, box->x - p->x1, box->y - p->y1, box->width - 1, box->height - 1);
410        gdk_gc_set_line_attributes (p->gc, 1, values.line_style, values.cap_style, values.join_style);
411}
412
413static void
414draw (HTMLObject *o,
415      HTMLPainter *painter,
416      gint x, gint y,
417      gint width, gint height,
418      gint tx, gint ty)
419{
420        HTMLImage *image;
421        HTMLImagePointer *ip;
422        GdkPixbuf *pixbuf;
423        gint base_x, base_y;
424        gint scale_width, scale_height;
425        GdkColor *highlight_color;
426        guint pixel_size;
427        GdkRectangle paint;
428        HTMLEngine *e;
429
430        if (painter->widget && GTK_IS_HTML (painter->widget))
431                e = GTK_HTML (painter->widget)->engine;
432        else
433                return;
434
435        /* printf ("Image::draw\n"); */
436
437        if (!html_object_intersect (o, &paint, x, y, width, height))
438                return;
439
440        if (HTML_IS_PLAIN_PAINTER (painter)) {
441                draw_plain (o, painter, x, y, width, height, tx, ty);
442                return;
443        }
444
445        image = HTML_IMAGE (o);
446        ip = image->image_ptr;
447
448        image->animation_active = TRUE;
449
450        if (ip->animation) {
451                if (HTML_IS_GDK_PAINTER (painter) && !gdk_pixbuf_animation_is_static_image (ip->animation)) {
452                        pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (ip->iter);
453                } else {
454                        pixbuf = gdk_pixbuf_animation_get_static_image (ip->animation);
455                }
456        } else {
457                pixbuf = NULL;
458        }
459
460        pixel_size = html_painter_get_pixel_size (painter);
461
462        if (o->selected) {
463                highlight_color = &html_colorset_get_color_allocated
464                        (e->settings->color_set, painter,
465                         painter->focus ? HTMLHighlightColor : HTMLHighlightNFColor)->color;
466        } else
467                highlight_color = NULL;
468
469        base_x = o->x + tx + (image->border + image->hspace) * pixel_size;
470        base_y = o->y + ty + (image->border + image->vspace) * pixel_size - o->ascent;
471
472        if (pixbuf == NULL) {
473                gint vspace, hspace;
474
475                hspace = image->hspace * pixel_size;
476                vspace = image->vspace * pixel_size;
477
478                if (image->image_ptr->loader && !image->image_ptr->stall)
479                        return;
480
481                if (o->selected) {
482                        html_painter_set_pen (painter, highlight_color);
483                        html_painter_fill_rect (painter,
484                                                o->x + tx + hspace,
485                                                o->y + ty - o->ascent + vspace,
486                                                o->width - 2 * hspace,
487                                                o->ascent + o->descent - 2 * vspace);
488                }
489                html_painter_draw_panel (painter,
490                                         &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
491                                         o->x + tx + hspace,
492                                         o->y + ty - o->ascent + vspace,
493                                         o->width - 2 * hspace,
494                                         o->ascent + o->descent - 2 * vspace,
495                                         GTK_HTML_ETCH_IN, 1);
496
497                if (ip->factory)
498                        pixbuf = html_image_factory_get_missing (ip->factory);
499
500                if (pixbuf &&
501                    (o->width > gdk_pixbuf_get_width (pixbuf)) &&
502                    (o->ascent  + o->descent > gdk_pixbuf_get_height (pixbuf)))
503                        html_painter_draw_pixmap (painter, pixbuf,
504                                                  base_x, base_y,
505                                                  gdk_pixbuf_get_width (pixbuf) * pixel_size,
506                                                  gdk_pixbuf_get_height (pixbuf) * pixel_size,
507                                                  highlight_color);
508                               
509                if (o->draw_focused) {
510                        GdkRectangle rect;
511
512                        scale_width = html_image_get_actual_width (image, painter);
513                        scale_height = html_image_get_actual_height (image, painter);
514
515                        rect.x = base_x - image->border * pixel_size;
516                        rect.y = base_y - image->border * pixel_size;
517                        rect.width = scale_width + (2 * image->border) * pixel_size;
518                        rect.height = scale_height + (2 * image->border) * pixel_size;
519
520                        draw_focus (painter, &rect);
521                }                                   
522
523                return;
524        }
525
526        scale_width = html_image_get_actual_width (image, painter);
527        scale_height = html_image_get_actual_height (image, painter);
528
529        if (image->border) {
530                if (image->have_color) {
531                        html_color_alloc (image->color, painter);
532                        html_painter_set_pen (painter, &image->color->color);
533                }
534               
535                html_painter_draw_panel (painter,
536                                         &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
537                                         base_x - image->border * pixel_size,
538                                         base_y - image->border * pixel_size,
539                                         scale_width + (2 * image->border) * pixel_size,
540                                         scale_height + (2 * image->border) * pixel_size,
541                                         GTK_HTML_ETCH_NONE, image->border);
542               
543        }
544       
545        html_painter_draw_pixmap (painter, pixbuf,
546                                  base_x, base_y,
547                                  scale_width, scale_height,
548                                  highlight_color);
549
550        if (o->draw_focused) {
551                GdkRectangle rect;
552                rect.x = base_x - image->border * pixel_size;
553                rect.y = base_y - image->border * pixel_size;
554                rect.width = scale_width + (2 * image->border) * pixel_size;
555                rect.height = scale_height + (2 * image->border) * pixel_size;
556
557                draw_focus (painter, &rect);
558        }
559}
560
561gchar *
562html_image_resolve_image_url (GtkHTML *html, gchar *image_url)
563{
564        gchar *url = NULL;
565
566        /* printf ("html_image_resolve_image_url %p\n", html->editor_api); */
567        if (html->editor_api) {
568                GValue  *iarg = g_new0 (GValue, 1);
569                GValue  *oarg;
570
571                g_value_init (iarg, G_TYPE_STRING);
572                g_value_set_string (iarg, image_url);
573
574                oarg = (* html->editor_api->event) (html, GTK_HTML_EDITOR_EVENT_IMAGE_URL, iarg, html->editor_data);
575
576                if (oarg) {
577                        if (G_VALUE_TYPE (oarg) == G_TYPE_STRING)
578                                url = (gchar *) g_strdup (g_value_get_string (oarg));
579
580                        g_value_unset (oarg);
581                        g_free (oarg);
582                }
583                g_value_unset (iarg);
584                g_free (iarg);
585        }
586        if (!url)
587                url = g_strdup (image_url);
588        /* printf ("image URL resolved to: %s (from: %s)\n", url, image_url); */
589
590        return url;
591}
592
593static gboolean
594save (HTMLObject *self,
595      HTMLEngineSaveState *state)
596{
597        HTMLImage *image;
598        gchar *url;
599        gboolean result, link = FALSE;
600
601        g_return_val_if_fail (self != NULL, FALSE);
602        g_return_val_if_fail (state != NULL, FALSE);
603
604        image  = HTML_IMAGE (self);
605
606        if (image->url && *image->url) {
607                url  = g_strconcat (image->url, image->target ? "#" : "", image->target, NULL);
608                link = TRUE;
609                result = html_engine_save_output_string (state, "<A HREF=\"%s\">", url);
610                g_free (url);
611                if (!result)
612                        return FALSE;   
613        }
614
615        url    = html_image_resolve_image_url (state->engine->widget, image->image_ptr->url);
616        result = html_engine_save_output_string (state, "<IMG SRC=\"%s\"", url);
617        g_free (url);
618        if (!result)
619                return FALSE;   
620
621        if (image->percent_width) {
622                if (!html_engine_save_output_string (state, " WIDTH=\"%d%%\"", image->specified_width))
623                        return FALSE;
624        } else if (image->specified_width > 0) {
625                if (!html_engine_save_output_string (state, " WIDTH=\"%d\"", image->specified_width))
626                        return FALSE;
627        }
628
629        if (image->percent_height) {
630                if (!html_engine_save_output_string (state, " HEIGHT=\"%d%%\"", image->specified_height))
631                        return FALSE;
632        } else if (image->specified_height > 0) {
633                if (!html_engine_save_output_string (state, " HEIGHT=\"%d\"", image->specified_height))
634                        return FALSE;
635        }
636
637        if (image->vspace) {
638                if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
639                        return FALSE;
640        }
641
642        if (image->hspace) {
643                if (!html_engine_save_output_string (state, " HSPACE=\"%d\"", image->hspace))
644                        return FALSE;
645        }
646
647        if (image->vspace) {
648                if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
649                        return FALSE;
650        }
651
652        if (image->valign != HTML_VALIGN_NONE) {
653                if (!html_engine_save_output_string (state, " ALIGN=\"%s\"", html_valign_name (image->valign)))
654                        return FALSE;
655        }
656
657        if (image->alt) {
658                if (!html_engine_save_output_string (state, " ALT=\"%s\"", image->alt))
659                        return FALSE;
660        }
661
662        /* FIXME this is the default set in htmlengine.c but there is no real way to tell
663         * if the usr specified it directly
664         */
665        if (image->border != 2) {
666                if (!html_engine_save_output_string (state, " BORDER=\"%d\"", image->border))
667                        return FALSE;
668        }
669
670        if (!html_engine_save_output_string (state, ">"))
671                return FALSE;
672        if (link && !html_engine_save_output_string (state, "</A>"))
673                return FALSE;
674       
675        return TRUE;
676}
677
678static gboolean
679save_plain (HTMLObject *self,
680            HTMLEngineSaveState *state,
681            gint requested_width)
682{
683        HTMLImage *image;
684        gboolean rv = TRUE;
685
686        image = HTML_IMAGE (self);
687       
688        if (image->alt)
689                rv = html_engine_save_output_string (state, "%s", image->alt);
690
691        return rv;
692}
693
694static const gchar *
695get_url (HTMLObject *o, gint offset)
696{
697        HTMLImage *image;
698
699        image = HTML_IMAGE (o);
700        return image->final_url ? image->final_url : image->url;
701}
702
703static const gchar *
704get_target (HTMLObject *o, gint offset)
705{
706        HTMLImage *image;
707
708        image = HTML_IMAGE (o);
709        return image->target;
710}
711
712static const gchar *
713get_src (HTMLObject *o)
714{
715        HTMLImage *image;
716       
717        image = HTML_IMAGE (o);
718        return image->image_ptr->url;
719}
720
721static HTMLObject *
722set_link (HTMLObject *self, HTMLColor *color, const gchar *url, const gchar *target)
723{
724        HTMLImage *image = HTML_IMAGE (self);
725
726        STRDUP_HELPER (image->url, url);
727        STRDUP_HELPER (image->target, target);
728        if (image->have_color)
729                html_color_unref (image->color);
730        image->color = color;
731        if (color) {
732                html_color_ref (color);
733                image->have_color = TRUE;
734        } else {
735                image->have_color = FALSE;
736        }
737
738        return NULL;
739}
740
741static gboolean
742accepts_cursor (HTMLObject *o)
743{
744        return TRUE;
745}
746
747static HTMLVAlignType
748get_valign (HTMLObject *self)
749{
750        HTMLImage *image;
751
752        image = HTML_IMAGE (self);
753
754        return image->valign;
755}
756
757static gboolean
758select_range (HTMLObject *self,
759              HTMLEngine *engine,
760              guint offset,
761              gint length,
762              gboolean queue_draw)
763{
764        /* printf ("IMAGE: select range\n"); */
765        if ((*parent_class->select_range) (self, engine, offset, length, queue_draw)) {
766                if (queue_draw) {
767                        html_engine_queue_draw (engine, self);
768                        /* printf ("IMAGE: draw queued\n"); */
769                }
770                return TRUE;
771        } else
772                return FALSE;
773}
774
775
776void
777html_image_type_init (void)
778{
779        html_image_class_init (&html_image_class, HTML_TYPE_IMAGE, sizeof (HTMLImage));
780}
781
782void
783html_image_class_init (HTMLImageClass *image_class,
784                       HTMLType type,
785                       guint size)
786{
787        HTMLObjectClass *object_class;
788
789        object_class = HTML_OBJECT_CLASS (image_class);
790
791        html_object_class_init (object_class, type, size);
792
793        object_class->copy = copy;
794        object_class->draw = draw;     
795        object_class->destroy = destroy;
796        object_class->calc_min_width = calc_min_width;
797        object_class->calc_preferred_width = calc_preferred_width;
798        object_class->calc_size = html_image_real_calc_size;
799        object_class->check_point = check_point;
800        object_class->get_url = get_url;
801        object_class->get_target = get_target;
802        object_class->get_src = get_src;
803        object_class->set_link = set_link;
804        object_class->accepts_cursor = accepts_cursor;
805        object_class->get_valign = get_valign;
806        object_class->save = save;
807        object_class->save_plain = save_plain;
808        object_class->select_range = select_range;
809
810        parent_class = &html_object_class;
811}
812
813void
814html_image_init (HTMLImage *image,
815                 HTMLImageClass *klass,
816                 HTMLImageFactory *imf,
817                 const gchar *filename,
818                 const gchar *url,
819                 const gchar *target,
820                 gint16 width, gint16 height,
821                 gboolean percent_width, gboolean percent_height,
822                 gint8 border,
823                 HTMLColor *color,
824                 HTMLVAlignType valign,
825                 gboolean reload)
826{
827        HTMLObject *object;
828
829        g_assert (filename);
830
831        object = HTML_OBJECT (image);
832
833        html_object_init (object, HTML_OBJECT_CLASS (klass));
834
835        image->animation_active = FALSE;
836        image->url = g_strdup (url);
837        image->target = g_strdup (target);
838        image->usemap = NULL;
839        image->final_url = NULL;
840        image->ismap = FALSE;
841
842        image->specified_width  = width;
843        image->specified_height = height;
844        image->percent_width    = percent_width;
845        image->percent_height   = percent_height;
846        image->border           = border;
847
848        if (color) {
849                image->color = color;
850                image->have_color = TRUE;
851                html_color_ref (color);
852        } else {
853                image->color = NULL;
854                image->have_color = FALSE;
855        }
856
857        image->alt = NULL;
858
859        image->hspace = 0;
860        image->vspace = 0;
861
862        if (valign == HTML_VALIGN_NONE)
863                valign = HTML_VALIGN_BOTTOM;
864        image->valign = valign;
865
866        image->image_ptr = html_image_factory_register (imf, image, filename, reload);
867}
868
869HTMLObject *
870html_image_new (HTMLImageFactory *imf,
871                const gchar *filename,
872                const gchar *url,
873                const gchar *target,
874                gint16 width, gint16 height,
875                gboolean percent_width, gboolean percent_height,
876                gint8 border,   
877                HTMLColor *color,
878                HTMLVAlignType valign,
879                gboolean reload)
880{
881        HTMLImage *image;
882
883        image = g_new(HTMLImage, 1);
884
885        html_image_init (image, &html_image_class,
886                         imf,
887                         filename,
888                         url,
889                         target,
890                         width, height,
891                         percent_width, percent_height,
892                         border,
893                         color,
894                         valign,
895                         reload);
896
897        return HTML_OBJECT (image);
898}
899
900void
901html_image_set_spacing (HTMLImage *image, gint hspace, gint vspace)
902{
903        gboolean changed = FALSE;
904
905        if (image->hspace != hspace) {
906                image->hspace = hspace;
907                changed = TRUE;
908        }
909
910        if (image->vspace != vspace) {
911                image->vspace = vspace;
912                changed = TRUE;
913        }
914
915        if (changed) {
916                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
917                html_engine_schedule_update (image->image_ptr->factory->engine);
918        }
919}
920
921void
922html_image_edit_set_url (HTMLImage *image, const gchar *url)
923{
924        if (url) {
925                HTMLImageFactory *imf = image->image_ptr->factory;
926
927                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
928                html_image_factory_unregister (imf, image->image_ptr, HTML_IMAGE (image));
929                image->image_ptr = html_image_factory_register (imf, image, url, TRUE);
930                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
931                html_engine_schedule_update (imf->engine);
932        }
933}
934
935void
936html_image_set_url (HTMLImage *image, const gchar *url)
937{
938        if (url && strcmp (image->image_ptr->url, url)) {
939                HTMLImageFactory *imf = image->image_ptr->factory;
940
941                html_image_factory_unregister (imf, image->image_ptr, HTML_IMAGE (image));
942                image->image_ptr = html_image_factory_register (imf, image, url, FALSE);
943        }
944}
945
946void
947html_image_set_valign (HTMLImage *image, HTMLVAlignType valign)
948{
949        if (image->valign != valign) {
950                image->valign = valign;
951                html_engine_schedule_update (image->image_ptr->factory->engine);
952        }
953}
954
955void
956html_image_set_border (HTMLImage *image, gint border)
957{
958        if (image->border != border) {
959                image->border = border;
960                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
961                html_engine_schedule_update (image->image_ptr->factory->engine);
962        }
963}
964
965void
966html_image_set_alt (HTMLImage *image, gchar *alt)
967{
968        g_free (image->alt);
969        image->alt = g_strdup (alt);
970}
971
972void
973html_image_set_map (HTMLImage *image, gchar *usemap, gboolean ismap)
974{
975        char *url = NULL;
976
977        g_free (image->usemap);
978
979        if (usemap != NULL) {
980                image->ismap = FALSE;
981                url = g_strdup (usemap);
982        } else {
983                image->ismap = ismap;
984        }
985        image->usemap = url;
986}
987
988void
989html_image_set_size (HTMLImage *image, gint w, gint h, gboolean pw, gboolean ph)
990{
991        gboolean changed = FALSE;
992
993        if (pw != image->percent_width) {
994                image->percent_width = pw;
995                changed = TRUE;
996        }
997
998        if (ph != image->percent_height) {
999                image->percent_height = ph;
1000                changed = TRUE;
1001        }
1002
1003        if (w != image->specified_width) {
1004                image->specified_width = w;
1005                changed = TRUE;
1006        }
1007
1008        if (h != image->specified_height) {
1009                image->specified_height = h;
1010                changed = TRUE;
1011        }
1012
1013        if (changed) {
1014                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
1015                html_engine_schedule_update (image->image_ptr->factory->engine);
1016        }
1017}
1018
1019static char *fallback_image_content_types[] = {"image/*", NULL};
1020
1021static char **
1022html_image_factory_types (GtkHTMLStream *stream,
1023                          gpointer user_data)
1024{
1025        static char**image_content_types = NULL;
1026       
1027#if 0
1028        /* this code should work in gtk+-2.2 but it is untested */
1029        if (image_content_types == NULL) {
1030                GSList *formats;
1031                GSList *cur;
1032                GSList *types = NULL;
1033                gint i;
1034
1035                formats = gdk_pixbuf_get_formats ();
1036               
1037                for (cur = formats; cur; cur = cur->next) {
1038                        GdkPixbufFormat *format = cur->data;
1039                        char **mime;
1040
1041                        mime = gdk_pixbuf_formats_get_mime_types ();
1042                        for (i = 0; mime && mime[i]; i++)
1043                                g_slist_prepend (types, g_strdup (mime[i]));
1044
1045                }
1046                g_slist_free (formats);
1047
1048                if (types) {
1049                        image_content_types = g_new0 (char *, g_slist_length (types) + 1);
1050                       
1051                        for (cur = types, i = 0; cur; cur = cur->next, i++) {
1052                                image_content_types[i] = cur->data;
1053                        }
1054                        g_slist_free (types);
1055                } else {
1056                        image_content_types = fallback_image_content_types;
1057                }
1058        }
1059#else
1060        image_content_types = fallback_image_content_types;
1061#endif
1062
1063        return image_content_types;
1064}
1065
1066static void
1067update_or_redraw (HTMLImagePointer *ip){
1068        GSList *list;
1069        gboolean update = FALSE;
1070
1071        for (list = ip->interests; list; list = list->next) {
1072                if (list->data == NULL)
1073                        update = TRUE;
1074                else {
1075                        HTMLImage *image = HTML_IMAGE (list->data);
1076                        gint pixel_size = html_painter_get_pixel_size (ip->factory->engine->painter);
1077                        gint w, h;
1078
1079                        w = html_image_get_actual_width (image, ip->factory->engine->painter)
1080                                + (image->border * 2 + 2 * image->hspace) * pixel_size;
1081                        h = html_image_get_actual_height (image, ip->factory->engine->painter)
1082                                + (image->border * 2 + 2 * image->vspace) * pixel_size;
1083
1084                        /* printf ("%dx%d  <-->  %dx%d\n", w, h, HTML_OBJECT (list->data)->width,
1085                           HTML_OBJECT (list->data)->ascent + HTML_OBJECT (list->data)->descent); */
1086
1087                        if (w != HTML_OBJECT (list->data)->width
1088                            || h != HTML_OBJECT (list->data)->ascent + HTML_OBJECT (list->data)->descent) {
1089                                html_object_change_set (HTML_OBJECT (list->data), HTML_CHANGE_ALL_CALC);
1090                                update = TRUE;
1091                        }
1092                }
1093        }
1094
1095        if (ip->factory->engine->block && ip->factory->engine->opened_streams)
1096                return;
1097
1098        if (!update) {
1099                /* printf ("REDRAW\n"); */
1100                for (list = ip->interests; list; list = list->next)
1101                        if (list->data) /* && html_object_is_visible (HTML_OBJECT (list->data))) */
1102                                html_engine_queue_draw (ip->factory->engine, HTML_OBJECT (list->data));
1103                if (ip->interests)
1104                        html_engine_flush_draw_queue (ip->factory->engine);
1105        } else {
1106                /* printf ("UPDATE\n"); */
1107                html_engine_schedule_update (ip->factory->engine);
1108        }
1109}
1110
1111static void
1112html_image_factory_end_pixbuf (GtkHTMLStream *stream,
1113                               GtkHTMLStreamStatus status,
1114                               gpointer user_data)
1115{
1116        HTMLImagePointer *ip = user_data;
1117
1118        gdk_pixbuf_loader_close (ip->loader, NULL);
1119
1120        if (!ip->animation) {
1121                ip->animation = gdk_pixbuf_loader_get_animation (ip->loader);
1122
1123                if (ip->animation)
1124                        g_object_ref (ip->animation);
1125        }
1126        html_image_pointer_start_animation (ip);
1127
1128        g_object_unref (ip->loader);
1129        ip->loader = NULL;
1130
1131        update_or_redraw (ip);
1132        if (ip->factory->engine->opened_streams && ip->factory->engine->block_images)
1133                html_engine_opened_streams_decrement (ip->factory->engine);
1134        /* printf ("IMAGE(%p) opened streams: %d\n", ip->factory->engine, ip->factory->engine->opened_streams); */
1135        if (ip->factory->engine->opened_streams == 0 && ip->factory->engine->block && ip->factory->engine->block_images)
1136                html_engine_schedule_update (ip->factory->engine);
1137        html_image_pointer_unref (ip);
1138}
1139
1140static void
1141html_image_factory_write_pixbuf (GtkHTMLStream *stream,
1142                                 const gchar *buffer,
1143                                 size_t size,
1144                                 gpointer user_data)
1145{
1146        HTMLImagePointer *p = user_data;
1147
1148        /* FIXME ! Check return value */
1149        gdk_pixbuf_loader_write (p->loader, buffer, size, NULL);
1150}
1151
1152static void
1153html_image_pointer_queue_animation (HTMLImagePointer *ip)
1154{
1155        if (!ip->animation_timeout && ip->factory && ip->factory->animate) {
1156                gint delay;
1157               
1158                gdk_pixbuf_animation_iter_advance (ip->iter, NULL);
1159                delay = gdk_pixbuf_animation_iter_get_delay_time (ip->iter);
1160               
1161                ip->animation_timeout = g_timeout_add (delay,
1162                                                       (GtkFunction) html_image_pointer_update,
1163                                                       (gpointer) ip);
1164        }
1165       
1166}
1167
1168static gint
1169html_image_pointer_update (HTMLImagePointer *ip)
1170{
1171        HTMLEngine *engine = ip->factory->engine;
1172        GSList *cur;
1173
1174        g_return_val_if_fail (ip->factory != NULL, FALSE);
1175        ip->animation_timeout = 0;
1176               
1177        DA (printf ("animation_timeout (%p)\n", ip);)
1178        for (cur = ip->interests; cur; cur = cur->next) {
1179                HTMLImage           *image = cur->data;
1180               
1181                if (image && image->animation_active && html_object_is_parent (engine->clue, HTML_OBJECT (image))) {
1182                        DA (printf ("queue draw (%p)\n", image);)
1183
1184                        image->animation_active = FALSE;
1185                        html_engine_queue_draw (engine, HTML_OBJECT (image));
1186                }
1187        }
1188       
1189        html_image_pointer_start_animation (ip);
1190        return FALSE;
1191}
1192
1193static void
1194html_image_pointer_start_animation (HTMLImagePointer *ip)
1195{
1196        if (ip->animation && !gdk_pixbuf_animation_is_static_image (ip->animation)) {
1197                if (!ip->iter)
1198                        ip->iter = gdk_pixbuf_animation_get_iter (ip->animation, NULL);
1199
1200                html_image_pointer_queue_animation (ip);
1201        }
1202}
1203
1204static void
1205html_image_pointer_stop_animation (HTMLImagePointer *ip)
1206{
1207        if (ip->animation_timeout) {
1208                g_source_remove (ip->animation_timeout);
1209                ip->animation_timeout = 0;
1210        }
1211}
1212
1213static void
1214html_image_factory_area_updated (GdkPixbufLoader *loader, guint x, guint y, guint width, guint height, HTMLImagePointer *ip)
1215{
1216        html_image_pointer_stop_animation (ip);
1217        /* update will requeue */
1218        html_image_pointer_update (ip);
1219}
1220
1221static void
1222html_image_factory_area_prepared (GdkPixbufLoader *loader, HTMLImagePointer *ip)
1223{
1224        if (!ip->animation) {
1225                ip->animation = gdk_pixbuf_loader_get_animation (loader);
1226                g_object_ref (ip->animation);
1227               
1228                html_image_pointer_start_animation (ip);
1229        }
1230        update_or_redraw (ip);
1231}
1232
1233static GdkPixbuf *
1234html_image_factory_get_missing (HTMLImageFactory *factory)
1235{
1236        if (!factory->missing)
1237                factory->missing = gtk_widget_render_icon (GTK_WIDGET (factory->engine->widget),
1238                                                          GTK_STOCK_MISSING_IMAGE,
1239                                                          GTK_ICON_SIZE_BUTTON, "GtkHTML.ImageMissing");
1240        return factory->missing;
1241}
1242
1243HTMLImageFactory *
1244html_image_factory_new (HTMLEngine *e)
1245{
1246        HTMLImageFactory *retval;
1247        retval = g_new (HTMLImageFactory, 1);
1248        retval->engine = e;
1249        retval->loaded_images = g_hash_table_new (g_str_hash, g_str_equal);
1250        retval->missing = NULL;
1251        retval->animate = TRUE;
1252
1253        return retval;
1254}
1255
1256static gboolean
1257cleanup_images (gpointer key, gpointer value, gpointer free_everything)
1258{
1259        HTMLImagePointer *ip = value;
1260
1261        /* free_everything means: NULL only clean, non-NULL free */
1262        if (free_everything){
1263                if (ip->interests != NULL) {
1264                        g_slist_free (ip->interests);
1265                        ip->interests = NULL;
1266                }
1267        }
1268
1269        /* clean only if this image is not used anymore */
1270        if (!ip->interests){
1271                html_image_pointer_unref (ip);
1272                ip->factory = NULL;
1273                return TRUE;
1274        }
1275
1276        return FALSE;
1277}
1278
1279void
1280html_image_factory_cleanup (HTMLImageFactory *factory)
1281{
1282        g_return_if_fail (factory);
1283        g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, NULL);
1284}
1285
1286void
1287html_image_factory_free (HTMLImageFactory *factory)
1288{
1289        g_return_if_fail (factory);
1290
1291        g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, factory);
1292        g_hash_table_destroy (factory->loaded_images);
1293
1294        if (factory->missing)
1295                gdk_pixbuf_unref (factory->missing);
1296
1297        g_free (factory);
1298}
1299
1300#define STALL_INTERVAL 1000
1301
1302static HTMLImagePointer *
1303html_image_pointer_new (const char *filename, HTMLImageFactory *factory)
1304{
1305        HTMLImagePointer *retval;
1306
1307        retval = g_new (HTMLImagePointer, 1);
1308        retval->refcount = 1;
1309        retval->url = g_strdup (filename);
1310        retval->loader = gdk_pixbuf_loader_new ();
1311        retval->iter = NULL;
1312        retval->animation = NULL;
1313        retval->interests = NULL;
1314        retval->factory = factory;
1315        retval->stall = FALSE;
1316        retval->stall_timeout = gtk_timeout_add (STALL_INTERVAL,
1317                                                 (GtkFunction)html_image_pointer_timeout,
1318                                                 retval);
1319        retval->animation_timeout = 0;
1320        return retval;
1321}
1322
1323static gboolean
1324html_image_pointer_timeout (HTMLImagePointer *ip)
1325{
1326        GSList *list;
1327        HTMLImage *image;
1328
1329        ip->stall_timeout = 0;
1330
1331        g_return_val_if_fail (ip->factory != NULL, FALSE);
1332
1333        ip->stall = TRUE;
1334
1335        list = ip->interests;
1336        /*
1337         * draw the frame now that we decided they've had enough time to
1338         * load the image
1339         */
1340        if (ip->animation == NULL) {
1341                while (list) {
1342                        image = (HTMLImage *)list->data;
1343
1344                        if (image)
1345                                html_engine_queue_draw (ip->factory->engine,
1346                                                        HTML_OBJECT (image));
1347                       
1348                        list = list->next;
1349                }
1350        }
1351        return FALSE;
1352}
1353
1354static void
1355html_image_pointer_ref (HTMLImagePointer *ip)
1356{
1357        ip->refcount++;
1358}
1359
1360static void
1361free_image_ptr_data (HTMLImagePointer *ip)
1362{
1363        if (ip->loader) {
1364                gdk_pixbuf_loader_close (ip->loader, NULL);
1365                g_object_unref (ip->loader);
1366                ip->loader = NULL;
1367        }
1368        if (ip->animation) {
1369                g_object_unref (ip->animation);
1370                ip->animation = NULL;
1371        }
1372        if (ip->iter) {
1373                g_object_unref (ip->iter);
1374                ip->iter = NULL;
1375        }
1376}
1377
1378static void
1379html_image_pointer_remove_stall (HTMLImagePointer *ip)
1380{
1381        if (ip->stall_timeout) {
1382                gtk_timeout_remove (ip->stall_timeout);
1383                ip->stall_timeout = 0;
1384        }
1385}
1386
1387static void
1388html_image_pointer_unref (HTMLImagePointer *ip)
1389{
1390        g_return_if_fail (ip != NULL);
1391
1392        ip->refcount--;
1393        /* printf ("unref(%p) %s --> %d\n", ip, ip->url, ip->refcount); */
1394        if (ip->refcount < 1) {
1395                /* printf ("freeing %s\n", ip->url); */
1396                html_image_pointer_remove_stall (ip);
1397                html_image_pointer_stop_animation (ip);
1398                g_free (ip->url);
1399                free_image_ptr_data (ip);
1400                g_free (ip);
1401        }
1402}
1403
1404static GtkHTMLStream *
1405html_image_pointer_load (HTMLImagePointer *ip)
1406{
1407        if (ip->factory->engine->stopped)
1408                return NULL;
1409
1410        html_image_pointer_ref (ip);
1411
1412        if (ip->factory->engine->block_images)
1413                html_engine_opened_streams_increment (ip->factory->engine);
1414        return gtk_html_stream_new (GTK_HTML (ip->factory->engine->widget),
1415                                    html_image_factory_types,
1416                                    html_image_factory_write_pixbuf,
1417                                    html_image_factory_end_pixbuf,
1418                                    ip);
1419}
1420
1421HTMLImagePointer *
1422html_image_factory_register (HTMLImageFactory *factory, HTMLImage *i, const char *url, gboolean reload)
1423{
1424        HTMLImagePointer *ip;
1425        GtkHTMLStream *stream = NULL;
1426
1427        g_return_val_if_fail (factory, NULL);
1428        g_return_val_if_fail (url, NULL);
1429
1430        ip = g_hash_table_lookup (factory->loaded_images, url);
1431
1432        if (!ip) {
1433                ip = html_image_pointer_new (url, factory);
1434                g_hash_table_insert (factory->loaded_images, ip->url, ip);
1435                if (*url) {
1436                        g_signal_connect (G_OBJECT (ip->loader), "area_prepared",
1437                                          G_CALLBACK (html_image_factory_area_prepared),
1438                                          ip);
1439
1440                        g_signal_connect (G_OBJECT (ip->loader), "area_updated",
1441                                          G_CALLBACK (html_image_factory_area_updated),
1442                                          ip);
1443                        stream = html_image_pointer_load (ip);
1444                }
1445        } else {
1446                if (reload) {
1447                        free_image_ptr_data (ip);
1448                        ip->loader = gdk_pixbuf_loader_new ();
1449                        stream = html_image_pointer_load (ip);
1450                }
1451        }
1452
1453        if (stream)
1454                g_signal_emit_by_name (factory->engine, "url_requested", ip->url, stream);
1455
1456        html_image_pointer_ref (ip);
1457
1458        /* we add also NULL ptrs, as we dont want these to be cleaned out */
1459        ip->interests = g_slist_prepend (ip->interests, i);
1460
1461        if (i) {
1462                i->image_ptr = ip;
1463        }
1464
1465        return ip;
1466}
1467
1468#if 0
1469HTMLEngine *
1470html_image_factory_get_engine (HTMLImageFactory *factory)
1471{
1472        return factory->engine;
1473}
1474#endif
1475
1476void
1477html_image_factory_unregister (HTMLImageFactory *factory, HTMLImagePointer *pointer, HTMLImage *i)
1478{
1479        pointer->interests = g_slist_remove (pointer->interests, i);
1480
1481        html_image_pointer_unref (pointer);
1482
1483        if (pointer->refcount == 1) {
1484                g_assert (pointer->interests == NULL);
1485                /*
1486                 * FIXME The factory can be NULL if the image was from an iframe
1487                 * that has been destroyed and the image is living in the cut buffer
1488                 * this isn't particularly clean and should be refactored.
1489                 *
1490                 * We really need a way to let cut objects know they are living outside
1491                 * the normal flow.
1492                 */
1493                if (factory)
1494                        g_hash_table_remove (factory->loaded_images, pointer->url);
1495                pointer->factory = NULL;
1496                html_image_pointer_unref (pointer);
1497        }
1498}
1499
1500static void
1501stop_anim (gpointer key, gpointer value, gpointer user_data)
1502{
1503        HTMLImagePointer *ip = value;
1504        html_image_pointer_remove_stall (ip);
1505        html_image_pointer_stop_animation (ip);
1506}
1507
1508void
1509html_image_factory_stop_animations (HTMLImageFactory *factory)
1510{
1511        DA (g_warning ("stop animations");)
1512        g_hash_table_foreach (factory->loaded_images, stop_anim, NULL);
1513}
1514
1515static void
1516start_anim (gpointer key, gpointer value, gpointer user_data)
1517{
1518        HTMLImagePointer *ip = value;
1519        html_image_pointer_start_animation (ip);
1520}
1521
1522void
1523html_image_factory_start_animations (HTMLImageFactory *factory)
1524{
1525        DA (g_warning ("start animations");)
1526        g_hash_table_foreach (factory->loaded_images, start_anim, NULL);
1527}
1528
1529gboolean
1530html_image_factory_get_animate (HTMLImageFactory *factory)
1531{
1532        return factory->animate;
1533}
1534
1535void
1536html_image_factory_set_animate (HTMLImageFactory *factory, gboolean animate)
1537{
1538        if (animate != factory->animate) {
1539                factory->animate = animate;
1540
1541                if (animate)
1542                        html_image_factory_start_animations (factory);
1543                else
1544                        html_image_factory_stop_animations (factory);
1545        }
1546}
1547
1548static gboolean
1549move_image_pointers (gpointer key, gpointer value, gpointer data)
1550{
1551        HTMLImageFactory *dst = HTML_IMAGE_FACTORY (data);
1552        HTMLImagePointer *ip  = HTML_IMAGE_POINTER (value);
1553
1554        ip->factory = dst;
1555       
1556        g_hash_table_insert (dst->loaded_images, ip->url, ip);
1557        if (!ip->factory->engine->stopped)
1558                g_signal_emit_by_name (ip->factory->engine, "url_requested", ip->url, html_image_pointer_load (ip));
1559
1560        return TRUE;
1561}
1562
1563void
1564html_image_factory_move_images (HTMLImageFactory *dst, HTMLImageFactory *src)
1565{
1566        g_hash_table_foreach_remove (src->loaded_images, move_image_pointers, dst);
1567}
1568
1569static void
1570deactivate_anim (gpointer key, gpointer value, gpointer user_data)
1571{
1572        HTMLImagePointer *ip = value;
1573        GSList *cur = ip->interests;
1574        HTMLImage *image;
1575       
1576
1577        while (cur) {
1578                if (cur->data) {
1579                        image = (HTMLImage *) cur->data;
1580                        image->animation_active = FALSE;
1581                }
1582                cur = cur->next;
1583        }
1584}
1585
1586void
1587html_image_factory_deactivate_animations (HTMLImageFactory *factory)
1588{
1589        g_hash_table_foreach (factory->loaded_images, deactivate_anim, NULL);
1590}
1591
1592static void
1593ref_image_ptr (gpointer key, gpointer val, gpointer data)
1594{
1595        if (HTML_IMAGE_POINTER (val)->animation)
1596                html_image_pointer_ref (HTML_IMAGE_POINTER (val));
1597        /* printf ("ref(%p) %s --> %d\n", val, HTML_IMAGE_POINTER (val)->url, HTML_IMAGE_POINTER (val)->refcount); */
1598}
1599
1600static void
1601unref_image_ptr (gpointer key, gpointer val, gpointer data)
1602{
1603        if (HTML_IMAGE_POINTER (val)->animation)
1604                html_image_pointer_unref (HTML_IMAGE_POINTER (val));
1605}
1606
1607void
1608html_image_factory_ref_all_images (HTMLImageFactory *factory)
1609{
1610        if (!factory->loaded_images)
1611                return;
1612
1613        g_hash_table_foreach (factory->loaded_images, ref_image_ptr, NULL);
1614}
1615
1616void
1617html_image_factory_unref_all_images (HTMLImageFactory *factory)
1618{
1619        if (!factory->loaded_images)
1620                return;
1621
1622        g_hash_table_foreach (factory->loaded_images, unref_image_ptr, NULL);
1623}
1624
1625void
1626html_image_factory_ref_image_ptr (HTMLImageFactory *factory, const gchar *url)
1627{
1628        HTMLImagePointer *ptr;
1629
1630        if (!factory->loaded_images)
1631                return;
1632
1633        ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
1634        if (ptr)
1635                html_image_pointer_ref (ptr);
1636}
1637
1638void
1639html_image_factory_unref_image_ptr (HTMLImageFactory *factory, const gchar *url)
1640{
1641        HTMLImagePointer *ptr;
1642
1643        if (!factory->loaded_images)
1644                return;
1645
1646        ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
1647        if (ptr)
1648                html_image_pointer_unref (ptr);
1649}
Note: See TracBrowser for help on using the repository browser.