// 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 #include #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(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(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)); } }