diff options
Diffstat (limited to 'wayland')
-rw-r--r-- | wayland/CMakeLists.txt | 3 | ||||
-rw-r--r-- | wayland/cairo.c | 105 |
2 files changed, 108 insertions, 0 deletions
diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 5633dd6e..8e19fc03 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt | |||
@@ -1,6 +1,7 @@ | |||
1 | include_directories( | 1 | include_directories( |
2 | ${PROTOCOLS_INCLUDE_DIRS} | 2 | ${PROTOCOLS_INCLUDE_DIRS} |
3 | ${PANGO_INCLUDE_DIRS} | 3 | ${PANGO_INCLUDE_DIRS} |
4 | ${GDK_PIXBUF_INCLUDE_DIRS} | ||
4 | ) | 5 | ) |
5 | 6 | ||
6 | add_library(sway-wayland | 7 | add_library(sway-wayland |
@@ -8,10 +9,12 @@ add_library(sway-wayland | |||
8 | pango.c | 9 | pango.c |
9 | registry.c | 10 | registry.c |
10 | window.c | 11 | window.c |
12 | cairo.c | ||
11 | ) | 13 | ) |
12 | 14 | ||
13 | target_link_libraries(sway-wayland | 15 | target_link_libraries(sway-wayland |
14 | sway-common | 16 | sway-common |
15 | sway-protocols | 17 | sway-protocols |
16 | ${PANGO_LIBRARIES} | 18 | ${PANGO_LIBRARIES} |
19 | ${GDK_PIXBUF_LIBRARIES} | ||
17 | ) | 20 | ) |
diff --git a/wayland/cairo.c b/wayland/cairo.c new file mode 100644 index 00000000..10a15f40 --- /dev/null +++ b/wayland/cairo.c | |||
@@ -0,0 +1,105 @@ | |||
1 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
2 | #include <cairo/cairo.h> | ||
3 | #include "client/cairo.h" | ||
4 | |||
5 | #ifndef GDK_PIXBUF_CHECK_VERSION | ||
6 | #define GDK_PIXBUF_CHECK_VERSION(major,minor,micro) \ | ||
7 | (GDK_PIXBUF_MAJOR > (major) || \ | ||
8 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR > (minor)) || \ | ||
9 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR == (minor) && \ | ||
10 | GDK_PIXBUF_MICRO >= (micro))) | ||
11 | #endif | ||
12 | |||
13 | cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { | ||
14 | int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
15 | if (chan < 3) return NULL; | ||
16 | |||
17 | #if GDK_PIXBUF_CHECK_VERSION(2,32,0) | ||
18 | const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
19 | #else | ||
20 | const guint8* gdkpix = gdk_pixbuf_get_pixels(gdkbuf); | ||
21 | #endif | ||
22 | if (!gdkpix) { | ||
23 | return NULL; | ||
24 | } | ||
25 | gint w = gdk_pixbuf_get_width(gdkbuf); | ||
26 | gint h = gdk_pixbuf_get_height(gdkbuf); | ||
27 | int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
28 | |||
29 | cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
30 | cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
31 | cairo_surface_flush (cs); | ||
32 | if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
33 | return NULL; | ||
34 | } | ||
35 | |||
36 | int cstride = cairo_image_surface_get_stride(cs); | ||
37 | unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
38 | |||
39 | if (chan == 3) { | ||
40 | int i; | ||
41 | for (i = h; i; --i) { | ||
42 | const guint8 *gp = gdkpix; | ||
43 | unsigned char *cp = cpix; | ||
44 | const guint8* end = gp + 3*w; | ||
45 | while (gp < end) { | ||
46 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
47 | cp[0] = gp[2]; | ||
48 | cp[1] = gp[1]; | ||
49 | cp[2] = gp[0]; | ||
50 | #else | ||
51 | cp[1] = gp[0]; | ||
52 | cp[2] = gp[1]; | ||
53 | cp[3] = gp[2]; | ||
54 | #endif | ||
55 | gp += 3; | ||
56 | cp += 4; | ||
57 | } | ||
58 | gdkpix += stride; | ||
59 | cpix += cstride; | ||
60 | } | ||
61 | } else { | ||
62 | /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
63 | * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
64 | * = z/256 + (z/256)/255 = (z + z/255)/256 | ||
65 | * # recurse once | ||
66 | * = (z + (z + z/255)/256)/256 | ||
67 | * = (z + z/256 + z/256/255) / 256 | ||
68 | * # only use 16bit uint operations, loose some precision, | ||
69 | * # result is floored. | ||
70 | * -> (z + z>>8)>>8 | ||
71 | * # add 0x80/255 = 0.5 to convert floor to round | ||
72 | * => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
73 | * ------ | ||
74 | * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
75 | */ | ||
76 | #define PREMUL_ALPHA(x,a,b,z) G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } G_STMT_END | ||
77 | int i; | ||
78 | for (i = h; i; --i) { | ||
79 | const guint8 *gp = gdkpix; | ||
80 | unsigned char *cp = cpix; | ||
81 | const guint8* end = gp + 4*w; | ||
82 | guint z1, z2, z3; | ||
83 | while (gp < end) { | ||
84 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
85 | PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
86 | PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
87 | PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
88 | cp[3] = gp[3]; | ||
89 | #else | ||
90 | PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
91 | PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
92 | PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
93 | cp[0] = gp[3]; | ||
94 | #endif | ||
95 | gp += 4; | ||
96 | cp += 4; | ||
97 | } | ||
98 | gdkpix += stride; | ||
99 | cpix += cstride; | ||
100 | } | ||
101 | #undef PREMUL_ALPHA | ||
102 | } | ||
103 | cairo_surface_mark_dirty(cs); | ||
104 | return cs; | ||
105 | } | ||