1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
/* This file is part of the GtkHTML library.
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.
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.
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.
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.
29
#include <gdk-pixbuf/gdk-pixbuf.h>
30
#include <gtk/gtkmain.h>
31
#include <gtk/gtksignal.h>
32
#include <gtk/gtkstock.h>
36
#include "gtkhtml-properties.h"
37
#include "gtkhtml-stream.h"
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"
49
#include "htmlprinter.h"
50
#include "htmlgdkpainter.h"
51
#include "htmlplainpainter.h"
52
#include "htmlsettings.h"
54
/* HTMLImageFactory stuff. */
56
struct _HTMLImageFactory {
58
GHashTable *loaded_images;
64
#define DEFAULT_SIZE 48
65
#define STRDUP_HELPER(i,j) if (i != j) {char *tmp = g_strdup (j); g_free(i); i = tmp;}
69
static HTMLImageClass html_image_class;
70
static HTMLObjectClass *parent_class = NULL;
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);
79
static GdkPixbuf * html_image_factory_get_missing (HTMLImageFactory *factory);
82
html_image_get_actual_width (HTMLImage *image, HTMLPainter *painter)
84
GdkPixbufAnimation *anim = image->image_ptr->animation;
85
gint pixel_size = painter ? html_painter_get_pixel_size (painter) : 1;
88
if (image->percent_width) {
89
/* The cast to `gdouble' is to avoid overflow (eg. when
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;
98
width = gdk_pixbuf_animation_get_width (anim) * pixel_size;
100
if (image->specified_height > 0 || image->percent_height) {
103
scale = ((double) html_image_get_actual_height (image, painter))
104
/ (gdk_pixbuf_animation_get_height (anim) * pixel_size);
115
html_image_get_actual_height (HTMLImage *image, HTMLPainter *painter)
117
GdkPixbufAnimation *anim = image->image_ptr->animation;
118
gint pixel_size = painter ? html_painter_get_pixel_size (painter) : 1;
121
if (image->percent_height) {
122
/* The cast to `gdouble' is to avoid overflow (eg. when
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;
131
height = gdk_pixbuf_animation_get_height (anim) * pixel_size;
133
if (image->specified_width > 0 || image->percent_width) {
136
scale = ((double) html_image_get_actual_width (image, painter))
137
/ (gdk_pixbuf_animation_get_width (anim) * pixel_size);
147
/* HTMLObject methods. */
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
154
destroy (HTMLObject *o)
156
HTMLImage *image = HTML_IMAGE (o);
158
html_image_factory_unregister (image->image_ptr->factory,
159
image->image_ptr, HTML_IMAGE (image));
162
g_free (image->target);
164
g_free (image->usemap);
165
g_free (image->final_url);
168
html_color_unref (image->color);
170
HTML_OBJECT_CLASS (parent_class)->destroy (o);
174
copy (HTMLObject *self,
177
HTMLImage *dimg = HTML_IMAGE (dest);
178
HTMLImage *simg = HTML_IMAGE (self);
180
/* FIXME not sure this is all correct. */
182
(* HTML_OBJECT_CLASS (parent_class)->copy) (self, dest);
184
dimg->image_ptr = simg->image_ptr;
185
dimg->color = simg->color;
187
html_color_ref (dimg->color);
189
dimg->have_color = simg->have_color;
191
dimg->border = simg->border;
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;
199
dimg->hspace = simg->hspace;
200
dimg->vspace = simg->vspace;
202
dimg->valign = simg->valign;
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;
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);
217
image_update_url (HTMLImage *image, gint x, gint y)
220
HTMLObject *o = HTML_OBJECT (image);
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.
228
if (image->usemap != NULL) {
229
map = html_engine_get_map (image->image_ptr->factory->engine,
233
url = html_map_calc_point (map, x - o->x , y - (o->y - o->ascent));
236
url = g_strdup (url);
238
} else if (image->ismap) {
240
url = g_strdup_printf ("%s?%d,%d", image->url, x - o->x, y - (o->y - o->ascent));
245
g_free (image->final_url);
246
image->final_url = url;
250
check_point (HTMLObject *self,
251
HTMLPainter *painter,
253
guint *offset_return,
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;
263
image_update_url (HTML_IMAGE (self), x, y);
271
calc_min_width (HTMLObject *o,
272
HTMLPainter *painter)
274
HTMLImage *image = HTML_IMAGE (o);
278
pixel_size = html_painter_get_pixel_size (painter);
280
if (image->percent_width || image->percent_height)
281
min_width = pixel_size;
283
min_width = html_image_get_actual_width (HTML_IMAGE (o), painter);
285
min_width += (image->border * 2 + 2 * image->hspace) * pixel_size;
291
calc_preferred_width (HTMLObject *o,
292
HTMLPainter *painter)
294
HTMLImage *image = HTML_IMAGE (o);
297
width = html_image_get_actual_width (HTML_IMAGE (o), painter)
298
+ (image->border * 2 + 2 * image->hspace) * html_painter_get_pixel_size (painter);
304
html_image_real_calc_size (HTMLObject *o, HTMLPainter *painter, GList **changed_objs)
309
gint old_width, old_ascent, old_descent;
311
old_width = o->width;
312
old_ascent = o->ascent;
313
old_descent = o->descent;
315
image = HTML_IMAGE (o);
317
pixel_size = html_painter_get_pixel_size (painter);
319
if (o->parent && HTML_IS_PLAIN_PAINTER (painter) && image->alt && *image->alt) {
320
HTMLClueFlow *cf = html_object_get_flow (o);
323
html_painter_set_font_style (painter, html_clueflow_get_default_font_style (cf));
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);
330
width = html_image_get_actual_width (image, painter);
331
height = html_image_get_actual_height (image, painter);
333
o->width = width + (image->border + image->hspace) * 2 * pixel_size;
334
o->ascent = height + (image->border + image->vspace) * 2 * pixel_size;
338
if (o->descent != old_descent
339
|| o->ascent != old_ascent
340
|| o->width != old_width)
347
draw_plain (HTMLObject *o, HTMLPainter *p, gint x, gint y, gint width, gint height, gint tx, gint ty)
349
HTMLImage *img = HTML_IMAGE (o);
352
if (p->widget && GTK_IS_HTML (p->widget))
353
e = html_object_engine (o, GTK_HTML (p->widget)->engine);
357
if (img->alt && *img->alt) {
358
HTMLClueFlow *cf = html_object_get_flow (o);
360
/* FIXME: cache items and glyphs? */
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);
370
html_painter_set_pen (p, &html_colorset_get_color_allocated (e->settings->color_set, p,
371
HTMLTextColor)->color);
375
html_painter_set_font_style (p, html_clueflow_get_default_font_style (cf));
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));
383
draw_focus (HTMLImage *image, HTMLPainter *painter, GdkRectangle *box)
387
gint8 dash_list[] = { 1, 1 };
390
if (painter->widget && GTK_IS_HTML (painter->widget))
391
e = html_object_engine (HTML_OBJECT (image), GTK_HTML (painter->widget)->engine);
395
if (HTML_IS_PRINTER (painter))
398
p = HTML_GDK_PAINTER (painter);
399
/* printf ("draw_image_focus\n"); */
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);
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);
413
HTMLPainter *painter,
415
gint width, gint height,
419
HTMLImagePointer *ip;
422
gint scale_width, scale_height;
423
GdkColor *highlight_color;
428
if (painter->widget && GTK_IS_HTML (painter->widget))
429
e = html_object_engine (o, GTK_HTML (painter->widget)->engine);
433
/* printf ("Image::draw\n"); */
435
if (!html_object_intersect (o, &paint, x, y, width, height))
438
if (HTML_IS_PLAIN_PAINTER (painter)) {
439
draw_plain (o, painter, x, y, width, height, tx, ty);
443
image = HTML_IMAGE (o);
444
ip = image->image_ptr;
446
image->animation_active = TRUE;
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);
452
pixbuf = gdk_pixbuf_animation_get_static_image (ip->animation);
458
pixel_size = html_painter_get_pixel_size (painter);
461
highlight_color = &html_colorset_get_color_allocated
462
(e->settings->color_set, painter,
463
painter->focus ? HTMLHighlightColor : HTMLHighlightNFColor)->color;
465
highlight_color = NULL;
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;
470
if (pixbuf == NULL) {
473
hspace = image->hspace * pixel_size;
474
vspace = image->vspace * pixel_size;
476
if (image->image_ptr->loader && !image->image_ptr->stall)
480
html_painter_set_pen (painter, highlight_color);
481
html_painter_fill_rect (painter,
483
o->y + ty - o->ascent + vspace,
484
o->width - 2 * hspace,
485
o->ascent + o->descent - 2 * vspace);
487
html_painter_draw_border (painter,
488
&((html_colorset_get_color (e->settings->color_set, HTMLBgColor))->color),
490
o->y + ty - o->ascent + vspace,
491
o->width - 2 * hspace,
492
o->ascent + o->descent - 2 * vspace,
493
HTML_BORDER_INSET, 1);
496
pixbuf = html_image_factory_get_missing (ip->factory);
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,
503
gdk_pixbuf_get_width (pixbuf) * pixel_size,
504
gdk_pixbuf_get_height (pixbuf) * pixel_size,
507
if (o->draw_focused) {
510
scale_width = html_image_get_actual_width (image, painter);
511
scale_height = html_image_get_actual_height (image, painter);
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;
518
draw_focus (image, painter, &rect);
524
scale_width = html_image_get_actual_width (image, painter);
525
scale_height = html_image_get_actual_height (image, painter);
528
if (image->have_color) {
529
html_color_alloc (image->color, painter);
530
html_painter_set_pen (painter, &image->color->color);
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);
543
html_painter_draw_pixmap (painter, pixbuf,
545
scale_width, scale_height,
548
if (o->draw_focused) {
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;
555
draw_focus (image, painter, &rect);
560
html_image_resolve_image_url (GtkHTML *html, gchar *image_url)
564
/* printf ("html_image_resolve_image_url %p\n", html->editor_api); */
565
if (html->editor_api) {
566
GValue *iarg = g_new0 (GValue, 1);
569
g_value_init (iarg, G_TYPE_STRING);
570
g_value_set_string (iarg, image_url);
572
oarg = (* html->editor_api->event) (html, GTK_HTML_EDITOR_EVENT_IMAGE_URL, iarg, html->editor_data);
575
if (G_VALUE_TYPE (oarg) == G_TYPE_STRING)
576
url = (gchar *) g_strdup (g_value_get_string (oarg));
578
g_value_unset (oarg);
581
g_value_unset (iarg);
585
url = g_strdup (image_url);
586
/* printf ("image URL resolved to: %s (from: %s)\n", url, image_url); */
592
save (HTMLObject *self,
593
HTMLEngineSaveState *state)
597
gboolean result, link = FALSE;
599
g_return_val_if_fail (self != NULL, FALSE);
600
g_return_val_if_fail (state != NULL, FALSE);
602
image = HTML_IMAGE (self);
604
if (image->url && *image->url) {
605
url = g_strconcat (image->url, image->target ? "#" : "", image->target, NULL);
607
result = html_engine_save_output_string (state, "<A HREF=\"%s\">", url);
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);
619
if (image->percent_width) {
620
if (!html_engine_save_output_string (state, " WIDTH=\"%d%%\"", image->specified_width))
622
} else if (image->specified_width > 0) {
623
if (!html_engine_save_output_string (state, " WIDTH=\"%d\"", image->specified_width))
627
if (image->percent_height) {
628
if (!html_engine_save_output_string (state, " HEIGHT=\"%d%%\"", image->specified_height))
630
} else if (image->specified_height > 0) {
631
if (!html_engine_save_output_string (state, " HEIGHT=\"%d\"", image->specified_height))
636
if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
641
if (!html_engine_save_output_string (state, " HSPACE=\"%d\"", image->hspace))
646
if (!html_engine_save_output_string (state, " VSPACE=\"%d\"", image->vspace))
650
if (image->valign != HTML_VALIGN_NONE) {
651
if (!html_engine_save_output_string (state, " ALIGN=\"%s\"", html_valign_name (image->valign)))
656
if (!html_engine_save_output_string (state, " ALT=\"%s\"", image->alt))
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
663
if (image->border != 2) {
664
if (!html_engine_save_output_string (state, " BORDER=\"%d\"", image->border))
668
if (!html_engine_save_output_string (state, ">"))
670
if (link && !html_engine_save_output_string (state, "</A>"))
677
save_plain (HTMLObject *self,
678
HTMLEngineSaveState *state,
679
gint requested_width)
684
image = HTML_IMAGE (self);
687
rv = html_engine_save_output_string (state, "%s", image->alt);
693
get_url (HTMLObject *o, gint offset)
697
image = HTML_IMAGE (o);
698
return image->final_url ? image->final_url : image->url;
702
get_target (HTMLObject *o, gint offset)
706
image = HTML_IMAGE (o);
707
return image->target;
711
get_src (HTMLObject *o)
715
image = HTML_IMAGE (o);
716
return image->image_ptr->url;
720
set_link (HTMLObject *self, HTMLColor *color, const gchar *url, const gchar *target)
722
HTMLImage *image = HTML_IMAGE (self);
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;
730
html_color_ref (color);
731
image->have_color = TRUE;
733
image->have_color = FALSE;
740
accepts_cursor (HTMLObject *o)
745
static HTMLVAlignType
746
get_valign (HTMLObject *self)
750
image = HTML_IMAGE (self);
752
return image->valign;
756
select_range (HTMLObject *self,
762
/* printf ("IMAGE: select range\n"); */
763
if ((*parent_class->select_range) (self, engine, offset, length, queue_draw)) {
765
html_engine_queue_draw (engine, self);
766
/* printf ("IMAGE: draw queued\n"); */
775
html_image_type_init (void)
777
html_image_class_init (&html_image_class, HTML_TYPE_IMAGE, sizeof (HTMLImage));
781
html_image_class_init (HTMLImageClass *image_class,
785
HTMLObjectClass *object_class;
787
object_class = HTML_OBJECT_CLASS (image_class);
789
html_object_class_init (object_class, type, size);
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;
808
parent_class = &html_object_class;
812
html_image_init (HTMLImage *image,
813
HTMLImageClass *klass,
814
HTMLImageFactory *imf,
815
const gchar *filename,
818
gint16 width, gint16 height,
819
gboolean percent_width, gboolean percent_height,
822
HTMLVAlignType valign,
829
object = HTML_OBJECT (image);
831
html_object_init (object, HTML_OBJECT_CLASS (klass));
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;
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;
847
image->color = color;
848
image->have_color = TRUE;
849
html_color_ref (color);
852
image->have_color = FALSE;
860
if (valign == HTML_VALIGN_NONE)
861
valign = HTML_VALIGN_BOTTOM;
862
image->valign = valign;
864
image->image_ptr = html_image_factory_register (imf, image, filename, reload);
868
html_image_new (HTMLImageFactory *imf,
869
const gchar *filename,
872
gint16 width, gint16 height,
873
gboolean percent_width, gboolean percent_height,
876
HTMLVAlignType valign,
881
image = g_new(HTMLImage, 1);
883
html_image_init (image, &html_image_class,
889
percent_width, percent_height,
895
return HTML_OBJECT (image);
899
html_image_set_spacing (HTMLImage *image, gint hspace, gint vspace)
901
gboolean changed = FALSE;
903
if (image->hspace != hspace) {
904
image->hspace = hspace;
908
if (image->vspace != vspace) {
909
image->vspace = vspace;
914
html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
915
html_engine_schedule_update (image->image_ptr->factory->engine);
920
html_image_edit_set_url (HTMLImage *image, const gchar *url)
923
HTMLImageFactory *imf = image->image_ptr->factory;
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);
934
html_image_set_url (HTMLImage *image, const gchar *url)
936
if (url && strcmp (image->image_ptr->url, url)) {
937
HTMLImageFactory *imf = image->image_ptr->factory;
939
html_image_factory_unregister (imf, image->image_ptr, HTML_IMAGE (image));
940
image->image_ptr = html_image_factory_register (imf, image, url, FALSE);
945
html_image_set_valign (HTMLImage *image, HTMLVAlignType valign)
947
if (image->valign != valign) {
948
image->valign = valign;
949
html_engine_schedule_update (image->image_ptr->factory->engine);
954
html_image_set_border (HTMLImage *image, gint border)
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);
964
html_image_set_alt (HTMLImage *image, gchar *alt)
967
image->alt = g_strdup (alt);
971
html_image_set_map (HTMLImage *image, gchar *usemap, gboolean ismap)
975
g_free (image->usemap);
977
if (usemap != NULL) {
978
image->ismap = FALSE;
979
url = g_strdup (usemap);
981
image->ismap = ismap;
987
html_image_set_size (HTMLImage *image, gint w, gint h, gboolean pw, gboolean ph)
989
gboolean changed = FALSE;
991
if (pw != image->percent_width) {
992
image->percent_width = pw;
996
if (ph != image->percent_height) {
997
image->percent_height = ph;
1001
if (w != image->specified_width) {
1002
image->specified_width = w;
1006
if (h != image->specified_height) {
1007
image->specified_height = h;
1012
html_object_change_set (HTML_OBJECT (image), HTML_CHANGE_ALL_CALC);
1013
html_engine_schedule_update (image->image_ptr->factory->engine);
1017
static char *fallback_image_content_types[] = {"image/*", NULL};
1020
html_image_factory_types (GtkHTMLStream *stream,
1023
static char**image_content_types = NULL;
1026
/* this code should work in gtk+-2.2 but it is untested */
1027
if (image_content_types == NULL) {
1030
GSList *types = NULL;
1033
formats = gdk_pixbuf_get_formats ();
1035
for (cur = formats; cur; cur = cur->next) {
1036
GdkPixbufFormat *format = cur->data;
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]));
1044
g_slist_free (formats);
1047
image_content_types = g_new0 (char *, g_slist_length (types) + 1);
1049
for (cur = types, i = 0; cur; cur = cur->next, i++) {
1050
image_content_types[i] = cur->data;
1052
g_slist_free (types);
1054
image_content_types = fallback_image_content_types;
1058
image_content_types = fallback_image_content_types;
1061
return image_content_types;
1065
update_or_redraw (HTMLImagePointer *ip){
1067
gboolean update = FALSE;
1069
for (list = ip->interests; list; list = list->next) {
1070
if (list->data == NULL)
1073
HTMLImage *image = HTML_IMAGE (list->data);
1074
gint pixel_size = html_painter_get_pixel_size (ip->factory->engine->painter);
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;
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); */
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);
1093
if (ip->factory->engine->block && ip->factory->engine->opened_streams)
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));
1102
html_engine_flush_draw_queue (ip->factory->engine);
1104
/* printf ("UPDATE\n"); */
1105
html_engine_schedule_update (ip->factory->engine);
1110
html_image_factory_end_pixbuf (GtkHTMLStream *stream,
1111
GtkHTMLStreamStatus status,
1114
HTMLImagePointer *ip = user_data;
1116
gdk_pixbuf_loader_close (ip->loader, NULL);
1118
if (!ip->animation) {
1119
ip->animation = gdk_pixbuf_loader_get_animation (ip->loader);
1122
g_object_ref (ip->animation);
1124
html_image_pointer_start_animation (ip);
1126
g_object_unref (ip->loader);
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);
1139
html_image_factory_write_pixbuf (GtkHTMLStream *stream,
1140
const gchar *buffer,
1144
HTMLImagePointer *p = user_data;
1146
/* FIXME ! Check return value */
1147
gdk_pixbuf_loader_write (p->loader, (const guchar *) buffer, size, NULL);
1151
html_image_pointer_queue_animation (HTMLImagePointer *ip)
1153
if (!ip->animation_timeout && ip->factory && ip->factory->animate) {
1156
gdk_pixbuf_animation_iter_advance (ip->iter, NULL);
1157
delay = gdk_pixbuf_animation_iter_get_delay_time (ip->iter);
1159
ip->animation_timeout = g_timeout_add (delay,
1160
(GtkFunction) html_image_pointer_update,
1167
html_image_pointer_update (HTMLImagePointer *ip)
1169
HTMLEngine *engine = ip->factory->engine;
1172
g_return_val_if_fail (ip->factory != NULL, FALSE);
1173
ip->animation_timeout = 0;
1175
DA (printf ("animation_timeout (%p)\n", ip);)
1176
for (cur = ip->interests; cur; cur = cur->next) {
1177
HTMLImage *image = cur->data;
1179
if (image && image->animation_active && html_object_is_parent (engine->clue, HTML_OBJECT (image))) {
1180
DA (printf ("queue draw (%p)\n", image);)
1182
image->animation_active = FALSE;
1183
html_engine_queue_draw (engine, HTML_OBJECT (image));
1187
html_image_pointer_start_animation (ip);
1192
html_image_pointer_start_animation (HTMLImagePointer *ip)
1194
if (ip->animation && !gdk_pixbuf_animation_is_static_image (ip->animation)) {
1196
ip->iter = gdk_pixbuf_animation_get_iter (ip->animation, NULL);
1198
html_image_pointer_queue_animation (ip);
1203
html_image_pointer_stop_animation (HTMLImagePointer *ip)
1205
if (ip->animation_timeout) {
1206
g_source_remove (ip->animation_timeout);
1207
ip->animation_timeout = 0;
1212
html_image_factory_area_updated (GdkPixbufLoader *loader, guint x, guint y, guint width, guint height, HTMLImagePointer *ip)
1214
html_image_pointer_stop_animation (ip);
1215
/* update will requeue */
1216
html_image_pointer_update (ip);
1220
html_image_factory_area_prepared (GdkPixbufLoader *loader, HTMLImagePointer *ip)
1222
if (!ip->animation) {
1223
ip->animation = gdk_pixbuf_loader_get_animation (loader);
1224
g_object_ref (ip->animation);
1226
html_image_pointer_start_animation (ip);
1228
update_or_redraw (ip);
1232
html_image_factory_get_missing (HTMLImageFactory *factory)
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;
1242
html_image_factory_new (HTMLEngine *e)
1244
HTMLImageFactory *retval;
1245
retval = g_new (HTMLImageFactory, 1);
1247
retval->loaded_images = g_hash_table_new (g_str_hash, g_str_equal);
1248
retval->missing = NULL;
1249
retval->animate = TRUE;
1255
cleanup_images (gpointer key, gpointer value, gpointer free_everything)
1257
HTMLImagePointer *ip = value;
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;
1267
/* clean only if this image is not used anymore */
1268
if (!ip->interests){
1269
html_image_pointer_unref (ip);
1278
html_image_factory_cleanup (HTMLImageFactory *factory)
1280
g_return_if_fail (factory);
1281
g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, NULL);
1285
html_image_factory_free (HTMLImageFactory *factory)
1287
g_return_if_fail (factory);
1289
g_hash_table_foreach_remove (factory->loaded_images, cleanup_images, factory);
1290
g_hash_table_destroy (factory->loaded_images);
1292
if (factory->missing)
1293
g_object_unref (factory->missing);
1298
#define STALL_INTERVAL 1000
1300
static HTMLImagePointer *
1301
html_image_pointer_new (const char *filename, HTMLImageFactory *factory)
1303
HTMLImagePointer *retval;
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,
1317
retval->animation_timeout = 0;
1322
html_image_pointer_timeout (HTMLImagePointer *ip)
1327
ip->stall_timeout = 0;
1329
g_return_val_if_fail (ip->factory != NULL, FALSE);
1333
list = ip->interests;
1335
* draw the frame now that we decided they've had enough time to
1338
if (ip->animation == NULL) {
1340
image = (HTMLImage *)list->data;
1343
html_engine_queue_draw (ip->factory->engine,
1344
HTML_OBJECT (image));
1353
html_image_pointer_ref (HTMLImagePointer *ip)
1359
free_image_ptr_data (HTMLImagePointer *ip)
1362
gdk_pixbuf_loader_close (ip->loader, NULL);
1363
g_object_unref (ip->loader);
1366
if (ip->animation) {
1367
g_object_unref (ip->animation);
1368
ip->animation = NULL;
1371
g_object_unref (ip->iter);
1377
html_image_pointer_remove_stall (HTMLImagePointer *ip)
1379
if (ip->stall_timeout) {
1380
g_source_remove (ip->stall_timeout);
1381
ip->stall_timeout = 0;
1386
html_image_pointer_unref (HTMLImagePointer *ip)
1388
g_return_if_fail (ip != NULL);
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);
1397
free_image_ptr_data (ip);
1402
static GtkHTMLStream *
1403
html_image_pointer_load (HTMLImagePointer *ip)
1405
if (ip->factory->engine->stopped)
1408
html_image_pointer_ref (ip);
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,
1420
html_image_factory_register (HTMLImageFactory *factory, HTMLImage *i, const char *url, gboolean reload)
1422
HTMLImagePointer *ip;
1423
GtkHTMLStream *stream = NULL;
1425
g_return_val_if_fail (factory, NULL);
1426
g_return_val_if_fail (url, NULL);
1428
ip = g_hash_table_lookup (factory->loaded_images, url);
1431
ip = html_image_pointer_new (url, factory);
1432
g_hash_table_insert (factory->loaded_images, ip->url, ip);
1434
g_signal_connect (G_OBJECT (ip->loader), "area_prepared",
1435
G_CALLBACK (html_image_factory_area_prepared),
1438
g_signal_connect (G_OBJECT (ip->loader), "area_updated",
1439
G_CALLBACK (html_image_factory_area_updated),
1441
stream = html_image_pointer_load (ip);
1445
free_image_ptr_data (ip);
1446
ip->loader = gdk_pixbuf_loader_new ();
1447
stream = html_image_pointer_load (ip);
1452
g_signal_emit_by_name (factory->engine, "url_requested", ip->url, stream);
1454
html_image_pointer_ref (ip);
1456
/* we add also NULL ptrs, as we dont want these to be cleaned out */
1457
ip->interests = g_slist_prepend (ip->interests, i);
1468
html_image_factory_get_engine (HTMLImageFactory *factory)
1470
return factory->engine;
1475
html_image_factory_unregister (HTMLImageFactory *factory, HTMLImagePointer *pointer, HTMLImage *i)
1477
pointer->interests = g_slist_remove (pointer->interests, i);
1479
html_image_pointer_unref (pointer);
1481
if (pointer->refcount == 1) {
1482
g_assert (pointer->interests == NULL);
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.
1488
* We really need a way to let cut objects know they are living outside
1492
g_hash_table_remove (factory->loaded_images, pointer->url);
1493
pointer->factory = NULL;
1494
html_image_pointer_unref (pointer);
1499
stop_anim (gpointer key, gpointer value, gpointer user_data)
1501
HTMLImagePointer *ip = value;
1502
html_image_pointer_remove_stall (ip);
1503
html_image_pointer_stop_animation (ip);
1507
html_image_factory_stop_animations (HTMLImageFactory *factory)
1509
DA (g_warning ("stop animations");)
1510
g_hash_table_foreach (factory->loaded_images, stop_anim, NULL);
1514
start_anim (gpointer key, gpointer value, gpointer user_data)
1516
HTMLImagePointer *ip = value;
1517
html_image_pointer_start_animation (ip);
1521
html_image_factory_start_animations (HTMLImageFactory *factory)
1523
DA (g_warning ("start animations");)
1524
g_hash_table_foreach (factory->loaded_images, start_anim, NULL);
1528
html_image_factory_get_animate (HTMLImageFactory *factory)
1530
return factory->animate;
1534
html_image_factory_set_animate (HTMLImageFactory *factory, gboolean animate)
1536
if (animate != factory->animate) {
1537
factory->animate = animate;
1540
html_image_factory_start_animations (factory);
1542
html_image_factory_stop_animations (factory);
1547
move_image_pointers (gpointer key, gpointer value, gpointer data)
1549
HTMLImageFactory *dst = HTML_IMAGE_FACTORY (data);
1550
HTMLImagePointer *ip = HTML_IMAGE_POINTER (value);
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));
1562
html_image_factory_move_images (HTMLImageFactory *dst, HTMLImageFactory *src)
1564
g_hash_table_foreach_remove (src->loaded_images, move_image_pointers, dst);
1568
deactivate_anim (gpointer key, gpointer value, gpointer user_data)
1570
HTMLImagePointer *ip = value;
1571
GSList *cur = ip->interests;
1577
image = (HTMLImage *) cur->data;
1578
image->animation_active = FALSE;
1585
html_image_factory_deactivate_animations (HTMLImageFactory *factory)
1587
g_hash_table_foreach (factory->loaded_images, deactivate_anim, NULL);
1591
ref_image_ptr (gpointer key, gpointer val, gpointer data)
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); */
1599
unref_image_ptr (gpointer key, gpointer val, gpointer data)
1601
if (HTML_IMAGE_POINTER (val)->animation)
1602
html_image_pointer_unref (HTML_IMAGE_POINTER (val));
1606
html_image_factory_ref_all_images (HTMLImageFactory *factory)
1608
if (!factory->loaded_images)
1611
g_hash_table_foreach (factory->loaded_images, ref_image_ptr, NULL);
1615
html_image_factory_unref_all_images (HTMLImageFactory *factory)
1617
if (!factory->loaded_images)
1620
g_hash_table_foreach (factory->loaded_images, unref_image_ptr, NULL);
1624
html_image_factory_ref_image_ptr (HTMLImageFactory *factory, const gchar *url)
1626
HTMLImagePointer *ptr;
1628
if (!factory->loaded_images)
1631
ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
1633
html_image_pointer_ref (ptr);
1637
html_image_factory_unref_image_ptr (HTMLImageFactory *factory, const gchar *url)
1639
HTMLImagePointer *ptr;
1641
if (!factory->loaded_images)
1644
ptr = HTML_IMAGE_POINTER (g_hash_table_lookup (factory->loaded_images, url));
1646
html_image_pointer_unref (ptr);