2
#include "general-support.h"
3
#include "cairo-support.h"
5
/***********************************************
8
* Get HSB values from RGB values.
10
* Modified from Smooth but originated in GTK+
11
***********************************************/
13
ge_hsb_from_color (const CairoColor *color,
18
gdouble min, max, delta;
19
gdouble red, green, blue;
28
min = MIN(green, blue);
32
max = MAX(green, blue);
36
*brightness = (max + min) / 2;
38
if (fabs(max - min) < 0.0001)
45
if (*brightness <= 0.5)
46
*saturation = (max - min) / (max + min);
48
*saturation = (max - min) / (2 - max - min);
53
*hue = (green - blue) / delta;
54
else if (green == max)
55
*hue = 2 + (blue - red) / delta;
57
*hue = 4 + (red - green) / delta;
65
/***********************************************
68
* Get RGB values from HSB values.
70
* Modified from Smooth but originated in GTK+
71
***********************************************/
72
#define MODULA(number, divisor) (((gint)number % divisor) + (number - (gint)number))
74
ge_color_from_hsb (gdouble hue,
80
gdouble hue_shift[3], color_shift[3];
85
if (brightness <= 0.5)
86
m2 = brightness * (1 + saturation);
88
m2 = brightness + saturation - brightness * saturation;
90
m1 = 2 * brightness - m2;
92
hue_shift[0] = hue + 120;
94
hue_shift[2] = hue - 120;
96
color_shift[0] = color_shift[1] = color_shift[2] = brightness;
98
i = (saturation == 0)?3:0;
105
m3 = MODULA(m3, 360);
107
m3 = 360 - MODULA(ABS(m3), 360);
110
color_shift[i] = m1 + (m2 - m1) * m3 / 60;
114
color_shift[i] = m1 + (m2 - m1) * (240 - m3) / 60;
119
color->r = color_shift[0];
120
color->g = color_shift[1];
121
color->b = color_shift[2];
126
ge_gdk_color_to_cairo (const GdkColor *c, CairoColor *cc)
130
g_return_if_fail (c && cc);
132
r = c->red / 65535.0;
133
g = c->green / 65535.0;
134
b = c->blue / 65535.0;
143
ge_cairo_color_to_gtk (const CairoColor *cc, GdkColor *c)
147
g_return_if_fail (c && cc);
159
ge_gtk_style_to_cairo_color_cube (GtkStyle * style, CairoColorCube *cube)
163
g_return_if_fail (style && cube);
165
for (i = 0; i < 5; i++)
167
ge_gdk_color_to_cairo (&style->bg[i], &cube->bg[i]);
168
ge_gdk_color_to_cairo (&style->fg[i], &cube->fg[i]);
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]);
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]);
179
cube->black.r = cube->black.g = cube->black.b = 0;
182
cube->white.r = cube->white.g = cube->white.b = 1;
187
ge_shade_color(const CairoColor *base, gdouble shade_ratio, CairoColor *composite)
190
gdouble saturation = 0;
191
gdouble brightness = 0;
193
g_return_if_fail (base && composite);
195
ge_hsb_from_color (base, &hue, &saturation, &brightness);
197
brightness = MIN(brightness*shade_ratio, 1.0);
198
brightness = MAX(brightness, 0.0);
200
saturation = MIN(saturation*shade_ratio, 1.0);
201
saturation = MAX(saturation, 0.0);
203
ge_color_from_hsb (hue, saturation, brightness, composite);
204
composite->a = base->a;
208
ge_saturate_color (const CairoColor *base, gdouble saturate_level, CairoColor *composite)
211
gdouble saturation = 0;
212
gdouble brightness = 0;
214
g_return_if_fail (base && composite);
216
ge_hsb_from_color (base, &hue, &saturation, &brightness);
218
saturation = MIN(saturation*saturate_level, 1.0);
219
saturation = MAX(saturation, 0.0);
221
ge_color_from_hsb (hue, saturation, brightness, composite);
222
composite->a = base->a;
226
ge_mix_color (const CairoColor *color1, const CairoColor *color2,
227
gdouble mix_factor, CairoColor *composite)
229
g_return_if_fail (color1 && color2 && composite);
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;
238
ge_gdk_drawable_to_cairo (GdkDrawable *window, GdkRectangle *area)
242
g_return_val_if_fail (window != NULL, NULL);
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);
251
cairo_rectangle (cr, area->x, area->y, area->width, area->height);
252
cairo_clip_preserve (cr);
260
ge_cairo_set_color (cairo_t *cr, const CairoColor *color)
262
g_return_if_fail (cr && color);
264
cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);
268
ge_cairo_set_gdk_color_with_alpha (cairo_t *cr, const GdkColor *color, gdouble alpha)
270
g_return_if_fail (cr && color);
272
cairo_set_source_rgba (cr, color->red / 65535.0,
273
color->green / 65535.0,
274
color->blue / 65535.0,
279
ge_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
281
const CairoColor *color)
283
g_return_if_fail (pattern && color);
285
cairo_pattern_add_color_stop_rgba (pattern, offset, color->r, color->g, color->b, color->a);
289
ge_cairo_pattern_add_color_stop_shade(cairo_pattern_t *pattern,
291
const CairoColor *color,
296
g_return_if_fail (pattern && color && (shade >= 0) && (shade <= 3));
302
ge_shade_color(color, shade, &shaded);
305
ge_cairo_pattern_add_color_stop_color(pattern, offset, &shaded);
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. */
312
ge_cairo_rounded_corner (cairo_t *cr,
320
cairo_line_to (cr, x, y);
326
cairo_line_to (cr, x, y);
328
case CR_CORNER_TOPLEFT:
329
cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 3/2);
331
case CR_CORNER_TOPRIGHT:
332
cairo_arc (cr, x - radius, y + radius, radius, G_PI * 3/2, G_PI * 2);
334
case CR_CORNER_BOTTOMRIGHT:
335
cairo_arc (cr, x - radius, y - radius, radius, 0, G_PI * 1/2);
337
case CR_CORNER_BOTTOMLEFT:
338
cairo_arc (cr, x + radius, y - radius, radius, G_PI * 1/2, G_PI);
342
/* A bitfield and not a sane value ... */
343
g_assert_not_reached ();
344
cairo_line_to (cr, x, y);
351
ge_cairo_rounded_rectangle (cairo_t *cr,
352
double x, double y, double w, double h,
353
double radius, CairoCorners corners)
355
g_return_if_fail (cr != NULL);
357
if (radius < 0.0001 || corners == CR_CORNER_NONE)
359
cairo_rectangle (cr, x, y, w, h);
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");
369
if (corners & CR_CORNER_TOPLEFT)
370
cairo_move_to (cr, x+radius, y);
372
cairo_move_to (cr, x, y);
374
if (corners & CR_CORNER_TOPRIGHT)
375
cairo_arc (cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
377
cairo_line_to (cr, x+w, y);
379
if (corners & CR_CORNER_BOTTOMRIGHT)
380
cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
382
cairo_line_to (cr, x+w, y+h);
384
if (corners & CR_CORNER_BOTTOMLEFT)
385
cairo_arc (cr, x+radius, y+h-radius, radius, G_PI * 0.5, G_PI);
387
cairo_line_to (cr, x, y+h);
389
if (corners & CR_CORNER_TOPLEFT)
390
cairo_arc (cr, x+radius, y+radius, radius, G_PI, G_PI * 1.5);
392
cairo_line_to (cr, x, y);
396
/* ge_cairo_stroke_rectangle.
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.)
403
ge_cairo_stroke_rectangle (cairo_t *cr, double x, double y, double w, double h)
405
cairo_rectangle (cr, x, y, w, h);
409
/***********************************************
410
* ge_cairo_simple_border -
412
* A simple routine to draw thin squared
413
* borders with a topleft and bottomright color.
415
* It originated in Smooth-Engine.
416
***********************************************/
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)
423
gboolean solid_color;
425
g_return_if_fail (cr != NULL);
426
g_return_if_fail (tl != NULL);
427
g_return_if_fail (br != NULL);
430
solid_color = (tl == br) || ((tl->r == br->r) && (tl->g == br->g) && (tl->b == br->b) && (tl->a == br->a));
432
topleft_overlap &= !solid_color;
436
cairo_set_line_width (cr, 1);
440
ge_cairo_set_color(cr, br);
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);
449
ge_cairo_set_color(cr, tl);
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);
455
if (!topleft_overlap)
460
ge_cairo_set_color(cr, br);
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);
473
void ge_cairo_polygon (cairo_t *cr,
474
const CairoColor *color,
482
ge_cairo_set_color(cr, color);
483
cairo_move_to(cr, points[0].x, points[0].y);
485
for (i = 1; i < npoints; i++)
487
if (!((points[i].x == points[i + 1].x) &&
488
(points[i].y == points[i + 1].y)))
490
cairo_line_to(cr, points[i].x, points[i].y);
494
if ((points[npoints-1].x != points[0].x) ||
495
(points[npoints-1].y != points[0].y))
497
cairo_line_to(cr, points[0].x, points[0].y);
505
void ge_cairo_line (cairo_t *cr,
506
const CairoColor *color,
514
ge_cairo_set_color(cr, color);
515
cairo_set_line_width (cr, 1);
517
cairo_move_to(cr, x1 + 0.5, y1 + 0.5);
518
cairo_line_to(cr, x2 + 0.5, y2 + 0.5);
526
ge_cairo_mirror (cairo_t *cr,
533
cairo_matrix_t matrix;
535
cairo_matrix_init_identity (&matrix);
537
cairo_translate (cr, *x, *y);
541
if (mirror & CR_MIRROR_HORIZONTAL)
543
cairo_matrix_scale (&matrix, -1, 1);
546
if (mirror & CR_MIRROR_VERTICAL)
548
cairo_matrix_scale (&matrix, 1, -1);
552
cairo_transform (cr, &matrix);
556
ge_cairo_exchange_axis (cairo_t *cr,
563
cairo_matrix_t matrix;
565
cairo_translate (cr, *x, *y);
566
cairo_matrix_init (&matrix, 0, 1, 1, 0, 0, 0);
568
cairo_transform (cr, &matrix);
570
/* swap width/height */
579
/***********************************************
580
* ge_cairo_pattern_fill -
582
* Fill an area with some pattern
583
* Scaling or tiling if needed
584
***********************************************/
586
ge_cairo_pattern_fill(cairo_t *canvas,
587
CairoPattern *pattern,
593
cairo_matrix_t original_matrix, current_matrix;
595
if (pattern->operator == CAIRO_OPERATOR_DEST)
600
cairo_pattern_get_matrix(pattern->handle, &original_matrix);
601
current_matrix = original_matrix;
603
if (pattern->scale != GE_DIRECTION_NONE)
605
gdouble scale_x = 1.0;
606
gdouble scale_y = 1.0;
608
if ((pattern->scale == GE_DIRECTION_VERTICAL) || (pattern->scale == GE_DIRECTION_BOTH))
613
if ((pattern->scale == GE_DIRECTION_HORIZONTAL) || (pattern->scale == GE_DIRECTION_BOTH))
615
scale_y = 1.0/height;
618
cairo_matrix_scale(¤t_matrix, scale_x, scale_y);
621
if (pattern->translate != GE_DIRECTION_NONE)
623
gdouble translate_x = 0;
624
gdouble translate_y = 0;
626
if ((pattern->translate == GE_DIRECTION_VERTICAL) || (pattern->translate == GE_DIRECTION_BOTH))
631
if ((pattern->translate == GE_DIRECTION_HORIZONTAL) || (pattern->translate == GE_DIRECTION_BOTH))
636
cairo_matrix_translate(¤t_matrix, translate_x, translate_y);
639
cairo_pattern_set_matrix(pattern->handle, ¤t_matrix);
643
cairo_set_source(canvas, pattern->handle);
644
cairo_set_operator(canvas, pattern->operator);
645
cairo_rectangle(canvas, x, y, width, height);
649
cairo_restore(canvas);
651
cairo_pattern_set_matrix(pattern->handle, &original_matrix);
654
/***********************************************
655
* ge_cairo_color_pattern -
657
* Create A Solid Color Pattern
658
***********************************************/
660
ge_cairo_color_pattern(CairoColor *base)
662
CairoPattern * result = g_new0(CairoPattern, 1);
664
#if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
665
result->type = CAIRO_PATTERN_TYPE_SOLID;
668
result->scale = GE_DIRECTION_NONE;
669
result->translate = GE_DIRECTION_NONE;
671
result->handle = cairo_pattern_create_rgba(base->r,
676
result->operator = CAIRO_OPERATOR_SOURCE;
681
/***********************************************
682
* ge_cairo_pixbuf_pattern -
684
* Create A Tiled Pixbuf Pattern
685
***********************************************/
687
ge_cairo_pixbuf_pattern(GdkPixbuf *pixbuf)
689
CairoPattern * result = g_new0(CairoPattern, 1);
692
cairo_surface_t * surface;
695
#if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
696
result->type = CAIRO_PATTERN_TYPE_SURFACE;
699
result->scale = GE_DIRECTION_NONE;
700
result->translate = GE_DIRECTION_BOTH;
702
width = gdk_pixbuf_get_width(pixbuf);
703
height = gdk_pixbuf_get_height(pixbuf);
705
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
707
canvas = cairo_create(surface);
709
gdk_cairo_set_source_pixbuf (canvas, pixbuf, 0, 0);
710
cairo_rectangle (canvas, 0, 0, width, height);
712
cairo_destroy(canvas);
714
result->handle = cairo_pattern_create_for_surface (surface);
715
cairo_surface_destroy(surface);
717
cairo_pattern_set_extend (result->handle, CAIRO_EXTEND_REPEAT);
719
result->operator = CAIRO_OPERATOR_SOURCE;
724
/***********************************************
725
* ge_cairo_pixmap_pattern -
727
* Create A Tiled Pixmap Pattern
728
***********************************************/
730
ge_cairo_pixmap_pattern(GdkPixmap *pixmap)
732
CairoPattern * result = NULL;
737
gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
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);
743
result = ge_cairo_pixbuf_pattern(pixbuf);
745
g_object_unref (pixbuf);
750
/***********************************************
751
* ge_cairo_linear_shade_gradient_pattern -
753
* Create A Linear Shade Gradient Pattern
754
* Aka Smooth Shade Gradient, from/to gradient
755
* With End points defined as shades of the
757
***********************************************/
759
ge_cairo_linear_shade_gradient_pattern(CairoColor *base,
764
CairoPattern * result = g_new0(CairoPattern, 1);
766
#if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
767
result->type = CAIRO_PATTERN_TYPE_LINEAR;
772
result->scale = GE_DIRECTION_VERTICAL;
774
result->handle = cairo_pattern_create_linear(0, 0, 1, 0);
778
result->scale = GE_DIRECTION_HORIZONTAL;
780
result->handle = cairo_pattern_create_linear(0, 0, 0, 1);
783
result->translate = GE_DIRECTION_BOTH;
784
result->operator = CAIRO_OPERATOR_SOURCE;
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);
793
ge_cairo_pattern_destroy(CairoPattern *pattern)
798
cairo_pattern_destroy(pattern->handle);
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.
808
GE_EXPORT const gchar* g_module_check_init (GModule *module);
810
g_module_check_init (GModule *module)
814
return gtk_check_version (GTK_MAJOR_VERSION,
816
GTK_MICRO_VERSION - GTK_INTERFACE_AGE);