1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
2 | /* This file is part of the GtkHTML library. |
---|
3 | |
---|
4 | Copyright (C) 2000 Helix Code, Inc. |
---|
5 | |
---|
6 | This library is free software; you can redistribute it and/or |
---|
7 | modify it under the terms of the GNU Library General Public |
---|
8 | License as published by the Free Software Foundation; either |
---|
9 | version 2 of the License, or (at your option) any later version. |
---|
10 | |
---|
11 | This library is distributed in the hope that it will be useful, |
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | Library General Public License for more details. |
---|
15 | |
---|
16 | You should have received a copy of the GNU Library General Public License |
---|
17 | along with this library; see the file COPYING.LIB. If not, write to |
---|
18 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
19 | Boston, MA 02111-1307, USA. |
---|
20 | */ |
---|
21 | |
---|
22 | #include <config.h> |
---|
23 | #include "gtkhtml-compat.h" |
---|
24 | |
---|
25 | #include <string.h> |
---|
26 | #include <stdlib.h> |
---|
27 | #include <ctype.h> |
---|
28 | |
---|
29 | #include <glib.h> |
---|
30 | #include <gdk/gdkx.h> |
---|
31 | #include <gtk/gtksignal.h> |
---|
32 | |
---|
33 | #include <libgnome/gnome-defs.h> |
---|
34 | #include <libgnome/gnome-i18n.h> |
---|
35 | #include <libart_lgpl/art_rect.h> |
---|
36 | #include <gal/unicode/gunicode.h> |
---|
37 | #include <gal/widgets/e-font.h> |
---|
38 | |
---|
39 | #include "htmlentity.h" |
---|
40 | #include "htmlgdkpainter.h" |
---|
41 | #include "htmlcolor.h" |
---|
42 | #include "htmlcolorset.h" |
---|
43 | #include "htmlembedded.h" |
---|
44 | #include "htmlengine.h" |
---|
45 | #include "gtkhtml-embedded.h" |
---|
46 | |
---|
47 | static HTMLPainterClass *parent_class = NULL; |
---|
48 | |
---|
49 | static EFontStyle e_style (GtkHTMLFontStyle style); |
---|
50 | |
---|
51 | /* GtkObject methods. */ |
---|
52 | |
---|
53 | static void |
---|
54 | finalize (GtkObject *object) |
---|
55 | { |
---|
56 | HTMLGdkPainter *painter; |
---|
57 | |
---|
58 | painter = HTML_GDK_PAINTER (object); |
---|
59 | |
---|
60 | if (painter->gc != NULL) |
---|
61 | gdk_gc_destroy (painter->gc); |
---|
62 | |
---|
63 | if (painter->pixmap != NULL) |
---|
64 | gdk_pixmap_unref (painter->pixmap); |
---|
65 | |
---|
66 | (* GTK_OBJECT_CLASS (parent_class)->finalize) (object); |
---|
67 | } |
---|
68 | |
---|
69 | static gchar * |
---|
70 | get_font_attr (gchar *font_name, gint pos) |
---|
71 | { |
---|
72 | gchar *s, *end, *rv = NULL; |
---|
73 | gint n; |
---|
74 | |
---|
75 | /* Search paramether */ |
---|
76 | for (s=font_name, n=pos; n; n--,s++) |
---|
77 | s = strchr (s,'-'); |
---|
78 | |
---|
79 | if (s && *s != 0) { |
---|
80 | end = strchr (s, '-'); |
---|
81 | if (end) |
---|
82 | rv = g_strndup (s, end - s); |
---|
83 | } |
---|
84 | |
---|
85 | return rv; |
---|
86 | } |
---|
87 | |
---|
88 | static gint |
---|
89 | get_size (gchar *font_name, gboolean points) |
---|
90 | { |
---|
91 | gchar *s, *end; |
---|
92 | gint n; |
---|
93 | |
---|
94 | /* Search paramether */ |
---|
95 | for (s=font_name, n=points ? 8 : 7; n; n--,s++) |
---|
96 | s = strchr (s,'-'); |
---|
97 | |
---|
98 | if (s && *s != 0) { |
---|
99 | end = strchr (s, '-'); |
---|
100 | if (end) { |
---|
101 | *end = 0; |
---|
102 | n = atoi (s); |
---|
103 | *end = '-'; |
---|
104 | return n; |
---|
105 | } else |
---|
106 | return 0; |
---|
107 | } else |
---|
108 | return 0; |
---|
109 | } |
---|
110 | |
---|
111 | static gchar * |
---|
112 | font_name_substitute_attr (const gchar *name, gint nth, gchar *val) |
---|
113 | { |
---|
114 | const gchar *s; |
---|
115 | gchar *s1, *s2, *rv; |
---|
116 | |
---|
117 | if (!name) |
---|
118 | return NULL; |
---|
119 | |
---|
120 | for (s = name; nth; nth--) { |
---|
121 | s = strchr (s, '-'); |
---|
122 | if (!s) |
---|
123 | return NULL; |
---|
124 | s ++; |
---|
125 | } |
---|
126 | s2 = strchr (s, '-'); |
---|
127 | if (!s2) |
---|
128 | return NULL; |
---|
129 | s1 = g_strndup (name, s - name); |
---|
130 | |
---|
131 | rv = g_strconcat (s1, val, s2, NULL); |
---|
132 | g_free (s1); |
---|
133 | |
---|
134 | return rv; |
---|
135 | } |
---|
136 | |
---|
137 | static GHashTable *cache_x_list_fonts_results = NULL; |
---|
138 | typedef struct _HTMLGdkPainterFontList |
---|
139 | { |
---|
140 | gchar **list; |
---|
141 | gint n; |
---|
142 | } HTMLGdkPainterFontList; |
---|
143 | |
---|
144 | static gint |
---|
145 | html_str_case_equal (gconstpointer v, gconstpointer v2) |
---|
146 | { |
---|
147 | return strcasecmp ((const gchar*) v, (const gchar*)v2) == 0; |
---|
148 | } |
---|
149 | |
---|
150 | static guint |
---|
151 | html_str_case_hash (gconstpointer key) |
---|
152 | { |
---|
153 | const char *p = key; |
---|
154 | guint h = tolower (*p); |
---|
155 | |
---|
156 | if (h) |
---|
157 | for (p += 1; *p != '\0'; p++) |
---|
158 | h = (h << 5) - h + tolower (*p); |
---|
159 | |
---|
160 | return h; |
---|
161 | } |
---|
162 | |
---|
163 | static gchar ** |
---|
164 | lookup_fonts (gchar *face, gint *n) |
---|
165 | { |
---|
166 | HTMLGdkPainterFontList *fl; |
---|
167 | |
---|
168 | if (!cache_x_list_fonts_results) |
---|
169 | cache_x_list_fonts_results = g_hash_table_new (html_str_case_hash, html_str_case_equal); |
---|
170 | |
---|
171 | fl = (HTMLGdkPainterFontList *) g_hash_table_lookup (cache_x_list_fonts_results, face); |
---|
172 | if (!fl) { |
---|
173 | GTimer *timer; |
---|
174 | gdouble elapsed; |
---|
175 | |
---|
176 | fl = g_new (HTMLGdkPainterFontList, 1); |
---|
177 | |
---|
178 | timer = g_timer_new (); |
---|
179 | g_timer_start (timer); |
---|
180 | fl->list = XListFonts (GDK_DISPLAY (), face, 0x7fff, &fl->n); |
---|
181 | elapsed = g_timer_elapsed (timer, NULL); |
---|
182 | g_timer_destroy (timer); |
---|
183 | |
---|
184 | if (!fl->list) |
---|
185 | fl->n = 0; |
---|
186 | printf ("(%1.4fs) [list] %s --> %d\n", elapsed, face, fl->n); |
---|
187 | /* printf ("inserting %d results for %s\n", fl->n, face); */ |
---|
188 | /* { |
---|
189 | gint i; |
---|
190 | for (i = 0; i < fl->n; i ++) |
---|
191 | printf ("\t%s\n", fl->list [i]); |
---|
192 | } */ |
---|
193 | g_hash_table_insert (cache_x_list_fonts_results, g_strdup (face), fl); |
---|
194 | } /* else |
---|
195 | printf ("%d results found in cache (%s)\n", fl->n, face); */ |
---|
196 | |
---|
197 | *n = fl->n; |
---|
198 | |
---|
199 | return fl->list; |
---|
200 | } |
---|
201 | |
---|
202 | static gchar ** |
---|
203 | filter_fonts_with_style (gchar **list, gint *n, gchar *weight, gchar *slant) |
---|
204 | { |
---|
205 | if (*n) { |
---|
206 | GSList *cur, *tmp_list = NULL; |
---|
207 | gchar **filtered, *fw, *fs; |
---|
208 | gint i, nf; |
---|
209 | |
---|
210 | nf = 0; |
---|
211 | for (i = 0; i < *n; i ++) { |
---|
212 | fw = get_font_attr (list [i], 3); |
---|
213 | fs = get_font_attr (list [i], 4); |
---|
214 | if (fw && fs) { |
---|
215 | if (!strcasecmp (fw, weight) && !strcasecmp (fs, slant)) { |
---|
216 | tmp_list = g_slist_prepend (tmp_list, list [i]); |
---|
217 | nf ++; |
---|
218 | } |
---|
219 | } |
---|
220 | g_free (fw); |
---|
221 | g_free (fs); |
---|
222 | } |
---|
223 | |
---|
224 | filtered = g_new (gchar *, nf); |
---|
225 | for (i = 0, cur = tmp_list; cur; i++, cur = cur->next) |
---|
226 | filtered [i] = (gchar *) cur->data; |
---|
227 | g_slist_free (tmp_list); |
---|
228 | *n = nf; |
---|
229 | |
---|
230 | /* printf ("found %d fonts (%s,%s)\n", *n, weight, slant); */ |
---|
231 | |
---|
232 | return filtered; |
---|
233 | } |
---|
234 | |
---|
235 | return list; |
---|
236 | } |
---|
237 | |
---|
238 | static gchar * |
---|
239 | find_font_with_similar_size (gchar **list, gint n, gint size, gboolean points, gboolean smaller) |
---|
240 | { |
---|
241 | if (n) { |
---|
242 | gint i, small, large, as, small_idx, large_idx; |
---|
243 | |
---|
244 | small = large = small_idx = large_idx = 0; |
---|
245 | for (i = 0; i < n; i++) { |
---|
246 | as = get_size (list [i], points); |
---|
247 | |
---|
248 | if (as > size && (as < large || !large)) { |
---|
249 | large = as; |
---|
250 | large_idx = i; |
---|
251 | } else if (as < size && (as > small || !small)) { |
---|
252 | small = as; |
---|
253 | small_idx = i; |
---|
254 | } |
---|
255 | } |
---|
256 | |
---|
257 | if (!small && !large) |
---|
258 | return NULL; |
---|
259 | if (!small && large) |
---|
260 | return list [large_idx]; |
---|
261 | if (small && !large) |
---|
262 | return list [small_idx]; |
---|
263 | return list [smaller ? small_idx : large_idx]; |
---|
264 | } |
---|
265 | |
---|
266 | return NULL; |
---|
267 | } |
---|
268 | |
---|
269 | static gpointer |
---|
270 | load_font_with_name (gchar *name) |
---|
271 | { |
---|
272 | GdkFont *gdk_font; |
---|
273 | gboolean need_fontset = FALSE; |
---|
274 | gpointer font; |
---|
275 | GTimer *timer; |
---|
276 | gdouble elapsed; |
---|
277 | |
---|
278 | if (strchr (name, ',')) |
---|
279 | need_fontset = TRUE; |
---|
280 | |
---|
281 | timer = g_timer_new (); |
---|
282 | g_timer_start (timer); |
---|
283 | gdk_font = need_fontset ? gdk_fontset_load (name) : gdk_font_load (name); |
---|
284 | elapsed = g_timer_elapsed (timer, NULL); |
---|
285 | g_timer_destroy (timer); |
---|
286 | printf ("(%1.4fs) [load] %s --> %p\n", elapsed, name, gdk_font); |
---|
287 | |
---|
288 | if (gdk_font) { |
---|
289 | font = e_font_from_gdk_font_gtkhtml (gdk_font); |
---|
290 | gdk_font_unref (gdk_font); |
---|
291 | } else |
---|
292 | font = NULL; |
---|
293 | |
---|
294 | return font; |
---|
295 | } |
---|
296 | |
---|
297 | static gchar * |
---|
298 | e_font_lookup_face (gchar *face, gint size, gboolean points, gchar *weight, gchar *slant, |
---|
299 | gboolean known_size, gboolean smaller) |
---|
300 | { |
---|
301 | gchar *f1, *f2, *f3, *f4, **list, **filtered = NULL; |
---|
302 | gchar *font_name = NULL; |
---|
303 | gint n; |
---|
304 | |
---|
305 | /* clear weight, slant and size */ |
---|
306 | f1 = font_name_substitute_attr (face, 7, "*"); |
---|
307 | f2 = font_name_substitute_attr (f1, 8, "*"); |
---|
308 | g_free (f1); |
---|
309 | f3 = font_name_substitute_attr (f2, 3, "*"); |
---|
310 | g_free (f2); |
---|
311 | f4 = font_name_substitute_attr (f3, 4, "*"); |
---|
312 | g_free (f3); |
---|
313 | |
---|
314 | if (!f4) { |
---|
315 | g_warning ("Don't know how to use face: %s", face ? face : "NULL"); |
---|
316 | return NULL; |
---|
317 | } |
---|
318 | |
---|
319 | list = lookup_fonts (f4, &n); |
---|
320 | g_free (f4); |
---|
321 | |
---|
322 | if (n == 0) |
---|
323 | return NULL; |
---|
324 | |
---|
325 | filtered = filter_fonts_with_style (list, &n, weight, slant); |
---|
326 | if (n) { |
---|
327 | gchar *name; |
---|
328 | if (known_size) { |
---|
329 | |
---|
330 | |
---|
331 | name = find_font_with_similar_size (filtered, n, size, points, smaller); |
---|
332 | |
---|
333 | if (name) |
---|
334 | font_name = g_strdup (name); |
---|
335 | } else { |
---|
336 | gchar *s; |
---|
337 | |
---|
338 | f1 = font_name_substitute_attr (face, 3, weight); |
---|
339 | f2 = font_name_substitute_attr (f1, 4, slant); |
---|
340 | if (!f2) { |
---|
341 | g_warning ("Don't know how to use face: %s", face ? face : "NULL"); |
---|
342 | return NULL; |
---|
343 | } |
---|
344 | s = g_strdup_printf ("%d", size); |
---|
345 | name = font_name_substitute_attr (f2, points ? 8 : 7, s); |
---|
346 | if (!name) { |
---|
347 | g_warning ("Don't know how to use face: %s", face ? face : "NULL"); |
---|
348 | return NULL; |
---|
349 | } |
---|
350 | g_free (f1); |
---|
351 | g_free (f2); |
---|
352 | g_free (s); |
---|
353 | |
---|
354 | font_name = name; |
---|
355 | } |
---|
356 | |
---|
357 | } |
---|
358 | if (filtered != list) |
---|
359 | g_free (filtered); |
---|
360 | |
---|
361 | return font_name; |
---|
362 | } |
---|
363 | |
---|
364 | static gpointer |
---|
365 | e_font_from_face (gchar *face, gint size, gboolean points, gchar *weight, gchar *slant, |
---|
366 | gboolean known_size, gboolean smaller) |
---|
367 | { |
---|
368 | gchar *better_name; |
---|
369 | gchar **fontnames; |
---|
370 | GString *newface; |
---|
371 | gint i; |
---|
372 | gpointer font = NULL; |
---|
373 | gboolean found = FALSE; |
---|
374 | |
---|
375 | newface = g_string_new (""); |
---|
376 | fontnames = g_strsplit (face, ",", 50); |
---|
377 | for (i = 0; fontnames && fontnames[i] != NULL; i++) { |
---|
378 | char *name = g_strstrip (fontnames[i]); |
---|
379 | |
---|
380 | better_name = e_font_lookup_face (name, size, points, weight, slant, known_size, smaller); |
---|
381 | |
---|
382 | if (i) |
---|
383 | g_string_append (newface, ","); |
---|
384 | |
---|
385 | if (better_name) { |
---|
386 | g_string_append (newface, better_name); |
---|
387 | g_free (better_name); |
---|
388 | found = TRUE; |
---|
389 | } else { |
---|
390 | g_string_append (newface, name); |
---|
391 | } |
---|
392 | } |
---|
393 | g_strfreev (fontnames); |
---|
394 | |
---|
395 | if (found) |
---|
396 | font = load_font_with_name (newface->str); |
---|
397 | g_string_free (newface, TRUE); |
---|
398 | |
---|
399 | return font; |
---|
400 | } |
---|
401 | |
---|
402 | static GdkFont * |
---|
403 | get_fallback_gdk_font (void) |
---|
404 | { |
---|
405 | static GdkFont *fallback_font = NULL; |
---|
406 | |
---|
407 | if (!fallback_font) { |
---|
408 | GtkWidget *tmp_window = gtk_window_new (GTK_WINDOW_POPUP); |
---|
409 | gtk_widget_ensure_style (tmp_window); |
---|
410 | fallback_font = gdk_font_ref (tmp_window->style->font); |
---|
411 | gtk_widget_destroy (tmp_window); |
---|
412 | } |
---|
413 | |
---|
414 | return fallback_font; |
---|
415 | } |
---|
416 | |
---|
417 | static gpointer |
---|
418 | alloc_e_font_try (gchar *face, gdouble size, gboolean points, GtkHTMLFontStyle style, |
---|
419 | gchar *medium, gchar *bold, gchar *roman, gchar *italic, gboolean known_size) |
---|
420 | { |
---|
421 | EFont *font; |
---|
422 | |
---|
423 | /* printf ("alloc font %s %f\n", face, size); */ |
---|
424 | |
---|
425 | if (face) { |
---|
426 | font = e_font_from_face (face, MAX (1, size), points, |
---|
427 | style & GTK_HTML_FONT_STYLE_BOLD ? bold : medium, |
---|
428 | style & GTK_HTML_FONT_STYLE_ITALIC ? italic : roman, |
---|
429 | known_size, (style & GTK_HTML_FONT_STYLE_SIZE_MASK) > GTK_HTML_FONT_STYLE_SIZE_3); |
---|
430 | } else { |
---|
431 | font = e_font_from_gdk_font (get_fallback_gdk_font ()); |
---|
432 | } |
---|
433 | |
---|
434 | return font; |
---|
435 | } |
---|
436 | |
---|
437 | static EFont * |
---|
438 | try_font_possible_names (gchar *face, gdouble size, gboolean points, |
---|
439 | GtkHTMLFontStyle style, gboolean known) |
---|
440 | { |
---|
441 | EFont *font; |
---|
442 | |
---|
443 | font = alloc_e_font_try (face, size, points, style, "medium", "bold", "r", "i", known); |
---|
444 | if (!font && style & GTK_HTML_FONT_STYLE_ITALIC) |
---|
445 | font = alloc_e_font_try (face, size, points, style, "medium", "bold", "r", "o", known); |
---|
446 | if (!font) |
---|
447 | font = alloc_e_font_try (face, size, points, style, "book", "demi", "r", "i", known); |
---|
448 | if (!font && style & GTK_HTML_FONT_STYLE_ITALIC) |
---|
449 | font = alloc_e_font_try (face, size, points, style, "book", "demi", "r", "o", known); |
---|
450 | if (!font) |
---|
451 | font = alloc_e_font_try (face, size, points, style, "light", "demibold", "r", "i", known); |
---|
452 | if (!font && style & GTK_HTML_FONT_STYLE_ITALIC) |
---|
453 | font = alloc_e_font_try (face, size, points, style, "light", "demibold", "r", "o", known); |
---|
454 | |
---|
455 | return font; |
---|
456 | } |
---|
457 | |
---|
458 | static HTMLFont * |
---|
459 | alloc_e_font_do (gchar *face, gdouble size, gboolean points, GtkHTMLFontStyle style) |
---|
460 | { |
---|
461 | EFont *font; |
---|
462 | |
---|
463 | font = try_font_possible_names (face, size, points, style, FALSE); |
---|
464 | if (!font) |
---|
465 | font = try_font_possible_names (face, size, points, style, TRUE); |
---|
466 | |
---|
467 | return font ? html_font_new (font, |
---|
468 | e_font_utf8_text_width (font, e_style (style), " ", 1), |
---|
469 | e_font_utf8_text_width (font, e_style (style), "\xc2\xa0", 2), |
---|
470 | e_font_utf8_text_width (font, e_style (style), "\t", 1)) |
---|
471 | |
---|
472 | : NULL; |
---|
473 | } |
---|
474 | |
---|
475 | static HTMLFont * |
---|
476 | alloc_e_font (gchar *face, gdouble size, gboolean points, GtkHTMLFontStyle style) |
---|
477 | { |
---|
478 | HTMLFont *font; |
---|
479 | |
---|
480 | font = alloc_e_font_do (face, size, points, style); |
---|
481 | if (!font && style & GTK_HTML_FONT_STYLE_BOLD) |
---|
482 | font = alloc_e_font_do (face, size, points, style & (~GTK_HTML_FONT_STYLE_BOLD)); |
---|
483 | if (!font && style & GTK_HTML_FONT_STYLE_ITALIC) |
---|
484 | font = alloc_e_font_do (face, size, points, style & (~GTK_HTML_FONT_STYLE_ITALIC)); |
---|
485 | if (!font && style & GTK_HTML_FONT_STYLE_ITALIC && style & GTK_HTML_FONT_STYLE_BOLD) |
---|
486 | font = alloc_e_font_do (face, size, points, |
---|
487 | style & ((~GTK_HTML_FONT_STYLE_ITALIC) & (~GTK_HTML_FONT_STYLE_BOLD))); |
---|
488 | |
---|
489 | return font; |
---|
490 | } |
---|
491 | |
---|
492 | static void |
---|
493 | ref_font (HTMLFont *font) |
---|
494 | { |
---|
495 | e_font_ref ((EFont *) font->data); |
---|
496 | } |
---|
497 | |
---|
498 | static void |
---|
499 | unref_font (HTMLFont *font) |
---|
500 | { |
---|
501 | e_font_unref ((EFont *) font->data); |
---|
502 | } |
---|
503 | |
---|
504 | |
---|
505 | static void |
---|
506 | alloc_color (HTMLPainter *painter, |
---|
507 | GdkColor *color) |
---|
508 | { |
---|
509 | HTMLGdkPainter *gdk_painter; |
---|
510 | GdkColormap *colormap; |
---|
511 | |
---|
512 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
513 | g_return_if_fail (gdk_painter->window != NULL); |
---|
514 | |
---|
515 | colormap = gdk_window_get_colormap (gdk_painter->window); |
---|
516 | |
---|
517 | gdk_colormap_alloc_color (colormap, color, FALSE, TRUE); |
---|
518 | } |
---|
519 | |
---|
520 | static void |
---|
521 | free_color (HTMLPainter *painter, |
---|
522 | GdkColor *color) |
---|
523 | { |
---|
524 | HTMLGdkPainter *gdk_painter; |
---|
525 | GdkColormap *colormap; |
---|
526 | |
---|
527 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
528 | |
---|
529 | g_return_if_fail (gdk_painter->window != NULL); |
---|
530 | g_return_if_fail (gdk_painter->gc != NULL); |
---|
531 | |
---|
532 | colormap = gdk_window_get_colormap (gdk_painter->window); |
---|
533 | gdk_colormap_free_colors (colormap, color, 1); |
---|
534 | } |
---|
535 | |
---|
536 | |
---|
537 | static void |
---|
538 | begin (HTMLPainter *painter, int x1, int y1, int x2, int y2) |
---|
539 | { |
---|
540 | HTMLGdkPainter *gdk_painter; |
---|
541 | GdkVisual *visual; |
---|
542 | |
---|
543 | /* printf ("painter begin %d,%d %d,%d\n", x1, y1, x2, y2); */ |
---|
544 | |
---|
545 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
546 | g_return_if_fail (gdk_painter->window != NULL); |
---|
547 | visual = gdk_window_get_visual (gdk_painter->window); |
---|
548 | g_return_if_fail (visual != NULL); |
---|
549 | |
---|
550 | if (gdk_painter->double_buffer){ |
---|
551 | const int width = x2 - x1 + 1; |
---|
552 | const int height = y2 - y1 + 1; |
---|
553 | |
---|
554 | g_assert (gdk_painter->pixmap == NULL); |
---|
555 | |
---|
556 | gdk_painter->pixmap = gdk_pixmap_new (gdk_painter->pixmap, width, height, visual->depth); |
---|
557 | gdk_painter->x1 = x1; |
---|
558 | gdk_painter->y1 = y1; |
---|
559 | gdk_painter->x2 = x2; |
---|
560 | gdk_painter->y2 = y2; |
---|
561 | |
---|
562 | if (gdk_painter->set_background){ |
---|
563 | gdk_gc_set_background (gdk_painter->gc, &gdk_painter->background); |
---|
564 | gdk_painter->set_background = FALSE; |
---|
565 | } |
---|
566 | |
---|
567 | gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->background); |
---|
568 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, |
---|
569 | TRUE, 0, 0, width, height); |
---|
570 | } else { |
---|
571 | gdk_painter->pixmap = gdk_painter->window; |
---|
572 | gdk_painter->x1 = 0; |
---|
573 | gdk_painter->y1 = 0; |
---|
574 | gdk_painter->x2 = 0; |
---|
575 | gdk_painter->y2 = 0; |
---|
576 | } |
---|
577 | } |
---|
578 | |
---|
579 | static void |
---|
580 | end (HTMLPainter *painter) |
---|
581 | { |
---|
582 | HTMLGdkPainter *gdk_painter; |
---|
583 | |
---|
584 | /* printf ("painter end\n"); */ |
---|
585 | |
---|
586 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
587 | |
---|
588 | if (! gdk_painter->double_buffer) |
---|
589 | return; |
---|
590 | |
---|
591 | gdk_draw_pixmap (gdk_painter->window, gdk_painter->gc, |
---|
592 | gdk_painter->pixmap, |
---|
593 | 0, 0, |
---|
594 | gdk_painter->x1, gdk_painter->y1, |
---|
595 | gdk_painter->x2 - gdk_painter->x1, |
---|
596 | gdk_painter->y2 - gdk_painter->y1); |
---|
597 | |
---|
598 | gdk_pixmap_unref (gdk_painter->pixmap); |
---|
599 | gdk_painter->pixmap = NULL; |
---|
600 | } |
---|
601 | |
---|
602 | static HTMLFontManagerId |
---|
603 | get_font_manager_id () |
---|
604 | { |
---|
605 | return HTML_FONT_MANAGER_ID_GDK; |
---|
606 | } |
---|
607 | |
---|
608 | static void |
---|
609 | clear (HTMLPainter *painter) |
---|
610 | { |
---|
611 | HTMLGdkPainter *gdk_painter; |
---|
612 | |
---|
613 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
614 | |
---|
615 | if (! gdk_painter->double_buffer){ |
---|
616 | gdk_window_clear (gdk_painter->window); |
---|
617 | } else { |
---|
618 | if (gdk_painter->pixmap != NULL) |
---|
619 | gdk_window_clear (gdk_painter->pixmap); |
---|
620 | else |
---|
621 | gdk_painter->do_clear = TRUE; |
---|
622 | } |
---|
623 | } |
---|
624 | |
---|
625 | |
---|
626 | static void |
---|
627 | set_clip_rectangle (HTMLPainter *painter, |
---|
628 | gint x, gint y, |
---|
629 | gint width, gint height) |
---|
630 | { |
---|
631 | HTMLGdkPainter *gdk_painter; |
---|
632 | GdkRectangle rect; |
---|
633 | |
---|
634 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
635 | |
---|
636 | if (width == 0 || height == 0) { |
---|
637 | gdk_gc_set_clip_rectangle (gdk_painter->gc, NULL); |
---|
638 | return; |
---|
639 | } |
---|
640 | |
---|
641 | rect.x = x; |
---|
642 | rect.y = y; |
---|
643 | rect.width = width; |
---|
644 | rect.height = height; |
---|
645 | |
---|
646 | gdk_gc_set_clip_rectangle (gdk_painter->gc, &rect); |
---|
647 | } |
---|
648 | |
---|
649 | static void |
---|
650 | set_background_color (HTMLPainter *painter, |
---|
651 | const GdkColor *color) |
---|
652 | { |
---|
653 | g_warning ("HTMLGdkPainter::set_background_color() needs to be implemented."); |
---|
654 | } |
---|
655 | |
---|
656 | static void |
---|
657 | set_pen (HTMLPainter *painter, |
---|
658 | const GdkColor *color) |
---|
659 | { |
---|
660 | HTMLGdkPainter *gdk_painter; |
---|
661 | |
---|
662 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
663 | |
---|
664 | /* GdkColor API not const-safe! */ |
---|
665 | gdk_gc_set_foreground (gdk_painter->gc, (GdkColor *) color); |
---|
666 | } |
---|
667 | |
---|
668 | static const GdkColor * |
---|
669 | get_black (const HTMLPainter *painter) |
---|
670 | { |
---|
671 | HTMLGdkPainter *gdk_painter; |
---|
672 | |
---|
673 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
674 | return &gdk_painter->black; |
---|
675 | } |
---|
676 | |
---|
677 | |
---|
678 | /* HTMLPainter drawing functions. */ |
---|
679 | |
---|
680 | static void |
---|
681 | draw_line (HTMLPainter *painter, |
---|
682 | gint x1, gint y1, |
---|
683 | gint x2, gint y2) |
---|
684 | { |
---|
685 | HTMLGdkPainter *gdk_painter; |
---|
686 | |
---|
687 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
688 | |
---|
689 | x1 -= gdk_painter->x1; |
---|
690 | y1 -= gdk_painter->y1; |
---|
691 | x2 -= gdk_painter->x1; |
---|
692 | y2 -= gdk_painter->y1; |
---|
693 | |
---|
694 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x1, y1, x2, y2); |
---|
695 | } |
---|
696 | |
---|
697 | static void |
---|
698 | draw_ellipse (HTMLPainter *painter, |
---|
699 | gint x, gint y, |
---|
700 | gint width, gint height) |
---|
701 | { |
---|
702 | HTMLGdkPainter *gdk_painter; |
---|
703 | |
---|
704 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
705 | |
---|
706 | gdk_draw_arc (gdk_painter->pixmap, gdk_painter->gc, TRUE, |
---|
707 | x - gdk_painter->x1, y - gdk_painter->y1, |
---|
708 | width, height, |
---|
709 | 0, 360 * 64); |
---|
710 | } |
---|
711 | |
---|
712 | static void |
---|
713 | draw_rect (HTMLPainter *painter, |
---|
714 | gint x, gint y, |
---|
715 | gint width, gint height) |
---|
716 | { |
---|
717 | HTMLGdkPainter *gdk_painter; |
---|
718 | |
---|
719 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
720 | |
---|
721 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, FALSE, |
---|
722 | x - gdk_painter->x1, y - gdk_painter->y1, |
---|
723 | width, height); |
---|
724 | } |
---|
725 | |
---|
726 | static void |
---|
727 | draw_panel (HTMLPainter *painter, |
---|
728 | GdkColor *bg, |
---|
729 | gint x, gint y, |
---|
730 | gint width, gint height, |
---|
731 | GtkHTMLEtchStyle inset, |
---|
732 | gint bordersize) |
---|
733 | { |
---|
734 | HTMLGdkPainter *gdk_painter; |
---|
735 | GdkColor *col1 = NULL, *col2 = NULL; |
---|
736 | GdkColor dark, light; |
---|
737 | |
---|
738 | #define INC 0x8000 |
---|
739 | #define DARK(c) dark.c = MAX (((gint) bg->c) - INC, 0) |
---|
740 | #define LIGHT(c) light.c = MIN (((gint) bg->c) + INC, 0xffff) |
---|
741 | |
---|
742 | DARK(red); |
---|
743 | DARK(green); |
---|
744 | DARK(blue); |
---|
745 | LIGHT(red); |
---|
746 | LIGHT(green); |
---|
747 | LIGHT(blue); |
---|
748 | |
---|
749 | alloc_color (painter, &dark); |
---|
750 | alloc_color (painter, &light); |
---|
751 | |
---|
752 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
753 | |
---|
754 | switch (inset) { |
---|
755 | case GTK_HTML_ETCH_NONE: |
---|
756 | /* use the current pen color */ |
---|
757 | col1 = NULL; |
---|
758 | col2 = NULL; |
---|
759 | break; |
---|
760 | case GTK_HTML_ETCH_OUT: |
---|
761 | col1 = &light; |
---|
762 | col2 = &dark; |
---|
763 | break; |
---|
764 | default: |
---|
765 | case GTK_HTML_ETCH_IN: |
---|
766 | col1 = &dark; |
---|
767 | col2 = &light; |
---|
768 | break; |
---|
769 | } |
---|
770 | |
---|
771 | x -= gdk_painter->x1; |
---|
772 | y -= gdk_painter->y1; |
---|
773 | |
---|
774 | while (bordersize > 0) { |
---|
775 | if (col2) { |
---|
776 | gdk_gc_set_foreground (gdk_painter->gc, col2); |
---|
777 | } |
---|
778 | |
---|
779 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
780 | x + width - 1, y, x + width - 1, y + height - 1); |
---|
781 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
782 | x + 1, y + height - 1, x + width - 1, y + height - 1); |
---|
783 | if (col1) { |
---|
784 | gdk_gc_set_foreground (gdk_painter->gc, col1); |
---|
785 | } |
---|
786 | |
---|
787 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
788 | x, y, x + width - 2, y); |
---|
789 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
790 | x, y, x, y + height - 1); |
---|
791 | bordersize--; |
---|
792 | x++; |
---|
793 | y++; |
---|
794 | width-=2; |
---|
795 | height-=2; |
---|
796 | } |
---|
797 | |
---|
798 | free_color (painter, &dark); |
---|
799 | free_color (painter, &light); |
---|
800 | } |
---|
801 | |
---|
802 | static void |
---|
803 | draw_background (HTMLPainter *painter, |
---|
804 | GdkColor *color, |
---|
805 | GdkPixbuf *pixbuf, |
---|
806 | gint x, gint y, |
---|
807 | gint width, gint height, |
---|
808 | gint tile_x, gint tile_y) |
---|
809 | { |
---|
810 | HTMLGdkPainter *gdk_painter; |
---|
811 | gint pw; |
---|
812 | gint ph; |
---|
813 | gint tile_width, tile_height; |
---|
814 | gint w, h; |
---|
815 | ArtIRect expose, paint, clip; |
---|
816 | |
---|
817 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
818 | |
---|
819 | expose.x0 = x; |
---|
820 | expose.y0 = y; |
---|
821 | expose.x1 = x + width; |
---|
822 | expose.y1 = y + height; |
---|
823 | |
---|
824 | clip.x0 = gdk_painter->x1; |
---|
825 | clip.x1 = gdk_painter->x2; |
---|
826 | clip.y0 = gdk_painter->y1; |
---|
827 | clip.y1 = gdk_painter->y2; |
---|
828 | clip.x0 = gdk_painter->x1; |
---|
829 | |
---|
830 | art_irect_intersect (&paint, &clip, &expose); |
---|
831 | if (art_irect_empty (&paint)) |
---|
832 | return; |
---|
833 | |
---|
834 | width = paint.x1 - paint.x0; |
---|
835 | height = paint.y1 - paint.y0; |
---|
836 | |
---|
837 | tile_x += paint.x0 - x; |
---|
838 | tile_y += paint.y0 - y; |
---|
839 | |
---|
840 | x = paint.x0; |
---|
841 | y = paint.y0; |
---|
842 | |
---|
843 | if (!color && !pixbuf) |
---|
844 | return; |
---|
845 | |
---|
846 | if (color && !pixbuf) { |
---|
847 | gdk_gc_set_foreground (gdk_painter->gc, color); |
---|
848 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, |
---|
849 | TRUE, x - gdk_painter->x1, y - gdk_painter->y1, |
---|
850 | width, height); |
---|
851 | |
---|
852 | } |
---|
853 | |
---|
854 | if (!pixbuf) |
---|
855 | return; |
---|
856 | |
---|
857 | pw = gdk_pixbuf_get_width (pixbuf); |
---|
858 | ph = gdk_pixbuf_get_height (pixbuf); |
---|
859 | |
---|
860 | /* optimize out some special cases */ |
---|
861 | if (pw == 1 && ph == 1) { |
---|
862 | GdkColor pixcol; |
---|
863 | guchar *p; |
---|
864 | |
---|
865 | p = gdk_pixbuf_get_pixels (pixbuf); |
---|
866 | |
---|
867 | if (!(gdk_pixbuf_get_has_alpha (pixbuf) && (p[3] < 0x80))) { |
---|
868 | pixcol.red = p[0] * 0xff; |
---|
869 | pixcol.green = p[1] * 0xff; |
---|
870 | pixcol.blue = p[2] * 0xff; |
---|
871 | |
---|
872 | html_painter_alloc_color (painter, &pixcol); |
---|
873 | color = &pixcol; |
---|
874 | } |
---|
875 | |
---|
876 | if (color) { |
---|
877 | gdk_gc_set_foreground (gdk_painter->gc, color); |
---|
878 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, |
---|
879 | TRUE, x - gdk_painter->x1, y - gdk_painter->y1, |
---|
880 | width, height); |
---|
881 | } |
---|
882 | |
---|
883 | return; |
---|
884 | } |
---|
885 | |
---|
886 | tile_width = (tile_x % pw) + width; |
---|
887 | tile_height = (tile_y % ph) + height; |
---|
888 | |
---|
889 | /* do tiling */ |
---|
890 | if (tile_width > pw || tile_height > ph) { |
---|
891 | GdkPixmap *pixmap = NULL; |
---|
892 | gint cw, ch, cx, cy; |
---|
893 | gint dw, dh; |
---|
894 | GdkGC *gc; |
---|
895 | GdkBitmap *bitmap = NULL; |
---|
896 | |
---|
897 | dw = MIN (pw, tile_width); |
---|
898 | dh = MIN (ph, tile_height); |
---|
899 | |
---|
900 | gc = gdk_gc_new (gdk_painter->window); |
---|
901 | |
---|
902 | if (color || !gdk_pixbuf_get_has_alpha (pixbuf)) { |
---|
903 | pixmap = gdk_pixmap_new (gdk_painter->window, dw, dh, -1); |
---|
904 | |
---|
905 | if (color) { |
---|
906 | gdk_gc_set_foreground (gc, color); |
---|
907 | gdk_draw_rectangle (pixmap, gc, |
---|
908 | TRUE, 0, 0, |
---|
909 | dw, dh); |
---|
910 | } |
---|
911 | |
---|
912 | gdk_pixbuf_render_to_drawable_alpha (pixbuf, pixmap, |
---|
913 | 0, 0, |
---|
914 | 0, 0, |
---|
915 | dw, dh, |
---|
916 | GDK_PIXBUF_ALPHA_BILEVEL, |
---|
917 | 128, |
---|
918 | GDK_RGB_DITHER_NORMAL, |
---|
919 | x, y); |
---|
920 | |
---|
921 | gdk_gc_set_tile (gc, pixmap); |
---|
922 | gdk_gc_set_fill (gc, GDK_TILED); |
---|
923 | gdk_gc_set_ts_origin (gc, |
---|
924 | x - (tile_x % pw) - gdk_painter->x1, |
---|
925 | y - (tile_y % ph) - gdk_painter->y1); |
---|
926 | |
---|
927 | gdk_draw_rectangle (gdk_painter->pixmap, gc, TRUE, |
---|
928 | x - gdk_painter->x1, y - gdk_painter->y1, |
---|
929 | width, height); |
---|
930 | |
---|
931 | gdk_pixmap_unref (pixmap); |
---|
932 | gdk_gc_unref (gc); |
---|
933 | } else { |
---|
934 | int incr_x = 0; |
---|
935 | int incr_y = 0; |
---|
936 | |
---|
937 | /* Right now we only support GDK_PIXBUF_ALPHA_BILEVEL, so we |
---|
938 | * unconditionally create the clipping mask. |
---|
939 | */ |
---|
940 | bitmap = gdk_pixmap_new (NULL, dw, dh, 1); |
---|
941 | |
---|
942 | gdk_pixbuf_render_threshold_alpha (pixbuf, bitmap, |
---|
943 | 0, 0, |
---|
944 | 0, 0, |
---|
945 | dw, dh, |
---|
946 | 128); |
---|
947 | |
---|
948 | gdk_gc_set_clip_mask (gc, bitmap); |
---|
949 | |
---|
950 | pixmap = gdk_pixmap_new (gdk_painter->window, dw, dh, -1); |
---|
951 | gdk_pixbuf_render_to_drawable (pixbuf, pixmap, gc, |
---|
952 | 0, 0, |
---|
953 | 0, 0, |
---|
954 | dw, dh, |
---|
955 | GDK_RGB_DITHER_NORMAL, |
---|
956 | x, y); |
---|
957 | |
---|
958 | cy = y; |
---|
959 | ch = height; |
---|
960 | h = tile_y % ph; |
---|
961 | while (ch > 0) { |
---|
962 | incr_y = dh - h; |
---|
963 | |
---|
964 | cx = x; |
---|
965 | cw = width; |
---|
966 | w = tile_x % pw; |
---|
967 | while (cw > 0) { |
---|
968 | incr_x = dw - w; |
---|
969 | |
---|
970 | gdk_gc_set_clip_origin (gc, |
---|
971 | cx - w - gdk_painter->x1, |
---|
972 | cy - h - gdk_painter->y1); |
---|
973 | |
---|
974 | |
---|
975 | gdk_draw_pixmap (gdk_painter->pixmap, gc, pixmap, |
---|
976 | w, h, cx - gdk_painter->x1, cy - gdk_painter->y1, |
---|
977 | (cw >= incr_x) ? incr_x : cw, |
---|
978 | (ch >= incr_y) ? incr_y : ch); |
---|
979 | cw -= incr_x; |
---|
980 | cx += incr_x; |
---|
981 | w = 0; |
---|
982 | } |
---|
983 | ch -= incr_y; |
---|
984 | cy += incr_y; |
---|
985 | h = 0; |
---|
986 | } |
---|
987 | gdk_pixmap_unref (pixmap); |
---|
988 | gdk_bitmap_unref (bitmap); |
---|
989 | gdk_gc_unref (gc); |
---|
990 | } |
---|
991 | } else { |
---|
992 | if (color && gdk_pixbuf_get_has_alpha (pixbuf)) { |
---|
993 | gdk_gc_set_foreground (gdk_painter->gc, color); |
---|
994 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, TRUE, |
---|
995 | x - gdk_painter->x1, y - gdk_painter->y1, |
---|
996 | width, height); |
---|
997 | } |
---|
998 | |
---|
999 | gdk_pixbuf_render_to_drawable_alpha (pixbuf, gdk_painter->pixmap, |
---|
1000 | tile_x % pw, tile_y % ph, |
---|
1001 | x - gdk_painter->x1, y - gdk_painter->y1, |
---|
1002 | width, height, |
---|
1003 | GDK_PIXBUF_ALPHA_BILEVEL, |
---|
1004 | 128, |
---|
1005 | GDK_RGB_DITHER_NORMAL, |
---|
1006 | x, y); |
---|
1007 | } |
---|
1008 | } |
---|
1009 | |
---|
1010 | static GdkPixbuf * |
---|
1011 | create_temporary_pixbuf (GdkPixbuf *src, |
---|
1012 | gint clip_width, gint clip_height) |
---|
1013 | { |
---|
1014 | GdkPixbuf *pixbuf; |
---|
1015 | gboolean has_alpha; |
---|
1016 | guint bits_per_sample; |
---|
1017 | |
---|
1018 | has_alpha = gdk_pixbuf_get_has_alpha (src); |
---|
1019 | bits_per_sample = gdk_pixbuf_get_bits_per_sample (src); |
---|
1020 | |
---|
1021 | pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, bits_per_sample, clip_width, clip_height); |
---|
1022 | |
---|
1023 | return pixbuf; |
---|
1024 | } |
---|
1025 | |
---|
1026 | static void |
---|
1027 | draw_pixmap (HTMLPainter *painter, |
---|
1028 | GdkPixbuf *pixbuf, |
---|
1029 | gint x, gint y, |
---|
1030 | gint scale_width, gint scale_height, |
---|
1031 | const GdkColor *color) |
---|
1032 | { |
---|
1033 | ArtIRect clip, image, paint; |
---|
1034 | HTMLGdkPainter *gdk_painter; |
---|
1035 | GdkPixbuf *tmp_pixbuf; |
---|
1036 | guint n_channels; |
---|
1037 | gint orig_width; |
---|
1038 | gint orig_height; |
---|
1039 | gint paint_width; |
---|
1040 | gint paint_height; |
---|
1041 | gint bilinear; |
---|
1042 | |
---|
1043 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1044 | |
---|
1045 | orig_width = gdk_pixbuf_get_width (pixbuf); |
---|
1046 | orig_height = gdk_pixbuf_get_height (pixbuf); |
---|
1047 | |
---|
1048 | if (scale_width < 0) |
---|
1049 | scale_width = orig_width; |
---|
1050 | if (scale_height < 0) |
---|
1051 | scale_height = orig_height; |
---|
1052 | |
---|
1053 | image.x0 = x; |
---|
1054 | image.y0 = y; |
---|
1055 | image.x1 = x + scale_width; |
---|
1056 | image.y1 = y + scale_height; |
---|
1057 | |
---|
1058 | clip.x0 = gdk_painter->x1; |
---|
1059 | clip.x1 = gdk_painter->x2; |
---|
1060 | clip.y0 = gdk_painter->y1; |
---|
1061 | clip.y1 = gdk_painter->y2; |
---|
1062 | |
---|
1063 | art_irect_intersect (&paint, &clip, &image); |
---|
1064 | if (art_irect_empty (&paint)) |
---|
1065 | return; |
---|
1066 | |
---|
1067 | paint_width = paint.x1 - paint.x0; |
---|
1068 | paint_height = paint.y1 - paint.y0; |
---|
1069 | |
---|
1070 | |
---|
1071 | if (scale_width == orig_width && scale_height == orig_height && color == NULL && (!gdk_painter->alpha)) { |
---|
1072 | gdk_pixbuf_render_to_drawable_alpha (pixbuf, gdk_painter->pixmap, |
---|
1073 | paint.x0 - image.x0, |
---|
1074 | paint.y0 - image.y0, |
---|
1075 | paint.x0 - clip.x0, |
---|
1076 | paint.y0 - clip.y0, |
---|
1077 | paint_width, |
---|
1078 | paint_height, |
---|
1079 | GDK_PIXBUF_ALPHA_BILEVEL, |
---|
1080 | 128, |
---|
1081 | GDK_RGB_DITHER_NORMAL, |
---|
1082 | x, y); |
---|
1083 | return; |
---|
1084 | } |
---|
1085 | |
---|
1086 | if (gdk_pixbuf_get_has_alpha (pixbuf) && gdk_painter->alpha) { |
---|
1087 | tmp_pixbuf = gdk_pixbuf_get_from_drawable(NULL, |
---|
1088 | gdk_painter->pixmap, |
---|
1089 | gdk_window_get_colormap (gdk_painter->window), |
---|
1090 | paint.x0 - clip.x0, |
---|
1091 | paint.y0 - clip.y0, |
---|
1092 | 0, 0, paint_width, paint_height); |
---|
1093 | } else { |
---|
1094 | tmp_pixbuf = create_temporary_pixbuf (pixbuf, |
---|
1095 | paint_width, |
---|
1096 | paint_height); |
---|
1097 | } |
---|
1098 | |
---|
1099 | if (tmp_pixbuf == NULL) |
---|
1100 | return; |
---|
1101 | |
---|
1102 | /* |
---|
1103 | * FIXME this is a hack to work around a gdk-pixbuf bug |
---|
1104 | * it could be removed when |
---|
1105 | * http://bugzilla.ximian.com/show_bug.cgi?id=12968 |
---|
1106 | * is fixed. |
---|
1107 | */ |
---|
1108 | bilinear = !((scale_width == 1) && (scale_height == 1)); |
---|
1109 | |
---|
1110 | gdk_pixbuf_composite (pixbuf, tmp_pixbuf, |
---|
1111 | 0, |
---|
1112 | 0, |
---|
1113 | paint_width, paint_height, |
---|
1114 | (double)-(paint.x0 - image.x0), |
---|
1115 | (double)-(paint.y0 - image.y0), |
---|
1116 | (gdouble) scale_width/ (gdouble) orig_width, |
---|
1117 | (gdouble) scale_height/ (gdouble) orig_height, |
---|
1118 | bilinear ? GDK_INTERP_BILINEAR : GDK_INTERP_NEAREST, |
---|
1119 | 255); |
---|
1120 | |
---|
1121 | if (color != NULL) { |
---|
1122 | guchar *p, *q; |
---|
1123 | guint i, j; |
---|
1124 | |
---|
1125 | n_channels = gdk_pixbuf_get_n_channels (tmp_pixbuf); |
---|
1126 | p = q = gdk_pixbuf_get_pixels (tmp_pixbuf); |
---|
1127 | for (i = 0; i < paint_height; i++) { |
---|
1128 | p = q; |
---|
1129 | |
---|
1130 | for (j = 0; j < paint_width; j++) { |
---|
1131 | gint r, g, b, a; |
---|
1132 | |
---|
1133 | if (n_channels > 3) |
---|
1134 | a = p[3]; |
---|
1135 | else |
---|
1136 | a = 0xff; |
---|
1137 | |
---|
1138 | r = (a * p[0] + color->red) >> 9; |
---|
1139 | g = (a * p[1] + color->green) >> 9; |
---|
1140 | b = (a * p[2] + color->blue) >> 9; |
---|
1141 | |
---|
1142 | p[0] = r; |
---|
1143 | p[1] = g; |
---|
1144 | p[2] = b; |
---|
1145 | |
---|
1146 | if (n_channels > 3) |
---|
1147 | p[3] = 0xff; |
---|
1148 | |
---|
1149 | p += n_channels; |
---|
1150 | } |
---|
1151 | |
---|
1152 | q += gdk_pixbuf_get_rowstride (tmp_pixbuf); |
---|
1153 | } |
---|
1154 | } |
---|
1155 | |
---|
1156 | gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, gdk_painter->pixmap, |
---|
1157 | 0, |
---|
1158 | 0, |
---|
1159 | paint.x0 - clip.x0, |
---|
1160 | paint.y0 - clip.y0, |
---|
1161 | paint_width, |
---|
1162 | paint_height, |
---|
1163 | GDK_PIXBUF_ALPHA_BILEVEL, |
---|
1164 | 128, |
---|
1165 | GDK_RGB_DITHER_NORMAL, |
---|
1166 | x, y); |
---|
1167 | gdk_pixbuf_unref (tmp_pixbuf); |
---|
1168 | } |
---|
1169 | |
---|
1170 | static void |
---|
1171 | fill_rect (HTMLPainter *painter, |
---|
1172 | gint x, gint y, |
---|
1173 | gint width, gint height) |
---|
1174 | { |
---|
1175 | HTMLGdkPainter *gdk_painter; |
---|
1176 | |
---|
1177 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1178 | |
---|
1179 | gdk_draw_rectangle (gdk_painter->pixmap, gdk_painter->gc, |
---|
1180 | TRUE, x - gdk_painter->x1, y - gdk_painter->y1, |
---|
1181 | width, height); |
---|
1182 | } |
---|
1183 | |
---|
1184 | static EFontStyle |
---|
1185 | e_style (GtkHTMLFontStyle style) |
---|
1186 | { |
---|
1187 | EFontStyle rv = E_FONT_PLAIN; |
---|
1188 | |
---|
1189 | if (style & GTK_HTML_FONT_STYLE_BOLD) rv |= E_FONT_BOLD; |
---|
1190 | if (style & GTK_HTML_FONT_STYLE_ITALIC) rv |= E_FONT_ITALIC; |
---|
1191 | |
---|
1192 | return rv; |
---|
1193 | } |
---|
1194 | |
---|
1195 | static gint |
---|
1196 | draw_spell_error (HTMLPainter *painter, gint x, gint y, const gchar *text, gint len) |
---|
1197 | { |
---|
1198 | HTMLGdkPainter *gdk_painter; |
---|
1199 | EFont *e_font; |
---|
1200 | GdkGCValues values; |
---|
1201 | guint width; |
---|
1202 | gchar dash [2]; |
---|
1203 | |
---|
1204 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1205 | |
---|
1206 | x -= gdk_painter->x1; |
---|
1207 | y -= gdk_painter->y1; |
---|
1208 | |
---|
1209 | e_font = html_painter_get_font (painter, painter->font_face, painter->font_style); |
---|
1210 | width = e_font_utf8_text_width (e_font, e_style (painter->font_style), text, |
---|
1211 | g_utf8_offset_to_pointer (text, len) - text); |
---|
1212 | |
---|
1213 | gdk_gc_get_values (gdk_painter->gc, &values); |
---|
1214 | gdk_gc_set_fill (gdk_painter->gc, GDK_OPAQUE_STIPPLED); |
---|
1215 | dash [0] = 2; |
---|
1216 | dash [1] = 2; |
---|
1217 | gdk_gc_set_line_attributes (gdk_painter->gc, 1, GDK_LINE_ON_OFF_DASH, values.cap_style, values.join_style); |
---|
1218 | gdk_gc_set_dashes (gdk_painter->gc, 2, dash, 2); |
---|
1219 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y, x + width, y); |
---|
1220 | gdk_gc_set_dashes (gdk_painter->gc, 0, dash, 2); |
---|
1221 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y + 1, x + width, y + 1); |
---|
1222 | gdk_gc_set_line_attributes (gdk_painter->gc, values.line_width, |
---|
1223 | values.line_style, values.cap_style, values.join_style); |
---|
1224 | |
---|
1225 | return width; |
---|
1226 | } |
---|
1227 | |
---|
1228 | static void |
---|
1229 | draw_embedded (HTMLPainter * p, HTMLEmbedded *o, gint x, gint y) |
---|
1230 | { |
---|
1231 | HTMLGdkPainter *gdk_painter = HTML_GDK_PAINTER(p); |
---|
1232 | GtkWidget *embedded_widget; |
---|
1233 | |
---|
1234 | embedded_widget = html_embedded_get_widget (o); |
---|
1235 | if (embedded_widget && GTK_IS_HTML_EMBEDDED (embedded_widget)) { |
---|
1236 | gtk_signal_emit_by_name (GTK_OBJECT (embedded_widget), |
---|
1237 | "draw_gdk", |
---|
1238 | gdk_painter->pixmap, |
---|
1239 | gdk_painter->gc, |
---|
1240 | x, y); |
---|
1241 | } |
---|
1242 | } |
---|
1243 | |
---|
1244 | static void |
---|
1245 | draw_text (HTMLPainter *painter, |
---|
1246 | gint x, gint y, |
---|
1247 | const gchar *text, |
---|
1248 | gint len) |
---|
1249 | { |
---|
1250 | HTMLGdkPainter *gdk_painter; |
---|
1251 | EFont *e_font; |
---|
1252 | |
---|
1253 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1254 | |
---|
1255 | if (len == -1) |
---|
1256 | len = g_utf8_strlen (text, -1); |
---|
1257 | |
---|
1258 | x -= gdk_painter->x1; |
---|
1259 | y -= gdk_painter->y1; |
---|
1260 | |
---|
1261 | e_font = html_painter_get_font (painter, |
---|
1262 | painter->font_face, |
---|
1263 | painter->font_style); |
---|
1264 | |
---|
1265 | e_font_draw_utf8_text (gdk_painter->pixmap, |
---|
1266 | e_font, |
---|
1267 | e_style (painter->font_style), |
---|
1268 | gdk_painter->gc, |
---|
1269 | x, y, |
---|
1270 | text, |
---|
1271 | g_utf8_offset_to_pointer (text, len) - text); |
---|
1272 | |
---|
1273 | if (painter->font_style & (GTK_HTML_FONT_STYLE_UNDERLINE |
---|
1274 | | GTK_HTML_FONT_STYLE_STRIKEOUT)) { |
---|
1275 | guint width; |
---|
1276 | |
---|
1277 | width = e_font_utf8_text_width (e_font, |
---|
1278 | e_style (painter->font_style), |
---|
1279 | text, |
---|
1280 | g_utf8_offset_to_pointer (text, len) - text); |
---|
1281 | |
---|
1282 | if (painter->font_style & GTK_HTML_FONT_STYLE_UNDERLINE) |
---|
1283 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
1284 | x, y + 1, |
---|
1285 | x + width, y + 1); |
---|
1286 | |
---|
1287 | if (painter->font_style & GTK_HTML_FONT_STYLE_STRIKEOUT) |
---|
1288 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, |
---|
1289 | x, y - e_font_ascent (e_font) / 2, |
---|
1290 | x + width, y - e_font_ascent (e_font) / 2); |
---|
1291 | } |
---|
1292 | } |
---|
1293 | |
---|
1294 | static void |
---|
1295 | draw_shade_line (HTMLPainter *painter, |
---|
1296 | gint x, gint y, |
---|
1297 | gint width) |
---|
1298 | { |
---|
1299 | HTMLGdkPainter *gdk_painter; |
---|
1300 | |
---|
1301 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1302 | |
---|
1303 | x -= gdk_painter->x1; |
---|
1304 | y -= gdk_painter->y1; |
---|
1305 | |
---|
1306 | gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->dark); |
---|
1307 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y, x+width, y); |
---|
1308 | gdk_gc_set_foreground (gdk_painter->gc, &gdk_painter->light); |
---|
1309 | gdk_draw_line (gdk_painter->pixmap, gdk_painter->gc, x, y + 1, x + width, y + 1); |
---|
1310 | } |
---|
1311 | |
---|
1312 | static guint |
---|
1313 | calc_ascent (HTMLPainter *painter, GtkHTMLFontStyle style, HTMLFontFace *face) |
---|
1314 | { |
---|
1315 | HTMLGdkPainter *gdk_painter; |
---|
1316 | EFont *e_font; |
---|
1317 | |
---|
1318 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1319 | |
---|
1320 | e_font = html_painter_get_font (painter, face, style); |
---|
1321 | if (e_font == NULL) |
---|
1322 | return 0; |
---|
1323 | |
---|
1324 | return e_font_ascent (e_font); |
---|
1325 | } |
---|
1326 | |
---|
1327 | static guint |
---|
1328 | calc_descent (HTMLPainter *painter, GtkHTMLFontStyle style, HTMLFontFace *face) |
---|
1329 | { |
---|
1330 | HTMLGdkPainter *gdk_painter; |
---|
1331 | EFont *e_font; |
---|
1332 | |
---|
1333 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1334 | |
---|
1335 | e_font = html_painter_get_font (painter, face, style); |
---|
1336 | if (e_font == NULL) |
---|
1337 | return 0; |
---|
1338 | |
---|
1339 | return e_font_descent (e_font); |
---|
1340 | } |
---|
1341 | |
---|
1342 | static guint |
---|
1343 | calc_text_width (HTMLPainter *painter, |
---|
1344 | const gchar *text, |
---|
1345 | guint len, |
---|
1346 | GtkHTMLFontStyle style, |
---|
1347 | HTMLFontFace *face) |
---|
1348 | { |
---|
1349 | HTMLGdkPainter *gdk_painter; |
---|
1350 | HTMLFont *font; |
---|
1351 | EFont *e_font; |
---|
1352 | gint width; |
---|
1353 | |
---|
1354 | gdk_painter = HTML_GDK_PAINTER (painter); |
---|
1355 | font = html_painter_get_html_font (painter, face, style); |
---|
1356 | e_font = font->data; |
---|
1357 | |
---|
1358 | width = e_font_utf8_text_width (e_font, e_style (style), text, g_utf8_offset_to_pointer (text, len) - text); |
---|
1359 | |
---|
1360 | /* printf ("calc_text_width text: %s len: %d\n", text, len); |
---|
1361 | { gint i; printf ("["); for (i=0;i<g_utf8_offset_to_pointer (text, len)-text; i++) |
---|
1362 | printf ("%c", text [i]); printf ("] ");} |
---|
1363 | printf ("%d (%p)\n", width, e_font); */ |
---|
1364 | return width; |
---|
1365 | } |
---|
1366 | |
---|
1367 | static guint |
---|
1368 | calc_text_width_bytes (HTMLPainter *painter, const gchar *text, |
---|
1369 | guint bytes_len, HTMLFont *font, GtkHTMLFontStyle style) |
---|
1370 | { |
---|
1371 | return e_font_utf8_text_width (font->data, e_style (style), text, bytes_len); |
---|
1372 | } |
---|
1373 | |
---|
1374 | static guint |
---|
1375 | get_pixel_size (HTMLPainter *painter) |
---|
1376 | { |
---|
1377 | return 1; |
---|
1378 | } |
---|
1379 | |
---|
1380 | static guint |
---|
1381 | get_page_width (HTMLPainter *painter, HTMLEngine *e) |
---|
1382 | { |
---|
1383 | return html_engine_get_view_width (e) + e->leftBorder + e->rightBorder; |
---|
1384 | } |
---|
1385 | |
---|
1386 | static guint |
---|
1387 | get_page_height (HTMLPainter *painter, HTMLEngine *e) |
---|
1388 | { |
---|
1389 | return html_engine_get_view_height (e) + e->topBorder + e->bottomBorder; |
---|
1390 | } |
---|
1391 | |
---|
1392 | static void |
---|
1393 | init_color (GdkColor *color, gushort red, gushort green, gushort blue) |
---|
1394 | { |
---|
1395 | color->pixel = 0; |
---|
1396 | color->red = red; |
---|
1397 | color->green = green; |
---|
1398 | color->blue = blue; |
---|
1399 | } |
---|
1400 | |
---|
1401 | static void |
---|
1402 | init (GtkObject *object) |
---|
1403 | { |
---|
1404 | HTMLGdkPainter *gdk_painter; |
---|
1405 | |
---|
1406 | gdk_painter = HTML_GDK_PAINTER (object); |
---|
1407 | |
---|
1408 | gdk_painter->window = NULL; |
---|
1409 | |
---|
1410 | gdk_painter->alpha = TRUE; |
---|
1411 | gdk_painter->gc = NULL; |
---|
1412 | |
---|
1413 | gdk_painter->double_buffer = TRUE; |
---|
1414 | gdk_painter->pixmap = NULL; |
---|
1415 | gdk_painter->x1 = gdk_painter->y1 = 0; |
---|
1416 | gdk_painter->x2 = gdk_painter->y2 = 0; |
---|
1417 | gdk_painter->set_background = FALSE; |
---|
1418 | gdk_painter->do_clear = FALSE; |
---|
1419 | |
---|
1420 | init_color (& gdk_painter->background, 0xffff, 0xffff, 0xffff); |
---|
1421 | init_color (& gdk_painter->dark, 0, 0, 0); |
---|
1422 | init_color (& gdk_painter->light, 0, 0, 0); |
---|
1423 | } |
---|
1424 | |
---|
1425 | static void |
---|
1426 | class_init (GtkObjectClass *object_class) |
---|
1427 | { |
---|
1428 | HTMLPainterClass *painter_class; |
---|
1429 | |
---|
1430 | painter_class = HTML_PAINTER_CLASS (object_class); |
---|
1431 | |
---|
1432 | object_class->finalize = finalize; |
---|
1433 | |
---|
1434 | painter_class->begin = begin; |
---|
1435 | painter_class->end = end; |
---|
1436 | painter_class->alloc_font = alloc_e_font; |
---|
1437 | painter_class->ref_font = ref_font; |
---|
1438 | painter_class->unref_font = unref_font; |
---|
1439 | painter_class->alloc_color = alloc_color; |
---|
1440 | painter_class->free_color = free_color; |
---|
1441 | painter_class->calc_ascent = calc_ascent; |
---|
1442 | painter_class->calc_descent = calc_descent; |
---|
1443 | painter_class->calc_text_width = calc_text_width; |
---|
1444 | painter_class->calc_text_width_bytes = calc_text_width_bytes; |
---|
1445 | painter_class->set_pen = set_pen; |
---|
1446 | painter_class->get_black = get_black; |
---|
1447 | painter_class->draw_line = draw_line; |
---|
1448 | painter_class->draw_rect = draw_rect; |
---|
1449 | painter_class->draw_text = draw_text; |
---|
1450 | painter_class->draw_spell_error = draw_spell_error; |
---|
1451 | painter_class->fill_rect = fill_rect; |
---|
1452 | painter_class->draw_pixmap = draw_pixmap; |
---|
1453 | painter_class->draw_ellipse = draw_ellipse; |
---|
1454 | painter_class->clear = clear; |
---|
1455 | painter_class->set_background_color = set_background_color; |
---|
1456 | painter_class->draw_shade_line = draw_shade_line; |
---|
1457 | painter_class->draw_panel = draw_panel; |
---|
1458 | painter_class->set_clip_rectangle = set_clip_rectangle; |
---|
1459 | painter_class->draw_background = draw_background; |
---|
1460 | painter_class->get_pixel_size = get_pixel_size; |
---|
1461 | painter_class->draw_embedded = draw_embedded; |
---|
1462 | painter_class->get_page_width = get_page_width; |
---|
1463 | painter_class->get_page_height = get_page_height; |
---|
1464 | painter_class->get_font_manager_id = get_font_manager_id; |
---|
1465 | |
---|
1466 | parent_class = gtk_type_class (html_painter_get_type ()); |
---|
1467 | } |
---|
1468 | |
---|
1469 | GtkType |
---|
1470 | html_gdk_painter_get_type (void) |
---|
1471 | { |
---|
1472 | static GtkType type = 0; |
---|
1473 | |
---|
1474 | if (type == 0) { |
---|
1475 | static const GtkTypeInfo info = { |
---|
1476 | "HTMLGdkPainter", |
---|
1477 | sizeof (HTMLGdkPainter), |
---|
1478 | sizeof (HTMLGdkPainterClass), |
---|
1479 | (GtkClassInitFunc) class_init, |
---|
1480 | (GtkObjectInitFunc) init, |
---|
1481 | /* reserved_1 */ NULL, |
---|
1482 | /* reserved_2 */ NULL, |
---|
1483 | (GtkClassInitFunc) NULL, |
---|
1484 | }; |
---|
1485 | |
---|
1486 | type = gtk_type_unique (HTML_TYPE_PAINTER, &info); |
---|
1487 | } |
---|
1488 | |
---|
1489 | return type; |
---|
1490 | } |
---|
1491 | |
---|
1492 | |
---|
1493 | HTMLPainter * |
---|
1494 | html_gdk_painter_new (gboolean double_buffer) |
---|
1495 | { |
---|
1496 | HTMLGdkPainter *new; |
---|
1497 | |
---|
1498 | new = gtk_type_new (html_gdk_painter_get_type ()); |
---|
1499 | |
---|
1500 | new->double_buffer = double_buffer; |
---|
1501 | |
---|
1502 | return HTML_PAINTER (new); |
---|
1503 | } |
---|
1504 | |
---|
1505 | void |
---|
1506 | html_gdk_painter_realize (HTMLGdkPainter *gdk_painter, |
---|
1507 | GdkWindow *window) |
---|
1508 | { |
---|
1509 | GdkColormap *colormap; |
---|
1510 | |
---|
1511 | g_return_if_fail (gdk_painter != NULL); |
---|
1512 | g_return_if_fail (window != NULL); |
---|
1513 | |
---|
1514 | gdk_painter->gc = gdk_gc_new (window); |
---|
1515 | gdk_painter->window = window; |
---|
1516 | |
---|
1517 | colormap = gdk_window_get_colormap (window); |
---|
1518 | |
---|
1519 | gdk_painter->light.red = 0xffff; |
---|
1520 | gdk_painter->light.green = 0xffff; |
---|
1521 | gdk_painter->light.blue = 0xffff; |
---|
1522 | gdk_colormap_alloc_color (colormap, &gdk_painter->light, TRUE, TRUE); |
---|
1523 | |
---|
1524 | gdk_painter->dark.red = 0x7fff; |
---|
1525 | gdk_painter->dark.green = 0x7fff; |
---|
1526 | gdk_painter->dark.blue = 0x7fff; |
---|
1527 | gdk_colormap_alloc_color (colormap, &gdk_painter->dark, TRUE, TRUE); |
---|
1528 | |
---|
1529 | gdk_painter->black.red = 0x0000; |
---|
1530 | gdk_painter->black.green = 0x0000; |
---|
1531 | gdk_painter->black.blue = 0x0000; |
---|
1532 | gdk_colormap_alloc_color (colormap, &gdk_painter->black, TRUE, TRUE); |
---|
1533 | } |
---|
1534 | |
---|
1535 | void |
---|
1536 | html_gdk_painter_unrealize (HTMLGdkPainter *painter) |
---|
1537 | { |
---|
1538 | g_return_if_fail (painter != NULL); |
---|
1539 | g_return_if_fail (HTML_IS_GDK_PAINTER (painter)); |
---|
1540 | |
---|
1541 | if (html_gdk_painter_realized (painter)) { |
---|
1542 | gdk_gc_unref (painter->gc); |
---|
1543 | painter->gc = NULL; |
---|
1544 | |
---|
1545 | painter->window = NULL; |
---|
1546 | } |
---|
1547 | } |
---|
1548 | |
---|
1549 | gboolean |
---|
1550 | html_gdk_painter_realized (HTMLGdkPainter *painter) |
---|
1551 | { |
---|
1552 | g_return_val_if_fail (painter != NULL, FALSE); |
---|
1553 | g_return_val_if_fail (HTML_IS_GDK_PAINTER (painter), FALSE); |
---|
1554 | |
---|
1555 | if (painter->window == NULL) |
---|
1556 | return FALSE; |
---|
1557 | else |
---|
1558 | return TRUE; |
---|
1559 | } |
---|