From 9506fd5db783f013dcb5f042f15f4f0feb4a191f Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Thu, 26 Sep 2013 13:49:18 -0300 Subject: [PATCH] evas/image: Add video surface caps. Wayland subsurfaces can be used as video surfaces too, similarly to Ecore_X windows. However, they support a different set of features. Some of them, like subsurface clipping and scaling, might be added in the future, but so far we must work with what we have. This commit allows to set an enum bitfield to the Video_Surface, with the default value being one that will keep the same behavior as before, for Ecore_X window. Thus, backward compatibility should not be broken. It's possible to inform Evas that the surface in question is not able to resize or scale, or that it's above or below the original canvas surface. This allows Evas to show the surface itself, or use a buffer of pixels instead, when the capabilities are not available. --- src/lib/evas/Evas_Common.h | 10 ++++ src/lib/evas/Evas_Eo.h | 26 ++++++++++ src/lib/evas/Evas_Legacy.h | 3 ++ src/lib/evas/canvas/evas_object_image.c | 53 ++++++++++++++++++- src/lib/evas/canvas/evas_render.c | 68 ++++++++++++++++++++++++- 5 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h index 0c2d9b3655..007c0acf8f 100644 --- a/src/lib/evas/Evas_Common.h +++ b/src/lib/evas/Evas_Common.h @@ -486,6 +486,16 @@ struct _Evas_Video_Surface void *data; }; +typedef enum _Evas_Video_Surface_Caps +{ + EVAS_VIDEO_SURFACE_MOVE = 1, + EVAS_VIDEO_SURFACE_RESIZE = 2, + EVAS_VIDEO_SURFACE_CLIP = 4, + EVAS_VIDEO_SURFACE_BELOW = 8, + EVAS_VIDEO_SURFACE_STACKING_CHECK = 16, + EVAS_VIDEO_SURFACE_IGNORE_WINDOW = 32, +} Evas_Video_Surface_Caps; + #define EVAS_LAYER_MIN -32768 /**< bottom-most layer number */ #define EVAS_LAYER_MAX 32767 /**< top-most layer number */ diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index 232483107b..63783c5b66 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -5592,6 +5592,8 @@ enum EVAS_OBJ_IMAGE_SUB_ID_COLORSPACE_GET, EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_SET, EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_GET, + EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_SET, + EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_GET, EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_SET, EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_GET, EVAS_OBJ_IMAGE_SUB_ID_SCALE_HINT_SET, @@ -6379,6 +6381,30 @@ enum */ #define evas_obj_image_video_surface_get(surf) EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_GET), EO_TYPECHECK(const Evas_Video_Surface **, surf) +/** + * @def evas_obj_image_video_surface_caps_set + * @since 1.8 + * + * Set the video surface capabilities to a given image of the canvas + * + * @param[in] caps in + * + * @see evas_object_image_video_surface_caps_set + */ +#define evas_obj_image_video_surface_caps_set(caps) EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_SET), EO_TYPECHECK(unsigned int, caps) + +/** + * @def evas_obj_image_video_surface_caps_get + * @since 1.8 + * + * Get the video surface capabilities to a given image of the canvas + * + * @param[out] caps out + * + * @see evas_object_image_video_surface_caps_get + */ +#define evas_obj_image_video_surface_caps_get(caps) EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_GET), EO_TYPECHECK(unsigned int *, caps) + /** * @def evas_obj_image_native_surface_set * @since 1.8 diff --git a/src/lib/evas/Evas_Legacy.h b/src/lib/evas/Evas_Legacy.h index 5294ce7909..ffb3bb821e 100644 --- a/src/lib/evas/Evas_Legacy.h +++ b/src/lib/evas/Evas_Legacy.h @@ -4738,6 +4738,9 @@ EAPI void evas_object_image_video_surface_set(Evas_Obje */ EAPI const Evas_Video_Surface *evas_object_image_video_surface_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); +EAPI void evas_object_image_video_surface_caps_set(Evas_Object *obj, unsigned int caps) EINA_ARG_NONNULL(1); +EAPI unsigned int evas_object_image_video_surface_caps_get(const Evas_Object *obj) EINA_ARG_NONNULL(1); + /** * Set the scale hint of a given image of the canvas. * diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index af76f53fc2..00c1cf6fa6 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -64,6 +64,7 @@ struct _Evas_Object_Image_Pixels } func; Evas_Video_Surface video; + unsigned int video_caps; }; struct _Evas_Object_Image_State @@ -216,7 +217,7 @@ static const Evas_Object_Image_Load_Opts default_load_opts = { }; static const Evas_Object_Image_Pixels default_pixels = { - NULL, { NULL, NULL }, { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL } + NULL, { NULL, NULL }, { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, ~0x0 }; static const Evas_Object_Image_State default_state = { @@ -2578,6 +2579,52 @@ _image_video_surface_get(Eo *eo_obj EINA_UNUSED, void *_pd, va_list *list) *surf = (!o->video_surface ? NULL : &o->pixels->video); } +EAPI void +evas_object_image_video_surface_caps_set(Evas_Object *eo_obj, unsigned int caps) +{ + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return; + MAGIC_CHECK_END(); + eo_do(eo_obj, evas_obj_image_video_surface_caps_set(caps)); +} + +static void +_image_video_surface_caps_set(Eo *eo_obj, void *_pd, va_list *list) +{ + unsigned int caps = va_arg(*list, unsigned int); + Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS); + Evas_Object_Image *o = _pd; + + _evas_object_image_cleanup(eo_obj, obj, o); + + if (caps == o->pixels->video_caps) + return; + + EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write) + pixi_write->video_caps = caps; + EINA_COW_PIXEL_WRITE_END(o, pixi_write) +} + +EAPI unsigned int +evas_object_image_video_surface_caps_get(const Evas_Object *eo_obj) +{ + MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ); + return 0; + MAGIC_CHECK_END(); + unsigned int caps = ~0x0; + eo_do((Eo *)eo_obj, evas_obj_image_video_surface_caps_get(&caps)); + return caps; +} + +static void +_image_video_surface_caps_get(Eo *eo_obj EINA_UNUSED, void *_pd, va_list *list) +{ + unsigned int *caps = va_arg(*list, unsigned int *); + const Evas_Object_Image *o = _pd; + + *caps = (!o->video_surface ? 0 : o->pixels->video_caps); +} + EAPI void evas_object_image_native_surface_set(Evas_Object *eo_obj, Evas_Native_Surface *surf) { @@ -5359,6 +5406,8 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_COLORSPACE_GET), _image_colorspace_get), EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_SET), _image_video_surface_set), EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_GET), _image_video_surface_get), + EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_SET), _image_video_surface_caps_set), + EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_GET), _image_video_surface_caps_get), EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_SET), _image_native_surface_set), EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_GET), _image_native_surface_get), EO_OP_FUNC(EVAS_OBJ_IMAGE_ID(EVAS_OBJ_IMAGE_SUB_ID_SCALE_HINT_SET), _image_scale_hint_set), @@ -5437,6 +5486,8 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_COLORSPACE_GET, "Get the colorspace of a given image of the canvas."), EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_SET, "Set the video surface linked to a given image of the canvas."), EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_GET, "Get the video surface linekd to a given image of the canvas."), + EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_SET, "Set the surface capabilities (clip, resize, scale) of the video surface associated with this image."), + EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_VIDEO_SURFACE_CAPS_GET, "Get the surface capabilities (clip, resize, scale) of the video surface associated with this image."), EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_SET, "Set the native surface of a given image of the canvas."), EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_NATIVE_SURFACE_GET, "Get the native surface of a given image of the canvas."), EO_OP_DESCRIPTION(EVAS_OBJ_IMAGE_SUB_ID_SCALE_HINT_SET, "Set the scale hint of a given image of the canvas."), diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 49fbefefe8..e1b824fa37 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -810,6 +810,10 @@ _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj) Eina_Bool nooverlay; Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJ_CLASS); Evas_Object_Protected_Data *tmp = NULL; + Evas_Coord imgw, imgh; + unsigned int caps; + Eina_Bool surface_below, stacking_check, object_above = EINA_FALSE; + Eina_Bool ignore_window; video_parent = _evas_object_image_video_parent_get(eo_obj); @@ -832,6 +836,62 @@ _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj) (obj->cur->cache.clip.a != 255)) return EINA_FALSE; + caps = evas_object_image_video_surface_caps_get(eo_obj); + + /* check if surface is above the canvas */ + surface_below = !!(caps & EVAS_VIDEO_SURFACE_BELOW); + if (!surface_below) + { + /* above canvas, must support resize and clipping */ + + /* check if video surface supports resize */ + evas_object_image_size_get(eo_obj, &imgw, &imgh); + if ((obj->cur->geometry.w != imgw) || + (obj->cur->geometry.h != imgh)) + { + if (!(caps & EVAS_VIDEO_SURFACE_RESIZE)) + return EINA_FALSE; + } + /* check if video surface supports clipping */ + evas_object_image_size_get(eo_obj, &imgw, &imgh); + if ((obj->cur->cache.clip.x != obj->cur->geometry.x) || + (obj->cur->cache.clip.y != obj->cur->geometry.y) || + (obj->cur->cache.clip.w != obj->cur->geometry.w) || + (obj->cur->cache.clip.h != obj->cur->geometry.h)) + { + if (!(caps & EVAS_VIDEO_SURFACE_CLIP)) + return EINA_FALSE; + } + } + + /* check for window/surface/canvas limits */ + ignore_window = !!(caps & EVAS_VIDEO_SURFACE_IGNORE_WINDOW); + if (!ignore_window) + { + Evas_Coord x1, x2, y1, y2; + Evas_Coord fx, fy, fw, fh; + + fx = e->framespace.x; + fy = e->framespace.y; + fw = e->framespace.w; + fh = e->framespace.h; + + x1 = obj->cur->geometry.x + fx; + y1 = obj->cur->geometry.y + fy; + x2 = obj->cur->geometry.x + obj->cur->geometry.w + fx; + y2 = obj->cur->geometry.y + obj->cur->geometry.h + fy; + + if ((x1 < fx) || (y1 < fy) || + (x2 > e->output.w - (fw - fx)) || + (y2 > e->output.h - (fh - fy))) + return EINA_FALSE; + } + + /* check if there are other objects above the video object? */ + stacking_check = !!(caps & EVAS_VIDEO_SURFACE_STACKING_CHECK); + if (!stacking_check) + return EINA_TRUE; + /* Check presence of transparent object on top of the video object */ EINA_RECTANGLE_SET(&zone, obj->cur->cache.clip.x, @@ -878,6 +938,12 @@ _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj) { Eina_Bool included = EINA_FALSE; + if (!surface_below) + { + object_above = EINA_TRUE; + break; + } + if (evas_object_is_opaque(eo_current, current) || ((current->func->has_opaque_rect) && (current->func->has_opaque_rect(eo_current, current, current->private_data)))) @@ -990,7 +1056,7 @@ _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj) EINA_LIST_FREE(opaques, r) eina_rectangle_free(r); - if (nooverlay) + if (nooverlay || object_above) return EINA_FALSE; return EINA_TRUE;