summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-19 22:41:12 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-19 22:41:12 +0000
commit3f5fa6170c50d9c1c455ed545eca44614730109d (patch)
tree3e626ebc855d690b482c916b0ccbcfbfd210f05c /src
parent7c19e1b34d28d224dfb50f2b942209e3986b9eeb (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/lib/evas/canvas/evas_object_image.c486
1 files changed, 372 insertions, 114 deletions
diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c
index 5913f367cd..aef8c7a32d 100644
--- a/src/lib/evas/canvas/evas_object_image.c
+++ b/src/lib/evas/canvas/evas_object_image.c
@@ -3998,143 +3998,401 @@ evas_object_image_was_opaque(Evas_Object *eo_obj, Evas_Object_Protected_Data *ob
3998 return obj->prev.opaque; 3998 return obj->prev.opaque;
3999} 3999}
4000 4000
4001static inline Eina_Bool
4002_pixel_alpha_get(RGBA_Image *im, int x, int y, DATA8 *alpha,
4003 int src_region_x, int src_region_y, int src_region_w, int src_region_h,
4004 int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h)
4005{
4006 int px, py, dx, dy, sx, sy, src_w, src_h;
4007 double scale_w, scale_h;
4008
4009 if ((dst_region_x > x) || (x >= (dst_region_x + dst_region_w)) ||
4010 (dst_region_y > y) || (y >= (dst_region_y + dst_region_h)))
4011 {
4012 *alpha = 0;
4013 return EINA_FALSE;
4014 }
4015
4016 src_w = im->cache_entry.w;
4017 src_h = im->cache_entry.h;
4018 if ((src_w == 0) || (src_h == 0))
4019 {
4020 *alpha = 0;
4021 return EINA_TRUE;
4022 }
4023
4024 EINA_SAFETY_ON_TRUE_GOTO(src_region_x < 0, error_oob);
4025 EINA_SAFETY_ON_TRUE_GOTO(src_region_y < 0, error_oob);
4026 EINA_SAFETY_ON_TRUE_GOTO(src_region_x + src_region_w > src_w, error_oob);
4027 EINA_SAFETY_ON_TRUE_GOTO(src_region_y + src_region_h > src_h, error_oob);
4028
4029 scale_w = (double)dst_region_w / (double)src_region_w;
4030 scale_h = (double)dst_region_h / (double)src_region_h;
4031
4032 /* point at destination */
4033 dx = x - dst_region_x;
4034 dy = y - dst_region_y;
4035
4036 /* point at source */
4037 sx = dx / scale_w;
4038 sy = dy / scale_h;
4039
4040 /* pixel point (translated) */
4041 px = src_region_x + sx;
4042 py = src_region_y + sy;
4043 EINA_SAFETY_ON_TRUE_GOTO(px >= src_w, error_oob);
4044 EINA_SAFETY_ON_TRUE_GOTO(py >= src_h, error_oob);
4045
4046 switch (im->cache_entry.space)
4047 {
4048 case EVAS_COLORSPACE_ARGB8888:
4049 {
4050 DATA32 *pixel = im->image.data;
4051 pixel += ((py * src_w) + px);
4052 *alpha = ((*pixel) >> 24) & 0xff;
4053 }
4054 break;
4055
4056 default:
4057 ERR("Colorspace %d not supported.", im->cache_entry.space);
4058 *alpha = 0;
4059 }
4060
4061 return EINA_TRUE;
4062
4063 error_oob:
4064 ERR("Invalid region src=(%d, %d, %d, %d), dst=(%d, %d, %d, %d), image=%dx%d",
4065 src_region_x, src_region_y, src_region_w, src_region_h,
4066 dst_region_x, dst_region_y, dst_region_w, dst_region_h,
4067 src_w, src_h);
4068 *alpha = 0;
4069 return EINA_TRUE;
4070}
4071
4001static int 4072static int
4002evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord x, Evas_Coord y) 4073evas_object_image_is_inside(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord px, Evas_Coord py)
4003{ 4074{
4004 Evas_Object_Image *o = eo_data_get(eo_obj, MY_CLASS); 4075 Evas_Object_Image *o = eo_data_get(eo_obj, MY_CLASS);
4005 DATA32 *data; 4076 int imagew, imageh, uvw, uvh;
4006 int w, h, stride, iw, ih; 4077 void *pixels;
4007 int a; 4078 int is_inside = 0;
4008 int return_value; 4079
4009 4080 /* the following code is similar to evas_object_image_render(), but doesn't
4010 x -= obj->cur.cache.clip.x; 4081 * draw, just get the pixels so we can check the transparency.
4011 y -= obj->cur.cache.clip.y; 4082 */
4012 w = obj->cur.cache.clip.w; 4083 Evas_Object_Protected_Data *source =
4013 h = obj->cur.cache.clip.h; 4084 (o->cur.source ?
4014 iw = o->cur.image.w; 4085 eo_data_get(o->cur.source, EVAS_OBJ_CLASS):
4015 ih = o->cur.image.h; 4086 NULL);
4016 4087 if (!o->cur.source)
4017 if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return 0; 4088 {
4018 if (!o->cur.has_alpha) return 1; 4089 pixels = o->engine_data;
4019 4090 imagew = o->cur.image.w;
4020 // FIXME: proxy needs to be honored 4091 imageh = o->cur.image.h;
4021 if (obj->cur.map) 4092 uvw = imagew;
4093 uvh = imageh;
4094 }
4095 else if (source->proxy.surface && !source->proxy.redraw)
4022 { 4096 {
4023 x = obj->cur.map->mx; 4097 pixels = source->proxy.surface;
4024 y = obj->cur.map->my; 4098 imagew = source->proxy.w;
4099 imageh = source->proxy.h;
4100 uvw = imagew;
4101 uvh = imageh;
4102 }
4103 else if (source->type == o_type &&
4104 ((Evas_Object_Image *)eo_data_get(o->cur.source, MY_CLASS))->engine_data)
4105 {
4106 Evas_Object_Image *oi;
4107 oi = eo_data_get(o->cur.source, MY_CLASS);
4108 pixels = oi->engine_data;
4109 imagew = oi->cur.image.w;
4110 imageh = oi->cur.image.h;
4111 uvw = source->cur.geometry.w;
4112 uvh = source->cur.geometry.h;
4025 } 4113 }
4026 else 4114 else
4027 { 4115 {
4028 int bl, br, bt, bb, bsl, bsr, bst, bsb; 4116 o->proxyrendering = EINA_TRUE;
4117 _proxy_subrender(obj->layer->evas->evas, o->cur.source, EINA_FALSE);
4118 pixels = source->proxy.surface;
4119 imagew = source->proxy.w;
4120 imageh = source->proxy.h;
4121 uvw = imagew;
4122 uvh = imageh;
4123 o->proxyrendering = EINA_FALSE;
4124 }
4029 4125
4030 bl = o->cur.border.l; 4126 if (pixels)
4031 br = o->cur.border.r; 4127 {
4032 bt = o->cur.border.t; 4128 Evas_Coord idw, idh, idx, idy;
4033 bb = o->cur.border.b; 4129 int ix, iy, iw, ih;
4034 if ((bl + br) > iw) 4130
4035 { 4131 /* TODO: not handling o->dirty_pixels && o->func.get_pixels,
4036 bl = iw / 2; 4132 * should we handle it now or believe they were done in the last render?
4037 br = iw - bl; 4133 */
4038 } 4134 if (o->dirty_pixels)
4039 if ((bl + br) > iw)
4040 {
4041 bl = iw / 2;
4042 br = iw - bl;
4043 }
4044 if ((bt + bb) > ih)
4045 {
4046 bt = ih / 2;
4047 bb = ih - bt;
4048 }
4049 if ((bt + bb) > ih)
4050 { 4135 {
4051 bt = ih / 2; 4136 if (o->func.get_pixels)
4052 bb = ih - bt; 4137 {
4138 ERR("dirty_pixels && get_pixels not supported");
4139 }
4053 } 4140 }
4054 if (o->cur.border.scale != 1.0) 4141
4142 /* TODO: not handling map, need to apply map to point */
4143 if ((obj->cur.map) && (obj->cur.map->count > 3) && (obj->cur.usemap))
4055 { 4144 {
4056 bsl = ((double)bl * o->cur.border.scale); 4145 evas_object_map_update(eo_obj, 0, 0, imagew, imageh, uvw, uvh);
4057 bsr = ((double)br * o->cur.border.scale); 4146
4058 bst = ((double)bt * o->cur.border.scale); 4147 ERR("map not supported");
4059 bsb = ((double)bb * o->cur.border.scale);
4060 } 4148 }
4061 else 4149 else
4062 { 4150 {
4063 bsl = bl; bsr = br; bst = bt; bsb = bb; 4151 RGBA_Image *im;
4064 } 4152 DATA32 *data = NULL;
4065 4153 int err = 0;
4066 w = o->cur.fill.w;
4067 h = o->cur.fill.h;
4068 x -= o->cur.fill.x;
4069 y -= o->cur.fill.y;
4070 x %= w;
4071 y %= h;
4072
4073 if (x < 0) x += w;
4074 if (y < 0) y += h;
4075 4154
4076 if (o->cur.border.fill != EVAS_BORDER_FILL_DEFAULT) 4155 im = obj->layer->evas->engine.func->image_data_get
4077 { 4156 (obj->layer->evas->engine.data.output, pixels, 0, &data, &err);
4078 if ((x > bsl) && (x < (w - bsr)) && 4157 if ((!im) || (!data) || (err))
4079 (y > bst) && (y < (h - bsb)))
4080 { 4158 {
4081 if (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) return 1; 4159 ERR("Couldn't get image pixels RGBA_Image %p: im=%p, data=%p, err=%d", pixels, im, data, err);
4082 return 0; 4160 goto end;
4083 } 4161 }
4084 }
4085
4086 if (x < bsl) x = (x * bl) / bsl;
4087 else if (x > (w - bsr)) x = iw - (((w - x) * br) / bsr);
4088 else if ((bsl + bsr) < w) x = bl + (((x - bsl) * (iw - bl - br)) / (w - bsl - bsr));
4089 else return 1;
4090
4091 if (y < bst) y = (y * bt) / bst;
4092 else if (y > (h - bsb)) y = ih - (((h - y) * bb) / bsb);
4093 else if ((bst + bsb) < h) y = bt + (((y - bst) * (ih - bt - bb)) / (h - bst - bsb));
4094 else return 1;
4095 }
4096 4162
4097 if (x < 0) x = 0; 4163 idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur.fill.x, o->cur.fill.w, &idw);
4098 if (y < 0) y = 0; 4164 idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur.fill.y, o->cur.fill.h, &idh);
4099 if (x >= iw) x = iw - 1; 4165 if (idw < 1) idw = 1;
4100 if (y >= ih) y = ih - 1; 4166 if (idh < 1) idh = 1;
4101 4167 if (idx > 0) idx -= idw;
4102 stride = o->cur.image.stride; 4168 if (idy > 0) idy -= idh;
4169 while ((int)idx < obj->cur.geometry.w)
4170 {
4171 Evas_Coord ydy;
4172 int dobreak_w = 0;
4173 ydy = idy;
4174 ix = idx;
4175 if ((o->cur.fill.w == obj->cur.geometry.w) &&
4176 (o->cur.fill.x == 0))
4177 {
4178 dobreak_w = 1;
4179 iw = obj->cur.geometry.w;
4180 }
4181 else
4182 iw = ((int)(idx + idw)) - ix;
4183 while ((int)idy < obj->cur.geometry.h)
4184 {
4185 int dobreak_h = 0;
4103 4186
4104 o->engine_data = obj->layer->evas->engine.func->image_data_get 4187 iy = idy;
4105 (obj->layer->evas->engine.data.output, 4188 if ((o->cur.fill.h == obj->cur.geometry.h) &&
4106 o->engine_data, 4189 (o->cur.fill.y == 0))
4107 0, 4190 {
4108 &data, 4191 ih = obj->cur.geometry.h;
4109 &o->load_error); 4192 dobreak_h = 1;
4193 }
4194 else
4195 ih = ((int)(idy + idh)) - iy;
4196 if ((o->cur.border.l == 0) &&
4197 (o->cur.border.r == 0) &&
4198 (o->cur.border.t == 0) &&
4199 (o->cur.border.b == 0) &&
4200 (o->cur.border.fill != 0))
4201 {
4202 /* NOTE: render handles cserve2 here,
4203 * we don't need to
4204 */
4205 {
4206 DATA8 alpha = 0;
4207 if (_pixel_alpha_get(pixels, px, py, &alpha, 0, 0, imagew, imageh, obj->cur.geometry.x + ix, obj->cur.geometry.y + iy, iw, ih))
4208 {
4209 is_inside = alpha > 0;
4210 dobreak_h = 1;
4211 dobreak_w = 1;
4212 break;
4213 }
4214 }
4215 }
4216 else
4217 {
4218 int inx, iny, inw, inh, outx, outy, outw, outh;
4219 int bl, br, bt, bb, bsl, bsr, bst, bsb;
4220 int imw, imh, ox, oy;
4221 DATA8 alpha = 0;
4110 4222
4111 if (!data) 4223 ox = obj->cur.geometry.x + ix;
4112 { 4224 oy = obj->cur.geometry.y + iy;
4113 return_value = 0; 4225 imw = imagew;
4114 goto finish; 4226 imh = imageh;
4115 } 4227 bl = o->cur.border.l;
4228 br = o->cur.border.r;
4229 bt = o->cur.border.t;
4230 bb = o->cur.border.b;
4231 if ((bl + br) > iw)
4232 {
4233 bl = iw / 2;
4234 br = iw - bl;
4235 }
4236 if ((bl + br) > imw)
4237 {
4238 bl = imw / 2;
4239 br = imw - bl;
4240 }
4241 if ((bt + bb) > ih)
4242 {
4243 bt = ih / 2;
4244 bb = ih - bt;
4245 }
4246 if ((bt + bb) > imh)
4247 {
4248 bt = imh / 2;
4249 bb = imh - bt;
4250 }
4251 if (o->cur.border.scale != 1.0)
4252 {
4253 bsl = ((double)bl * o->cur.border.scale);
4254 bsr = ((double)br * o->cur.border.scale);
4255 bst = ((double)bt * o->cur.border.scale);
4256 bsb = ((double)bb * o->cur.border.scale);
4257 }
4258 else
4259 {
4260 bsl = bl; bsr = br; bst = bt; bsb = bb;
4261 }
4262 // #--
4263 // |
4264 inx = 0; iny = 0;
4265 inw = bl; inh = bt;
4266 outx = ox; outy = oy;
4267 outw = bsl; outh = bst;
4268 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4269 {
4270 is_inside = alpha > 0;
4271 dobreak_h = 1;
4272 dobreak_w = 1;
4273 break;
4274 }
4116 4275
4117 switch (o->cur.cspace) 4276 // .##
4118 { 4277 // |
4119 case EVAS_COLORSPACE_ARGB8888: 4278 inx = bl; iny = 0;
4120 data = ((DATA32*)(data) + ((y * (stride >> 2)) + x)); 4279 inw = imw - bl - br; inh = bt;
4121 a = (*((DATA32*)(data)) >> 24) & 0xff; 4280 outx = ox + bsl; outy = oy;
4122 break; 4281 outw = iw - bsl - bsr; outh = bst;
4123 case EVAS_COLORSPACE_RGB565_A5P: 4282 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4124 data = (void*) ((DATA16*)(data) + (h * (stride >> 1))); 4283 {
4125 data = (void*) ((DATA8*)(data) + ((y * (stride >> 1)) + x)); 4284 is_inside = alpha > 0;
4126 a = (*((DATA8*)(data))) & 0x1f; 4285 dobreak_h = 1;
4127 break; 4286 dobreak_w = 1;
4128 default: 4287 break;
4129 return_value = 1; 4288 }
4130 goto finish; 4289 // --#
4131 break; 4290 // |
4291 inx = imw - br; iny = 0;
4292 inw = br; inh = bt;
4293 outx = ox + iw - bsr; outy = oy;
4294 outw = bsr; outh = bst;
4295 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4296 {
4297 is_inside = alpha > 0;
4298 dobreak_h = 1;
4299 dobreak_w = 1;
4300 break;
4301 }
4302 // .--
4303 // #
4304 inx = 0; iny = bt;
4305 inw = bl; inh = imh - bt - bb;
4306 outx = ox; outy = oy + bst;
4307 outw = bsl; outh = ih - bst - bsb;
4308 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4309 {
4310 is_inside = alpha > 0;
4311 dobreak_h = 1;
4312 dobreak_w = 1;
4313 break;
4314 }
4315 // .--.
4316 // |##|
4317 if (o->cur.border.fill > EVAS_BORDER_FILL_NONE)
4318 {
4319 inx = bl; iny = bt;
4320 inw = imw - bl - br; inh = imh - bt - bb;
4321 outx = ox + bsl; outy = oy + bst;
4322 outw = iw - bsl - bsr; outh = ih - bst - bsb;
4323 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4324 {
4325 is_inside = alpha > 0;
4326 dobreak_h = 1;
4327 dobreak_w = 1;
4328 break;
4329 }
4330 }
4331 // --.
4332 // #
4333 inx = imw - br; iny = bt;
4334 inw = br; inh = imh - bt - bb;
4335 outx = ox + iw - bsr; outy = oy + bst;
4336 outw = bsr; outh = ih - bst - bsb;
4337 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4338 {
4339 is_inside = alpha > 0;
4340 dobreak_h = 1;
4341 dobreak_w = 1;
4342 break;
4343 }
4344 // |
4345 // #--
4346 inx = 0; iny = imh - bb;
4347 inw = bl; inh = bb;
4348 outx = ox; outy = oy + ih - bsb;
4349 outw = bsl; outh = bsb;
4350 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4351 {
4352 is_inside = alpha > 0;
4353 dobreak_h = 1;
4354 dobreak_w = 1;
4355 break;
4356 }
4357 // |
4358 // .##
4359 inx = bl; iny = imh - bb;
4360 inw = imw - bl - br; inh = bb;
4361 outx = ox + bsl; outy = oy + ih - bsb;
4362 outw = iw - bsl - bsr; outh = bsb;
4363 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4364 {
4365 is_inside = alpha > 0;
4366 dobreak_h = 1;
4367 dobreak_w = 1;
4368 break;
4369 }
4370 // |
4371 // --#
4372 inx = imw - br; iny = imh - bb;
4373 inw = br; inh = bb;
4374 outx = ox + iw - bsr; outy = oy + ih - bsb;
4375 outw = bsr; outh = bsb;
4376 if (_pixel_alpha_get(pixels, px, py, &alpha, inx, iny, inw, inh, outx, outy, outw, outh))
4377 {
4378 is_inside = alpha > 0;
4379 dobreak_h = 1;
4380 dobreak_w = 1;
4381 break;
4382 }
4383 }
4384 idy += idh;
4385 if (dobreak_h) break;
4386 }
4387 idx += idw;
4388 idy = ydy;
4389 if (dobreak_w) break;
4390 }
4391 }
4132 } 4392 }
4133 4393
4134 return_value = (a != 0); 4394 end:
4135 4395 return is_inside;
4136finish:
4137 return return_value;
4138} 4396}
4139 4397
4140static int 4398static int