| ... | ... | @@ -317,17 +317,19 @@ static void pw_cursor(struct spa_buffer *buffer) { |
| 317 | 317 | struct spa_meta *meta = spa_buffer_find_meta(buffer, SPA_META_Cursor); |
| 318 | 318 | if (!meta || meta->size < sizeof(struct spa_meta_cursor)) return; |
| 319 | 319 | struct spa_meta_cursor cursor; memcpy(&cursor, meta->data, sizeof(cursor)); |
| 320 | position(cursor.position.x, cursor.position.y, cursor.id != 0); |
| 320 | 321 | if (!cursor.id) return; |
| 321 | | position(cursor.position.x, cursor.position.y, pointer[SG_POINTER_VISIBLE]); |
| 322 | 322 | if (!cursor.bitmap_offset) return; |
| 323 | 323 | if (cursor.bitmap_offset < sizeof(cursor) || cursor.bitmap_offset > meta->size - sizeof(struct spa_meta_bitmap)) return; |
| 324 | 324 | struct spa_meta_bitmap bitmap; memcpy(&bitmap, (uint8_t *)meta->data + cursor.bitmap_offset, sizeof(bitmap)); |
| 325 | if (!bitmap.offset || !bitmap.size.width || !bitmap.size.height) { |
| 326 | cursor_shape(1, 1, 0, 0, (uint8_t[4]){0}); return; |
| 327 | } |
| 325 | 328 | if (!bitmap.format) return; |
| 326 | | if (!bitmap.offset) { position(cursor.position.x, cursor.position.y, 0); return; } |
| 327 | 329 | uint32_t w = bitmap.size.width, h = bitmap.size.height; |
| 328 | 330 | size_t available = meta->size - cursor.bitmap_offset; |
| 329 | | if (!w || !h || w > SG_MAX_CURSOR_SIZE || h > SG_MAX_CURSOR_SIZE || bitmap.stride < (int32_t)w * 4 || bitmap.offset < sizeof(bitmap) || bitmap.offset > available || (size_t)(h - 1) * bitmap.stride + w * 4 > available - bitmap.offset) { |
| 330 | | position(cursor.position.x, cursor.position.y, 1); cursor_shape(0, 0, 0, 0, NULL); return; |
| 331 | if (w > SG_MAX_CURSOR_SIZE || h > SG_MAX_CURSOR_SIZE || bitmap.stride < (int32_t)w * 4 || bitmap.offset < sizeof(bitmap) || bitmap.offset > available || (size_t)(h - 1) * bitmap.stride + w * 4 > available - bitmap.offset) { |
| 332 | cursor_shape(0, 0, 0, 0, NULL); return; |
| 331 | 333 | } |
| 332 | 334 | unsigned offsets[4]; |
| 333 | 335 | switch (bitmap.format) { |
| ... | ... | @@ -335,21 +337,19 @@ static void pw_cursor(struct spa_buffer *buffer) { |
| 335 | 337 | case SPA_VIDEO_FORMAT_BGRA: offsets[0] = 2; offsets[1] = 1; offsets[2] = 0; offsets[3] = 3; break; |
| 336 | 338 | case SPA_VIDEO_FORMAT_ARGB: offsets[0] = 1; offsets[1] = 2; offsets[2] = 3; offsets[3] = 0; break; |
| 337 | 339 | case SPA_VIDEO_FORMAT_ABGR: offsets[0] = 3; offsets[1] = 2; offsets[2] = 1; offsets[3] = 0; break; |
| 338 | | default: position(cursor.position.x, cursor.position.y, 1); cursor_shape(0, 0, 0, 0, NULL); return; |
| 340 | default: cursor_shape(0, 0, 0, 0, NULL); return; |
| 339 | 341 | } |
| 340 | 342 | uint8_t rgba[SG_MAX_CURSOR_SIZE * SG_MAX_CURSOR_SIZE * 4]; |
| 341 | 343 | const uint8_t *pixels = (uint8_t *)meta->data + cursor.bitmap_offset + bitmap.offset; |
| 342 | | int visible = 0; |
| 343 | 344 | for (uint32_t y = 0; y < h; ++y) for (uint32_t x = 0; x < w; ++x) { |
| 344 | 345 | const uint8_t *src = pixels + (size_t)y * bitmap.stride + x * 4; |
| 345 | 346 | uint8_t *dst = rgba + ((size_t)y * w + x) * 4; |
| 346 | | unsigned alpha = src[offsets[3]]; dst[3] = (uint8_t)alpha; visible |= alpha != 0; |
| 347 | unsigned alpha = src[offsets[3]]; dst[3] = (uint8_t)alpha; |
| 347 | 348 | for (unsigned c = 0; c < 3; ++c) { |
| 348 | 349 | unsigned value = alpha ? (src[offsets[c]] * 255u + alpha / 2) / alpha : 0; |
| 349 | 350 | dst[c] = (uint8_t)(value > 255 ? 255 : value); |
| 350 | 351 | } |
| 351 | 352 | } |
| 352 | | position(cursor.position.x, cursor.position.y, visible); |
| 353 | 353 | cursor_shape(w, h, cursor.hotspot.x, cursor.hotspot.y, rgba); |
| 354 | 354 | } |
| 355 | 355 | |
| ... | ... | @@ -401,7 +401,11 @@ static void pw_format(void *unused, uint32_t id, const struct spa_pod *param) { |
| 401 | 401 | SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int((1 << SPA_DATA_MemPtr) | (1 << SPA_DATA_MemFd))); |
| 402 | 402 | params[1] = spa_pod_builder_add_object(&builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, |
| 403 | 403 | SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Cursor), |
| 404 | | SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + SG_MAX_CURSOR_SIZE * SG_MAX_CURSOR_SIZE * 4)); |
| 404 | /* Compositors can require a larger allocation than the transmitted cursor limit. */ |
| 405 | SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int( |
| 406 | sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + SG_MAX_CURSOR_SIZE * SG_MAX_CURSOR_SIZE * 4, |
| 407 | sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + 4, |
| 408 | sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + 384 * 384 * 4)); |
| 405 | 409 | params[2] = spa_pod_builder_add_object(&builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, |
| 406 | 410 | SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform), SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform))); |
| 407 | 411 | pw_stream_update_params(pw_stream, params, 3); |