~ubuntu-branches/ubuntu/trusty/gtkhtml3.14/trusty-proposed

« back to all changes in this revision

Viewing changes to src/htmlimage.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-03-13 11:26:39 UTC
  • Revision ID: james.westby@ubuntu.com-20070313112639-5calgv5774i4f95v
Tags: upstream-3.14.0
ImportĀ upstreamĀ versionĀ 3.14.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
56
struct _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
 
 
69
static HTMLImageClass html_image_class;
 
70
static HTMLObjectClass *parent_class = NULL;
 
71
 
 
72
static HTMLImagePointer   *html_image_pointer_new               (const char *filename, HTMLImageFactory *factory);
 
73
static void                html_image_pointer_ref               (HTMLImagePointer *ip);
 
74
static void                html_image_pointer_unref             (HTMLImagePointer *ip);
 
75
static gboolean            html_image_pointer_timeout           (HTMLImagePointer *ip);
 
76
static gint                html_image_pointer_update            (HTMLImagePointer *ip);
 
77
static void                html_image_pointer_start_animation   (HTMLImagePointer *ip);
 
78
 
 
79
static GdkPixbuf *         html_image_factory_get_missing       (HTMLImageFactory *factory);
 
80
 
 
81
guint
 
82
html_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
 
 
114
guint
 
115
html_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.  */
 
153
static void
 
154
destroy (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
 
 
173
static void
 
174
copy (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
 
 
216
static void 
 
217
image_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
 
 
249
static HTMLObject *
 
250
check_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
 
 
270
static gint
 
271
calc_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
 
 
290
static gint
 
291
calc_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
 
 
303
static gboolean
 
304
html_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
                HTMLClueFlow *cf = html_object_get_flow (o);
 
321
 
 
322
                if (cf)
 
323
                        html_painter_set_font_style (painter, html_clueflow_get_default_font_style (cf));
 
324
 
 
325
                html_painter_set_font_face (painter, NULL);
 
326
                /* FIXME: cache items and glyphs? */
 
327
                html_painter_calc_text_size (painter, image->alt, g_utf8_strlen (image->alt, -1),
 
328
                                             &o->width, &o->ascent, &o->descent);
 
329
        } else {
 
330
                width = html_image_get_actual_width (image, painter);
 
331
                height = html_image_get_actual_height (image, painter);
 
332
 
 
333
                o->width  = width + (image->border + image->hspace) * 2 * pixel_size;
 
334
                o->ascent = height + (image->border + image->vspace) * 2 * pixel_size;
 
335
                o->descent = 0;
 
336
        }
 
337
 
 
338
        if (o->descent != old_descent
 
339
            || o->ascent != old_ascent
 
340
            || o->width != old_width)
 
341
                return TRUE;
 
342
 
 
343
        return FALSE;
 
344
}
 
345
 
 
346
static void
 
347
draw_plain (HTMLObject *o, HTMLPainter *p, gint x, gint y, gint width, gint height, gint tx, gint ty)
 
348
{
 
349
        HTMLImage *img = HTML_IMAGE (o);
 
350
        HTMLEngine *e;
 
351
 
 
352
        if (p->widget && GTK_IS_HTML (p->widget))
 
353
                e = html_object_engine (o, GTK_HTML (p->widget)->engine);
 
354
        else
 
355
                return;
 
356
 
 
357
        if (img->alt && *img->alt) {
 
358
                HTMLClueFlow *cf = html_object_get_flow (o);
 
359
 
 
360
                /* FIXME: cache items and glyphs? */
 
361
                if (o->selected) {
 
362
                        html_painter_set_pen (p, &html_colorset_get_color_allocated
 
363
                                              (e->settings->color_set, p,
 
364
                                               p->focus ? HTMLHighlightColor : HTMLHighlightNFColor)->color);
 
365
                        html_painter_fill_rect (p, o->x + tx, o->y + ty - o->ascent, o->width, o->ascent + o->descent);
 
366
                        html_painter_set_pen (p, &html_colorset_get_color_allocated
 
367
                                              (e->settings->color_set, p,
 
368
                                               p->focus ? HTMLHighlightTextColor : HTMLHighlightTextNFColor)->color);
 
369
                } else { 
 
370
                        html_painter_set_pen (p, &html_colorset_get_color_allocated (e->settings->color_set, p,
 
371
                                                                                     HTMLTextColor)->color);
 
372
                }
 
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));
 
379
        }
 
380
}
 
381
 
 
382
static void
 
383
draw_focus  (HTMLImage *image, HTMLPainter *painter, GdkRectangle *box)
 
