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