From 29a768944a7b3bf789fa25beb9c63fe44ba57223 Mon Sep 17 00:00:00 2001 From: barbieri Date: Thu, 22 Oct 2009 20:11:33 +0000 Subject: [PATCH] evas_map: more extensible and safe. add docs change evas_map to return a structure that serves as an array of points. This way we'll know for sure the number of points in it. Right now it's hardcoded to 4, so check it, but in future we can just allow more points and it should work. added docs. I'm not sure about most of it, so it would be good to have someone to review and fill in more, maybe that's raster? Grep for "TODO" and you'll see the missing stuff. It would be good to add examples in evas_map_point_coord_set() and evas_map_point_image_uv_set() git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@43211 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/Evas.h | 30 ++-- src/lib/canvas/evas_map.c | 354 +++++++++++++++++++++++++++++-------- src/lib/canvas/evas_object_image.c | 31 ++-- src/lib/include/evas_private.h | 8 +- 4 files changed, 316 insertions(+), 107 deletions(-) diff --git a/src/lib/Evas.h b/src/lib/Evas.h index a39c0bb..e2e3ec5 100644 --- a/src/lib/Evas.h +++ b/src/lib/Evas.h @@ -105,6 +105,7 @@ typedef struct _Evas_Transform Evas_Transform; /**< An Evas projective or affine typedef struct _Evas_Coord_Rectangle Evas_Coord_Rectangle; /**< A generic rectangle handle */ typedef struct _Evas_Smart_Class Evas_Smart_Class; /**< A smart object base class */ typedef struct _Evas_Map_Point Evas_Map_Point; /**< A point with attributes for x, y, z texture u & v etc. */ +typedef struct _Evas_Map Evas_Map; /**< An array of map points */ typedef struct _Evas Evas; /**< An Evas canvas handle */ typedef struct _Evas_Object Evas_Object; /**< An Evas Object handle */ @@ -847,22 +848,23 @@ extern "C" { EAPI Eina_List *evas_objects_at_xy_get (const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; EAPI Eina_List *evas_objects_in_rectangle_get (const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; - + EAPI void evas_object_map_enable_set (Evas_Object *obj, Eina_Bool enabled); EAPI Eina_Bool evas_object_map_enable_get (const Evas_Object *obj); - EAPI void evas_object_map_set (Evas_Object *obj, const Evas_Map_Point *points); - EAPI void evas_object_map_get (const Evas_Object *obj, Evas_Map_Point *points); - - EAPI void evas_map_util_rotate (Evas_Map_Point *mp, double degrees, Evas_Coord cx, Evas_Coord cy); - EAPI void evas_map_util_zoom (Evas_Map_Point *mp, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy); - - EAPI Evas_Map_Point *evas_map_new (int num); - EAPI void evas_map_free (Evas_Map_Point *mp); - EAPI void evas_map_point_coord_set (Evas_Map_Point *mp, int n, Evas_Coord x, Evas_Coord y, Evas_Coord z); - EAPI void evas_map_point_coord_get (const Evas_Map_Point *mp, int n, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z); - EAPI void evas_map_point_image_uv_set (Evas_Map_Point *mp, int n, double u, double v); - EAPI void evas_map_point_image_uv_get (const Evas_Map_Point *mp, int n, double *u, double *v); - + EAPI void evas_object_map_set (Evas_Object *obj, const Evas_Map *map); + EAPI const Evas_Map *evas_object_map_get (const Evas_Object *obj); + + EAPI void evas_map_util_rotate (Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy); + EAPI void evas_map_util_zoom (Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy); + + EAPI Evas_Map *evas_map_new (unsigned long count); + EAPI Evas_Map *evas_map_dup (const Evas_Map *m); + EAPI void evas_map_free (Evas_Map *m); + EAPI void evas_map_point_coord_set (Evas_Map *m, unsigned long idx, Evas_Coord x, Evas_Coord y, Evas_Coord z); + EAPI void evas_map_point_coord_get (const Evas_Map *m, unsigned long idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z); + EAPI void evas_map_point_image_uv_set (Evas_Map *m, unsigned long idx, double u, double v); + EAPI void evas_map_point_image_uv_get (const Evas_Map *m, unsigned long idx, double *u, double *v); + /* smart objects */ EINA_DEPRECATED EAPI Evas_Smart *evas_smart_new (const char *name, void (*func_add) (Evas_Object *obj), void (*func_del) (Evas_Object *obj), void (*func_layer_set) (Evas_Object *obj, int l), void (*func_raise) (Evas_Object *obj), void (*func_lower) (Evas_Object *obj), void (*func_stack_above) (Evas_Object *obj, Evas_Object *above), void (*func_stack_below) (Evas_Object *obj, Evas_Object *below), void (*func_move) (Evas_Object *obj, Evas_Coord x, Evas_Coord y), void (*func_resize) (Evas_Object *obj, Evas_Coord w, Evas_Coord h), void (*func_show) (Evas_Object *obj), void (*func_hide) (Evas_Object *obj), void (*func_color_set) (Evas_Object *obj, int r, int g, int b, int a), void (*func_clip_set) (Evas_Object *obj, Evas_Object *clip), void (*func_clip_unset) (Evas_Object *obj), const void *data) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; EAPI void evas_smart_free (Evas_Smart *s) EINA_ARG_NONNULL(1); diff --git a/src/lib/canvas/evas_map.c b/src/lib/canvas/evas_map.c index 8aa3190..8f792a4 100644 --- a/src/lib/canvas/evas_map.c +++ b/src/lib/canvas/evas_map.c @@ -5,21 +5,24 @@ static void _calc_map_geometry(Evas_Object *obj) { - int i; int is, was = 0, pass = 0; Evas_Coord x1, x2, y1, y2; - - if (!obj->cur.mappoints) return; - x1 = obj->cur.mappoints[0].x; - x2 = obj->cur.mappoints[0].x; - y1 = obj->cur.mappoints[0].y; - y2 = obj->cur.mappoints[0].y; - for (i = 1; i < 4; i++) + const Evas_Map_Point *p, *p_end; + + if (!obj->cur.map) return; + p = obj->cur.map->points; + p_end = p + 4; + x1 = p->x; + x2 = p->x; + y1 = p->y; + y2 = p->y; + p++; + for (; p < p_end; p++) { - if (obj->cur.mappoints[i].x < x1) x1 = obj->cur.mappoints[i].x; - if (obj->cur.mappoints[i].x > x2) x2 = obj->cur.mappoints[i].x; - if (obj->cur.mappoints[i].y < y1) y1 = obj->cur.mappoints[i].y; - if (obj->cur.mappoints[i].y > y2) y2 = obj->cur.mappoints[i].y; + if (p->x < x1) x1 = p->x; + if (p->x > x2) x2 = p->x; + if (p->y < y1) y1 = p->y; + if (p->y > y2) y2 = p->y; } obj->cur.geometry.x = x1; obj->cur.geometry.y = y1; @@ -70,142 +73,337 @@ evas_object_map_enable_get(const Evas_Object *obj) return obj->cur.usemap; } +static inline Evas_Map * +_evas_map_new(unsigned long count) +{ + Evas_Map *m = malloc(sizeof(Evas_Map) + count * sizeof(Evas_Map_Point)); + if (!m) + return NULL; + m->count = count; + return m; +} + +static inline Evas_Map * +_evas_map_dup(const Evas_Map *orig) +{ + Evas_Map *copy = _evas_map_new(orig->count); + if (!orig) + return NULL; + memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point)); + return copy; +} + +static inline Eina_Bool +_evas_map_copy(Evas_Map *dst, const Evas_Map *src) +{ + if (dst->count != src->count) + { + ERR("cannot copy map of different sizes: dst=%lu, src=%lu", + dst->count, src->count); + return EINA_FALSE; + } + memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point)); + return EINA_TRUE; +} + +static inline void +_evas_map_free(Evas_Map *m) +{ + free(m); +} + +/** + * Set current object transformation map (or unset if it's @c NULL). + * + * @param obj object to change transformation map. + * @param map new map to use or @c NULL to unset map. This function + * will copy the given map, so it's safe to destroy it + * afterwards. + * + * @see evas_map_new() + */ EAPI void -evas_object_map_set(Evas_Object *obj, const Evas_Map_Point *points) +evas_object_map_set(Evas_Object *obj, const Evas_Map *map) { MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); return; MAGIC_CHECK_END(); - if (!points) + if (!map) { - if (obj->cur.mappoints) + if (obj->cur.map) { - if (!obj->prev.mappoints) + if (!obj->prev.map) { - free(obj->cur.mappoints); - obj->cur.mappoints = NULL; + _evas_map_free(obj->cur.map); + obj->cur.map = NULL; return; } - obj->cur.mappoints = NULL; + obj->cur.map = NULL; } return; } - if (!obj->cur.mappoints) + if (!obj->cur.map) { - obj->cur.mappoints = malloc(4 * sizeof(Evas_Map_Point)); - if (obj->cur.mappoints) - { - memcpy(obj->cur.mappoints, points, 4 * sizeof(Evas_Map_Point)); - } - obj->prev.mappoints = NULL; + obj->cur.map = _evas_map_dup(map); + obj->prev.map = NULL; } else { - memcpy(obj->cur.mappoints, points, 4 * sizeof(Evas_Map_Point)); - obj->prev.mappoints = NULL; + _evas_map_copy(obj->cur.map, map); + obj->prev.map = NULL; } if (obj->cur.usemap) _calc_map_geometry(obj); } -EAPI void -evas_object_map_get(const Evas_Object *obj, Evas_Map_Point *points) +/** + * Get current object transformation map. + * + * @param obj object to query transformation map. + * @return map reference to map in use. This is an internal reference, + * don't change it anyhow. Use evas_map_dup() if you want to + * change it and use somewhere else, or even take reference + * for long time. The returned reference may go away when + * another map is set or object is destroyed. + * + * @see evas_object_map_set() + */ +EAPI const Evas_Map * +evas_object_map_get(const Evas_Object *obj) { MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); - return; + return NULL; MAGIC_CHECK_END(); - if (obj->cur.mappoints) + if (obj->cur.map) + return obj->cur.map; + else + return NULL; +} + +/** + * Creates map of transformation points to be later used with an evas object. + * + * @param count number of points in the map. So far it @b must be 4 as + * evas will use that exact number. The parameter is for + * extensibility. Giving any value other than 4 will return @c NULL. + * + * @return a newly allocated map or @c NULL on errors. + * + * @see evas_map_free() + * @see evas_map_dup() + * @see evas_map_point_coord_set() + * @see evas_map_point_image_uv_set() + * + * @see evas_object_map_set() + */ +EAPI Evas_Map * +evas_map_new(unsigned long count) +{ + if (count != 4) { - memcpy(points, obj->cur.mappoints, 4 * sizeof(Evas_Map_Point)); + ERR("num (%lu) != 4 is unsupported!", count); + return NULL; } + return _evas_map_new(count); } - -EAPI Evas_Map_Point * -evas_map_new(int num) +/** + * Copy a previously allocated map. + * + * @param m map to copy. Must not be @c NULL. + * + * @return newly allocated map with the same count and contents as @a m. + */ +EAPI Evas_Map * +evas_map_dup(const Evas_Map *m) { - return calloc(num, sizeof(Evas_Map_Point)); + if (!m) return NULL; + return _evas_map_dup(m); } +/** + * Destroys a previously allocated map. + * + * @param m map to destroy. Must not be @c NULL. + */ EAPI void -evas_map_free(Evas_Map_Point *mp) +evas_map_free(Evas_Map *m) { - if (!mp) return; - free(mp); + if (!m) return; + _evas_map_free(m); } +/** + * Change the map point's coordinate. + * + * @param m map to change point. Must not be @c NULL. + * @param idx index of point to change. Must be smaller than map size. + * @param x TODO + * @param y TODO + * @param z TODO + * + * @see evas_map_util_rotate() + * @see evas_map_util_zoom() + */ EAPI void -evas_map_point_coord_set(Evas_Map_Point *mp, int n, Evas_Coord x, Evas_Coord y, Evas_Coord z) +evas_map_point_coord_set(Evas_Map *m, unsigned long idx, Evas_Coord x, Evas_Coord y, Evas_Coord z) { - if (!mp) return; - mp[n].x = x; - mp[n].y = y; - mp[n].z = z; + Evas_Map_Point *p; + if (!m) return; + if (idx >= m->count) return; + p = m->points + idx; + p->x = x; + p->y = y; + p->z = z; } +/** + * Get the map point's coordinate. + * + * @param m map to query point. Must not be @c NULL. + * @param idx index of point to query. Must be smaller than map size. + * @param x where to return TODO. If non @c NULL, it's guaranteed to + * be set (on error it's set to zero). + * @param y where to return TODO. If non @c NULL, it's guaranteed to + * be set (on error it's set to zero). + * @param z where to return TODO. If non @c NULL, it's guaranteed to + * be set (on error it's set to zero). + */ EAPI void -evas_map_point_coord_get(const Evas_Map_Point *mp, int n, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z) +evas_map_point_coord_get(const Evas_Map *m, unsigned long idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z) { - if (!mp) return; - if (x) *x = mp[n].x; - if (y) *y = mp[n].y; - if (z) *z = mp[n].z; + const Evas_Map_Point *p; + if (!m) goto error; + if (idx >= m->count) goto error; + p = m->points + idx; + if (x) *x = p->x; + if (y) *y = p->y; + if (z) *z = p->z; + return; + + error: + if (x) *x = 0; + if (y) *y = 0; + if (z) *z = 0; } +/** + * Change the map point's TODO. + * + * @param m map to change point. Must not be @c NULL. + * @param idx index of point to change. Must be smaller than map size. + * @param u TODO + * @param v TODO + */ EAPI void -evas_map_point_image_uv_set(Evas_Map_Point *mp, int n, double u, double v) +evas_map_point_image_uv_set(Evas_Map *m, unsigned long idx, double u, double v) { - if (!mp) return; - mp[n].u = u; - mp[n].v = v; + Evas_Map_Point *p; + if (!m) return; + if (idx >= m->count) return; + p = m->points + idx; + p->u = u; + p->v = v; } +/** + * Get the map point's TODO. + * + * @param m map to query point. Must not be @c NULL. + * @param idx index of point to query. Must be smaller than map size. + * @param u where to return TODO. If non @c NULL, it's guaranteed to + * be set (on error it's set to zero). + * @param v where to return TODO. If non @c NULL, it's guaranteed to + * be set (on error it's set to zero). + */ EAPI void -evas_map_point_image_uv_get(const Evas_Map_Point *mp, int n, double *u, double *v) +evas_map_point_image_uv_get(const Evas_Map *m, unsigned long idx, double *u, double *v) { - if (!mp) return; - if (u) *u = mp[n].u; - if (v) *v = mp[n].v; + const Evas_Map_Point *p; + if (!m) goto error; + if (idx >= m->count) goto error; + p = m->points + idx; + if (u) *u = p->u; + if (v) *v = p->v; + return; + + error: + if (u) *u = 0.0; + if (v) *v = 0.0; } +/** + * Change the map to apply the given rotation to object. + * + * @param m map to change. Must not be @c NULL. + * @param degrees amount of degrees from 0.0 to 360.0 to rotate the + * object. This is the canonical reference, counter-clockwise. TODO + * @param cx rotation's center horizontal positon. TODO (offset from object center? left?) + * @param cy rotation's center vertical positon. TODO (offset from object center? top?) + * + * @see evas_map_point_coord_set() + */ EAPI void -evas_map_util_rotate(Evas_Map_Point *mp, double degrees, Evas_Coord cx, Evas_Coord cy) +evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy) { double r = (degrees * M_PI) / 180.0; - int i; + Evas_Map_Point *p, *p_end; + + if (!m) return; + if (m->count != 4) return; - for (i = 0; i < 4; i++) + p = m->points; + p_end = p + 4; + + for (; p < p_end; p++) { Evas_Coord x, y, xx, yy; - - xx = x = mp[i].x - cx; - yy = y = mp[i].y - cy; - + + xx = x = p->x - cx; + yy = y = p->y - cy; + xx = (x * cos(r)); yy = (x * sin(r)); x = xx + (y * cos(r + (M_PI / 2.0))); y = yy + (y * sin(r + (M_PI / 2.0))); - - mp[i].x = x + cx; - mp[i].y = y + cy; + + p->x = x + cx; + p->y = y + cy; } } +/** + * Change the map to apply the given zooming to object. + * + * @param m map to change. Must not be @c NULL. + * @param zoomx horizontal zoom to use. + * @param zoomy vertical zoom to use. + * @param cx zooming center horizontal positon. TODO (offset from object center? left?) + * @param cy zooming center vertical positon. TODO (offset from object center? top?) + * + * @see evas_map_point_coord_set() + */ EAPI void -evas_map_util_zoom(Evas_Map_Point *mp, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy) +evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy) { - int i; + Evas_Map_Point *p, *p_end; + + if (!m) return; + if (m->count != 4) return; - for (i = 0; i < 4; i++) + p = m->points; + p_end = p + 4; + + for (; p < p_end; p++) { Evas_Coord x, y; - - x = mp[i].x - cx; - y = mp[i].y - cy; - + + x = p->x - cx; + y = p->y - cy; + x = (((double)x) * zoomx); y = (((double)y) * zoomy); - - mp[i].x = x + cx; - mp[i].y = y + cy; + + p->x = x + cx; + p->y = y + cy; } } diff --git a/src/lib/canvas/evas_object_image.c b/src/lib/canvas/evas_object_image.c index e94fb6c..6cdf5e1 100644 --- a/src/lib/canvas/evas_object_image.c +++ b/src/lib/canvas/evas_object_image.c @@ -2327,19 +2327,23 @@ evas_object_image_render(Evas_Object *obj, void *output, void *context, void *su } o->dirty_pixels = 0; } - if ((obj->cur.mappoints) && (obj->cur.usemap)) + if ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap)) { - RGBA_Map_Point pts[4]; - int i; - + const Evas_Map_Point *p, *p_end; + RGBA_Map_Point pts[4], *pt; + + p = obj->cur.map->points; + p_end = p + 4; + pt = pts; + // draw geom +x +y - for (i = 0; i < 4; i++) + for (; p < p_end; p++, pt++) { - pts[i].x = (obj->cur.mappoints[i].x + x) << FP; - pts[i].y = (obj->cur.mappoints[i].y + y) << FP; - pts[i].z = (obj->cur.mappoints[i].z) << FP; - pts[i].u = obj->cur.mappoints[i].u * FP1; - pts[i].v = obj->cur.mappoints[i].v * FP1; + pt->x = (p->x + x) << FP; + pt->y = (p->y + y) << FP; + pt->z = (p->z) << FP; + pt->u = p->u * FP1; + pt->v = p->v * FP1; } obj->layer->evas->engine.func->image_map4_draw(output, context, @@ -2794,7 +2798,6 @@ static int evas_object_image_is_opaque(Evas_Object *obj) { Evas_Object_Image *o; - int v; /* this returns 1 if the internal object data implies that the object is */ /* currently fully opaque over the entire rectangle it occupies */ @@ -2807,7 +2810,7 @@ evas_object_image_is_opaque(Evas_Object *obj) (o->cur.border.b != 0)) && (!o->cur.border.fill)) return 0; if (!o->engine_data) return 0; - if ((obj->cur.mappoints) && (obj->cur.usemap)) return 0; + if ((obj->cur.map) && (obj->cur.usemap)) return 0; if (obj->cur.render_op == EVAS_RENDER_COPY) return 1; if (o->cur.has_alpha) return 0; return 1; @@ -2829,7 +2832,7 @@ evas_object_image_was_opaque(Evas_Object *obj) (o->prev.border.b != 0)) && (!o->prev.border.fill)) return 0; if (!o->engine_data) return 0; - if ((obj->prev.mappoints) && (obj->prev.usemap)) return 0; + if ((obj->prev.map) && (obj->prev.usemap)) return 0; if (obj->prev.render_op == EVAS_RENDER_COPY) return 1; if (o->prev.has_alpha) return 0; if (obj->prev.render_op != EVAS_RENDER_BLEND) return 0; @@ -2973,7 +2976,7 @@ evas_object_image_has_opaque_rect(Evas_Object *obj) Evas_Object_Image *o; o = (Evas_Object_Image *)(obj->object_data); - if ((obj->cur.mappoints) && (obj->cur.usemap)) return 0; + if ((obj->cur.map) && (obj->cur.usemap)) return 0; if (((o->cur.border.l | o->cur.border.r | o->cur.border.t | o->cur.border.b) != 0) && (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) && (obj->cur.render_op == EVAS_RENDER_BLEND) && diff --git a/src/lib/include/evas_private.h b/src/lib/include/evas_private.h index 6e9ce9e..9892083 100644 --- a/src/lib/include/evas_private.h +++ b/src/lib/include/evas_private.h @@ -364,6 +364,12 @@ struct _Evas_Map_Point // FIXME: add color? }; +struct _Evas_Map +{ + unsigned long count; + Evas_Map_Point points[]; +}; + struct _Evas_Object { EINA_INLIST; @@ -389,7 +395,7 @@ struct _Evas_Object } clip; } cache; double scale; - Evas_Map_Point *mappoints; + Evas_Map *map; Evas_Coord_Rectangle geometry; struct { unsigned char r, g, b, a; -- 2.7.4