summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2014-11-13 10:47:29 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2014-12-22 22:33:11 +0900
commit5a9786c0f3c67337f9641753e7d1355867826a58 (patch)
treeddaddf7c97dc163c75de3994ba03bcf1be976b2e
parent89ed329352aa0a6752d8d63be39aa1831588cb9e (diff)
Evas masking: Implement mask support in evas_render
This implements supports for masking inside evas_render, which means: - Render the mask itself into a surface (ALPHA if possible) - Pass this mask surface to the draw context - Apply mask recursively in case a masked object is contained by another masked object. @feature
-rw-r--r--src/lib/evas/canvas/evas_render.c343
-rw-r--r--src/lib/evas/include/evas_inline.x39
2 files changed, 362 insertions, 20 deletions
diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c
index 4a340ee48f..896a3303a8 100644
--- a/src/lib/evas/canvas/evas_render.c
+++ b/src/lib/evas/canvas/evas_render.c
@@ -255,6 +255,7 @@ _evas_render_cur_clip_cache_del(Evas_Public_Data *e, Evas_Object_Protected_Data
255 y + e->framespace.y, w, h); 255 y + e->framespace.y, w, h);
256} 256}
257 257
258/* sets the redraw flag for all the proxies depending on this obj as a source */
258static void 259static void
259_evas_proxy_redraw_set(Evas_Public_Data *e, Evas_Object_Protected_Data *obj, 260_evas_proxy_redraw_set(Evas_Public_Data *e, Evas_Object_Protected_Data *obj,
260 Eina_Bool render) 261 Eina_Bool render)
@@ -293,6 +294,59 @@ _evas_proxy_redraw_set(Evas_Public_Data *e, Evas_Object_Protected_Data *obj,
293 } 294 }
294} 295}
295 296
297/* sets the mask redraw flag for all the objects clipped by this mask */
298static void
299_evas_mask_redraw_set(Evas_Public_Data *e EINA_UNUSED,
300 Evas_Object_Protected_Data *obj)
301{
302 Evas_Object_Protected_Data *clippee;
303 Eina_List *l;
304
305 if (!(obj->mask->redraw &&
306 obj->mask->x == obj->cur->geometry.x &&
307 obj->mask->y == obj->cur->geometry.y &&
308 obj->mask->w == obj->cur->geometry.w &&
309 obj->mask->h == obj->cur->geometry.h))
310 {
311 EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask,
312 Evas_Object_Mask_Data, mask)
313 mask->redraw = EINA_TRUE;
314 mask->x = obj->cur->geometry.x;
315 mask->y = obj->cur->geometry.y;
316 mask->w = obj->cur->geometry.w;
317 mask->h = obj->cur->geometry.h;
318 EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mask);
319 }
320
321 if (!obj->cur->cache.clip.dirty)
322 {
323 EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
324 state_write->cache.clip.dirty = EINA_TRUE;
325 EINA_COW_STATE_WRITE_END(obj, state_write, cur);
326 }
327
328 EINA_LIST_FOREACH(obj->clip.clipees, l, clippee)
329 {
330 evas_object_clip_recalc(clippee);
331 }
332}
333
334static inline Eina_Bool
335_evas_render_object_changed_get(Evas_Object_Protected_Data *obj)
336{
337 if (obj->smart.smart)
338 return evas_object_smart_changed_get(obj->object);
339 else
340 return obj->changed;
341}
342
343static inline Eina_Bool
344_evas_render_object_is_mask(Evas_Object_Protected_Data *obj)
345{
346 if (!obj) return EINA_FALSE;
347 return (obj->mask->is_mask && obj->clip.clipees);
348}
349
296static void 350static void
297_evas_render_phase1_direct(Evas_Public_Data *e, 351_evas_render_phase1_direct(Evas_Public_Data *e,
298 Eina_Array *active_objects, 352 Eina_Array *active_objects,
@@ -302,7 +356,6 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
302{ 356{
303 unsigned int i; 357 unsigned int i;
304 Evas_Object *eo_obj; 358 Evas_Object *eo_obj;
305 Eina_Bool changed;
306 359
307 RD(" [--- PHASE 1 DIRECT\n"); 360 RD(" [--- PHASE 1 DIRECT\n");
308 for (i = 0; i < active_objects->count; i++) 361 for (i = 0; i < active_objects->count; i++)
@@ -311,13 +364,19 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
311 eina_array_data_get(active_objects, i); 364 eina_array_data_get(active_objects, i);
312 365
313 if (obj->changed) evas_object_clip_recalc(obj); 366 if (obj->changed) evas_object_clip_recalc(obj);
314 if (!obj->proxy->proxies && !obj->proxy->proxy_textures) continue;
315
316 if (obj->smart.smart)
317 changed = evas_object_smart_changed_get(obj->object);
318 else changed = obj->changed;
319 367
320 if (changed) _evas_proxy_redraw_set(e, obj, EINA_FALSE); 368 if (obj->proxy->proxies || obj->proxy->proxy_textures)
369 {
370 /* is proxy source */
371 if (_evas_render_object_changed_get(obj))
372 _evas_proxy_redraw_set(e, obj, EINA_FALSE);
373 }
374 if (_evas_render_object_is_mask(obj))
375 {
376 /* is image clipper */
377 if (_evas_render_object_changed_get(obj))
378 _evas_mask_redraw_set(e, obj);
379 }
321 } 380 }
322 for (i = 0; i < render_objects->count; i++) 381 for (i = 0; i < render_objects->count; i++)
323 { 382 {
@@ -336,11 +395,14 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
336 { 395 {
337 evas_object_clip_recalc(obj); 396 evas_object_clip_recalc(obj);
338 obj->func->render_pre(eo_obj, obj, obj->private_data); 397 obj->func->render_pre(eo_obj, obj, obj->private_data);
339 if (obj->proxy->redraw) 398
399 if (obj->proxy->redraw || obj->mask->redraw)
340 _evas_render_prev_cur_clip_cache_add(e, obj); 400 _evas_render_prev_cur_clip_cache_add(e, obj);
341 if (obj->proxy->proxies || obj->proxy->proxy_textures) 401
402 if (!obj->smart.smart || evas_object_smart_changed_get(eo_obj))
342 { 403 {
343 if (!obj->smart.smart || evas_object_smart_changed_get(eo_obj)) 404 /* proxy sources */
405 if (obj->proxy->proxies || obj->proxy->proxy_textures)
344 { 406 {
345 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, 407 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
346 Evas_Object_Proxy_Data, proxy_write) 408 Evas_Object_Proxy_Data, proxy_write)
@@ -349,6 +411,10 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
349 proxy_write); 411 proxy_write);
350 _evas_proxy_redraw_set(e, obj, EINA_TRUE); 412 _evas_proxy_redraw_set(e, obj, EINA_TRUE);
351 } 413 }
414
415 /* clipper objects (image masks) */
416 if (_evas_render_object_is_mask(obj))
417 _evas_mask_redraw_set(e, obj);
352 } 418 }
353 419
354 RD(" pre-render-done smart:%p|%p [%p, %i] | [%p, %i] has_map:%i had_map:%i\n", 420 RD(" pre-render-done smart:%p|%p [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
@@ -547,6 +613,7 @@ _evas_render_phase1_object_process(Evas_Public_Data *e, Evas_Object *eo_obj,
547 } 613 }
548 else 614 else
549 { 615 {
616 /* non smart object */
550 if ((!obj->clip.clipees) && _evas_render_is_relevant(eo_obj)) 617 if ((!obj->clip.clipees) && _evas_render_is_relevant(eo_obj))
551 { 618 {
552 if (is_active) 619 if (is_active)
@@ -573,6 +640,20 @@ _evas_render_phase1_object_process(Evas_Public_Data *e, Evas_Object *eo_obj,
573 RD(" skip - not smart, not active or clippees or not relevant\n"); 640 RD(" skip - not smart, not active or clippees or not relevant\n");
574 } 641 }
575 } 642 }
643 else if (is_active && _evas_render_object_is_mask(obj) &&
644 (evas_object_is_visible(eo_obj, obj) || evas_object_was_visible(eo_obj, obj)))
645 {
646 if (obj->restack)
647 OBJ_ARRAY_PUSH(restack_objects, obj);
648 else
649 {
650 OBJ_ARRAY_PUSH(render_objects, obj);
651 obj->render_pre = EINA_TRUE;
652 }
653
654 RDI(level);
655 RD(" relevant + active: clipper image\n");
656 }
576 else 657 else
577 { 658 {
578 RDI(level); 659 RDI(level);
@@ -582,6 +663,7 @@ _evas_render_phase1_object_process(Evas_Public_Data *e, Evas_Object *eo_obj,
582 } 663 }
583 else 664 else
584 { 665 {
666 /* not changed */
585 RD(" not changed... [%i] -> (%i %i %p %i) [%i]\n", 667 RD(" not changed... [%i] -> (%i %i %p %i) [%i]\n",
586 evas_object_is_visible(eo_obj, obj), 668 evas_object_is_visible(eo_obj, obj),
587 obj->cur->visible, obj->cur->cache.clip.visible, obj->smart.smart, 669 obj->cur->visible, obj->cur->cache.clip.visible, obj->smart.smart,
@@ -615,6 +697,7 @@ _evas_render_phase1_object_process(Evas_Public_Data *e, Evas_Object *eo_obj,
615 } 697 }
616 else 698 else
617 { 699 {
700 /* not smart */
618 if (evas_object_is_opaque(eo_obj, obj) && 701 if (evas_object_is_opaque(eo_obj, obj) &&
619 evas_object_is_visible(eo_obj, obj)) 702 evas_object_is_visible(eo_obj, obj))
620 { 703 {
@@ -637,6 +720,14 @@ _evas_render_phase1_object_process(Evas_Public_Data *e, Evas_Object *eo_obj,
637 } 720 }
638 } 721 }
639 } 722 }
723 else if (is_active && _evas_render_object_is_mask(obj) &&
724 evas_object_is_visible(eo_obj, obj))
725 {
726 RDI(level);
727 RD(" visible clipper image\n");
728 OBJ_ARRAY_PUSH(render_objects, obj);
729 obj->render_pre = EINA_TRUE;
730 }
640 /* else if (obj->smart.smart) 731 /* else if (obj->smart.smart)
641 { 732 {
642 RDI(level); 733 RDI(level);
@@ -1139,7 +1230,11 @@ evas_render_mapped(Evas_Public_Data *e, Evas_Object *eo_obj,
1139 1230
1140 if (mapped) 1231 if (mapped)
1141 { 1232 {
1142 if (proxy_src_clip) 1233 if (_evas_render_object_is_mask(obj))
1234 {
1235 // don't return;
1236 }
1237 else if (proxy_src_clip)
1143 { 1238 {
1144 if ((!evas_object_is_visible(eo_obj, obj)) || (obj->clip.clipees) 1239 if ((!evas_object_is_visible(eo_obj, obj)) || (obj->clip.clipees)
1145 || (obj->cur->have_clipees)) 1240 || (obj->cur->have_clipees))
@@ -1395,6 +1490,7 @@ evas_render_mapped(Evas_Public_Data *e, Evas_Object *eo_obj,
1395 obj->cur->bounding_box.x, obj->cur->bounding_box.x, 1490 obj->cur->bounding_box.x, obj->cur->bounding_box.x,
1396 obj->cur->bounding_box.w, obj->cur->bounding_box.h); 1491 obj->cur->bounding_box.w, obj->cur->bounding_box.h);
1397#endif 1492#endif
1493
1398 if (mapped) 1494 if (mapped)
1399 { 1495 {
1400 RDI(level); 1496 RDI(level);
@@ -1431,11 +1527,31 @@ evas_render_mapped(Evas_Public_Data *e, Evas_Object *eo_obj,
1431 1527
1432 if (obj->cur->clipper) 1528 if (obj->cur->clipper)
1433 { 1529 {
1434 if (_evas_render_has_map(eo_obj, obj)) 1530 if (_evas_render_has_map(eo_obj, obj) ||
1531 _evas_render_object_is_mask(obj->cur->clipper))
1435 evas_object_clip_recalc(obj); 1532 evas_object_clip_recalc(obj);
1436 _evas_render_mapped_context_clip_set(e, eo_obj, obj, ctx, 1533 _evas_render_mapped_context_clip_set(e, eo_obj, obj, ctx,
1437 proxy_render_data, 1534 proxy_render_data,
1438 off_x, off_y); 1535 off_x, off_y);
1536
1537 /* Clipper masks */
1538 if (_evas_render_object_is_mask(obj->cur->clipper))
1539 {
1540 // This path can be hit when we're multiplying masks on top of each other...
1541 Evas_Object_Protected_Data *mask =
1542 (Evas_Object_Protected_Data *) obj->cur->clipper;
1543 if (mask->mask->redraw || !mask->mask->surface)
1544 evas_render_mask_subrender(obj->layer->evas, mask, NULL);
1545
1546 if (mask->mask->surface)
1547 {
1548 e->engine.func->context_clip_image_set
1549 (e->engine.data.output, ctx,
1550 mask->mask->surface,
1551 mask->mask->x + off_x,
1552 mask->mask->y + off_y);
1553 }
1554 }
1439 } 1555 }
1440 obj->func->render(eo_obj, obj, obj->private_data, 1556 obj->func->render(eo_obj, obj, obj->private_data,
1441 e->engine.data.output, ctx, 1557 e->engine.data.output, ctx,
@@ -1448,19 +1564,21 @@ evas_render_mapped(Evas_Public_Data *e, Evas_Object *eo_obj,
1448 { 1564 {
1449 if (obj->cur->clipper) 1565 if (obj->cur->clipper)
1450 { 1566 {
1567 Evas_Object_Protected_Data *clipper = obj->cur->clipper;
1451 int x, y, w, h; 1568 int x, y, w, h;
1452 1569
1453 if (_evas_render_has_map(eo_obj, obj)) 1570 if (_evas_render_has_map(eo_obj, obj) ||
1571 _evas_render_object_is_mask(obj->cur->clipper))
1454 evas_object_clip_recalc(obj); 1572 evas_object_clip_recalc(obj);
1455 x = obj->cur->cache.clip.x; 1573 x = obj->cur->cache.clip.x;
1456 y = obj->cur->cache.clip.y; 1574 y = obj->cur->cache.clip.y;
1457 w = obj->cur->cache.clip.w; 1575 w = obj->cur->cache.clip.w;
1458 h = obj->cur->cache.clip.h; 1576 h = obj->cur->cache.clip.h;
1459 RECTS_CLIP_TO_RECT(x, y, w, h, 1577 RECTS_CLIP_TO_RECT(x, y, w, h,
1460 obj->cur->clipper->cur->cache.clip.x, 1578 clipper->cur->cache.clip.x,
1461 obj->cur->clipper->cur->cache.clip.y, 1579 clipper->cur->cache.clip.y,
1462 obj->cur->clipper->cur->cache.clip.w, 1580 clipper->cur->cache.clip.w,
1463 obj->cur->clipper->cur->cache.clip.h); 1581 clipper->cur->cache.clip.h);
1464 e->engine.func->context_clip_set(e->engine.data.output, 1582 e->engine.func->context_clip_set(e->engine.data.output,
1465 context, 1583 context,
1466 x + off_x, y + off_y, w, h); 1584 x + off_x, y + off_y, w, h);
@@ -1558,6 +1676,161 @@ evas_render_proxy_subrender(Evas *eo_e, Evas_Object *eo_source, Evas_Object *eo_
1558 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write); 1676 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write);
1559} 1677}
1560 1678
1679/* @internal
1680 * Synchronously render a mask image (or smart object) into a surface.
1681 * In SW the target surface will be ALPHA only (GRY8), after conversion.
1682 * In GL the target surface will be RGBA for now. TODO: Find out how to
1683 * render GL to alpha, if that's possible.
1684 */
1685void
1686evas_render_mask_subrender(Evas_Public_Data *evas,
1687 Evas_Object_Protected_Data *mask,
1688 Evas_Object_Protected_Data *prev_mask)
1689{
1690 int x, y, w, h, r, g, b, a;
1691 void *ctx;
1692
1693 if (!mask) return;
1694 if (!mask->mask->redraw && mask->mask->surface)
1695 {
1696 DBG("Requested mask redraw but the redraw flag is off.");
1697 return;
1698 }
1699
1700 x = mask->cur->geometry.x;
1701 y = mask->cur->geometry.y;
1702 w = mask->cur->geometry.w;
1703 h = mask->cur->geometry.h;
1704
1705 r = mask->cur->color.r;
1706 g = mask->cur->color.g;
1707 b = mask->cur->color.b;
1708 a = mask->cur->color.a;
1709 if ((r != 255) || (g != 255) || (b != 255) || (a != 255))
1710 {
1711 EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
1712 {
1713 state_write->color.r = 255;
1714 state_write->color.g = 255;
1715 state_write->color.b = 255;
1716 state_write->color.a = 255;
1717 }
1718 EINA_COW_STATE_WRITE_END(mask, state_write, cur);
1719 }
1720
1721 if (prev_mask == mask)
1722 prev_mask = NULL;
1723
1724 if (prev_mask)
1725 {
1726 if (!prev_mask->mask->is_mask)
1727 {
1728 ERR("Passed invalid mask that is not a mask");
1729 prev_mask = NULL;
1730 }
1731 else if (!prev_mask->mask->surface)
1732 {
1733 // FIXME?
1734 WRN("Mask render order may be invalid");
1735 evas_render_mask_subrender(evas, prev_mask, NULL);
1736 }
1737 }
1738
1739 EINA_COW_WRITE_BEGIN(evas_object_mask_cow, mask->mask, Evas_Object_Mask_Data, mdata)
1740 mdata->redraw = EINA_FALSE;
1741
1742 /* delete render surface if changed or if already alpha
1743 * (we don't know how to render objects to alpha) */
1744 if (mdata->surface && ((w != mdata->w) || (h != mdata->h) || mdata->is_alpha))
1745 {
1746 ENFN->image_map_surface_free(ENDT, mdata->surface);
1747 mdata->surface = NULL;
1748 }
1749
1750 /* create new RGBA render surface if needed */
1751 if (!mdata->surface)
1752 {
1753 mdata->surface = ENFN->image_map_surface_new(ENDT, w, h, EINA_TRUE);
1754 if (!mdata->surface) goto end;
1755 mdata->w = w;
1756 mdata->h = h;
1757 }
1758
1759 mdata->x = x;
1760 mdata->y = y;
1761 mdata->is_alpha = EINA_FALSE;
1762
1763 /* Clear surface with transparency */
1764 ctx = ENFN->context_new(ENDT);
1765 ENFN->context_color_set(ENDT, ctx, 0, 0, 0, 0);
1766 ENFN->context_render_op_set(ENDT, ctx, EVAS_RENDER_COPY);
1767 ENFN->rectangle_draw(ENDT, ctx, mdata->surface, 0, 0, w, h, EINA_FALSE);
1768 ENFN->context_free(ENDT, ctx);
1769
1770 /* Render mask to RGBA surface */
1771 ctx = ENFN->context_new(ENDT);
1772 if (prev_mask)
1773 {
1774 ENFN->context_clip_image_set(ENDT, ctx,
1775 prev_mask->mask->surface,
1776 prev_mask->mask->x - x,
1777 prev_mask->mask->y - y);
1778 }
1779 evas_render_mapped(evas, mask->object, mask, ctx, mdata->surface,
1780 -x, -y, 1, 0, 0, evas->output.w, evas->output.h,
1781 NULL, 1, EINA_TRUE, EINA_FALSE);
1782 ENFN->context_free(ENDT, ctx);
1783
1784 /* BEGIN HACK */
1785
1786 /* Now we want to convert this RGBA surface to Alpha.
1787 * NOTE: So, this is not going to work with the GL engine but only with
1788 * the SW engine. Here's the detection hack:
1789 * FIXME: If you know of a way to support rendering to GL_ALPHA in GL,
1790 * then we should render directly to an ALPHA surface. A priori,
1791 * GLES FBO does not support this.
1792 */
1793 if (!ENFN->gl_surface_read_pixels)
1794 {
1795 RGBA_Image *alpha_surface;
1796 DATA32 *rgba;
1797 DATA8* alpha;
1798
1799 alpha_surface = ENFN->image_new_from_copied_data
1800 (ENDT, w, h, NULL, EINA_TRUE, EVAS_COLORSPACE_GRY8);
1801 if (!alpha_surface) goto end;
1802
1803 /* Copy alpha channel */
1804 rgba = ((RGBA_Image *) mdata->surface)->image.data;
1805 alpha = alpha_surface->image.data8;
1806 for (y = h; y; --y)
1807 for (x = w; x; --x, alpha++, rgba++)
1808 *alpha = (DATA8) A_VAL(rgba);
1809
1810 /* Now we can drop the original surface */
1811 ENFN->image_map_surface_free(ENDT, mdata->surface);
1812 mdata->surface = alpha_surface;
1813 mdata->is_alpha = EINA_TRUE;
1814 }
1815
1816 /* END OF HACK */
1817
1818end:
1819 EINA_COW_WRITE_END(evas_object_mask_cow, mask->mask, mdata);
1820
1821 if ((r != 255) || (g != 255) || (b != 255) || (a != 255))
1822 {
1823 EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
1824 {
1825 state_write->color.r = r;
1826 state_write->color.g = g;
1827 state_write->color.b = b;
1828 state_write->color.a = a;
1829 }
1830 EINA_COW_STATE_WRITE_END(mask, state_write, cur);
1831 }
1832}
1833
1561static void 1834static void
1562_evas_render_cutout_add(Evas_Public_Data *e, Evas_Object_Protected_Data *obj, int off_x, int off_y) 1835_evas_render_cutout_add(Evas_Public_Data *e, Evas_Object_Protected_Data *obj, int off_x, int off_y)
1563{ 1836{
@@ -1878,6 +2151,7 @@ evas_render_updates_internal(Evas *eo_e,
1878 if (UNLIKELY((evas_object_is_opaque(eo_obj, obj) || 2151 if (UNLIKELY((evas_object_is_opaque(eo_obj, obj) ||
1879 ((obj->func->has_opaque_rect) && 2152 ((obj->func->has_opaque_rect) &&
1880 (obj->func->has_opaque_rect(eo_obj, obj, obj->private_data)))) && 2153 (obj->func->has_opaque_rect(eo_obj, obj, obj->private_data)))) &&
2154 (!obj->mask->is_mask) &&
1881 evas_object_is_visible(eo_obj, obj) && 2155 evas_object_is_visible(eo_obj, obj) &&
1882 (!obj->clip.clipees) && 2156 (!obj->clip.clipees) &&
1883 (obj->cur->visible) && 2157 (obj->cur->visible) &&
@@ -1999,6 +2273,9 @@ evas_render_updates_internal(Evas *eo_e,
1999 x = cx; y = cy; w = cw; h = ch; 2273 x = cx; y = cy; w = cw; h = ch;
2000 if (((w > 0) && (h > 0)) || (obj->is_smart)) 2274 if (((w > 0) && (h > 0)) || (obj->is_smart))
2001 { 2275 {
2276 Evas_Object_Protected_Data *prev_mask = NULL;
2277 Evas_Object_Protected_Data *mask = NULL;
2278
2002 if (!obj->is_smart) 2279 if (!obj->is_smart)
2003 { 2280 {
2004 RECTS_CLIP_TO_RECT(x, y, w, h, 2281 RECTS_CLIP_TO_RECT(x, y, w, h,
@@ -2011,6 +2288,30 @@ evas_render_updates_internal(Evas *eo_e,
2011 e->engine.func->context_clip_set(e->engine.data.output, 2288 e->engine.func->context_clip_set(e->engine.data.output,
2012 e->engine.data.context, 2289 e->engine.data.context,
2013 x, y, w, h); 2290 x, y, w, h);
2291
2292 /* Clipper masks */
2293 if (_evas_render_object_is_mask(obj->cur->clipper))
2294 mask = (Evas_Object_Protected_Data *) obj->cur->clipper; // main object clipped by this mask
2295 else if (obj->cur->cache.clip.mask)
2296 mask = (Evas_Object_Protected_Data *) obj->cur->cache.clip.mask; // propagated clip
2297 prev_mask = (Evas_Object_Protected_Data *) obj->cur->cache.clip.prev_mask;
2298
2299 if (mask)
2300 {
2301 if (mask->mask->redraw || !mask->mask->surface)
2302 evas_render_mask_subrender(obj->layer->evas, mask, prev_mask);
2303
2304 if (mask->mask->surface)
2305 {
2306 e->engine.func->context_clip_image_set
2307 (e->engine.data.output,
2308 e->engine.data.context,
2309 mask->mask->surface,
2310 mask->mask->x + off_x,
2311 mask->mask->y + off_y);
2312 }
2313 }
2314
2014#if 1 /* FIXME: this can slow things down... figure out optimum... coverage */ 2315#if 1 /* FIXME: this can slow things down... figure out optimum... coverage */
2015 for (j = offset; j < e->temporary_objects.count; ++j) 2316 for (j = offset; j < e->temporary_objects.count; ++j)
2016 { 2317 {
@@ -2030,6 +2331,12 @@ evas_render_updates_internal(Evas *eo_e,
2030 do_async); 2331 do_async);
2031 e->engine.func->context_cutout_clear(e->engine.data.output, 2332 e->engine.func->context_cutout_clear(e->engine.data.output,
2032 e->engine.data.context); 2333 e->engine.data.context);
2334
2335 if (mask)
2336 {
2337 e->engine.func->context_clip_image_unset
2338 (e->engine.data.output, e->engine.data.context);
2339 }
2033 } 2340 }
2034 } 2341 }
2035 } 2342 }
diff --git a/src/lib/evas/include/evas_inline.x b/src/lib/evas/include/evas_inline.x
index 756a60f0ba..0a86e9bb0d 100644
--- a/src/lib/evas/include/evas_inline.x
+++ b/src/lib/evas/include/evas_inline.x
@@ -1,6 +1,8 @@
1#ifndef EVAS_INLINE_H 1#ifndef EVAS_INLINE_H
2#define EVAS_INLINE_H 2#define EVAS_INLINE_H
3 3
4#include "evas_private.h"
5
4static inline Eina_Bool 6static inline Eina_Bool
5_evas_render_has_map(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj) 7_evas_render_has_map(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
6{ 8{
@@ -65,9 +67,13 @@ static inline int
65evas_object_is_opaque(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj) 67evas_object_is_opaque(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
66{ 68{
67 if (obj->is_smart) return 0; 69 if (obj->is_smart) return 0;
68 /* If a mask: Assume alpha */ 70 /* If clipped: Assume alpha */
69 if (obj->cur->cache.clip.a == 255) 71 if (obj->cur->cache.clip.a == 255)
70 { 72 {
73 /* If has mask image: Always assume non opaque */
74 if ((obj->cur->clipper && obj->cur->clipper->mask->is_mask) ||
75 (obj->cur->cache.clip.mask))
76 return 0;
71 if (obj->func->is_opaque) 77 if (obj->func->is_opaque)
72 return obj->func->is_opaque(eo_obj, obj, obj->private_data); 78 return obj->func->is_opaque(eo_obj, obj, obj->private_data);
73 return 1; 79 return 1;
@@ -240,6 +246,7 @@ evas_object_clip_recalc(Evas_Object_Protected_Data *obj)
240 Evas_Object_Protected_Data *clipper = NULL; 246 Evas_Object_Protected_Data *clipper = NULL;
241 int cx, cy, cw, ch, cr, cg, cb, ca; 247 int cx, cy, cw, ch, cr, cg, cb, ca;
242 int nx, ny, nw, nh, nr, ng, nb, na; 248 int nx, ny, nw, nh, nr, ng, nb, na;
249 const Evas_Object_Protected_Data *mask = NULL, *prev_mask = NULL;
243 Eina_Bool cvis, nvis; 250 Eina_Bool cvis, nvis;
244 Evas_Object *eo_obj; 251 Evas_Object *eo_obj;
245 252
@@ -293,6 +300,29 @@ evas_object_clip_recalc(Evas_Object_Protected_Data *obj)
293 RECTS_CLIP_TO_RECT(cx, cy, cw, ch, nx, ny, nw, nh); 300 RECTS_CLIP_TO_RECT(cx, cy, cw, ch, nx, ny, nw, nh);
294 } 301 }
295 302
303 if (clipper->mask->is_mask)
304 {
305 // Set complex masks the object being clipped (parent)
306 mask = clipper;
307
308 // Forward any mask from the parents
309 if (EINA_LIKELY(obj->smart.parent != NULL))
310 {
311 Evas_Object_Protected_Data *parent =
312 eo_data_scope_get(obj->smart.parent, EVAS_OBJECT_CLASS);
313 if (parent->cur->cache.clip.mask)
314 {
315 if (parent->cur->cache.clip.mask != mask)
316 prev_mask = parent->cur->cache.clip.mask;
317 }
318 }
319 }
320 else if (clipper->cur->cache.clip.mask)
321 {
322 // Pass complex masks to children
323 mask = clipper->cur->cache.clip.mask;
324 }
325
296 nvis = clipper->cur->cache.clip.visible; 326 nvis = clipper->cur->cache.clip.visible;
297 nr = clipper->cur->cache.clip.r; 327 nr = clipper->cur->cache.clip.r;
298 ng = clipper->cur->cache.clip.g; 328 ng = clipper->cur->cache.clip.g;
@@ -304,6 +334,7 @@ evas_object_clip_recalc(Evas_Object_Protected_Data *obj)
304 cb = (cb * (nb + 1)) >> 8; 334 cb = (cb * (nb + 1)) >> 8;
305 ca = (ca * (na + 1)) >> 8; 335 ca = (ca * (na + 1)) >> 8;
306 } 336 }
337
307 if ((ca == 0 && obj->cur->render_op == EVAS_RENDER_BLEND) || 338 if ((ca == 0 && obj->cur->render_op == EVAS_RENDER_BLEND) ||
308 (cw <= 0) || (ch <= 0)) cvis = EINA_FALSE; 339 (cw <= 0) || (ch <= 0)) cvis = EINA_FALSE;
309 340
@@ -316,7 +347,9 @@ evas_object_clip_recalc(Evas_Object_Protected_Data *obj)
316 obj->cur->cache.clip.g == cg && 347 obj->cur->cache.clip.g == cg &&
317 obj->cur->cache.clip.b == cb && 348 obj->cur->cache.clip.b == cb &&
318 obj->cur->cache.clip.a == ca && 349 obj->cur->cache.clip.a == ca &&
319 obj->cur->cache.clip.dirty == EINA_FALSE) 350 obj->cur->cache.clip.dirty == EINA_FALSE &&
351 obj->cur->cache.clip.mask == mask &&
352 obj->cur->cache.clip.prev_mask == prev_mask)
320 return ; 353 return ;
321 354
322 EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur) 355 EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
@@ -331,6 +364,8 @@ evas_object_clip_recalc(Evas_Object_Protected_Data *obj)
331 state_write->cache.clip.b = cb; 364 state_write->cache.clip.b = cb;
332 state_write->cache.clip.a = ca; 365 state_write->cache.clip.a = ca;
333 state_write->cache.clip.dirty = EINA_FALSE; 366 state_write->cache.clip.dirty = EINA_FALSE;
367 state_write->cache.clip.mask = mask;
368 state_write->cache.clip.prev_mask = prev_mask;
334 } 369 }
335 EINA_COW_STATE_WRITE_END(obj, state_write, cur); 370 EINA_COW_STATE_WRITE_END(obj, state_write, cur);
336} 371}