This repository was archived by the owner on Jan 30, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsommelier-xshape.cc
199 lines (151 loc) · 5.62 KB
/
sommelier-xshape.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <pixman.h>
#include "compositor/sommelier-formats.h" // NOLINT(build/include_directory)
#include "sommelier.h" // NOLINT(build/include_directory)
#include "sommelier-tracing.h" // NOLINT(build/include_directory)
#include "sommelier-xshape.h" // NOLINT(build/include_directory)
static void sl_clear_shape_region(sl_window* window) {
window->shaped = false;
pixman_region32_clear(&window->shape_rectangles);
}
static void sl_attach_shape_region(struct sl_context* ctx,
xcb_window_t window) {
sl_window* sl_window = nullptr;
xcb_shape_get_rectangles_reply_t* reply;
int i;
sl_window = sl_lookup_window(ctx, window);
if (!sl_window)
return;
reply = xcb_shape_get_rectangles_reply(
ctx->connection,
xcb_shape_get_rectangles(ctx->connection, window, XCB_SHAPE_SK_BOUNDING),
nullptr);
if (!reply)
return;
int nrects = xcb_shape_get_rectangles_rectangles_length(reply);
xcb_rectangle_t* rects = xcb_shape_get_rectangles_rectangles(reply);
if (!rects || nrects <= 0)
return;
pixman_box32_t* boxes =
static_cast<pixman_box32_t*>(calloc(sizeof(pixman_box32_t), nrects));
if (!boxes) {
free(reply);
return;
}
for (i = 0; i < nrects; i++) {
boxes[i].x1 = rects[i].x;
boxes[i].y1 = rects[i].y;
boxes[i].x2 = rects[i].x + rects[i].width;
boxes[i].y2 = rects[i].y + rects[i].height;
}
pixman_region32_init_rects(&sl_window->shape_rectangles, boxes, nrects);
free(boxes);
free(reply);
sl_window->shaped = true;
}
void sl_handle_shape_notify(struct sl_context* ctx,
struct xcb_shape_notify_event_t* event) {
sl_window* window = nullptr;
window = sl_lookup_window(ctx, event->affected_window);
if (!window)
return;
sl_clear_shape_region(window);
if (event->shaped)
sl_attach_shape_region(ctx, event->affected_window);
return;
}
void sl_shape_query(struct sl_context* ctx, xcb_window_t xwindow) {
xcb_shape_query_extents_reply_t* reply;
sl_window* sl_window = nullptr;
sl_window = sl_lookup_window(ctx, xwindow);
if (!sl_window)
return;
reply = xcb_shape_query_extents_reply(
ctx->connection, xcb_shape_query_extents(ctx->connection, xwindow),
nullptr);
if (!reply)
return;
sl_clear_shape_region(sl_window);
if (reply->bounding_shaped) {
sl_attach_shape_region(ctx, xwindow);
}
}
pixman_format_code_t sl_pixman_format_for_shm_format(uint32_t shm_format) {
assert(sl_shm_format_is_supported(shm_format));
pixman_format_code_t fmt = PIXMAN_a1;
switch (shm_format) {
case WL_SHM_FORMAT_ARGB8888:
fmt = PIXMAN_a8r8g8b8;
break;
case WL_SHM_FORMAT_XRGB8888:
fmt = PIXMAN_x8r8g8b8;
break;
case WL_SHM_FORMAT_ABGR8888:
fmt = PIXMAN_a8b8g8r8;
break;
case WL_SHM_FORMAT_XBGR8888:
fmt = PIXMAN_x8b8g8r8;
break;
case WL_SHM_FORMAT_RGB565:
fmt = PIXMAN_r5g6b5;
break;
default:
assert(0);
break;
}
return fmt;
}
void sl_xshape_generate_argb_image(struct sl_context* ctx,
pixman_region32_t* shape,
struct sl_mmap* src_mmap,
pixman_image_t* dst_image,
uint32_t src_shm_format) {
int buf_width, buf_height, nrects;
pixman_region32_t intersect_rects;
pixman_image_t* src;
assert(ctx);
assert(shape);
assert(src_mmap);
assert(dst_image);
buf_width = pixman_image_get_width(dst_image);
buf_height = pixman_image_get_height(dst_image);
if (buf_width <= 0 || buf_height <= 0)
return;
// Intersect with the pixmap bounds to ensure we do not perform
// any OOB accesses
// In addition, we can assume the dimensions of the dst_image is
// the same size as the input image
pixman_region32_init(&intersect_rects);
pixman_region32_intersect_rect(&intersect_rects, shape, 0, 0, buf_width,
buf_height);
// With the blank destination image, we will take the source image and the
// shape rectangles and generate the "stamped out" ARGB image.
//
// This is accomplished by clearing out the destination image to be
// completely transparent as a first step. Then for each rectangular
// region within the shape data, we will use pixman_image_composite to
// copy that portion of the image from the source to the ARGB stamp out
// buffer.
//
// pixman_image_composite is used as it will automatically perform pixel
// format conversion for us.
src = pixman_image_create_bits_no_clear(
sl_pixman_format_for_shm_format(src_shm_format), buf_width, buf_height,
reinterpret_cast<uint32_t*>(src_mmap->addr), src_mmap->stride[0]);
pixman_box32_t* rects = pixman_region32_rectangles(&intersect_rects, &nrects);
pixman_color_t clear = {.red = 0, .green = 0, .blue = 0, .alpha = 0};
pixman_box32_t dstbox = {.x1 = 0, .y1 = 0, .x2 = buf_width, .y2 = buf_height};
pixman_image_fill_boxes(PIXMAN_OP_SRC, dst_image, &clear, 1, &dstbox);
for (int i = 0; i < nrects; i++) {
pixman_image_composite(PIXMAN_OP_SRC, src, nullptr, dst_image, rects[i].x1,
rects[i].y1, 0, 0, rects[i].x1, rects[i].y1,
(rects[i].x2 - rects[i].x1),
(rects[i].y2 - rects[i].y1));
}
// Release the memory associated with the above
pixman_image_unref(src);
pixman_region32_fini(&intersect_rects);
}