1 /* Helper functions for gtk-engines
2 *
3 * Copyright (C) 2006 Andrew Johnson <acjgenius@earthlink.net>
4 * Copyright (C) 2006 Thomas Wood <thos@gnome.org>
5 * Copyright (C) 2006-2007 Benjamin Berg <benjamin@sipsolutions.net>
6 * Copyright (C) 2007 Andrea Cimitan <andrea.cimitan@gmail.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Project contact: <gnome-themes-list@gnome.org>
23 *
24 *
25 * Written by Andrew Johnson <acjgenius@earthlink.net>
26 * Written by Benjamin Berg <benjamin@sipsolutions.net>
27 * Written by Thomas Wood <thos@gnome.org>
28 * modified by Andrea Cimitan <andrea.cimitan@gmail.com>
29 *
30 */
31
32 #include <math.h>
33 #include "general-support.h"
34 #include "cairo-support.h"
35
36 /***********************************************
37 * ge_hsb_from_color -
38 *
39 * Get HSB values from RGB values.
40 *
41 * Modified from Smooth but originated in GTK+
42 ***********************************************/
43 void
ge_hsb_from_color(const CairoColor * color,gdouble * hue,gdouble * saturation,gdouble * brightness)44 ge_hsb_from_color (const CairoColor *color,
45 gdouble *hue,
46 gdouble *saturation,
47 gdouble *brightness)
48 {
49 gdouble min, max, delta;
50 gdouble red, green, blue;
51
52 red = color->r;
53 green = color->g;
54 blue = color->b;
55
56 if (red > green)
57 {
58 max = MAX(red, blue);
59 min = MIN(green, blue);
60 }
61 else
62 {
63 max = MAX(green, blue);
64 min = MIN(red, blue);
65 }
66
67 *brightness = (max + min) / 2;
68
69 if (fabs(max - min) < 0.0001)
70 {
71 *hue = 0;
72 *saturation = 0;
73 }
74 else
75 {
76 if (*brightness <= 0.5)
77 *saturation = (max - min) / (max + min);
78 else
79 *saturation = (max - min) / (2 - max - min);
80
81 delta = max -min;
82
83 if (red == max)
84 *hue = (green - blue) / delta;
85 else if (green == max)
86 *hue = 2 + (blue - red) / delta;
87 else if (blue == max)
88 *hue = 4 + (red - green) / delta;
89
90 *hue *= 60;
91 if (*hue < 0.0)
92 *hue += 360;
93 }
94 }
95
96 /***********************************************
97 * ge_color_from_hsb -
98 *
99 * Get RGB values from HSB values.
100 *
101 * Modified from Smooth but originated in GTK+
102 ***********************************************/
103 #define MODULA(number, divisor) (((gint)number % divisor) + (number - (gint)number))
104 void
ge_color_from_hsb(gdouble hue,gdouble saturation,gdouble brightness,CairoColor * color)105 ge_color_from_hsb (gdouble hue,
106 gdouble saturation,
107 gdouble brightness,
108 CairoColor *color)
109 {
110 gint i;
111 gdouble hue_shift[3], color_shift[3];
112 gdouble m1, m2, m3;
113
114 if (!color) return;
115
116 if (brightness <= 0.5)
117 m2 = brightness * (1 + saturation);
118 else
119 m2 = brightness + saturation - brightness * saturation;
120
121 m1 = 2 * brightness - m2;
122
123 hue_shift[0] = hue + 120;
124 hue_shift[1] = hue;
125 hue_shift[2] = hue - 120;
126
127 color_shift[0] = color_shift[1] = color_shift[2] = brightness;
128
129 i = (saturation == 0)?3:0;
130
131 for (; i < 3; i++)
132 {
133 m3 = hue_shift[i];
134
135 if (m3 > 360)
136 m3 = MODULA(m3, 360);
137 else if (m3 < 0)
138 m3 = 360 - MODULA(ABS(m3), 360);
139
140 if (m3 < 60)
141 color_shift[i] = m1 + (m2 - m1) * m3 / 60;
142 else if (m3 < 180)
143 color_shift[i] = m2;
144 else if (m3 < 240)
145 color_shift[i] = m1 + (m2 - m1) * (240 - m3) / 60;
146 else
147 color_shift[i] = m1;
148 }
149
150 color->r = color_shift[0];
151 color->g = color_shift[1];
152 color->b = color_shift[2];
153 color->a = 1.0;
154 }
155
156 void
ge_gdk_color_to_cairo(const GdkColor * c,CairoColor * cc)157 ge_gdk_color_to_cairo (const GdkColor *c, CairoColor *cc)
158 {
159 gdouble r, g, b;
160
161 g_return_if_fail (c && cc);
162
163 r = c->red / 65535.0;
164 g = c->green / 65535.0;
165 b = c->blue / 65535.0;
166
167 cc->r = r;
168 cc->g = g;
169 cc->b = b;
170 cc->a = 1.0;
171 }
172
173 void
ge_cairo_color_to_gtk(const CairoColor * cc,GdkColor * c)174 ge_cairo_color_to_gtk (const CairoColor *cc, GdkColor *c)
175 {
176 gdouble r, g, b;
177
178 g_return_if_fail (c && cc);
179
180 r = cc->r * 65535.0;
181 g = cc->g * 65535.0;
182 b = cc->b * 65535.0;
183
184 c->red = r;
185 c->green = g;
186 c->blue = b;
187 }
188
189 void
ge_gtk_style_to_cairo_color_cube(GtkStyle * style,CairoColorCube * cube)190 ge_gtk_style_to_cairo_color_cube (GtkStyle * style, CairoColorCube *cube)
191 {
192 int i;
193
194 g_return_if_fail (style && cube);
195
196 for (i = 0; i < 5; i++)
197 {
198 ge_gdk_color_to_cairo (&style->bg[i], &cube->bg[i]);
199 ge_gdk_color_to_cairo (&style->fg[i], &cube->fg[i]);
200
201 ge_gdk_color_to_cairo (&style->dark[i], &cube->dark[i]);
202 ge_gdk_color_to_cairo (&style->light[i], &cube->light[i]);
203 ge_gdk_color_to_cairo (&style->mid[i], &cube->mid[i]);
204
205 ge_gdk_color_to_cairo (&style->base[i], &cube->base[i]);
206 ge_gdk_color_to_cairo (&style->text[i], &cube->text[i]);
207 ge_gdk_color_to_cairo (&style->text_aa[i], &cube->text_aa[i]);
208 }
209
210 cube->black.r = cube->black.g = cube->black.b = 0;
211 cube->black.a = 1;
212
213 cube->white.r = cube->white.g = cube->white.b = 1;
214 cube->white.a = 1;
215 }
216
217 void
ge_shade_color(const CairoColor * base,gdouble shade_ratio,CairoColor * composite)218 ge_shade_color(const CairoColor *base, gdouble shade_ratio, CairoColor *composite)
219 {
220 gdouble hue = 0;
221 gdouble saturation = 0;
222 gdouble brightness = 0;
223
224 g_return_if_fail (base && composite);
225
226 if (shade_ratio == 1.0)
227 {
228 composite->r = base->r;
229 composite->g = base->g;
230 composite->b = base->b;
231 composite->a = base->a;
232
233 return;
234 }
235
236 ge_hsb_from_color (base, &hue, &saturation, &brightness);
237
238 brightness = MIN(brightness*shade_ratio, 1.0);
239 brightness = MAX(brightness, 0.0);
240
241 saturation = MIN(saturation*shade_ratio, 1.0);
242 saturation = MAX(saturation, 0.0);
243
244 ge_color_from_hsb (hue, saturation, brightness, composite);
245 composite->a = base->a;
246 }
247
248 void
ge_saturate_color(const CairoColor * base,gdouble saturate_level,CairoColor * composite)249 ge_saturate_color (const CairoColor *base, gdouble saturate_level, CairoColor *composite)
250 {
251 gdouble hue = 0;
252 gdouble saturation = 0;
253 gdouble brightness = 0;
254
255 g_return_if_fail (base && composite);
256
257 ge_hsb_from_color (base, &hue, &saturation, &brightness);
258
259 saturation = MIN(saturation*saturate_level, 1.0);
260 saturation = MAX(saturation, 0.0);
261
262 ge_color_from_hsb (hue, saturation, brightness, composite);
263 composite->a = base->a;
264 }
265
266 void
ge_mix_color(const CairoColor * color1,const CairoColor * color2,gdouble mix_factor,CairoColor * composite)267 ge_mix_color (const CairoColor *color1, const CairoColor *color2,
268 gdouble mix_factor, CairoColor *composite)
269 {
270 g_return_if_fail (color1 && color2 && composite);
271
272 composite->r = color1->r * (1-mix_factor) + color2->r * mix_factor;
273 composite->g = color1->g * (1-mix_factor) + color2->g * mix_factor;
274 composite->b = color1->b * (1-mix_factor) + color2->b * mix_factor;
275 composite->a = 1.0;
276 }
277
278 cairo_t *
ge_gdk_drawable_to_cairo(GdkDrawable * window,GdkRectangle * area)279 ge_gdk_drawable_to_cairo (GdkDrawable *window, GdkRectangle *area)
280 {
281 cairo_t *cr;
282
283 g_return_val_if_fail (window != NULL, NULL);
284
285 cr = (cairo_t*) gdk_cairo_create (window);
286 cairo_set_line_width (cr, 1.0);
287 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
288 cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
289
290 if (area)
291 {
292 cairo_rectangle (cr, area->x, area->y, area->width, area->height);
293 cairo_clip_preserve (cr);
294 cairo_new_path (cr);
295 }
296
297 return cr;
298 }
299
300 void
ge_cairo_set_color(cairo_t * cr,const CairoColor * color)301 ge_cairo_set_color (cairo_t *cr, const CairoColor *color)
302 {
303 g_return_if_fail (cr && color);
304
305 cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);
306 }
307
308 void
ge_cairo_set_gdk_color_with_alpha(cairo_t * cr,const GdkColor * color,gdouble alpha)309 ge_cairo_set_gdk_color_with_alpha (cairo_t *cr, const GdkColor *color, gdouble alpha)
310 {
311 g_return_if_fail (cr && color);
312
313 cairo_set_source_rgba (cr, color->red / 65535.0,
314 color->green / 65535.0,
315 color->blue / 65535.0,
316 alpha);
317 }
318
319 void
ge_cairo_pattern_add_color_stop_color(cairo_pattern_t * pattern,gfloat offset,const CairoColor * color)320 ge_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
321 gfloat offset,
322 const CairoColor *color)
323 {
324 g_return_if_fail (pattern && color);
325
326 cairo_pattern_add_color_stop_rgba (pattern, offset, color->r, color->g, color->b, color->a);
327 }
328
329 void
ge_cairo_pattern_add_color_stop_shade(cairo_pattern_t * pattern,gdouble offset,const CairoColor * color,gdouble shade)330 ge_cairo_pattern_add_color_stop_shade (cairo_pattern_t *pattern,
331 gdouble offset,
332 const CairoColor *color,
333 gdouble shade)
334 {
335 CairoColor shaded;
336
337 g_return_if_fail (pattern && color && (shade >= 0) && (shade <= 3));
338
339 shaded = *color;
340
341 if (shade != 1)
342 {
343 ge_shade_color(color, shade, &shaded);
344 }
345
346 ge_cairo_pattern_add_color_stop_color(pattern, offset, &shaded);
347 }
348
349 /*
350 * This function will draw a rounded corner at position x,y. If the radius
351 * is very small (or negative) it will instead just do a line_to.
352 * ge_cairo_rounded_corner assumes clockwise drawing.
353 */
354 void
ge_cairo_rounded_corner(cairo_t * cr,double x,double y,double radius,CairoCorners corner)355 ge_cairo_rounded_corner (cairo_t *cr,
356 double x,
357 double y,
358 double radius,
359 CairoCorners corner)
360 {
361 if (radius < 0.0001)
362 {
363 cairo_line_to (cr, x, y);
364 }
365 else
366 {
367 switch (corner)
368 {
369 case CR_CORNER_NONE:
370 cairo_line_to (cr, x, y);
371 break;
372 case CR_CORNER_TOPLEFT:
373 cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 3/2);
374 break;
375 case CR_CORNER_TOPRIGHT:
376 cairo_arc (cr, x - radius, y + radius, radius, G_PI * 3/2, G_PI * 2);
377 break;
378 case CR_CORNER_BOTTOMRIGHT:
379 cairo_arc (cr, x - radius, y - radius, radius, 0, G_PI * 1/2);
380 break;
381 case CR_CORNER_BOTTOMLEFT:
382 cairo_arc (cr, x + radius, y - radius, radius, G_PI * 1/2, G_PI);
383 break;
384
385 default:
386 /* A bitfield and not a sane value ... */
387 g_assert_not_reached ();
388 cairo_line_to (cr, x, y);
389 return;
390 }
391 }
392 }
393
394 void
ge_cairo_rounded_rectangle(cairo_t * cr,double x,double y,double w,double h,double radius,CairoCorners corners)395 ge_cairo_rounded_rectangle (cairo_t *cr,
396 double x, double y, double w, double h,
397 double radius, CairoCorners corners)
398 {
399 g_return_if_fail (cr != NULL);
400
401 if (radius < 0.0001 || corners == CR_CORNER_NONE)
402 {
403 cairo_rectangle (cr, x, y, w, h);
404 return;
405 }
406 #ifdef DEVELOPMENT
407 if ((corners == CR_CORNER_ALL) && (radius > w / 2.0 || radius > h / 2.0))
408 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
409 else if (radius > w || radius > h) /* This isn't perfect. Assumes that only one corner is set. */
410 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
411 #endif
412
413 if (corners & CR_CORNER_TOPLEFT)
414 cairo_move_to (cr, x+radius, y);
415 else
416 cairo_move_to (cr, x, y);
417
418 if (corners & CR_CORNER_TOPRIGHT)
419 cairo_arc (cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
420 else
421 cairo_line_to (cr, x+w, y);
422
423 if (corners & CR_CORNER_BOTTOMRIGHT)
424 cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
425 else
426 cairo_line_to (cr, x+w, y+h);
427
428 if (corners & CR_CORNER_BOTTOMLEFT)
429 cairo_arc (cr, x+radius, y+h-radius, radius, G_PI * 0.5, G_PI);
430 else
431 cairo_line_to (cr, x, y+h);
432
433 if (corners & CR_CORNER_TOPLEFT)
434 cairo_arc (cr, x+radius, y+radius, radius, G_PI, G_PI * 1.5);
435 else
436 cairo_line_to (cr, x, y);
437 }
438
439
440 /* ge_cairo_stroke_rectangle.
441 *
442 * A simple function to stroke the rectangle { x, y, w, h}.
443 * (This function only exists because of a cairo performance bug that
444 * has been fixed and it may be a good idea to get rid of it again.)
445 */
446 void
ge_cairo_stroke_rectangle(cairo_t * cr,double x,double y,double w,double h)447 ge_cairo_stroke_rectangle (cairo_t *cr, double x, double y, double w, double h)
448 {
449 cairo_rectangle (cr, x, y, w, h);
450 cairo_stroke (cr);
451 }
452
453 void
ge_cairo_inner_rectangle(cairo_t * cr,double x,double y,double width,double height)454 ge_cairo_inner_rectangle (cairo_t *cr,
455 double x, double y,
456 double width, double height)
457 {
458 double line_width = cairo_get_line_width (cr);
459
460 cairo_rectangle (cr, x + line_width / 2.0,
461 y + line_width / 2.0,
462 width - line_width,
463 height - line_width);
464 }
465
466 void
ge_cairo_inner_rounded_rectangle(cairo_t * cr,double x,double y,double width,double height,double radius,CairoCorners corners)467 ge_cairo_inner_rounded_rectangle (cairo_t *cr,
468 double x, double y,
469 double width, double height,
470 double radius, CairoCorners corners)
471 {
472 double line_width = cairo_get_line_width (cr);
473
474 ge_cairo_rounded_rectangle (cr,
475 x + line_width / 2.0,
476 y + line_width / 2.0,
477 width - line_width,
478 height - line_width,
479 radius, corners);
480 }
481
482 /***********************************************
483 * ge_cairo_simple_border -
484 *
485 * A simple routine to draw thin squared
486 * borders with a topleft and bottomright color.
487 *
488 * It originated in Smooth-Engine.
489 ***********************************************/
490 void
ge_cairo_simple_border(cairo_t * cr,const CairoColor * tl,const CairoColor * br,gint x,gint y,gint width,gint height,gboolean topleft_overlap)491 ge_cairo_simple_border (cairo_t *cr,
492 const CairoColor * tl, const CairoColor * br,
493 gint x, gint y, gint width, gint height,
494 gboolean topleft_overlap)
495 {
496 gboolean solid_color;
497
498 g_return_if_fail (cr != NULL);
499 g_return_if_fail (tl != NULL);
500 g_return_if_fail (br != NULL);
501
502
503 solid_color = (tl == br) || ((tl->r == br->r) && (tl->g == br->g) && (tl->b == br->b) && (tl->a == br->a));
504
505 topleft_overlap &= !solid_color;
506
507 cairo_save(cr);
508
509 cairo_set_line_width (cr, 1);
510
511 if (topleft_overlap)
512 {
513 ge_cairo_set_color(cr, br);
514
515 cairo_move_to(cr, x + 0.5, y + height - 0.5);
516 cairo_line_to(cr, x + width - 0.5, y + height - 0.5);
517 cairo_line_to(cr, x + width - 0.5, y + 0.5);
518
519 cairo_stroke (cr);
520 }
521
522 ge_cairo_set_color(cr, tl);
523
524 cairo_move_to(cr, x + 0.5, y + height - 0.5);
525 cairo_line_to(cr, x + 0.5, y + 0.5);
526 cairo_line_to(cr, x + width - 0.5, y + 0.5);
527
528 if (!topleft_overlap)
529 {
530 if (!solid_color)
531 {
532 cairo_stroke(cr);
533 ge_cairo_set_color(cr, br);
534 }
535
536 cairo_move_to(cr, x + 0.5, y + height - 0.5);
537 cairo_line_to(cr, x + width - 0.5, y + height - 0.5);
538 cairo_line_to(cr, x + width - 0.5, y + 0.5);
539 }
540
541 cairo_stroke(cr);
542
543 cairo_restore(cr);
544 }
545
ge_cairo_polygon(cairo_t * cr,const CairoColor * color,GdkPoint * points,gint npoints)546 void ge_cairo_polygon (cairo_t *cr,
547 const CairoColor *color,
548 GdkPoint *points,
549 gint npoints)
550 {
551 int i = 0;
552
553 cairo_save(cr);
554
555 ge_cairo_set_color(cr, color);
556 cairo_move_to(cr, points[0].x, points[0].y);
557
558 for (i = 1; i < npoints; i++)
559 {
560 if (!((points[i].x == points[i + 1].x) &&
561 (points[i].y == points[i + 1].y)))
562 {
563 cairo_line_to(cr, points[i].x, points[i].y);
564 }
565 }
566
567 if ((points[npoints-1].x != points[0].y) ||
568 (points[npoints-1].y != points[0].y))
569 {
570 cairo_line_to(cr, points[0].x, points[0].y);
571 }
572
573 cairo_fill(cr);
574
575 cairo_restore(cr);
576 }
577
ge_cairo_line(cairo_t * cr,const CairoColor * color,gint x1,gint y1,gint x2,gint y2)578 void ge_cairo_line (cairo_t *cr,
579 const CairoColor *color,
580 gint x1,
581 gint y1,
582 gint x2,
583 gint y2)
584 {
585 cairo_save(cr);
586
587 ge_cairo_set_color(cr, color);
588 cairo_set_line_width (cr, 1);
589
590 cairo_move_to(cr, x1 + 0.5, y1 + 0.5);
591 cairo_line_to(cr, x2 + 0.5, y2 + 0.5);
592
593 cairo_stroke(cr);
594
595 cairo_restore(cr);
596 }
597
598 void
ge_cairo_mirror(cairo_t * cr,CairoMirror mirror,gint * x,gint * y,gint * width,gint * height)599 ge_cairo_mirror (cairo_t *cr,
600 CairoMirror mirror,
601 gint *x,
602 gint *y,
603 gint *width,
604 gint *height)
605 {
606 cairo_matrix_t matrix;
607
608 cairo_matrix_init_identity (&matrix);
609
610 cairo_translate (cr, *x, *y);
611 *x = 0;
612 *y = 0;
613
614 if (mirror & CR_MIRROR_HORIZONTAL)
615 {
616 cairo_matrix_scale (&matrix, -1, 1);
617 *x = -*width;
618 }
619 if (mirror & CR_MIRROR_VERTICAL)
620 {
621 cairo_matrix_scale (&matrix, 1, -1);
622 *y = -*height;
623 }
624
625 cairo_transform (cr, &matrix);
626 }
627
628 void
ge_cairo_exchange_axis(cairo_t * cr,gint * x,gint * y,gint * width,gint * height)629 ge_cairo_exchange_axis (cairo_t *cr,
630 gint *x,
631 gint *y,
632 gint *width,
633 gint *height)
634 {
635 gint tmp;
636 cairo_matrix_t matrix;
637
638 cairo_translate (cr, *x, *y);
639 cairo_matrix_init (&matrix, 0, 1, 1, 0, 0, 0);
640
641 cairo_transform (cr, &matrix);
642
643 /* swap width/height */
644 tmp = *width;
645 *x = 0;
646 *y = 0;
647 *width = *height;
648 *height = tmp;
649 }
650
651
652 /***********************************************
653 * ge_cairo_pattern_fill -
654 *
655 * Fill an area with some pattern
656 * Scaling or tiling if needed
657 ***********************************************/
658 void
ge_cairo_pattern_fill(cairo_t * canvas,CairoPattern * pattern,gint x,gint y,gint width,gint height)659 ge_cairo_pattern_fill(cairo_t *canvas,
660 CairoPattern *pattern,
661 gint x,
662 gint y,
663 gint width,
664 gint height)
665 {
666 cairo_matrix_t original_matrix, current_matrix;
667
668 if (pattern->operator == CAIRO_OPERATOR_DEST)
669 return;
670
671 if (width <= 0 || height <= 0)
672 return;
673
674 cairo_pattern_get_matrix(pattern->handle, &original_matrix);
675 current_matrix = original_matrix;
676
677 if (pattern->scale != GE_DIRECTION_NONE)
678 {
679 gdouble scale_x = 1.0;
680 gdouble scale_y = 1.0;
681
682 if ((pattern->scale == GE_DIRECTION_VERTICAL) || (pattern->scale == GE_DIRECTION_BOTH))
683 {
684 scale_x = 1.0/width;
685 }
686
687 if ((pattern->scale == GE_DIRECTION_HORIZONTAL) || (pattern->scale == GE_DIRECTION_BOTH))
688 {
689 scale_y = 1.0/height;
690 }
691
692 cairo_matrix_scale(¤t_matrix, scale_x, scale_y);
693 }
694
695 if (pattern->translate != GE_DIRECTION_NONE)
696 {
697 gdouble translate_x = 0;
698 gdouble translate_y = 0;
699
700 if ((pattern->translate == GE_DIRECTION_VERTICAL) || (pattern->translate == GE_DIRECTION_BOTH))
701 {
702 translate_x = 0.0-x;
703 }
704
705 if ((pattern->translate == GE_DIRECTION_HORIZONTAL) || (pattern->translate == GE_DIRECTION_BOTH))
706 {
707 translate_y = 0.0-y;
708 }
709
710 cairo_matrix_translate(¤t_matrix, translate_x, translate_y);
711 }
712
713 cairo_pattern_set_matrix(pattern->handle, ¤t_matrix);
714
715 cairo_save(canvas);
716
717 cairo_set_source(canvas, pattern->handle);
718 cairo_set_operator(canvas, pattern->operator);
719 cairo_rectangle(canvas, x, y, width, height);
720
721 cairo_fill (canvas);
722
723 cairo_restore(canvas);
724
725 cairo_pattern_set_matrix(pattern->handle, &original_matrix);
726 }
727
728 /***********************************************
729 * ge_cairo_color_pattern -
730 *
731 * Create A Solid Color Pattern
732 ***********************************************/
733 CairoPattern*
ge_cairo_color_pattern(CairoColor * base)734 ge_cairo_color_pattern(CairoColor *base)
735 {
736 CairoPattern * result = g_new0(CairoPattern, 1);
737
738 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
739 result->type = CAIRO_PATTERN_TYPE_SOLID;
740 #endif
741
742 result->scale = GE_DIRECTION_NONE;
743 result->translate = GE_DIRECTION_NONE;
744
745 result->handle = cairo_pattern_create_rgba(base->r,
746 base->g,
747 base->b,
748 base->a);
749
750 result->operator = CAIRO_OPERATOR_SOURCE;
751
752 return result;
753 }
754
755 /***********************************************
756 * ge_cairo_pixbuf_pattern -
757 *
758 * Create A Tiled Pixbuf Pattern
759 ***********************************************/
760 CairoPattern*
ge_cairo_pixbuf_pattern(GdkPixbuf * pixbuf)761 ge_cairo_pixbuf_pattern(GdkPixbuf *pixbuf)
762 {
763 CairoPattern * result = g_new0(CairoPattern, 1);
764
765 cairo_t *canvas;
766 cairo_surface_t * surface;
767 gint width, height;
768
769 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
770 result->type = CAIRO_PATTERN_TYPE_SURFACE;
771 #endif
772
773 result->scale = GE_DIRECTION_NONE;
774 result->translate = GE_DIRECTION_BOTH;
775
776 width = gdk_pixbuf_get_width(pixbuf);
777 height = gdk_pixbuf_get_height(pixbuf);
778
779 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
780
781 canvas = cairo_create(surface);
782
783 gdk_cairo_set_source_pixbuf (canvas, pixbuf, 0, 0);
784 cairo_rectangle (canvas, 0, 0, width, height);
785 cairo_fill (canvas);
786 cairo_destroy(canvas);
787
788 result->handle = cairo_pattern_create_for_surface (surface);
789 cairo_surface_destroy(surface);
790
791 cairo_pattern_set_extend (result->handle, CAIRO_EXTEND_REPEAT);
792
793 result->operator = CAIRO_OPERATOR_SOURCE;
794
795 return result;
796 }
797
798 /***********************************************
799 * ge_cairo_pixmap_pattern -
800 *
801 * Create A Tiled Pixmap Pattern
802 ***********************************************/
803 CairoPattern*
ge_cairo_pixmap_pattern(GdkPixmap * pixmap)804 ge_cairo_pixmap_pattern(GdkPixmap *pixmap)
805 {
806 CairoPattern * result = NULL;
807
808 GdkPixbuf * pixbuf;
809 gint width, height;
810
811 gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
812
813 pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE (pixmap),
814 gdk_drawable_get_colormap(GDK_DRAWABLE (pixmap)),
815 0, 0, 0, 0, width, height);
816
817 result = ge_cairo_pixbuf_pattern(pixbuf);
818
819 g_object_unref (pixbuf);
820
821 return result;
822 }
823
824 /***********************************************
825 * ge_cairo_linear_shade_gradient_pattern -
826 *
827 * Create A Linear Shade Gradient Pattern
828 * Aka Smooth Shade Gradient, from/to gradient
829 * With End points defined as shades of the
830 * base color
831 ***********************************************/
832 CairoPattern *
ge_cairo_linear_shade_gradient_pattern(CairoColor * base,gdouble shade1,gdouble shade2,gboolean vertical)833 ge_cairo_linear_shade_gradient_pattern(CairoColor *base,
834 gdouble shade1,
835 gdouble shade2,
836 gboolean vertical)
837 {
838 CairoPattern * result = g_new0(CairoPattern, 1);
839
840 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
841 result->type = CAIRO_PATTERN_TYPE_LINEAR;
842 #endif
843
844 if (vertical)
845 {
846 result->scale = GE_DIRECTION_VERTICAL;
847
848 result->handle = cairo_pattern_create_linear(0, 0, 1, 0);
849 }
850 else
851 {
852 result->scale = GE_DIRECTION_HORIZONTAL;
853
854 result->handle = cairo_pattern_create_linear(0, 0, 0, 1);
855 }
856
857 result->translate = GE_DIRECTION_BOTH;
858 result->operator = CAIRO_OPERATOR_SOURCE;
859
860 ge_cairo_pattern_add_color_stop_shade(result->handle, 0, base, shade1);
861 ge_cairo_pattern_add_color_stop_shade(result->handle, 1, base, shade2);
862
863 return result;
864 }
865
866 void
ge_cairo_pattern_destroy(CairoPattern * pattern)867 ge_cairo_pattern_destroy(CairoPattern *pattern)
868 {
869 if (pattern)
870 {
871 if (pattern->handle)
872 cairo_pattern_destroy(pattern->handle);
873
874 g_free(pattern);
875 }
876 }
877
878 /*
879 * The following function will be called by GTK+ when the module
880 * is loaded and checks to see if we are compatible with the
881 * version of GTK+ that loads us.
882 */
883 GE_EXPORT const gchar* g_module_check_init (GModule *module);
884 const gchar*
g_module_check_init(GModule * module)885 g_module_check_init (GModule *module)
886 {
887 return gtk_check_version (GTK_MAJOR_VERSION,
888 GTK_MINOR_VERSION,
889 GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
890 }
891