forked from enlightenment/efl
efl/evas_object_image_is_inside: fixed implementation.
This function was basically never working correctly. Everything was fixed by simulating the evas_object_image_render() workflow, but instead of actually draw we just check the pixel transparency. Bugs fixed: * fails when image is scaled up (could segv) or down (incorrect values); * fails when image is moved to negative x,y; * fails when border was being used. Now everything is fixed and seems to work properly, except I'm not handling the map and get_pixels() cases, these are marked with ERR() so we can fix them if someone needs. SVN revision: 81410
This commit is contained in:
parent
7c19e1b34d
commit
3f5fa6170c
|
@ -1,6 +1,7 @@
|
|||
2012-12-19 Gustavo Sverzut Barbieri (k-s)
|
||||
|
||||
* Fixed RGBA_Image->flags.loaded for copied images.
|
||||
* Fixed Evas RGBA_Image->flags.loaded for copied images.
|
||||
* Fixed evas_object_image_is_inside() implementation.
|
||||
|
||||
2012-12-19 Carsten Haitzler (The Rasterman)
|
||||
|
||||
|
|
1
NEWS
1
NEWS
|
@ -85,3 +85,4 @@ Fixes:
|
|||
* Fix the line drawing clipping problem on arm gl driver.
|
||||
* Fix many memory problems with ecore_evas_extn.
|
||||
* Fix Evas RGBA_Image->flags.loaded for copied images.
|
||||
* Fix evas_object_image_is_inside()
|
||||
|
|
|
@ -3998,35 +3998,232 @@ evas_object_image_was_opaque(Evas_Object *eo_obj, Evas_Object_Protected_Data *ob
|
|||
return obj->prev.opaque;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
_pixel_alpha_get(RGBA_Image *im, int x, int y, DATA8 *alpha,
|
||||
int src_region_x, int src_region_y, int src_region_w, int src_region_h,
|
||||
int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h)
|
||||
{
|
||||
int px, py, dx, dy, sx, sy, src_w, src_h;
|
||||
double scale_w, scale_h;
|
||||
|
||||
if ((dst_region_x > x) || (x >= (dst_region_x + dst_region_w)) ||
|
||||
(dst_region_y > y) || (y >= (dst_region_y + dst_region_h)))
|
||||
{
|
||||
*alpha = 0;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
src_w = im->cache_entry.w;
|
||||
src_h = im->cache_entry.h;
|
||||
if ((src_w == 0) || (src_h == 0))
|
||||
{
|
||||
*alpha = 0;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EINA_SAFETY_ON_TRUE_GOTO(src_region_x < 0, error_oob);
|
||||
EINA_SAFETY_ON_TRUE_GOTO(src_region_y < 0, error_oob);
|
||||
EINA_SAFETY_ON_TRUE_GOTO(src_region_x + src_region_w > src_w, error_oob);
|
||||
EINA_SAFETY_ON_TRUE_GOTO(src_region_y + src_region_h > src_h, error_oob);
|
||||
|
||||
scale_w = (double)dst_region_w / (double)src_region_w;
|
||||
scale_h = (double)dst_region_h / (double)src_region_h;
|
||||
|
||||
/* point at destination */
|
||||
dx = x - dst_region_x;
|
||||
dy = y - dst_region_y;
|
||||
|
||||
/* point at source */
|
||||
sx = dx / scale_w;
|
||||
sy = dy / scale_h;
|
||||
|
||||
/* pixel point (translated) */
|
||||
px = src_region_x + sx;
|
||||
py = src_region_y + sy;
|
||||
EINA_SAFETY_ON_TRUE_GOTO(px >= src_w, error_oob);
|
||||
EINA_SAFETY_ON_TRUE_GOTO(py >= src_h, error_oob);
|
||||
|
||||
switch (im->cache_entry.space)
|
||||
{
|
||||
case EVAS_COLORSPACE_ARGB8888:
|
||||
{
|
||||
DATA32 *pixel = im->image.data;
|
||||
pixel += ((py * src_w) + px);
|
||||
*alpha = ((*pixel) >> 24) & 0xff;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR("Colorspace %d not supported.", im->cache_entry.space);
|
||||
*alpha = 0;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
error_oob:
|
||||
ERR("Invalid region src=(%d, %d, %d, %d), dst=(%d, %d, %d, %d), image=%dx%d",
|
||||
src_region_x, src_region_y, src_region_w, src_region_h,
|
||||
dst_region_x, dst_region_y, dst_region_w, dst_region_h,
|
||||
src_w, src_h);
|
||||
*alpha = 0;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord x, Evas_Coord y)
|
||||
evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord px, Evas_Coord py)
|
||||
{
|
||||
Evas_Object_Image *o = eo_data_get(eo_obj, MY_CLASS);
|
||||
DATA32 *data;
|
||||
int w, h, stride, iw, ih;
|
||||
int a;
|
||||
int return_value;
|
||||
int imagew, imageh, uvw, uvh;
|
||||
void *pixels;
|
||||
int is_inside = 0;
|
||||
|
||||
x -= obj->cur.cache.clip.x;
|
||||
y -= obj->cur.cache.clip.y;
|
||||
w = obj->cur.cache.clip.w;
|
||||
h = obj->cur.cache.clip.h;
|
||||
iw = o->cur.image.w;
|
||||
ih = o->cur.image.h;
|
||||
|
||||
if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return 0;
|
||||
if (!o->cur.has_alpha) return 1;
|
||||
|
||||
// FIXME: proxy needs to be honored
|
||||
if (obj->cur.map)
|
||||
/* the following code is similar to evas_object_image_render(), but doesn't
|
||||
* draw, just get the pixels so we can check the transparency.
|
||||
*/
|
||||
Evas_Object_Protected_Data *source =
|
||||
(o->cur.source ?
|
||||
eo_data_get(o->cur.source, EVAS_OBJ_CLASS):
|
||||
NULL);
|
||||
if (!o->cur.source)
|
||||
{
|
||||
x = obj->cur.map->mx;
|
||||
y = obj->cur.map->my;
|
||||
pixels = o->engine_data;
|
||||
imagew = o->cur.image.w;
|
||||
imageh = o->cur.image.h;
|
||||
uvw = imagew;
|
||||
uvh = imageh;
|
||||
}
|
||||
else if (source->proxy.surface && !source->proxy.redraw)
|
||||
{
|
||||
pixels = source->proxy.surface;
|
||||
imagew = source->proxy.w;
|
||||
imageh = source->proxy.h;
|
||||
uvw = imagew;
|
||||
uvh = imageh;
|
||||
}
|
||||
else if (source->type == o_type &&
|
||||
((Evas_Object_Image *)eo_data_get(o->cur.source, MY_CLASS))->engine_data)
|
||||
{
|
||||
Evas_Object_Image *oi;
|
||||
oi = eo_data_get(o->cur.source, MY_CLASS);
|
||||
pixels = oi->engine_data;
|
||||
imagew = oi->cur.image.w;
|
||||
imageh = oi->cur.image.h;
|
||||
uvw = source->cur.geometry.w;
|
||||
uvh = source->cur.geometry.h;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bl, br, bt, bb, bsl, bsr, bst, bsb;
|
||||
o->proxyrendering = EINA_TRUE;
|
||||
_proxy_subrender(obj->layer->evas->evas, o->cur.source, EINA_FALSE);
|
||||
pixels = source->proxy.surface;
|
||||
imagew = source->proxy.w;
|
||||
imageh = source->proxy.h;
|
||||
uvw = imagew;
|
||||
uvh = imageh;
|
||||
o->proxyrendering = EINA_FALSE;
|
||||
}
|
||||
|
||||
if (pixels)
|
||||
{
|
||||
Evas_Coord idw, idh, idx, idy;
|
||||
int ix, iy, iw, ih;
|
||||
|
||||
/* TODO: not handling o->dirty_pixels && o->func.get_pixels,
|
||||
* should we handle it now or believe they were done in the last render?
|
||||
*/
|
||||
if (o->dirty_pixels)
|
||||
{
|
||||
if (o->func.get_pixels)
|
||||
{
|
||||
ERR("dirty_pixels && get_pixels not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: not handling map, need to apply map to point */
|
||||
if ((obj->cur.map) && (obj->cur.map->count > 3) && (obj->cur.usemap))
|
||||
{
|
||||
evas_object_map_update(eo_obj, 0, 0, imagew, imageh, uvw, uvh);
|
||||
|
||||
ERR("map not supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
RGBA_Image *im;
|
||||
DATA32 *data = NULL;
|
||||
int err = 0;
|
||||
|
||||
im = obj->layer->evas->engine.func->image_data_get
|
||||
(obj->layer->evas->engine.data.output, pixels, 0, &data, &err);
|
||||
if ((!im) || (!data) || (err))
|
||||
{
|
||||
ERR("Couldn't get image pixels RGBA_Image %p: im=%p, data=%p, err=%d", pixels, im, data, err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur.fill.x, o->cur.fill.w, &idw);
|
||||
idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur.fill.y, o->cur.fill.h, &idh);
|
||||
if (idw < 1) idw = 1;
|
||||
if (idh < 1) idh = 1;
|
||||
if (idx > 0) idx -= idw;
|
||||
if (idy > 0) idy -= idh;
|
||||
while ((int)idx < obj->cur.geometry.w)
|
||||
{
|
||||
Evas_Coord ydy;
|
||||
int dobreak_w = 0;
|
||||
ydy = idy;
|
||||
ix = idx;
|
||||
if ((o->cur.fill.w == obj->cur.geometry.w) &&
|
||||
(o->cur.fill.x == 0))
|
||||
{
|
||||
dobreak_w = 1;
|
||||
iw = obj->cur.geometry.w;
|
||||
}
|
||||
else
|
||||
iw = ((int)(idx + idw)) - ix;
|
||||
while ((int)idy < obj->cur.geometry.h)
|
||||
{
|
||||
int dobreak_h = 0;
|
||||
|
||||
iy = idy;
|
||||
if ((o->cur.fill.h == obj->cur.geometry.h) &&
|
||||
(o->cur.fill.y == 0))
|
||||
{
|
||||
ih = obj->cur.geometry.h;
|
||||
dobreak_h = 1;
|
||||
}
|
||||
else
|
||||
ih = ((int)(idy + idh)) - iy;
|
||||
if ((o->cur.border.l == 0) &&
|
||||
(o->cur.border.r == 0) &&
|
||||
(o->cur.border.t == 0) &&
|
||||
(o->cur.border.b == 0) &&
|
||||
(o->cur.border.fill != 0))
|
||||
{
|
||||
/* NOTE: render handles cserve2 here,
|
||||
* we don't need to
|
||||
*/
|
||||
{
|
||||
DATA8 alpha = 0;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, 0, 0, imagew, imageh, obj->cur.geometry.x + ix, obj->cur.geometry.y + iy, iw, ih))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int inx, iny, inw, inh, outx, outy, outw, outh;
|
||||
int bl, br, bt, bb, bsl, bsr, bst, bsb;
|
||||
int imw, imh, ox, oy;
|
||||
DATA8 alpha = 0;
|
||||
|
||||
ox = obj->cur.geometry.x + ix;
|
||||
oy = obj->cur.geometry.y + iy;
|
||||
imw = imagew;
|
||||
imh = imageh;
|
||||
bl = o->cur.border.l;
|
||||
br = o->cur.border.r;
|
||||
bt = o->cur.border.t;
|
||||
|
@ -4036,20 +4233,20 @@ evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj
|
|||
bl = iw / 2;
|
||||
br = iw - bl;
|
||||
}
|
||||
if ((bl + br) > iw)
|
||||
if ((bl + br) > imw)
|
||||
{
|
||||
bl = iw / 2;
|
||||
br = iw - bl;
|
||||
bl = imw / 2;
|
||||
br = imw - bl;
|
||||
}
|
||||
if ((bt + bb) > ih)
|
||||
{
|
||||
bt = ih / 2;
|
||||
bb = ih - bt;
|
||||
}
|
||||
if ((bt + bb) > ih)
|
||||
if ((bt + bb) > imh)
|
||||
{
|
||||
bt = ih / 2;
|
||||
bb = ih - bt;
|
||||
bt = imh / 2;
|
||||
bb = imh - bt;
|
||||
}
|
||||
if (o->cur.border.scale != 1.0)
|
||||
{
|
||||
|
@ -4062,79 +4259,140 @@ evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj
|
|||
{
|
||||
bsl = bl; bsr = br; bst = bt; bsb = bb;
|
||||
}
|
||||
|
||||
w = o->cur.fill.w;
|
||||
h = o->cur.fill.h;
|
||||
x -= o->cur.fill.x;
|
||||
y -= o->cur.fill.y;
|
||||
x %= w;
|
||||
y %= h;
|
||||
|
||||
if (x < 0) x += w;
|
||||
if (y < 0) y += h;
|
||||
|
||||
if (o->cur.border.fill != EVAS_BORDER_FILL_DEFAULT)
|
||||
// #--
|
||||
// |
|
||||
inx = 0; iny = 0;
|
||||
inw = bl; inh = bt;
|
||||
outx = ox; outy = oy;
|
||||
outw = bsl; outh = bst;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
if ((x > bsl) && (x < (w - bsr)) &&
|
||||
(y > bst) && (y < (h - bsb)))
|
||||
{
|
||||
if (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (x < bsl) x = (x * bl) / bsl;
|
||||
else if (x > (w - bsr)) x = iw - (((w - x) * br) / bsr);
|
||||
else if ((bsl + bsr) < w) x = bl + (((x - bsl) * (iw - bl - br)) / (w - bsl - bsr));
|
||||
else return 1;
|
||||
|
||||
if (y < bst) y = (y * bt) / bst;
|
||||
else if (y > (h - bsb)) y = ih - (((h - y) * bb) / bsb);
|
||||
else if ((bst + bsb) < h) y = bt + (((y - bst) * (ih - bt - bb)) / (h - bst - bsb));
|
||||
else return 1;
|
||||
}
|
||||
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x >= iw) x = iw - 1;
|
||||
if (y >= ih) y = ih - 1;
|
||||
|
||||
stride = o->cur.image.stride;
|
||||
|
||||
o->engine_data = obj->layer->evas->engine.func->image_data_get
|
||||
(obj->layer->evas->engine.data.output,
|
||||
o->engine_data,
|
||||
0,
|
||||
&data,
|
||||
&o->load_error);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
return_value = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
switch (o->cur.cspace)
|
||||
{
|
||||
case EVAS_COLORSPACE_ARGB8888:
|
||||
data = ((DATA32*)(data) + ((y * (stride >> 2)) + x));
|
||||
a = (*((DATA32*)(data)) >> 24) & 0xff;
|
||||
break;
|
||||
case EVAS_COLORSPACE_RGB565_A5P:
|
||||
data = (void*) ((DATA16*)(data) + (h * (stride >> 1)));
|
||||
data = (void*) ((DATA8*)(data) + ((y * (stride >> 1)) + x));
|
||||
a = (*((DATA8*)(data))) & 0x1f;
|
||||
break;
|
||||
default:
|
||||
return_value = 1;
|
||||
goto finish;
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return_value = (a != 0);
|
||||
// .##
|
||||
// |
|
||||
inx = bl; iny = 0;
|
||||
inw = imw - bl - br; inh = bt;
|
||||
outx = ox + bsl; outy = oy;
|
||||
outw = iw - bsl - bsr; outh = bst;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// --#
|
||||
// |
|
||||
inx = imw - br; iny = 0;
|
||||
inw = br; inh = bt;
|
||||
outx = ox + iw - bsr; outy = oy;
|
||||
outw = bsr; outh = bst;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// .--
|
||||
// #
|
||||
inx = 0; iny = bt;
|
||||
inw = bl; inh = imh - bt - bb;
|
||||
outx = ox; outy = oy + bst;
|
||||
outw = bsl; outh = ih - bst - bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// .--.
|
||||
// |##|
|
||||
if (o->cur.border.fill > EVAS_BORDER_FILL_NONE)
|
||||
{
|
||||
inx = bl; iny = bt;
|
||||
inw = imw - bl - br; inh = imh - bt - bb;
|
||||
outx = ox + bsl; outy = oy + bst;
|
||||
outw = iw - bsl - bsr; outh = ih - bst - bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// --.
|
||||
// #
|
||||
inx = imw - br; iny = bt;
|
||||
inw = br; inh = imh - bt - bb;
|
||||
outx = ox + iw - bsr; outy = oy + bst;
|
||||
outw = bsr; outh = ih - bst - bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// |
|
||||
// #--
|
||||
inx = 0; iny = imh - bb;
|
||||
inw = bl; inh = bb;
|
||||
outx = ox; outy = oy + ih - bsb;
|
||||
outw = bsl; outh = bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// |
|
||||
// .##
|
||||
inx = bl; iny = imh - bb;
|
||||
inw = imw - bl - br; inh = bb;
|
||||
outx = ox + bsl; outy = oy + ih - bsb;
|
||||
outw = iw - bsl - bsr; outh = bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
// |
|
||||
// --#
|
||||
inx = imw - br; iny = imh - bb;
|
||||
inw = br; inh = bb;
|
||||
outx = ox + iw - bsr; outy = oy + ih - bsb;
|
||||
outw = bsr; outh = bsb;
|
||||
if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
|
||||
{
|
||||
is_inside = alpha > 0;
|
||||
dobreak_h = 1;
|
||||
dobreak_w = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
idy += idh;
|
||||
if (dobreak_h) break;
|
||||
}
|
||||
idx += idw;
|
||||
idy = ydy;
|
||||
if (dobreak_w) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
return return_value;
|
||||
end:
|
||||
return is_inside;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in New Issue