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