Home | History | Annotate | Download | only in ewk
      1 /*
      2     Copyright (C) 2009-2010 ProFUSION embedded systems
      3     Copyright (C) 2009-2010 Samsung Electronics
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public License
     16     along with this library; see the file COPYING.LIB.  If not, write to
     17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18     Boston, MA 02110-1301, USA.
     19 */
     20 
     21 #include "config.h"
     22 #include "ewk_view.h"
     23 
     24 #include "ewk_frame.h"
     25 #include "ewk_logging.h"
     26 
     27 #include <Evas.h>
     28 #include <eina_safety_checks.h>
     29 #include <string.h>
     30 
     31 static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL;
     32 
     33 static void _ewk_view_single_on_del(void *data, Evas *e, Evas_Object *o, void *event_info)
     34 {
     35     Evas_Object *clip = (Evas_Object*)data;
     36     evas_object_del(clip);
     37 }
     38 
     39 static void _ewk_view_single_smart_add(Evas_Object *o)
     40 {
     41     Ewk_View_Smart_Data *sd;
     42 
     43     _parent_sc.sc.add(o);
     44 
     45     sd = (Ewk_View_Smart_Data *)evas_object_smart_data_get(o);
     46 
     47     Evas_Object *clip = evas_object_rectangle_add(sd->base.evas);
     48     evas_object_clip_set(sd->backing_store, clip);
     49     evas_object_smart_member_add(clip, o);
     50     evas_object_show(clip);
     51 
     52     evas_object_event_callback_add
     53         (sd->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip);
     54 }
     55 
     56 static Evas_Object *_ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data *sd)
     57 {
     58     Evas_Object *bs = evas_object_image_add(sd->base.evas);
     59     evas_object_image_alpha_set(bs, EINA_FALSE);
     60     evas_object_image_smooth_scale_set(bs, sd->zoom_weak_smooth_scale);
     61 
     62     return bs;
     63 }
     64 
     65 static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
     66 {
     67     Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o);
     68     _parent_sc.sc.resize(o, w, h);
     69 
     70     // these should be queued and processed in calculate as well!
     71     evas_object_image_size_set(sd->backing_store, w, h);
     72     if (sd->animated_zoom.zoom.current < 0.00001) {
     73         Evas_Object *clip = evas_object_clip_get(sd->backing_store);
     74         Evas_Coord x, y, cw, ch;
     75         evas_object_image_fill_set(sd->backing_store, 0, 0, w, h);
     76         evas_object_geometry_get(sd->backing_store, &x, &y, 0, 0);
     77         evas_object_move(clip, x, y);
     78         ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
     79         if (w > cw)
     80             w = cw;
     81         if (h > ch)
     82             h = ch;
     83         evas_object_resize(clip, w, h);
     84     }
     85 }
     86 
     87 static inline void _ewk_view_4b_move_region_up(uint32_t *image, size_t rows, size_t x, size_t y, size_t w, size_t h, size_t rowsize)
     88 {
     89     uint32_t *src;
     90     uint32_t *dst;
     91 
     92     dst = image + x + y * rowsize;
     93     src = dst + rows * rowsize;
     94     h -= rows;
     95 
     96     for (; h > 0; h--, dst += rowsize, src += rowsize)
     97         memcpy(dst, src, w * 4);
     98 }
     99 
    100 static inline void _ewk_view_4b_move_region_down(uint32_t *image, size_t rows, size_t x, size_t y, size_t w, size_t h, size_t rowsize)
    101 {
    102     uint32_t *src;
    103     uint32_t *dst;
    104 
    105     h -= rows;
    106     src = image + x + (y + h - 1) * rowsize;
    107     dst = src + rows * rowsize;
    108 
    109     for (; h > 0; h--, dst -= rowsize, src -= rowsize)
    110         memcpy(dst, src, w * 4);
    111 }
    112 
    113 static inline void _ewk_view_4b_move_line_left(uint32_t *dst, const uint32_t *src, size_t count)
    114 {
    115     uint32_t *dst_end = dst + count;
    116     /* no memcpy() as it does not allow overlapping regions */
    117     /* no memmove() as it will copy to a temporary buffer */
    118     /* TODO: loop unrolling, copying up to quad-words would help */
    119     for (; dst < dst_end; dst++, src++)
    120         *dst = *src;
    121 }
    122 
    123 static inline void _ewk_view_4b_move_line_right(uint32_t *dst, uint32_t *src, size_t count)
    124 {
    125     uint32_t *dst_end = dst - count;
    126     /* no memcpy() as it does not allow overlapping regions */
    127     /* no memmove() as it will copy to a temporary buffer */
    128     /* TODO: loop unrolling, copying up to quad-words would help */
    129     for (; dst > dst_end; dst--, src--)
    130         *dst = *src;
    131 }
    132 
    133 static inline void _ewk_view_4b_move_region_left(uint32_t *image, size_t cols, size_t x, size_t y, size_t w, size_t h, size_t rowsize)
    134 {
    135     uint32_t *src;
    136     uint32_t *dst;
    137 
    138     dst = image + x + y * rowsize;
    139     src = dst + cols;
    140     w -= cols;
    141 
    142     for (; h > 0; h--, dst += rowsize, src += rowsize)
    143         _ewk_view_4b_move_line_left(dst, src, w);
    144 }
    145 
    146 static inline void _ewk_view_4b_move_region_right(uint32_t *image, size_t cols, size_t x, size_t y, size_t w, size_t h, size_t rowsize)
    147 {
    148     uint32_t *src;
    149     uint32_t *dst;
    150 
    151     w -= cols;
    152     src = image + (x + w - 1) + y * rowsize;
    153     dst = src + cols;
    154 
    155     for (; h > 0; h--, dst += rowsize, src += rowsize)
    156         _ewk_view_4b_move_line_right(dst, src, w);
    157 }
    158 
    159 /* catch-all function, not as optimized as the others, but does the work. */
    160 static inline void _ewk_view_4b_move_region(uint32_t *image, int dx, int dy, size_t x, size_t y, size_t w, size_t h, size_t rowsize)
    161 {
    162     uint32_t *src;
    163     uint32_t *dst;
    164 
    165     if (dy < 0) {
    166         h += dy;
    167         dst = image + x + y * rowsize;
    168         src = dst - dy * rowsize;
    169         if (dx <= 0) {
    170             w += dx;
    171             src -= dx;
    172             for (; h > 0; h--, dst += rowsize, src += rowsize)
    173                 _ewk_view_4b_move_line_left(dst, src, w);
    174         } else {
    175             w -= dx;
    176             src += w - 1;
    177             dst += w + dx -1;
    178             for (; h > 0; h--, dst += rowsize, src += rowsize)
    179                 _ewk_view_4b_move_line_right(dst, src, w);
    180         }
    181     } else {
    182         h -= dy;
    183         src = image + x + (y + h - 1) * rowsize;
    184         dst = src + dy * rowsize;
    185         if (dx <= 0) {
    186             w += dx;
    187             src -= dx;
    188             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
    189                 _ewk_view_4b_move_line_left(dst, src, w);
    190         } else {
    191             w -= dx;
    192             src += w - 1;
    193             dst += w + dx - 1;
    194             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
    195                 _ewk_view_4b_move_line_right(dst, src, w);
    196         }
    197     }
    198 }
    199 
    200 static inline void _ewk_view_single_scroll_process_single(Ewk_View_Smart_Data *sd, void *pixels, Evas_Coord ow, Evas_Coord oh, const Ewk_Scroll_Request *sr)
    201 {
    202     Evas_Coord sx, sy, sw, sh;
    203 
    204     DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d",
    205         sr->x, sr->y, sr->w, sr->h, sr->dx, sr->dy, pixels, ow, oh);
    206 
    207     sx = sr->x;
    208     sy = sr->y;
    209     sw = sr->w;
    210     sh = sr->h;
    211 
    212     if (abs(sr->dx) >= sw || abs(sr->dy) >= sh) {
    213         /* doubt webkit would be so stupid... */
    214         DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
    215             sr->dx, sr->dy, sx, sy, sw, sh);
    216         ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh);
    217         return;
    218     }
    219 
    220     if (sx < 0) {
    221         sw += sx;
    222         sx = 0;
    223     }
    224     if (sy < 0) {
    225         sh += sy;
    226         sy = 0;
    227     }
    228 
    229     if (sx + sw > ow)
    230         sw = ow - sx;
    231     if (sy + sh > oh)
    232         sh = oh - sy;
    233 
    234     if (sw < 0)
    235         sw = 0;
    236     if (sh < 0)
    237         sh = 0;
    238 
    239     EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh);
    240     if (!sr->dx) {
    241         if (sr->dy < 0) {
    242             DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
    243                 "repaint=%d,%d+%dx%d",
    244                 sr->dx, sr->dy, sx, sy, sw, sh + sr->dy,
    245                 sx, sy + sh + sr->dy, sw, -sr->dy);
    246 
    247             _ewk_view_4b_move_region_up
    248                 ((uint32_t*)pixels, -sr->dy, sx, sy, sw, sh, ow);
    249             evas_object_image_data_update_add
    250                 (sd->backing_store, sx, sy, sw, sh + sr->dy);
    251 
    252             ewk_view_repaint_add(sd->_priv, sx, sy + sh + sr->dy, sw, -sr->dy);
    253         } else if (sr->dy > 0) {
    254             DBG("scroll down: %+03d,%+03d update=%d,%d+%dx%d, "
    255                 "repaint=%d,%d+%dx%d",
    256                 sr->dx, sr->dy, sx, sy + sr->dy, sw, sh - sr->dy,
    257                 sx, sy, sw, sr->dy);
    258 
    259             _ewk_view_4b_move_region_down
    260                 ((uint32_t*)pixels, sr->dy, sx, sy, sw, sh, ow);
    261             evas_object_image_data_update_add
    262                 (sd->backing_store, sx, sy + sr->dy, sw, sh - sr->dy);
    263 
    264             ewk_view_repaint_add(sd->_priv, sx, sy, sw, sr->dy);
    265         }
    266     } else if (!sr->dy) {
    267         if (sr->dx < 0) {
    268             DBG("scroll left: %+03d,%+03d update=%d,%d+%dx%d, "
    269                 "repaint=%d,%d+%dx%d",
    270                 sr->dx, sr->dy, sx, sy, sw + sr->dx, sh,
    271                 sx + sw + sr->dx, sy, -sr->dx, sh);
    272 
    273             _ewk_view_4b_move_region_left
    274                 ((uint32_t*)pixels, -sr->dx, sx, sy, sw, sh, ow);
    275             evas_object_image_data_update_add
    276                 (sd->backing_store, sx, sy, sw + sr->dx, sh);
    277 
    278             ewk_view_repaint_add(sd->_priv, sx + sw + sr->dx, sy, -sr->dx, sh);
    279         } else if (sr->dx > 0) {
    280             DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
    281                 "repaint=%d,%d+%dx%d",
    282                 sr->dx, sr->dy, sx + sr->dx, sy, sw - sr->dx, sh,
    283                 sx, sy, sr->dx, sh);
    284 
    285             _ewk_view_4b_move_region_right
    286                 ((uint32_t*)pixels, sr->dx, sx, sy, sw, sh, ow);
    287             evas_object_image_data_update_add
    288                 (sd->backing_store, sx + sr->dx, sy, sw - sr->dx, sh);
    289 
    290             ewk_view_repaint_add(sd->_priv, sx, sy, sr->dx, sh);
    291         }
    292     } else {
    293         Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh;
    294 
    295         if (sr->dx < 0) {
    296             mx = sx;
    297             mw = sw + sr->dx;
    298             ax = mx + mw;
    299             aw = -sr->dx;
    300         } else {
    301             ax = sx;
    302             aw = sr->dx;
    303             mx = ax + aw;
    304             mw = sw - sr->dx;
    305         }
    306 
    307         if (sr->dy < 0) {
    308             my = sy;
    309             mh = sh + sr->dy;
    310             by = my + mh;
    311             bh = -sr->dy;
    312         } else {
    313             by = sy;
    314             bh = sr->dy;
    315             my = by + bh;
    316             mh = sh - sr->dy;
    317         }
    318 
    319         ay = my;
    320         ah = mh;
    321         bx = sx;
    322         bw = sw;
    323 
    324         DBG("scroll diagonal: %+03d,%+03d update=%d,%d+%dx%d, "
    325             "repaints: h=%d,%d+%dx%d v=%d,%d+%dx%d",
    326             sr->dx, sr->dy, mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh);
    327 
    328         _ewk_view_4b_move_region
    329             ((uint32_t*)pixels, sr->dx, sr->dy, sx, sy, sw, sh, ow);
    330 
    331         evas_object_image_data_update_add(sd->backing_store, mx, my, mw, mh);
    332         ewk_view_repaint_add(sd->_priv, ax, ay, aw, ah);
    333         ewk_view_repaint_add(sd->_priv, bx, by, bw, bh);
    334     }
    335 }
    336 
    337 static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data *sd)
    338 {
    339     const Ewk_Scroll_Request *sr;
    340     const Ewk_Scroll_Request *sr_end;
    341     Evas_Coord ow, oh;
    342     size_t count;
    343     void *pixels = evas_object_image_data_get(sd->backing_store, 1);
    344     evas_object_image_size_get(sd->backing_store, &ow, &oh);
    345 
    346     sr = ewk_view_scroll_requests_get(sd->_priv, &count);
    347     sr_end = sr + count;
    348     for (; sr < sr_end; sr++)
    349         _ewk_view_single_scroll_process_single(sd, pixels, ow, oh, sr);
    350 
    351     evas_object_image_data_set(sd->backing_store, pixels);
    352 
    353     return EINA_TRUE;
    354 }
    355 
    356 static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd)
    357 {
    358     Ewk_View_Paint_Context *ctxt;
    359     Evas_Coord ow, oh;
    360     void *pixels;
    361     Eina_Rectangle *r;
    362     const Eina_Rectangle *pr;
    363     const Eina_Rectangle *pr_end;
    364     Eina_Tiler *tiler;
    365     Eina_Iterator *itr;
    366     cairo_status_t status;
    367     cairo_surface_t *surface;
    368     cairo_format_t format;
    369     cairo_t *cairo;
    370     size_t count;
    371     Eina_Bool ret = EINA_TRUE;
    372 
    373     if (sd->animated_zoom.zoom.current < 0.00001) {
    374         Evas_Object *clip = evas_object_clip_get(sd->backing_store);
    375         Evas_Coord w, h, cw, ch;
    376         // reset effects of zoom_weak_set()
    377         evas_object_image_fill_set
    378             (sd->backing_store, 0, 0, sd->view.w, sd->view.h);
    379         evas_object_move(clip, sd->view.x, sd->view.y);
    380 
    381         w = sd->view.w;
    382         h = sd->view.h;
    383 
    384         ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
    385         if (w > cw)
    386             w = cw;
    387         if (h > ch)
    388             h = ch;
    389         evas_object_resize(clip, w, h);
    390     }
    391 
    392     pixels = evas_object_image_data_get(sd->backing_store, 1);
    393     evas_object_image_size_get(sd->backing_store, &ow, &oh);
    394 
    395     if (sd->bg_color.a < 255)
    396         format = CAIRO_FORMAT_ARGB32;
    397     else
    398         format = CAIRO_FORMAT_RGB24;
    399 
    400     surface = cairo_image_surface_create_for_data
    401         ((unsigned char*)pixels, format, ow, oh, ow * 4);
    402     status = cairo_surface_status(surface);
    403     if (status != CAIRO_STATUS_SUCCESS) {
    404         ERR("could not create surface from data %dx%d: %s",
    405             ow, oh, cairo_status_to_string(status));
    406         ret = EINA_FALSE;
    407         goto error_cairo_surface;
    408     }
    409     cairo = cairo_create(surface);
    410     status = cairo_status(cairo);
    411     if (status != CAIRO_STATUS_SUCCESS) {
    412         ERR("could not create cairo from surface %dx%d: %s",
    413             ow, oh, cairo_status_to_string(status));
    414         ret = EINA_FALSE;
    415         goto error_cairo;
    416     }
    417 
    418     ctxt = ewk_view_paint_context_new(sd->_priv, cairo);
    419     if (!ctxt) {
    420         ERR("could not create paint context");
    421         ret = EINA_FALSE;
    422         goto error_paint_context;
    423     }
    424 
    425     tiler = eina_tiler_new(ow, oh);
    426     if (!tiler) {
    427         ERR("could not create tiler %dx%d", ow, oh);
    428         ret = EINA_FALSE;
    429         goto error_tiler;
    430     }
    431 
    432     pr = ewk_view_repaints_get(sd->_priv, &count);
    433     pr_end = pr + count;
    434     for (; pr < pr_end; pr++)
    435         eina_tiler_rect_add(tiler, pr);
    436 
    437     itr = eina_tiler_iterator_new(tiler);
    438     if (!itr) {
    439         ERR("could not get iterator for tiler");
    440         ret = EINA_FALSE;
    441         goto error_iterator;
    442     }
    443 
    444     int sx, sy;
    445     ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy);
    446 
    447     EINA_ITERATOR_FOREACH(itr, r) {
    448         Eina_Rectangle scrolled_rect = {
    449             r->x + sx, r->y + sy,
    450             r->w, r->h
    451         };
    452 
    453         ewk_view_paint_context_save(ctxt);
    454 
    455         if ((sx) || (sy))
    456             ewk_view_paint_context_translate(ctxt, -sx, -sy);
    457 
    458         ewk_view_paint_context_clip(ctxt, &scrolled_rect);
    459         ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);
    460 
    461         ewk_view_paint_context_restore(ctxt);
    462         evas_object_image_data_update_add
    463             (sd->backing_store, r->x, r->y, r->w, r->h);
    464     }
    465     eina_iterator_free(itr);
    466 
    467 error_iterator:
    468     eina_tiler_free(tiler);
    469 error_tiler:
    470     ewk_view_paint_context_free(ctxt);
    471 error_paint_context:
    472     cairo_destroy(cairo);
    473 error_cairo:
    474     cairo_surface_destroy(surface);
    475 error_cairo_surface:
    476     evas_object_image_data_set(sd->backing_store, pixels); /* dec refcount */
    477 
    478     return ret;
    479 }
    480 
    481 static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy)
    482 {
    483     // TODO: review
    484     float scale = zoom / sd->animated_zoom.zoom.start;
    485     Evas_Coord w = sd->view.w * scale;
    486     Evas_Coord h = sd->view.h * scale;
    487     Evas_Coord dx, dy, cw, ch;
    488     Evas_Object *clip = evas_object_clip_get(sd->backing_store);
    489 
    490     ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
    491     if (sd->view.w > 0 && sd->view.h > 0) {
    492         dx = (w * (sd->view.w - cx)) / sd->view.w;
    493         dy = (h * (sd->view.h - cy)) / sd->view.h;
    494     } else {
    495         dx = 0;
    496         dy = 0;
    497     }
    498 
    499     evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h);
    500 
    501     if (sd->view.w > 0 && sd->view.h > 0) {
    502         dx = ((sd->view.w - w) * cx) / sd->view.w;
    503         dy = ((sd->view.h - h) * cy) / sd->view.h;
    504     } else {
    505         dx = 0;
    506         dy = 0;
    507     }
    508     evas_object_move(clip, sd->view.x + dx, sd->view.y + dy);
    509 
    510     if (cw < sd->view.w)
    511         w = cw * scale;
    512     if (ch < sd->view.h)
    513         h = ch * scale;
    514     evas_object_resize(clip, w, h);
    515     return EINA_TRUE;
    516 }
    517 
    518 static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale)
    519 {
    520     evas_object_image_smooth_scale_set(sd->backing_store, smooth_scale);
    521 }
    522 
    523 static void _ewk_view_single_smart_bg_color_set(Ewk_View_Smart_Data *sd, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
    524 {
    525     evas_object_image_alpha_set(sd->backing_store, a < 255);
    526 }
    527 
    528 /**
    529  * Sets the smart class api using single backing store, enabling view
    530  * to be inherited.
    531  *
    532  * @param api class definition to be set, all members with the
    533  *        exception of Evas_Smart_Class->data may be overridden. Must
    534  *        @b not be @c NULL.
    535  *
    536  * @note Evas_Smart_Class->data is used to implement type checking and
    537  *       is not supposed to be changed/overridden. If you need extra
    538  *       data for your smart class to work, just extend
    539  *       Ewk_View_Smart_Class instead.
    540  *
    541  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (probably
    542  *         version mismatch).
    543  *
    544  * @see ewk_view_base_smart_set()
    545  */
    546 Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api)
    547 {
    548     if (!ewk_view_base_smart_set(api))
    549         return EINA_FALSE;
    550 
    551     if (EINA_UNLIKELY(!_parent_sc.sc.add))
    552         ewk_view_base_smart_set(&_parent_sc);
    553 
    554     api->sc.add = _ewk_view_single_smart_add;
    555     api->sc.resize = _ewk_view_single_smart_resize;
    556 
    557     api->backing_store_add = _ewk_view_single_smart_backing_store_add;
    558     api->scrolls_process = _ewk_view_single_smart_scrolls_process;
    559     api->repaints_process = _ewk_view_single_smart_repaints_process;
    560     api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set;
    561     api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set;
    562     api->bg_color_set = _ewk_view_single_smart_bg_color_set;
    563 
    564     return EINA_TRUE;
    565 }
    566 
    567 static inline Evas_Smart *_ewk_view_single_smart_class_new(void)
    568 {
    569     static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single");
    570     static Evas_Smart *smart = 0;
    571 
    572     if (EINA_UNLIKELY(!smart)) {
    573         ewk_view_single_smart_set(&api);
    574         smart = evas_smart_class_new(&api.sc);
    575     }
    576 
    577     return smart;
    578 }
    579 
    580 /**
    581  * Creates a new EFL WebKit View object.
    582  *
    583  * View objects are the recommended way to deal with EFL WebKit as it
    584  * abstracts the complex pieces of the process.
    585  *
    586  * Each view is composed by a set of frames. The set has at least one
    587  * frame, called 'main_frame'. See ewk_view_frame_main_get() and
    588  * ewk_view_frame_focused_get().
    589  *
    590  * @param e canvas where to create the view object.
    591  *
    592  * @return view object or @c NULL if errors.
    593  *
    594  * @see ewk_view_uri_set()
    595  */
    596 Evas_Object *ewk_view_single_add(Evas *e)
    597 {
    598     return evas_object_smart_add(e, _ewk_view_single_smart_class_new());
    599 }
    600