pH/sommelier/sommelier-xshape.cc

193 lines
5.3 KiB
C++

// 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 "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_fini(&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),
NULL);
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), NULL);
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) {
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, NULL, 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));
}
}