384
{
 
385
        HTMLGdkPainter *p;
 
386
        GdkGCValues values;
 
387
        gint8 dash_list[] = { 1, 1 };
 
388
        HTMLEngine *e;
 
389
 
 
390
        if (painter->widget && GTK_IS_HTML (painter->widget))
 
391
                e = html_object_engine (HTML_OBJECT (image), 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
        gdk_gc_set_line_attributes (p->gc, 1, GDK_LINE_ON_OFF_DASH, values.cap_style, values.join_style);
 
406
        gdk_gc_set_dashes (p->gc, 2, dash_list, 2);
 
407
        gdk_draw_rectangle (p->pixmap, p->gc, 0, box->x - p->x1, box->y - p->y1, box->width - 1, box->height - 1);
 
408
        gdk_gc_set_line_attributes (p->gc, 1, values.line_style, values.cap_style, values.join_style);
 
409
}
 
410
 
 
411
static void
 
412
draw (HTMLObject *o,
 
413
      HTMLPainter *painter,
 
414
      gint x, gint y,
 
415
      gint width, gint height,
 
416
      gint tx, gint ty)
 
417
{
 
418
        HTMLImage *image;
 
419
        HTMLImagePointer *ip;
 
420
        GdkPixbuf *pixbuf;
 
421
        gint base_x, base_y;
 
422
        gint scale_width, scale_height;
 
423
        GdkColor *highlight_color;
 
424
        guint pixel_size;
 
425
        GdkRectangle paint;
 
426
        HTMLEngine *e;
 
427
 
 
428
        if (painter->widget && GTK_IS_HTML (painter->widget))
 
429
                e = html_object_engine (o, GTK_HTML (painter->widget)->engine);
 
430
        else
 
431
                return;
 
432
 
 
433
        /* printf ("Image::draw\n"); */
 
434
 
 
435
        if (!html_object_intersect (o, &paint, x, y, width, height))
 
436
                return;
 
437
 
 
438
        if (HTML_IS_PLAIN_PAINTER (painter)) {
 
439
                draw_plain (o, painter, x, y, width, height, tx, ty);
 
440
                return;
 
441
        }
 
442
 
 
443
        image = HTML_IMAGE (o);
 
444
        ip = image->image_ptr;
 
445
 
 
446
        image->animation_active = TRUE;
 
447
 
 
448
        if (ip->animation) {
 
449
                if (HTML_IS_GDK_PAINTER (painter) && !gdk_pixbuf_animation_is_static_image (ip->animation)) {
 
450
                        pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (ip->iter);
 
451
                } else {
 
452
                        pixbuf = gdk_pixbuf_animation_get_static_image (ip->animation);
 
453
                }
 
454
        } else {
 
455
                pixbuf = NULL;
 
456
        }
 
457
 
 
458
        pixel_size = html_painter_get_pixel_size (painter);
 
459
 
 
460
        if (o->selected) {
 
461
                highlight_color = &html_colorset_get_color_allocated
 
462
                        (e->settings->color_set, painter,
 
463
                         painter->focus ? HTMLHighlightColor : HTMLHighlightNFColor)->color;
 
464
        } else
 
465
                highlight_color = NULL;
 
466
 
 
467
        base_x = o->x + tx + (image->border + image->hspace) * pixel_size;
 
468
        base_y = o->y + ty + (image->border + image->vspace) * pixel_size - o->ascent;
 
469
 
 
470
        if (pixbuf == NULL) {
 
471
                gint vspace, hspace;
 
472
 
 
473
                hspace = image->hspace * pixel_size;
 
474
                vspace = image->vspace * pixel_size;
 
475
 
 
476
                if (image->image_ptr->loader && !image->image_ptr->stall) 
 
477
                        return;
 
478
 
 
479
                if (o->selected) {
 
480
                        html_painter_set_pen (painter, highlight_color);
 
481
                        html_painter_fill_rect (painter, 
 
482
                                                o->x + tx + hspace,
 
483
                                                o->y + ty - o->ascent + vspace,
 
484
                                                o->width - 2 * hspace,
 
485
                                                o->ascent + o->descent - 2 * vspace);
 
486
                }
 
487
                html_painter_draw_border (painter,
 
488
                                          &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
 
489
                                          o->x + tx + hspace,
 
490
                                          o->y + ty - o->ascent + vspace,
 
491
                                          o->width - 2 * hspace,
 
492
                                          o->ascent + o->descent - 2 * vspace,
 
493
                                          HTML_BORDER_INSET, 1);
 
494
 
 
495
                if (ip->factory)
 
496
                        pixbuf = html_image_factory_get_missing (ip->factory);
 
497
 
 
498
                if (pixbuf && 
 
499
                    (o->width > gdk_pixbuf_get_width (pixbuf)) &&
 
500
                    (o->ascent  + o->descent > gdk_pixbuf_get_height (pixbuf)))
 
501
                        html_painter_draw_pixmap (painter, pixbuf,
 
502
                                                  base_x, base_y,
 
503
                                                  gdk_pixbuf_get_width (pixbuf) * pixel_size,
 
504
                                                  gdk_pixbuf_get_height (pixbuf) * pixel_size,
 
505
                                                  highlight_color);
 
506
                                
 
507
                if (o->draw_focused) {
 
508
                        GdkRectangle rect;
 
509
 
 
510
                        scale_width = html_image_get_actual_width (image, painter);
 
511
                        scale_height = html_image_get_actual_height (image, painter);
 
512
 
 
513
                        rect.x = base_x - image->border * pixel_size;
 
514
                        rect.y = base_y - image->border * pixel_size;
 
515
                        rect.width = scale_width + (2 * image->border) * pixel_size;
 
516
                        rect.height = scale_height + (2 * image->border) * pixel_size;
 
517
 
 
518
                        draw_focus (image, painter, &rect);
 
519
                }                                    
 
520
 
 
521
                return;
 
522
        }
 
523
 
 
524
        scale_width = html_image_get_actual_width (image, painter);
 
525
        scale_height = html_image_get_actual_height (image, painter);
 
526
 
 
527
        if (image->border) {
 
528
                if (image->have_color) {
 
529
                        html_color_alloc (image->color, painter);
 
530
                        html_painter_set_pen (painter, &image->color->color);
 
531
                }
 
532
                
 
533
                html_painter_draw_border (painter,
 
534
                                          &((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
 
535
                                          base_x - image->border * pixel_size,
 
536
                                          base_y - image->border * pixel_size,
 
537
                                          scale_width + (2 * image->border) * pixel_size,
 
538
                                          scale_height + (2 * image->border) * pixel_size,
 
539
                                          HTML_BORDER_SOLID, image->border);
 
540
                
 
541
        }
 
542
        
 
543
        html_painter_draw_pixmap (painter, pixbuf,
 
544
                                  base_x, base_y,
 
545
                                  scale_width, scale_height,
 
546
                                  highlight_color);
 
547
 
 
548
        if (o->draw_focused) {
 
549
                GdkRectangle rect;
 
550
                rect.x = base_x - image->border * pixel_size;
 
551
                rect.y = base_y - image->border * pixel_size;
 
552
                rect.width = scale_width + (2 * image->border) * pixel_size;
 
553
                rect.height = scale_height + (2 * image->border) * pixel_size;
 
554
 
 
555
                draw_focus (image, painter, &rect);
 
556
        }
 
557
}
 
558
 
 
559
gchar *
 
560
html_image_resolve_image_url (GtkHTML *html, gchar *image_url)
 
561
{
 
562
        gchar *url = NULL;
 
563
 
 
564
        /* printf ("html_image_resolve_image_url %p\n", html->editor_api); */
 
565
        if (html->editor_api) {
 
566
                GValue  *iarg = g_new0 (GValue, 1);
 
567
                GValue  *oarg;
 
568
 
 
569
                g_value_init (iarg, G_TYPE_STRING);
 
570
                g_value_set_string (iarg, image_url);
 
571
 
 
572
                oarg = (* html->editor_api->event) (html, GTK_HTML_EDITOR_EVENT_IMAGE_URL, iarg, html->editor_data);
 
573
 
 
574
                if (oarg) {
 
575
                        if (G_VALUE_TYPE (oarg) == G_TYPE_STRING)
 
576
                                url = (gchar *) g_strdup (g_value_get_string (oarg));
 
577
 
 
578
                        g_value_unset (oarg);
 
579
                        g_free (oarg);
 
580
                }
 
581
                g_value_unset (iarg);
 
582
                g_free (iarg);
 
583
        }
 
584
        if (!url)
 
585
                url = g_strdup (image_url);
 
586
        /* printf ("image URL resolved to: %s (from: %s)\n", url, image_url); */
 
587
 
 
588
        return url;
 
589
}
 
590
 
 
591
static gboolean
 
592
save (HTMLObject *self,
 
593
      HTMLEngineSaveState *state)
 
594
{
 
595
        HTMLImage *image;
 
596
        gchar *url;
 
597
        gboolean result, link = FALSE;
 
598
 
 
599
        g_return_val_if_fail (self != NULL, FALSE);
 
600
        g_return_val_if_fail (state != NULL, FALSE);
 
601
 
 
602
        image  = HTML_IMAGE (self);
 
603
 
 
604
        if (image->url && *image->url) {
 
605
                url  = g_strconcat (image->url, image->target ? "#" : "", image->target, NULL);
 
606
                link = TRUE;
 
607
                result = html_engine_save_output_string (state, "<A HREF=\"%s\">", url);
 
608
                g_free (url);
 
609
                if (!result)
 
610
                        return FALSE;   
 
611
        }
 
612
 
 
613
        url    = html_image_resolve_image_url (state->engine->widget, image->image_ptr->url);
 
614
        result = html_engine_save_output_string (state, "<IMG SRC=\"%s\"", url);
 
615
        g_free (url);
 
616
        if (!result)
 
617
                return FALSE;   
 
618
 
 
619
        if (image->percent_width) {
 
620
                if (!html_engine_save_output_string (state, " WIDTH=\"%d%%\"", image->specified_width))
 
621
                        return FALSE;
 
622
        } else if (image->specified_width > 0) {
 
623
                if (!html_engine_save_output_string (state, " WIDTH=\"%d\"", image->specified_width))
 
624
                        return FALSE;
 
625
        }
 
626
 
 
627
        if (image->percent_height) {
 
628
                if (!html_engine_save_output_string (state, " HEIGHT=\"%d%%\"", image->specified_height))
 
629
                        return FALSE;
 
630
        } else if (image->specified_height > 0) {
 
631
                if (!html_engine_save_output_string (state, " HEIGHT=\"%d\"", image->specified_height))
 
632
                        return FALSE;
 
633
        }
 
634
 
 
635
        if (image->vspace) {
 
636
                if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
 
637
                        return FALSE;
 
638
        }
 
639
 
 
640
        if (image->hspace) {
 
641
                if (!html_engine_save_output_string (state, " HSPACE=\"%d\"", image->hspace))
 
642
                        return FALSE;
 
643
        }
 
644
 
 
645
        if (image->vspace) {
 
646
                if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
 
647
                        return FALSE;
 
648
        }
 
649
 
 
650
        if (image->valign != HTML_VALIGN_NONE) {
 
651
                if (!html_engine_save_output_string (state, " ALIGN=\"%s\"", html_valign_name (image->valign)))
 
652
                        return FALSE;
 
653
        }
 
654
 
 
655
        if (image->alt) {
 
656
                if (!html_engine_save_output_string (state, " ALT=\"%s\"", image->alt))
 
657
                        return FALSE;
 
658
        }
 
659
 
 
660
        /* FIXME this is the default set in htmlengine.c but there is no real way to tell
 
661
         * if the usr specified it directly
 
662
         */
 
663
        if (image->border != 2) {
 
664
                if (!html_engine_save_output_string (state, " BORDER=\"%d\"", image->border))
 
665
                        return FALSE;
 
666
        }
 
667
 
 
668
        if (!html_engine_save_output_string (state, ">"))
 
669
                return FALSE;
 
670
        if (link && !html_engine_save_output_string (state, "</A>"))
 
671
                return FALSE;
 
672
        
 
673
        return TRUE;
 
674
}
 
675
 
 
676
static gboolean
 
677
save_plain (HTMLObject *self,
 
678
            HTMLEngineSaveState *state,
 
679
            gint requested_width)
 
680
{
 
681
        HTMLImage *image;
 
682
        gboolean rv = TRUE;
 
683
 
 
684
        image = HTML_IMAGE (self);
 
685
        
 
686
        if (image->alt)
 
687
                rv = html_engine_save_output_string (state, "%s", image->alt);
 
688
 
 
689
        return rv;
 
690
}
 
691
 
 
692
static const gchar *
 
693
get_url (HTMLObject *o, gint offset)
 
694
{
 
695
        HTMLImage *image;
 
696
 
 
697
        image = HTML_IMAGE (o);
 
698
        return image->final_url ? image->final_url : image->url;
 
699
}
 
700
 
 
701
static const gchar *
 
702
get_target (HTMLObject *o, gint offset)
 
703
{
 
704
        HTMLImage *image;
 
705
 
 
706
        image = HTML_IMAGE (o);
 
707
        return image->target;
 
708
}
 
709
 
 
710
static const gchar *
 
711
get_src (HTMLObject *o)
 
712
{
 
713
        HTMLImage *image;
 
714
        
 
715
        image = HTML_IMAGE (o);
 
716
        return image->image_ptr->url;
 
717
}
 
718
 
 
719
static HTMLObject *
 
720
set_link (HTMLObject *self, HTMLColor *color, const gchar *url, const gchar *target)
 
721
{
 
722
        HTMLImage *image = HTML_IMAGE (self);
 
723
 
 
724
        STRDUP_HELPER (image->url, url);
 
725
        STRDUP_HELPER (image->target, target);
 
726
        if (image->have_color)
 
727
                html_color_unref (image->color);
 
728
        image->color = color;
 
729
        if (color) {
 
730
                html_color_ref (color);
 
731
                image->have_color = TRUE;
 
732
        } else {
 
733
                image->have_color = FALSE;
 
734
        }
 
735
 
 
736
        return NULL;
 
737
}
 
738
 
 
739
static gboolean
 
740
accepts_cursor (HTMLObject *o)
 
741
{
 
742
        return TRUE;
 
743
}
 
744
 
 
745
static HTMLVAlignType
 
746
get_valign (HTMLObject *self)
 
747
{
 
748
        HTMLImage *image;
 
749
 
 
750
        image = HTML_IMAGE (self);
 
751
 
 
752
        return image->valign;
 
753
}
 
754
 
 
755
static gboolean
 
756
select_range (HTMLObject *self,
 
757
              HTMLEngine *engine,
 
758
              guint offset,
 
759
              gint length,
 
760
              gboolean queue_draw)
 
761
{
 
762
        /* printf ("IMAGE: select range\n"); */
 
763
        if ((*parent_class->select_range) (self, engine, offset, length, queue_draw)) {
 
764
                if (queue_draw) {
 
765
                        html_engine_queue_draw (engine, self);
 
766
                        /* printf ("IMAGE: draw queued\n"); */
 
767
                }
 
768
                return TRUE;
 
769
        } else
 
770
                return FALSE;
 
771
}
 
772
 
 
773
 
 
774
void
 
775
html_image_type_init (void)
 
776
{
 
777
        html_image_class_init (&html_image_class, HTML_TYPE_IMAGE, sizeof (HTMLImage));
 
778
}
 
779
 
 
780
void
 
781
html_image_class_init (HTMLImageClass *image_class,
 
782
                       HTMLType type,
 
783
                       guint size)
 
784
{
 
785
        HTMLObjectClass *object_class;
 
786
 
 
787
        object_class = HTML_OBJECT_CLASS (image_class);
 
788
 
 
789
        html_object_class_init (object_class, type, size);
 
790
 
 
791
        object_class->copy = copy;
 
792
        object_class->draw = draw;      
 
793
        object_class->destroy = destroy;
 
794
        object_class->calc_min_width = calc_min_width;
 
795
        object_class->calc_preferred_width = calc_preferred_width;
 
796
        object_class->calc_size = html_image_real_calc_size;
 
797
        object_class->check_point = check_point;
 
798
        object_class->get_url = get_url;
 
799
        object_class->get_target = get_target;
 
800
        object_class->get_src = get_src;
 
801
        object_class->set_link = set_link;
 
802
        object_class->accepts_cursor = accepts_cursor;
 
803
        object_class->get_valign = get_valign;
 
804
        object_class->save = save;
 
805
        object_class->save_plain = save_plain;
 
806
        object_class->select_range = select_range;
 
807
 
 
808
        parent_class = &html_object_class;
 
809
}
 
810
 
 
811
void
 
812
html_image_init (HTMLImage *image,
 
813
                 HTMLImageClass *klass,
 
814
                 HTMLImageFactory *imf,
 
815
                 const gchar *filename,
 
816
                 const gchar *url,
 
817
                 const gchar *target,
 
818
                 gint16 width, gint16 height,
 
819
                 gboolean percent_width, gboolean percent_height,
 
820
                 gint8 border,
 
821
                 HTMLColor *color,
 
822
                 HTMLVAlignType valign,
 
823
                 gboolean reload)
 
824
{
 
825
        HTMLObject *object;
 
826
 
 
827
        g_assert (filename);
 
828
 
 
829
        object = HTML_OBJECT (image);
 
830
 
 
831
        html_object_init (object, HTML_OBJECT_CLASS (klass));
 
832
 
 
833
        image->animation_active = FALSE;
 
834
        image->url = g_strdup (url);
 
835
        image->target = g_strdup (target);
 
836
        image->usemap = NULL;
 
837
        image->final_url = NULL;
 
838
        image->ismap = FALSE;
 
839
 
 
840
        image->specified_width  = width;
 
841
        image->specified_height = height;
 
842
        image->percent_width    = percent_width;
 
843
        image->percent_height   = percent_height;
 
844
        image->border           = border;
 
845
 
 
846
        if (color) {
 
847
                image->color = color;
 
848
                image->have_color = TRUE;
 
849
                html_color_ref (color);
 
850
        } else {
 
851
                image->color = NULL;
 
852
                image->have_color = FALSE;
 
853
        }
 
854
 
 
855
        image->alt = NULL;
 
856
 
 
857
        image->hspace = 0;
 
858
        image->vspace = 0;
 
859
 
 
860
        if (valign == HTML_VALIGN_NONE)
 
861
                valign = HTML_VALIGN_BOTTOM;
 
862
        image->valign = valign;
 
863
 
 
864
        image->image_ptr = html_image_factory_register (imf, image, filename, reload);
 
865
}
 
866
 
 
867
HTMLObject *
 
868
html_image_new (HTMLImageFactory *imf,
 
869
                const gchar *filename,
 
870
                const gchar *url,
 
871
                const gchar *target,
 
872
                gint16 width, gint16 height,
 
873
                gboolean percent_width, gboolean percent_height,
 
874
                gint8 border,   
 
875
                HTMLColor *color,
 
876
                HTMLVAlignType valign,
 
877
                gboolean reload)
 
878
{
 
879
        HTMLImage *image;
 
880
 
 
881
        image = g_new(HTMLImage, 1);
 
882
 
 
883
        html_image_init (image, &html_image_class,
 
884
                         imf,
 
885
                         filename,
 
886
                         url,
 
887
                         target,
 
888
                         width, height,
 
889
                         percent_width, percent_height,
 
890
                         border,
 
891
                         color,
 
892
                         valign,
 
893
                         reload);
 
894
 
 
895
        return HTML_OBJECT (image);
 
896
}
 
897
 
 
898
void
 
899
html_image_set_spacing (HTMLImage *image, gint hspace, gint vspace)
 
900
{
 
901
        gboolean changed = FALSE;
 
902
 
 
903
        if (image->hspace != hspace) {
 
904
                image->hspace = hspace;
 
905
                changed = TRUE;
 
906
        }
 
907
 
 
908
        if (image->vspace != vspace) {
 
909
                image->vspace = vspace;
 
910
                changed = TRUE;
 
911
        }
 
912
 
 
913
        if (changed) {
 
914
                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
 
915
                html_engine_schedule_update (image->image_ptr->factory->engine);
 
916
        }
 
917
}
 
918
 
 
919
void
 
920
html_image_edit_set_url (HTMLImage *image, const gchar *url)
 
921
{
 
922
        if (url) {
 
923
                HTMLImageFactory *imf = image->image_ptr->factory;
 
924
 
 
925
                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
 
926
                html_image_factory_unregister (imf, image->image_ptr, HTML_IMAGE (image));
 
927
                image->image_ptr = html_image_factory_register (imf, image, url, TRUE);
 
928
                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
 
929
                html_engine_schedule_update (imf->engine);
 
930
        }
 
931
}
 
932
 
 
933
void
 
934
html_image_set_url (HTMLImage *image, const gchar *url)
 
935
{
 
936
        if (url && strcmp (image->image_ptr->url, url)) {
 
937
                HTMLImageFactory *imf = image->image_ptr->factory;
 
938
 
 
939
                html_image_factory_unregister (imf, image->image_ptr, HTML_IMAGE (image));
 
940
                image->image_ptr = html_image_factory_register (imf, image, url, FALSE);
 
941
        }
 
942
}
 
943
 
 
944
void
 
945
html_image_set_valign (HTMLImage *image, HTMLVAlignType valign)
 
946
{
 
947
        if (image->valign != valign) {
 
948
                image->valign = valign;
 
949
                html_engine_schedule_update (image->image_ptr->factory->engine);
 
950
        }
 
951
}
 
952
 
 
953
void
 
954
html_image_set_border (HTMLImage *image, gint border)
 
955
{
 
956
        if (image->border != border) {
 
957
                image->border = border;
 
958
                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
 
959
                html_engine_schedule_update (image->image_ptr->factory->engine);
 
960
        }
 
961
}
 
962
 
 
963
void
 
964
html_image_set_alt (HTMLImage *image, gchar *alt)
 
965
{
 
966
        g_free (image->alt);
 
967
        image->alt = g_strdup (alt);
 
968
}
 
969
 
 
970
void
 
971
html_image_set_map (HTMLImage *image, gchar *usemap, gboolean ismap)
 
972
{
 
973
        char *url = NULL;
 
974
 
 
975
        g_free (image->usemap);
 
976
 
 
977
        if (usemap != NULL) {
 
978
                image->ismap = FALSE;
 
979
                url = g_strdup (usemap);
 
980
        } else {
 
981
                image->ismap = ismap;
 
982
        }
 
983
        image->usemap = url;
 
984
}
 
985
 
 
986
void
 
987
html_image_set_size (HTMLImage *image, gint w, gint h, gboolean pw, gboolean ph)
 
988
{
 
989
        gboolean changed = FALSE;
 
990
 
 
991
        if (pw != image->percent_width) {
 
992
                image->percent_width = pw;
 
993
                changed = TRUE;
 
994
        }
 
995
 
 
996
        if (ph != image->percent_height) {
 
997
                image->percent_height = ph;
 
998
                changed = TRUE;
 
999
        }
 
1000
 
 
1001
        if (w != image->specified_width) {
 
1002
                image->specified_width = w;
 
1003
                changed = TRUE;
 
1004
        }
 
1005
 
 
1006
        if (h != image->specified_height) {
 
1007
                image->specified_height = h;
 
1008
                changed = TRUE;
 
1009
        }
 
1010
 
 
1011
        if (changed) {
 
1012
                html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
 
1013
                html_engine_schedule_update (image->image_ptr->factory->engine);
 
1014
        }
 
1015
}
 
1016
 
 
1017
static char *fallback_image_content_types[] = {"image/*", NULL};
 
1018
 
 
1019
static char **
 
1020
html_image_factory_types (GtkHTMLStream *stream,
 
1021
                          gpointer user_data)
 
1022
{
 
1023
        static char**image_content_types = NULL;
 
1024
        
 
1025
#if 0
 
1026
        /* this code should work in gtk+-2.2 but it is untested */
 
1027
        if (image_content_types == NULL) {
 
1028
                GSList *formats;
 
1029
                GSList *cur;
 
1030
                GSList *types = NULL;
 
1031
                gint i;
 
1032
 
 
1033
                formats = gdk_pixbuf_get_formats ();
 
1034
                
 
1035
                for (cur = formats; cur; cur = cur->next) {
 
1036
                        GdkPixbufFormat *format = cur->data;
 
1037
                        char **mime;
 
1038
 
 
1039
                        mime = gdk_pixbuf_formats_get_mime_types ();
 
1040
                        for (i = 0; mime && mime[i]; i++)
 
1041
                                g_slist_prepend (types, g_strdup (mime[i]));
 
1042
 
 
1043
                }
 
1044
                g_slist_free (formats);
 
1045
 
 
1046
                if (types) {
 
1047
                        image_content_types = g_new0 (char *, g_slist_length (types) + 1);
 
1048
                        
 
1049
                        for (cur = types, i = 0; cur; cur = cur->next, i++) {
 
1050
                                image_content_types[i] = cur->data;
 
1051
                        }
 
1052
                        g_slist_free (types);
 
1053
                } else {
 
1054
                        image_content_types = fallback_image_content_types;
 
1055
                }
 
1056
        }
 
1057
#else 
 
1058
        image_content_types = fallback_image_content_types;
 
1059
#endif
 
1060
 
 
1061
        return image_content_types;
 
1062
}
 
1063
 
 
1064
static void
 
1065
update_or_redraw (HTMLImagePointer *ip){
 
1066
        GSList *list;
 
1067
        gboolean update = FALSE;
 
1068
 
 
1069
        for (list = ip->interests; list; list = list->next) {
 
1070
                if (list->data == NULL)
 
1071
                        update = TRUE;
 
1072
                else {
 
1073
                        HTMLImage *image = HTML_IMAGE (list->data);
 
1074
                        gint pixel_size = html_painter_get_pixel_size (ip->factory->engine->painter);
 
1075
                        gint w, h;
 
1076
 
 
1077
                        w = html_image_get_actual_width (image, ip->factory->engine->painter)
 
1078
                                + (image->border * 2 + 2 * image->hspace) * pixel_size;
 
1079
                        h = html_image_get_actual_height (image, ip->factory->engine->painter)
 
1080
                                + (image->border * 2 + 2 * image->vspace) * pixel_size;
 
1081
 
 
1082
                        /* printf ("%dx%d  <-->  %dx%d\n", w, h, HTML_OBJECT (list->data)->width,
 
1083
                           HTML_OBJECT (list->data)->ascent + HTML_OBJECT (list->data)->descent); */
 
1084
 
 
1085
                        if (w != HTML_OBJECT (list->data)->width
 
1086
                            || h != HTML_OBJECT (list->data)->ascent + HTML_OBJECT (list->data)->descent) {
 
1087
                                html_object_change_set (HTML_OBJECT (list->data), HTML_CHANGE_ALL_CALC);
 
1088
                                update = TRUE;
 
1089
                        }
 
1090
                }
 
1091
        }
 
1092
 
 
1093
        if (ip->factory->engine->block && ip->factory->engine->opened_streams)
 
1094
                return;
 
1095
 
 
1096
        if (!update) {
 
1097
                /* printf ("REDRAW\n"); */
 
1098
                for (list = ip->interests; list; list = list->next)
 
1099
                        if (list->data) /* && html_object_is_visible (HTML_OBJECT (list->data))) */
 
1100
                                html_engine_queue_draw (ip->factory->engine, HTML_OBJECT (list->data));
 
1101
                if (ip->interests)
 
1102
                        html_engine_flush_draw_queue (ip->factory->engine);
 
1103
        } else {
 
1104
                /* printf ("UPDATE\n"); */
 
1105
                html_engine_schedule_update (ip->factory->engine);
 
1106
        }
 
1107
}
 
1108
 
 
1109
static void
 
1110
html_image_factory_end_pixbuf (GtkHTMLStream *stream,
 
1111
                               GtkHTMLStreamStatus status,
 
1112
                               gpointer user_data)
 
1113
{
 
1114
        HTMLImagePointer *ip = user_data;
 
1115
 
 
1116
        gdk_pixbuf_loader_close (ip->loader, NULL);
 
1117
 
 
1118
        if (!ip->animation) {
 
1119
                ip->animation = gdk_pixbuf_loader_get_animation (ip->loader);
 
1120
 
 
1121
                if (ip->animation)
 
1122
                        g_object_ref (ip->animation);
 
1123
        }
 
1124
        html_image_pointer_start_animation (ip);
 
1125
 
 
1126
        g_object_unref (ip->loader);
 
1127
        ip->loader = NULL;
 
1128
 
 
1129
        update_or_redraw (ip);
 
1130
        if (ip->factory->engine->opened_streams && ip->factory->engine->block_images)
 
1131
                html_engine_opened_streams_decrement (ip->factory->engine);
 
1132
        /* printf ("IMAGE(%p) opened streams: %d\n", ip->factory->engine, ip->factory->engine->opened_streams); */
 
1133
        if (ip->factory->engine->opened_streams == 0 && ip->factory->engine->block && ip->factory->engine->block_images)
 
1134
                html_engine_schedule_update (ip->factory->engine);
 
1135
        html_image_pointer_unref (ip);
 
1136
}
 
1137
 
 
1138
static void
 
1139
html_image_factory_write_pixbuf (GtkHTMLStream *stream,
 
1140
                                 const gchar *buffer,
 
1141
                                 size_t size,
 
1142
                                 gpointer user_data)
 
1143
{
 
1144
        HTMLImagePointer *p = user_data;
 
1145
 
 
1146
        /* FIXME ! Check return value */
 
1147
        gdk_pixbuf_loader_write (p->loader, (const guchar *) buffer, size, NULL);
 
1148
}
 
1149
 
 
1150
static void
 
1151
html_image_pointer_queue_animation (HTMLImagePointer *ip)
 
1152
{
 
1153
        if (!ip->animation_timeout && ip->factory && ip->factory->animate) {
 
1154
                gint delay; 
 
1155
                
 
1156
                gdk_pixbuf_animation_iter_advance (ip->iter, NULL);
 
1157
                delay = gdk_pixbuf_animation_iter_get_delay_time (ip->iter);
 
1158
                
 
1159
                ip->animation_timeout = g_timeout_add (delay, 
 
1160
                                                       (GtkFunction) html_image_pointer_update, 
 
1161
                                                       (gpointer) ip);
 
1162
        }
 
1163
        
 
1164
}
 
1165
 
 
1166
static gint
 
1167
html_image_pointer_update (HTMLImagePointer *ip)
 
1168
{
 
1169
        HTMLEngine *engine = ip->factory->engine;
 
1170
        GSList *cur;
 
1171
 
 
1172
        g_return_val_if_fail (ip->factory != NULL, FALSE);
 
1173
        ip->animation_timeout = 0;
 
1174
                
 
1175
        DA (printf ("animation_timeout (%p)\n", ip);)
 
1176
        for (cur = ip->interests; cur; cur = cur->next) {
 
1177
                HTMLImage           *image = cur->data;
 
1178
                
 
1179
                if (image && image->animation_active && html_object_is_parent (engine->clue, HTML_OBJECT (image))) {
 
1180
                        DA (printf ("queue draw (%p)\n", image);)
 
1181
 
 
1182
                        image->animation_active = FALSE;
 
1183
                        html_engine_queue_draw (engine, HTML_OBJECT (image));
 
1184
                }
 
1185
        }
 
1186
        
 
1187
        html_image_pointer_start_animation (ip);
 
1188
        return FALSE;
 
1189
}
 
1190
 
 
1191
static void
 
1192
html_image_pointer_start_animation (HTMLImagePointer *ip)
 
1193
{
 
1194
        if (ip->animation && !gdk_pixbuf_animation_is_static_image (ip->animation)) {
 
1195
                if (!ip->iter)
 
1196
                        ip->iter = gdk_pixbuf_animation_get_iter (ip->animation, NULL);
 
1197
 
 
1198
                html_image_pointer_queue_animation (ip);
 
1199
        }
 
1200
}
 
1201
 
 
1202
static void
 
1203
html_image_pointer_stop_animation (HTMLImagePointer *ip)
 
1204
{
 
1205
        if (ip->animation_timeout) {
 
1206
                g_source_remove (ip->animation_timeout);
 
1207
                ip->animation_timeout = 0;
 
1208
        }
 
1209
}
 
1210
 
 
1211
static void
 
1212
html_image_factory_area_updated (GdkPixbufLoader *loader, guint x, guint y, guint width, guint height, HTMLImagePointer *ip)
 
1213
{
 
1214
        html_image_pointer_stop_animation (ip);
 
1215
        /* update will requeue */
 
1216
        html_image_pointer_update (ip);
 
1217
}
 
1218
 
 
1219
static void
 
1220
html_image_factory_area_prepared (GdkPixbufLoader *loader, HTMLImagePointer *ip)
 
1221
{
 
1222
        if (!ip->animation) {
 
1223
                ip->animation = gdk_pixbuf_loader_get_animation (loader);
 
1224
                g_object_ref (ip->animation);
 
1225
                
 
1226
                html_image_pointer_start_animation (ip);
 
1227
        }
 
1228
        update_or_redraw (ip);
 
1229
}
 
1230
 
 
1231
static GdkPixbuf *
 
1232
html_image_factory_get_missing (HTMLImageFactory *factory)
 
1233
{
 
1234
        if (!factory->missing)
 
1235
                factory->missing = gtk_widget_render_icon (GTK_WIDGET (factory->engine->widget),
 
1236
                                                          GTK_STOCK_MISSING_IMAGE,
 
1237
                                                          GTK_ICON_SIZE_BUTTON, "GtkHTML.ImageMissing");
 
1238
        return factory->missing;
 
1239
}
 
1240
 
 
1241
HTMLImageFactory *
 
1242
html_image_factory_new (HTMLEngine *e)
 
1243
{
 
1244
        HTMLImageFactory *retval;
 
1245
        retval = g_new (HTMLImageFactory, 1);
 
1246
        retval->engine = e;
 
1247
        retval->loaded_images = g_hash_table_new (g_str_hash, g_str_equal);
 
1248
        retval->missing = NULL;
 
1249
        retval->animate = TRUE;
 
1250
 
 
1251
        return retval;
 
1252
}
 
1253
 
 
1254
static gboolean
 
1255
cleanup_images (gpointer key, gpointer value, gpointer free_everything)
 
1256
{
 
1257
        HTMLImagePointer *ip = value;
 
1258
 
 
1259
        /* free_everything means: NULL only clean, non-NULL free */
 
1260
        if (free_everything){
 
1261
                if (ip->interests != NULL) {
 
1262
                        g_slist_free (ip->interests);
 
1263
                        ip->interests = NULL;
 
1264
                }
 
1265
        }
 
1266
 
 
1267
        /* clean only if this image is not used anymore */
 
1268
        if (!ip->interests){
 
1269
                html_image_pointer_unref (ip);
 
1270
                ip->factory = NULL;
 
1271
                return TRUE;
 
1272
        }
 
1273
 
 
1274
        return FALSE;
 
1275
}
 
1276
 
 
1277
void
 
1278
html_image_factory_cleanup (HTMLImageFactory *factory)
 
1279
{
 
1280
        g_return_if_fail (factory);
 
1281
        g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, NULL);
 
1282
}
 
1283
 
 
1284
void
 
1285
html_image_factory_free (HTMLImageFactory *factory)
 
1286
{
 
1287
        g_return_if_fail (factory);
 
1288
 
 
1289
        g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, factory);
 
1290
        g_hash_table_destroy (factory->loaded_images);
 
1291
 
 
1292
        if (factory->missing)
 
1293
                g_object_unref (factory->missing);
 
1294
 
 
1295
        g_free (factory);
 
1296
}
 
1297
 
 
1298
#define STALL_INTERVAL 1000
 
1299
 
 
1300
static HTMLImagePointer *
 
1301
html_image_pointer_new (const char *filename, HTMLImageFactory *factory)
 
1302
{
 
1303
        HTMLImagePointer *retval;
 
1304
 
 
1305
        retval = g_new (HTMLImagePointer, 1);
 
1306
        retval->refcount = 1;
 
1307
        retval->url = g_strdup (filename);
 
1308
        retval->loader = gdk_pixbuf_loader_new ();
 
1309
        retval->iter = NULL;
 
1310
        retval->animation = NULL;
 
1311
        retval->interests = NULL;
 
1312
        retval->factory = factory;
 
1313
        retval->stall = FALSE;
 
1314
        retval->stall_timeout = g_timeout_add (STALL_INTERVAL, 
 
1315
                                               (GtkFunction)html_image_pointer_timeout,
 
1316
                                               retval);
 
1317
        retval->animation_timeout = 0;
 
1318
        return retval;
 
1319
}
 
1320
 
 
1321
static gboolean
 
1322
html_image_pointer_timeout (HTMLImagePointer *ip)
 
1323
{
 
1324
        GSList *list;
 
1325
        HTMLImage *image;
 
1326
 
 
1327
        ip->stall_timeout = 0;
 
1328
 
 
1329
        g_return_val_if_fail (ip->factory != NULL, FALSE);
 
1330
 
 
1331
        ip->stall = TRUE;
 
1332
 
 
1333
        list = ip->interests;
 
1334
        /* 
 
1335
         * draw the frame now that we decided they've had enough time to
 
1336
         * load the image
 
1337
         */
 
1338
        if (ip->animation == NULL) {
 
1339
                while (list) {
 
1340
                        image = (HTMLImage *)list->data;
 
1341
 
 
1342
                        if (image)
 
1343
                                html_engine_queue_draw (ip->factory->engine,
 
1344
                                                        HTML_OBJECT (image));
 
1345
                        
 
1346
                        list = list->next;
 
1347
                }
 
1348
        }
 
1349
        return FALSE;
 
1350
}
 
1351
 
 
1352
static void
 
1353
html_image_pointer_ref (HTMLImagePointer *ip)
 
1354
{
 
1355
        ip->refcount++;
 
1356
}
 
1357
 
 
1358
static void
 
1359
free_image_ptr_data (HTMLImagePointer *ip)
 
1360
{
 
1361
        if (ip->loader) {
 
1362
                gdk_pixbuf_loader_close (ip->loader, NULL);
 
1363
                g_object_unref (ip->loader);
 
1364
                ip->loader = NULL;
 
1365
        }
 
1366
        if (ip->animation) {
 
1367
                g_object_unref (ip->animation);
 
1368
                ip->animation = NULL;
 
1369
        }
 
1370
        if (ip->iter) {
 
1371
                g_object_unref (ip->iter);
 
1372
                ip->iter = NULL;
 
1373
        }
 
1374
}
 
1375
 
 
1376
static void
 
1377
html_image_pointer_remove_stall (HTMLImagePointer *ip)
 
1378
{
 
1379
        if (ip->stall_timeout) {
 
1380
                g_source_remove (ip->stall_timeout);
 
1381
                ip->stall_timeout = 0;
 
1382
        }
 
1383
}
 
1384
 
 
1385
static void
 
1386
html_image_pointer_unref (HTMLImagePointer *ip)
 
1387
{
 
1388
        g_return_if_fail (ip != NULL);
 
1389
 
 
1390
        ip->refcount--;
 
1391
        /* printf ("unref(%p) %s --> %d\n", ip, ip->url, ip->refcount); */
 
1392
        if (ip->refcount < 1) {
 
1393
                /* printf ("freeing %s\n", ip->url); */
 
1394
                html_image_pointer_remove_stall (ip);
 
1395
                html_image_pointer_stop_animation (ip);
 
1396
                g_free (ip->url);
 
1397
                free_image_ptr_data (ip);
 
1398
                g_free (ip);
 
1399
        }
 
1400
}
 
1401
 
 
1402
static GtkHTMLStream *
 
1403
html_image_pointer_load (HTMLImagePointer *ip)
 
1404
{
 
1405
        if (ip->factory->engine->stopped)
 
1406
                return NULL;
 
1407
 
 
1408
        html_image_pointer_ref (ip);
 
1409
 
 
1410
        if (ip->factory->engine->block_images)
 
1411
                html_engine_opened_streams_increment (ip->factory->engine);
 
1412
        return gtk_html_stream_new (GTK_HTML (ip->factory->engine->widget),
 
1413
                                    html_image_factory_types,
 
1414
                                    html_image_factory_write_pixbuf,
 
1415
                                    html_image_factory_end_pixbuf,
 
1416
                                    ip);
 
1417
}
 
1418
 
 
1419
HTMLImagePointer *
 
1420
html_image_factory_register (HTMLImageFactory *factory, HTMLImage *i, const char *url, gboolean reload)
 
1421
{
 
1422
        HTMLImagePointer *ip;
 
1423
        GtkHTMLStream *stream = NULL;
 
1424
 
 
1425
        g_return_val_if_fail (factory, NULL);
 
1426
        g_return_val_if_fail (url, NULL);
 
1427
 
 
1428
        ip = g_hash_table_lookup (factory->loaded_images, url);
 
1429
 
 
1430
        if (!ip) {
 
1431
                ip = html_image_pointer_new (url, factory);
 
1432
                g_hash_table_insert (factory->loaded_images, ip->url, ip);
 
1433
                if (*url) {
 
1434
                        g_signal_connect (G_OBJECT (ip->loader), "area_prepared",
 
1435
                                          G_CALLBACK (html_image_factory_area_prepared),
 
1436
                                          ip);
 
1437
 
 
1438
                        g_signal_connect (G_OBJECT (ip->loader), "area_updated",
 
1439
                                          G_CALLBACK (html_image_factory_area_updated),
 
1440
                                          ip);
 
1441
                        stream = html_image_pointer_load (ip);
 
1442
                }
 
1443
        } else {
 
1444
                if (reload) {
 
1445
                        free_image_ptr_data (ip);
 
1446
                        ip->loader = gdk_pixbuf_loader_new ();
 
1447
                        stream = html_image_pointer_load (ip);
 
1448
                }
 
1449
        }
 
1450
 
 
1451
        if (stream)
 
1452
                g_signal_emit_by_name (factory->engine, "url_requested", ip->url, stream);
 
1453
 
 
1454
        html_image_pointer_ref (ip);
 
1455
 
 
1456
        /* we add also NULL ptrs, as we dont want these to be cleaned out */
 
1457
        ip->interests = g_slist_prepend (ip->interests, i);
 
1458
 
 
1459
        if (i) {
 
1460
                i->image_ptr = ip;
 
1461
        }
 
1462
 
 
1463
        return ip;
 
1464
}
 
1465
 
 
1466
#if 0
 
1467
HTMLEngine *
 
1468
html_image_factory_get_engine (HTMLImageFactory *factory)
 
1469
{
 
1470
        return factory->engine;
 
1471
}
 
1472
#endif
 
1473
 
 
1474
void
 
1475
html_image_factory_unregister (HTMLImageFactory *factory, HTMLImagePointer *pointer, HTMLImage *i)
 
1476
{
 
1477
        pointer->interests = g_slist_remove (pointer->interests, i);
 
1478
 
 
1479
        html_image_pointer_unref (pointer);
 
1480
 
 
1481
        if (pointer->refcount == 1) {
 
1482
                g_assert (pointer->interests == NULL);
 
1483
                /*
 
1484
                 * FIXME The factory can be NULL if the image was from an iframe 
 
1485
                 * that has been destroyed and the image is living in the cut buffer
 
1486
                 * this isn't particularly clean and should be refactored.
 
1487
                 *
 
1488
                 * We really need a way to let cut objects know they are living outside
 
1489
                 * the normal flow.
 
1490
                 */
 
1491
                if (factory) 
 
1492
                        g_hash_table_remove (factory->loaded_images, pointer->url);
 
1493
                pointer->factory = NULL;
 
1494
                html_image_pointer_unref (pointer);
 
1495
        }
 
1496
}
 
1497
 
 
1498
static void
 
1499
stop_anim (gpointer key, gpointer value, gpointer user_data)
 
1500
{
 
1501
        HTMLImagePointer *ip = value;
 
1502
        html_image_pointer_remove_stall (ip);
 
1503
        html_image_pointer_stop_animation (ip);
 
1504
}
 
1505
 
 
1506
void
 
1507
html_image_factory_stop_animations (HTMLImageFactory *factory)
 
1508
{
 
1509
        DA (g_warning ("stop animations");)
 
1510
        g_hash_table_foreach (factory->loaded_images, stop_anim, NULL);
 
1511
}
 
1512
 
 
1513
static void
 
1514
start_anim (gpointer key, gpointer value, gpointer user_data)
 
1515
{
 
1516
        HTMLImagePointer *ip = value;
 
1517
        html_image_pointer_start_animation (ip);
 
1518
}
 
1519
 
 
1520
void
 
1521
html_image_factory_start_animations (HTMLImageFactory *factory)
 
1522
{
 
1523
        DA (g_warning ("start animations");)
 
1524
        g_hash_table_foreach (factory->loaded_images, start_anim, NULL);
 
1525
}
 
1526
 
 
1527
gboolean
 
1528
html_image_factory_get_animate (HTMLImageFactory *factory)
 
1529
{
 
1530
        return factory->animate;
 
1531
}
 
1532
 
 
1533
void
 
1534
html_image_factory_set_animate (HTMLImageFactory *factory, gboolean animate)
 
1535
{
 
1536
        if (animate != factory->animate) {
 
1537
                factory->animate = animate;
 
1538
 
 
1539
                if (animate)
 
1540
                        html_image_factory_start_animations (factory);
 
1541
                else 
 
1542
                        html_image_factory_stop_animations (factory);
 
1543
        }
 
1544
}
 
1545
 
 
1546
static gboolean
 
1547
move_image_pointers (gpointer key, gpointer value, gpointer data)
 
1548
{
 
1549
        HTMLImageFactory *dst = HTML_IMAGE_FACTORY (data);
 
1550
        HTMLImagePointer *ip  = HTML_IMAGE_POINTER (value);
 
1551
 
 
1552
        ip->factory = dst;
 
1553
        
 
1554
        g_hash_table_insert (dst->loaded_images, ip->url, ip);
 
1555
        if (!ip->factory->engine->stopped)
 
1556
                g_signal_emit_by_name (ip->factory->engine, "url_requested", ip->url, html_image_pointer_load (ip));
 
1557
 
 
1558
        return TRUE;
 
1559
}
 
1560
 
 
1561
void
 
1562
html_image_factory_move_images (HTMLImageFactory *dst, HTMLImageFactory *src)
 
1563
{
 
1564
        g_hash_table_foreach_remove (src->loaded_images, move_image_pointers, dst);
 
1565
}
 
1566
 
 
1567
static void
 
1568
deactivate_anim (gpointer key, gpointer value, gpointer user_data)
 
1569
{
 
1570
        HTMLImagePointer *ip = value;
 
1571
        GSList *cur = ip->interests;
 
1572
        HTMLImage *image;
 
1573
        
 
1574
 
 
1575
        while (cur) {
 
1576
                if (cur->data) {
 
1577
                        image = (HTMLImage *) cur->data;
 
1578
                        image->animation_active = FALSE;
 
1579
                }
 
1580
                cur = cur->next;
 
1581
        }
 
1582
}
 
1583
 
 
1584
void
 
1585
html_image_factory_deactivate_animations (HTMLImageFactory *factory)
 
1586
{
 
1587
        g_hash_table_foreach (factory->loaded_images, deactivate_anim, NULL);
 
1588
}
 
1589
 
 
1590
static void
 
1591
ref_image_ptr (gpointer key, gpointer val, gpointer data)
 
1592
{
 
1593
        if (HTML_IMAGE_POINTER (val)->animation)
 
1594
                html_image_pointer_ref (HTML_IMAGE_POINTER (val));
 
1595
        /* printf ("ref(%p) %s --> %d\n", val, HTML_IMAGE_POINTER (val)->url, HTML_IMAGE_POINTER (val)->refcount); */
 
1596
}
 
1597
 
 
1598
static void
 
1599
unref_image_ptr (gpointer key, gpointer val, gpointer data)
 
1600
{
 
1601
        if (HTML_IMAGE_POINTER (val)->animation)
 
1602
                html_image_pointer_unref (HTML_IMAGE_POINTER (val));
 
1603
}
 
1604
 
 
1605
void
 
1606
html_image_factory_ref_all_images (HTMLImageFactory *factory)
 
1607
{
 
1608
        if (!factory->loaded_images)
 
1609
                return;
 
1610
 
 
1611
        g_hash_table_foreach (factory->loaded_images, ref_image_ptr, NULL);
 
1612
}
 
1613
 
 
1614
void
 
1615
html_image_factory_unref_all_images (HTMLImageFactory *factory)
 
1616
{
 
1617
        if (!factory->loaded_images)
 
1618
                return;
 
1619
 
 
1620
        g_hash_table_foreach (factory->loaded_images, unref_image_ptr, NULL);
 
1621
}
 
1622
 
 
1623
void
 
1624
html_image_factory_ref_image_ptr (HTMLImageFactory *factory, const gchar *url)
 
1625
{
 
1626
        HTMLImagePointer *ptr;
 
1627
 
 
1628
        if (!factory->loaded_images)
 
1629
                return;
 
1630
 
 
1631
        ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
 
1632
        if (ptr)
 
1633
                html_image_pointer_ref (ptr);
 
1634
}
 
1635
 
 
1636
void
 
1637
html_image_factory_unref_image_ptr (HTMLImageFactory *factory, const gchar *url)
 
1638
{
 
1639
        HTMLImagePointer *ptr;
 
1640
 
 
1641
        if (!factory->loaded_images)
 
1642
                return;
 
1643
 
 
1644
        ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
 
1645
        if (ptr)
 
1646
                html_image_pointer_unref (ptr);
 
1647
}