source: trunk/third/librsvg/gtk-engine/svg-render.c @ 18609

Revision 18609, 19.9 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18608, which included commits to RCS files with non-trunk default branches.
Line 
1/* GTK+ Rsvg Engine
2 * Copyright (C) 1998-2000 Red Hat, Inc.
3 * Copyright (C) 2002 Dom Lachowicz
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Written by Owen Taylor <otaylor@redhat.com>, based on code by
21 * Carsten Haitzler <raster@rasterman.com>
22 */
23
24#include <string.h>
25
26#include "svg.h"
27#include <gdk-pixbuf/gdk-pixbuf.h>
28#include <rsvg.h>
29
30GCache *pixbuf_cache = NULL;
31
32static GdkPixbuf *
33bilinear_gradient (GdkPixbuf    *src,
34                   gint          src_x,
35                   gint          src_y,
36                   gint          width,
37                   gint          height)
38{
39  guint n_channels = gdk_pixbuf_get_n_channels (src);
40  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
41  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
42  guchar *p1, *p2, *p3, *p4;
43  guint dest_rowstride;
44  guchar *dest_pixels;
45  GdkPixbuf *result;
46  int i, j;
47  guint k;
48
49  p1 = src_pixels + (src_y - 1) * src_rowstride + (src_x - 1) * n_channels;
50  p2 = p1 + n_channels;
51  p3 = src_pixels + src_y * src_rowstride + (src_x - 1) * n_channels;
52  p4 = p3 + n_channels;
53
54  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
55                           width, height);
56  dest_rowstride = gdk_pixbuf_get_rowstride (result);
57  dest_pixels = gdk_pixbuf_get_pixels (result);
58
59  for (i = 0; i < height; i++)
60    {
61      guchar *p = dest_pixels + dest_rowstride *i;
62      guint v[4];
63      gint dv[4];
64
65      for (k = 0; k < n_channels; k++)
66        {
67          guint start = ((height - i) * p1[k] + (1 + i) * p3[k]) / (height + 1);
68          guint end = ((height -  i) * p2[k] + (1 + i) * p4[k]) / (height + 1);
69
70          dv[k] = (((gint)end - (gint)start) << 16) / (width + 1);
71          v[k] = (start << 16) + dv[k] + 0x8000;
72        }
73
74      for (j = width; j; j--)
75        {
76          for (k = 0; k < n_channels; k++)
77            {
78              *(p++) = v[k] >> 16;
79              v[k] += dv[k];
80            }
81        }
82    }
83
84  return result;
85}
86
87static GdkPixbuf *
88horizontal_gradient (GdkPixbuf    *src,
89                     gint          src_x,
90                     gint          src_y,
91                     gint          width,
92                     gint          height)
93{
94  guint n_channels = gdk_pixbuf_get_n_channels (src);
95  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
96  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
97  guint dest_rowstride;
98  guchar *dest_pixels;
99  GdkPixbuf *result;
100  int i, j;
101  guint k;
102
103  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
104                           width, height);
105  dest_rowstride = gdk_pixbuf_get_rowstride (result);
106  dest_pixels = gdk_pixbuf_get_pixels (result);
107
108  for (i = 0; i < height; i++)
109    {
110      guchar *p = dest_pixels + dest_rowstride *i;
111      guchar *p1 = src_pixels + (src_y + i) * src_rowstride + (src_x - 1) * n_channels;
112      guchar *p2 = p1 + n_channels;
113
114      guint v[4];
115      gint dv[4];
116
117      for (k = 0; k < n_channels; k++)
118        {
119          dv[k] = (((gint)p2[k] - (gint)p1[k]) << 16) / (width + 1);
120          v[k] = (p1[k] << 16) + dv[k] + 0x8000;
121        }
122     
123      for (j = width; j; j--)
124        {
125          for (k = 0; k < n_channels; k++)
126            {
127              *(p++) = v[k] >> 16;
128              v[k] += dv[k];
129            }
130        }
131    }
132
133  return result;
134}
135
136static GdkPixbuf *
137vertical_gradient (GdkPixbuf    *src,
138                   gint          src_x,
139                   gint          src_y,
140                   gint          width,
141                   gint          height)
142{
143  guint n_channels = gdk_pixbuf_get_n_channels (src);
144  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
145  guchar *src_pixels = gdk_pixbuf_get_pixels (src);
146  guchar *top_pixels, *bottom_pixels;
147  guint dest_rowstride;
148  guchar *dest_pixels;
149  GdkPixbuf *result;
150  int i, j;
151
152  top_pixels = src_pixels + (src_y - 1) * src_rowstride + (src_x) * n_channels;
153  bottom_pixels = top_pixels + src_rowstride;
154
155  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
156                           width, height);
157  dest_rowstride = gdk_pixbuf_get_rowstride (result);
158  dest_pixels = gdk_pixbuf_get_pixels (result);
159
160  for (i = 0; i < height; i++)
161    {
162      guchar *p = dest_pixels + dest_rowstride *i;
163      guchar *p1 = top_pixels;
164      guchar *p2 = bottom_pixels;
165
166      for (j = width * n_channels; j; j--)
167        *(p++) = ((height - i) * *(p1++) + (1 + i) * *(p2++)) / (height + 1);
168    }
169
170  return result;
171}
172
173static GdkPixbuf *
174replicate_single (GdkPixbuf    *src,
175                  gint          src_x,
176                  gint          src_y,
177                  gint          width,
178                  gint          height)
179{
180  guint n_channels = gdk_pixbuf_get_n_channels (src);
181  guchar *pixels = (gdk_pixbuf_get_pixels (src) +
182                    src_y * gdk_pixbuf_get_rowstride (src) +
183                    src_x * n_channels);
184  guchar r = *(pixels++);
185  guchar g = *(pixels++);
186  guchar b = *(pixels++);
187  guint dest_rowstride;
188  guchar *dest_pixels;
189  guchar a = 0;
190  GdkPixbuf *result;
191  int i, j;
192
193  if (n_channels == 4)
194    a = *(pixels++);
195
196  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
197                           width, height);
198  dest_rowstride = gdk_pixbuf_get_rowstride (result);
199  dest_pixels = gdk_pixbuf_get_pixels (result);
200 
201  for (i = 0; i < height; i++)
202    {
203      guchar *p = dest_pixels + dest_rowstride *i;
204
205      for (j = 0; j < width; j++)
206        {
207          *(p++) = r;
208          *(p++) = g;
209          *(p++) = b;
210
211          if (n_channels == 4)
212            *(p++) = a;
213        }
214    }
215
216  return result;
217}
218
219static GdkPixbuf *
220replicate_rows (GdkPixbuf    *src,
221                gint          src_x,
222                gint          src_y,
223                gint          width,
224                gint          height)
225{
226  guint n_channels = gdk_pixbuf_get_n_channels (src);
227  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
228  guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels);
229  guchar *dest_pixels;
230  GdkPixbuf *result;
231  guint dest_rowstride;
232  int i;
233
234  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
235                           width, height);
236  dest_rowstride = gdk_pixbuf_get_rowstride (result);
237  dest_pixels = gdk_pixbuf_get_pixels (result);
238
239  for (i = 0; i < height; i++)
240    memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
241
242  return result;
243}
244
245static GdkPixbuf *
246replicate_cols (GdkPixbuf    *src,
247                gint          src_x,
248                gint          src_y,
249                gint          width,
250                gint          height)
251{
252  guint n_channels = gdk_pixbuf_get_n_channels (src);
253  guint src_rowstride = gdk_pixbuf_get_rowstride (src);
254  guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels);
255  guchar *dest_pixels;
256  GdkPixbuf *result;
257  guint dest_rowstride;
258  int i, j;
259
260  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
261                           width, height);
262  dest_rowstride = gdk_pixbuf_get_rowstride (result);
263  dest_pixels = gdk_pixbuf_get_pixels (result);
264
265  for (i = 0; i < height; i++)
266    {
267      guchar *p = dest_pixels + dest_rowstride * i;
268      guchar *q = pixels + src_rowstride * i;
269
270      guchar r = *(q++);
271      guchar g = *(q++);
272      guchar b = *(q++);
273      guchar a = 0;
274     
275      if (n_channels == 4)
276        a = *(q++);
277
278      for (j = 0; j < width; j++)
279        {
280          *(p++) = r;
281          *(p++) = g;
282          *(p++) = b;
283
284          if (n_channels == 4)
285            *(p++) = a;
286        }
287    }
288
289  return result;
290}
291
292/* Scale the rectangle (src_x, src_y, src_width, src_height)
293 * onto the rectangle (dest_x, dest_y, dest_width, dest_height)
294 * of the destination, clip by clip_rect and render
295 */
296static void
297pixbuf_render (GdkPixbuf    *src,
298               guint         hints,
299               GdkWindow    *window,
300               GdkBitmap    *mask,
301               GdkRectangle *clip_rect,
302               gint          src_x,
303               gint          src_y,
304               gint          src_width,
305               gint          src_height,
306               gint          dest_x,
307               gint          dest_y,
308               gint          dest_width,
309               gint          dest_height)
310{
311  GdkPixbuf *tmp_pixbuf;
312  GdkRectangle rect;
313  int x_offset, y_offset;
314  gboolean has_alpha = gdk_pixbuf_get_has_alpha (src);
315  gint src_rowstride = gdk_pixbuf_get_rowstride (src);
316  gint src_n_channels = gdk_pixbuf_get_n_channels (src);
317
318  if (dest_width <= 0 || dest_height <= 0)
319    return;
320
321  rect.x = dest_x;
322  rect.y = dest_y;
323  rect.width = dest_width;
324  rect.height = dest_height;
325
326  if (hints & THEME_MISSING)
327    return;
328
329  /* FIXME: Because we use the mask to shape windows, we don't use
330   * clip_rect to clip what we draw to the mask, only to clip
331   * what we actually draw. But this leads to the horrible ineffiency
332   * of scale the whole image to get a little bit of it.
333   */
334  if (!mask && clip_rect)
335    {
336      if (!gdk_rectangle_intersect (clip_rect, &rect, &rect))
337        return;
338    }
339
340  if (dest_width == src_width && dest_height == src_height)
341    {
342      tmp_pixbuf = g_object_ref (src);
343
344      x_offset = src_x + rect.x - dest_x;
345      y_offset = src_y + rect.y - dest_y;
346    }
347  else if (src_width == 0 && src_height == 0)
348    {
349      tmp_pixbuf = bilinear_gradient (src, src_x, src_y, dest_width, dest_height);     
350     
351      x_offset = rect.x - dest_x;
352      y_offset = rect.y - dest_y;
353    }
354  else if (src_width == 0 && dest_height == src_height)
355    {
356      tmp_pixbuf = horizontal_gradient (src, src_x, src_y, dest_width, dest_height);     
357     
358      x_offset = rect.x - dest_x;
359      y_offset = rect.y - dest_y;
360    }
361  else if (src_height == 0 && dest_width == src_width)
362    {
363      tmp_pixbuf = vertical_gradient (src, src_x, src_y, dest_width, dest_height);
364     
365      x_offset = rect.x - dest_x;
366      y_offset = rect.y - dest_y;
367    }
368  else if ((hints & THEME_CONSTANT_COLS) && (hints & THEME_CONSTANT_ROWS))
369    {
370      tmp_pixbuf = replicate_single (src, src_x, src_y, dest_width, dest_height);
371
372      x_offset = rect.x - dest_x;
373      y_offset = rect.y - dest_y;
374    }
375  else if (dest_width == src_width && (hints & THEME_CONSTANT_COLS))
376    {
377      tmp_pixbuf = replicate_rows (src, src_x, src_y, dest_width, dest_height);
378
379      x_offset = rect.x - dest_x;
380      y_offset = rect.y - dest_y;
381    }
382  else if (dest_height == src_height && (hints & THEME_CONSTANT_ROWS))
383    {
384      tmp_pixbuf = replicate_cols (src, src_x, src_y, dest_width, dest_height);
385
386      x_offset = rect.x - dest_x;
387      y_offset = rect.y - dest_y;
388    }
389  else
390    {
391      double x_scale = (double)dest_width / src_width;
392      double y_scale = (double)dest_height / src_height;
393      guchar *pixels;
394      GdkPixbuf *partial_src;
395     
396      pixels = (gdk_pixbuf_get_pixels (src)
397                + src_y * src_rowstride
398                + src_x * src_n_channels);
399
400      partial_src = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB,
401                                              has_alpha,
402                                              8, src_width, src_height,
403                                              src_rowstride,
404                                              NULL, NULL);
405                                                 
406      tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
407                                   has_alpha, 8,
408                                   rect.width, rect.height);
409
410      gdk_pixbuf_scale (partial_src, tmp_pixbuf,
411                        0, 0, rect.width, rect.height,
412                        dest_x - rect.x, dest_y - rect.y,
413                        x_scale, y_scale,
414                        GDK_INTERP_BILINEAR);
415
416      gdk_pixbuf_unref (partial_src);
417
418      x_offset = 0;
419      y_offset = 0;
420    }
421
422  if (mask)
423    {
424      gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask,
425                                         x_offset, y_offset,
426                                         rect.x, rect.y,
427                                         rect.width, rect.height,
428                                         128);
429    }
430
431  gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, window,
432                                       x_offset, y_offset,
433                                       rect.x, rect.y,
434                                       rect.width, rect.height,
435                                       GDK_PIXBUF_ALPHA_FULL, 128,
436                                       GDK_RGB_DITHER_NORMAL,
437                                       0, 0);
438  gdk_pixbuf_unref (tmp_pixbuf);
439}
440
441ThemePixbuf *
442theme_pixbuf_new (void)
443{
444  ThemePixbuf *result = g_new0 (ThemePixbuf, 1);
445  result->filename = NULL;
446  result->pixbuf = NULL;
447
448  result->stretch = TRUE;
449  result->border_left = 0;
450  result->border_right = 0;
451  result->border_bottom = 0;
452  result->border_top = 0;
453
454  return result;
455}
456
457void
458theme_pixbuf_destroy (ThemePixbuf *theme_pb)
459{
460  theme_pixbuf_set_filename (theme_pb, NULL);
461  g_free (theme_pb);
462}
463
464void         
465theme_pixbuf_set_filename (ThemePixbuf *theme_pb,
466                           const char  *filename)
467{
468  if (theme_pb->pixbuf)
469    {
470      g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
471      theme_pb->pixbuf = NULL;
472    }
473
474  if (theme_pb->filename)
475    g_free (theme_pb->filename);
476
477  if (filename)
478    theme_pb->filename = g_strdup (filename);
479  else
480    theme_pb->filename = NULL;
481}
482
483static guint
484compute_hint (GdkPixbuf *pixbuf,
485              gint       x0,
486              gint       x1,
487              gint       y0,
488              gint       y1)
489{
490  int i, j;
491  int hints = THEME_CONSTANT_ROWS | THEME_CONSTANT_COLS | THEME_MISSING;
492  int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
493 
494  guchar *data = gdk_pixbuf_get_pixels (pixbuf);
495  int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
496
497  if (x0 == x1 || y0 == y1)
498    return 0;
499
500  for (i = y0; i < y1; i++)
501    {
502      guchar *p = data + i * rowstride + x0 * n_channels;
503      guchar r = p[0];
504      guchar g = p[1];
505      guchar b = p[2];
506      guchar a = 0;
507     
508      if (n_channels == 4)
509        a = p[3];
510
511      for (j = x0; j < x1 ; j++)
512        {
513          if (n_channels != 4 || p[3] != 0)
514            {
515              hints &= ~THEME_MISSING;
516              if (!(hints & THEME_CONSTANT_ROWS))
517                goto cols;
518            }
519         
520          if (r != *(p++) ||
521              g != *(p++) ||
522              b != *(p++) ||
523              (n_channels != 4 && a != *(p++)))
524            {
525              hints &= ~THEME_CONSTANT_ROWS;
526              if (!(hints & THEME_MISSING))
527                goto cols;
528            }
529        }
530    }
531
532 cols:
533  for (i = y0 + 1; i < y1; i++)
534    {
535      guchar *base = data + y0 * rowstride + x0 * n_channels;
536      guchar *p = data + i * rowstride + x0 * n_channels;
537
538      if (memcmp (p, base, n_channels * (x1 - x0)) != 0)
539        {
540          hints &= ~THEME_CONSTANT_COLS;
541          return hints;
542        }
543    }
544
545  return hints;
546}
547
548static void
549theme_pixbuf_compute_hints (ThemePixbuf *theme_pb)
550{
551  int i, j;
552  gint width = gdk_pixbuf_get_width (theme_pb->pixbuf);
553  gint height = gdk_pixbuf_get_height (theme_pb->pixbuf);
554
555  if (theme_pb->border_left + theme_pb->border_right > width ||
556      theme_pb->border_top + theme_pb->border_bottom > height)
557    {
558      g_warning ("Invalid borders specified for theme pixmap:\n"
559                 "        %s,\n"
560                 "borders don't fit within the image", theme_pb->filename);
561      if (theme_pb->border_left + theme_pb->border_right > width)
562        {
563          theme_pb->border_left = width / 2;
564          theme_pb->border_right = (width + 1) / 2;
565        }
566      if (theme_pb->border_bottom + theme_pb->border_top > height)
567        {
568          theme_pb->border_top = height / 2;
569          theme_pb->border_bottom = (height + 1) / 2;
570        }
571    }
572 
573  for (i = 0; i < 3; i++)
574    {
575      gint y0, y1;
576
577      switch (i)
578        {
579        case 0:
580          y0 = 0;
581          y1 = theme_pb->border_top;
582          break;
583        case 1:
584          y0 = theme_pb->border_top;
585          y1 = height - theme_pb->border_bottom;
586          break;
587        default:
588          y0 = height - theme_pb->border_bottom;
589          y1 = height;
590          break;
591        }
592     
593      for (j = 0; j < 3; j++)
594        {
595          gint x0, x1;
596         
597          switch (j)
598            {
599            case 0:
600              x0 = 0;
601              x1 = theme_pb->border_left;
602              break;
603            case 1:
604              x0 = theme_pb->border_left;
605              x1 = width - theme_pb->border_right;
606              break;
607            default:
608              x0 = width - theme_pb->border_right;
609              x1 = width;
610              break;
611            }
612
613          theme_pb->hints[i][j] = compute_hint (theme_pb->pixbuf, x0, x1, y0, y1);
614        }
615    }
616 
617}
618
619void
620theme_pixbuf_set_border (ThemePixbuf *theme_pb,
621                         gint         left,
622                         gint         right,
623                         gint         top,
624                         gint         bottom)
625{
626  theme_pb->border_left = left;
627  theme_pb->border_right = right;
628  theme_pb->border_top = top;
629  theme_pb->border_bottom = bottom;
630
631  if (theme_pb->pixbuf)
632    theme_pixbuf_compute_hints (theme_pb);
633}
634
635void
636theme_pixbuf_set_stretch (ThemePixbuf *theme_pb,
637                          gboolean     stretch)
638{
639  theme_pb->stretch = stretch;
640
641  if (theme_pb->pixbuf)
642    theme_pixbuf_compute_hints (theme_pb);
643}
644
645static GdkPixbuf *
646pixbuf_cache_value_new (gchar *filename)
647{
648  GError *err = NULL;
649   
650  GdkPixbuf *result = rsvg_pixbuf_from_file (filename, &err);
651  if (!result)
652    {
653      g_warning ("Rsvg theme: Cannot load SVG file %s: %s\n",
654                 filename, err->message);
655      g_error_free (err);
656    }
657
658  return result;
659}
660
661GdkPixbuf *
662theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb)
663{
664  if (!theme_pb->pixbuf)
665    {
666      if (!pixbuf_cache)
667        pixbuf_cache = g_cache_new ((GCacheNewFunc)pixbuf_cache_value_new,
668                                    (GCacheDestroyFunc)gdk_pixbuf_unref,
669                                    (GCacheDupFunc)g_strdup,
670                                    (GCacheDestroyFunc)g_free,
671                                    g_str_hash, g_direct_hash, g_str_equal);
672     
673      theme_pb->pixbuf = g_cache_insert (pixbuf_cache, theme_pb->filename);
674
675      if (theme_pb->stretch)
676        theme_pixbuf_compute_hints (theme_pb);
677    }
678 
679  return theme_pb->pixbuf;
680}
681
682void
683theme_pixbuf_render (ThemePixbuf  *theme_pb,
684                     GdkWindow    *window,
685                     GdkBitmap    *mask,
686                     GdkRectangle *clip_rect,
687                     guint         component_mask,
688                     gboolean      center,
689                     gint          x,
690                     gint          y,
691                     gint          width,
692                     gint          height)
693{
694  GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (theme_pb);
695  gint src_x[4], src_y[4], dest_x[4], dest_y[4];
696  gint pixbuf_width = gdk_pixbuf_get_width (pixbuf);
697  gint pixbuf_height = gdk_pixbuf_get_height (pixbuf);
698
699  if (!pixbuf)
700    return;
701
702  if (theme_pb->stretch)
703    {
704      src_x[0] = 0;
705      src_x[1] = theme_pb->border_left;
706      src_x[2] = pixbuf_width - theme_pb->border_right;
707      src_x[3] = pixbuf_width;
708     
709      src_y[0] = 0;
710      src_y[1] = theme_pb->border_top;
711      src_y[2] = pixbuf_height - theme_pb->border_bottom;
712      src_y[3] = pixbuf_height;
713     
714      dest_x[0] = x;
715      dest_x[1] = x + theme_pb->border_left;
716      dest_x[2] = x + width - theme_pb->border_right;
717      dest_x[3] = x + width;
718
719      dest_y[0] = y;
720      dest_y[1] = y + theme_pb->border_top;
721      dest_y[2] = y + height - theme_pb->border_bottom;
722      dest_y[3] = y + height;
723
724      if (component_mask & COMPONENT_ALL)
725        component_mask = (COMPONENT_ALL - 1) & ~component_mask;
726
727#define RENDER_COMPONENT(X1,X2,Y1,Y2)                                            \
728        pixbuf_render (pixbuf, theme_pb->hints[Y1][X1], window, mask, clip_rect, \
729                       src_x[X1], src_y[Y1],                                     \
730                       src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1],             \
731                       dest_x[X1], dest_y[Y1],                                   \
732                       dest_x[X2] - dest_x[X1], dest_y[Y2] - dest_y[Y1]);
733     
734      if (component_mask & COMPONENT_NORTH_WEST)
735        RENDER_COMPONENT (0, 1, 0, 1);
736
737      if (component_mask & COMPONENT_NORTH)
738        RENDER_COMPONENT (1, 2, 0, 1);
739
740      if (component_mask & COMPONENT_NORTH_EAST)
741        RENDER_COMPONENT (2, 3, 0, 1);
742
743      if (component_mask & COMPONENT_WEST)
744        RENDER_COMPONENT (0, 1, 1, 2);
745
746      if (component_mask & COMPONENT_CENTER)
747        RENDER_COMPONENT (1, 2, 1, 2);
748
749      if (component_mask & COMPONENT_EAST)
750        RENDER_COMPONENT (2, 3, 1, 2);
751
752      if (component_mask & COMPONENT_SOUTH_WEST)
753        RENDER_COMPONENT (0, 1, 2, 3);
754
755      if (component_mask & COMPONENT_SOUTH)
756        RENDER_COMPONENT (1, 2, 2, 3);
757
758      if (component_mask & COMPONENT_SOUTH_EAST)
759        RENDER_COMPONENT (2, 3, 2, 3);
760    }
761  else
762    {
763      if (center)
764        {
765          x += (width - pixbuf_width) / 2;
766          y += (height - pixbuf_height) / 2;
767         
768          pixbuf_render (pixbuf, 0, window, NULL, clip_rect,
769                         0, 0,
770                         pixbuf_width, pixbuf_height,
771                         x, y,
772                         pixbuf_width, pixbuf_height);
773        }
774      else
775        {
776          GdkPixmap *tmp_pixmap;
777          GdkGC *tmp_gc;
778          GdkGCValues gc_values;
779
780          tmp_pixmap = gdk_pixmap_new (window,
781                                       pixbuf_width,
782                                       pixbuf_height,
783                                       -1);
784          tmp_gc = gdk_gc_new (tmp_pixmap);
785          gdk_pixbuf_render_to_drawable (pixbuf, tmp_pixmap, tmp_gc,
786                                         0, 0,
787                                         0, 0,
788                                         pixbuf_width, pixbuf_height,
789                                         GDK_RGB_DITHER_NORMAL,
790                                         0, 0);
791          gdk_gc_unref (tmp_gc);
792
793          gc_values.fill = GDK_TILED;
794          gc_values.tile = tmp_pixmap;
795          tmp_gc = gdk_gc_new_with_values (window,
796                                           &gc_values, GDK_GC_FILL | GDK_GC_TILE);
797          if (clip_rect)
798            gdk_draw_rectangle (window, tmp_gc, TRUE,
799                                clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height);
800          else
801            gdk_draw_rectangle (window, tmp_gc, TRUE, x, y, width, height);
802         
803          gdk_gc_unref (tmp_gc);
804          gdk_pixmap_unref (tmp_pixmap);
805        }
806    }
807}
Note: See TracBrowser for help on using the repository browser.