コード例 #1
0
static void invalidateView(Evas_Object* webView)
{
    Evas_Coord width, height;
    Evas_Object* mainFrame = ewk_view_frame_main_get(webView);
    if (mainFrame && ewk_frame_contents_size_get(mainFrame, &width, &height)) {
        WebCore::Page* page = EWKPrivate::corePage(webView);
        if (page)
            page->mainFrame()->view()->invalidateRect(WebCore::IntRect(0, 0, width, height));
    }
}
コード例 #2
0
static Eina_Bool _ewk_view_tiled_smart_scrolls_process(Ewk_View_Smart_Data* smartData)
{
    const Ewk_Scroll_Request* scrollRequest;
    const Ewk_Scroll_Request* endOfScrollRequest;
    size_t count;
    Evas_Coord contentsWidth, contentsHeight;

    ewk_frame_contents_size_get(smartData->main_frame, &contentsWidth, &contentsHeight);

    scrollRequest = ewk_view_scroll_requests_get(smartData->_priv, &count);
    endOfScrollRequest = scrollRequest + count;
    for (; scrollRequest < endOfScrollRequest; scrollRequest++) {
        if (scrollRequest->main_scroll)
            ewk_tiled_backing_store_scroll_full_offset_add
                (smartData->backing_store, scrollRequest->dx, scrollRequest->dy);
        else {
            Evas_Coord scrollX, scrollY, scrollWidth, scrollHeight;

            scrollX = scrollRequest->x;
            scrollY = scrollRequest->y;
            scrollWidth = scrollRequest->w;
            scrollHeight = scrollRequest->h;

            if (abs(scrollRequest->dx) >= scrollWidth || abs(scrollRequest->dy) >= scrollHeight) {
                /* doubt webkit would be so     stupid... */
                DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
                    scrollRequest->dx, scrollRequest->dy, scrollX, scrollY, scrollWidth, scrollHeight);
                ewk_view_repaint_add(smartData->_priv, scrollX, scrollY, scrollWidth, scrollHeight);
                continue;
            }

            if (scrollX + scrollWidth > contentsWidth)
                scrollWidth = contentsWidth - scrollX;
            if (scrollY + scrollHeight > contentsHeight)
                scrollHeight = contentsHeight - scrollY;

            if (scrollWidth < 0)
                scrollWidth = 0;
            if (scrollHeight < 0)
                scrollHeight = 0;

            if (!scrollWidth || !scrollHeight)
                continue;

            scrollX -= abs(scrollRequest->dx);
            scrollY -= abs(scrollRequest->dy);
            scrollWidth += abs(scrollRequest->dx);
            scrollHeight += abs(scrollRequest->dy);
            ewk_view_repaint_add(smartData->_priv, scrollX, scrollY, scrollWidth, scrollHeight);
            INF("using repaint for inner frame scolling!");
        }
    }

    return true;
}
コード例 #3
0
static Eina_Bool _ewk_view_tiled_smart_scrolls_process(Ewk_View_Smart_Data *sd)
{
    const Ewk_Scroll_Request *sr;
    const Ewk_Scroll_Request *sr_end;
    size_t count;
    Evas_Coord vw, vh;

    ewk_frame_contents_size_get(sd->main_frame, &vw, &vh);

    sr = ewk_view_scroll_requests_get(sd->_priv, &count);
    sr_end = sr + count;
    for (; sr < sr_end; sr++) {
        if (sr->main_scroll)
            ewk_tiled_backing_store_scroll_full_offset_add
                (sd->backing_store, sr->dx, sr->dy);
        else {
            Evas_Coord sx, sy, sw, sh;

            sx = sr->x;
            sy = sr->y;
            sw = sr->w;
            sh = sr->h;

            if (abs(sr->dx) >= sw || abs(sr->dy) >= sh) {
                /* doubt webkit would be so     stupid... */
                DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
                    sr->dx, sr->dy, sx, sy, sw, sh);
                ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh);
                continue;
            }

            if (sx + sw > vw)
                sw = vw - sx;
            if (sy + sh > vh)
                sh = vh - sy;

            if (sw < 0)
                sw = 0;
            if (sh < 0)
                sh = 0;

            if (!sw || !sh)
                continue;

            sx -= abs(sr->dx);
            sy -= abs(sr->dy);
            sw += abs(sr->dx);
            sh += abs(sr->dy);
            ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh);
            INF("using repaint for inner frame scolling!");
        }
    }

    return EINA_TRUE;
}
コード例 #4
0
static Eina_Bool _ewk_view_tiled_smart_scrolls_process(Ewk_View_Smart_Data* smartData)
{
    const Ewk_Scroll_Request* scrollRequest;
    const Ewk_Scroll_Request* endOfScrollRequest;
    size_t count;
    Evas_Coord contentsWidth, contentsHeight;

    ewk_frame_contents_size_get(smartData->main_frame, &contentsWidth, &contentsHeight);

    scrollRequest = ewk_view_scroll_requests_get(smartData->_priv, &count);
    endOfScrollRequest = scrollRequest + count;
    for (; scrollRequest < endOfScrollRequest; scrollRequest++)
        ewk_tiled_backing_store_scroll_full_offset_add(smartData->backing_store, scrollRequest->dx, scrollRequest->dy);

    return true;
}
コード例 #5
0
static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
    Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o);
    _parent_sc.sc.resize(o, w, h);

    // these should be queued and processed in calculate as well!
    evas_object_image_size_set(sd->backing_store, w, h);
    if (sd->animated_zoom.zoom.current < 0.00001) {
        Evas_Object *clip = evas_object_clip_get(sd->backing_store);
        Evas_Coord x, y, cw, ch;
        evas_object_image_fill_set(sd->backing_store, 0, 0, w, h);
        evas_object_geometry_get(sd->backing_store, &x, &y, 0, 0);
        evas_object_move(clip, x, y);
        ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
        if (w > cw)
            w = cw;
        if (h > ch)
            h = ch;
        evas_object_resize(clip, w, h);
    }
}
コード例 #6
0
static void _ewk_view_single_smart_resize(Evas_Object* ewkView, Evas_Coord width, Evas_Coord height)
{
    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkView));
    _parent_sc.sc.resize(ewkView, width, height);

    if (!smartData)
        return;

    // these should be queued and processed in calculate as well!
    evas_object_image_size_set(smartData->backing_store, width, height);
    if (smartData->animated_zoom.zoom.current < 0.00001) {
        Evas_Object* clip = evas_object_clip_get(smartData->backing_store);
        Evas_Coord x, y, cw, ch;
        evas_object_image_fill_set(smartData->backing_store, 0, 0, width, height);
        evas_object_geometry_get(smartData->backing_store, &x, &y, 0, 0);
        evas_object_move(clip, x, y);
        ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch);
        if (width > cw)
            width = cw;
        if (height > ch)
            height = ch;
        evas_object_resize(clip, width, height);
    }
}
コード例 #7
0
static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy)
{
    // TODO: review
    float scale = zoom / sd->animated_zoom.zoom.start;
    Evas_Coord w = sd->view.w * scale;
    Evas_Coord h = sd->view.h * scale;
    Evas_Coord dx, dy, cw, ch;
    Evas_Object *clip = evas_object_clip_get(sd->backing_store);

    ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
    if (sd->view.w > 0 && sd->view.h > 0) {
        dx = (w * (sd->view.w - cx)) / sd->view.w;
        dy = (h * (sd->view.h - cy)) / sd->view.h;
    } else {
        dx = 0;
        dy = 0;
    }

    evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h);

    if (sd->view.w > 0 && sd->view.h > 0) {
        dx = ((sd->view.w - w) * cx) / sd->view.w;
        dy = ((sd->view.h - h) * cy) / sd->view.h;
    } else {
        dx = 0;
        dy = 0;
    }
    evas_object_move(clip, sd->view.x + dx, sd->view.y + dy);

    if (cw < sd->view.w)
        w = cw * scale;
    if (ch < sd->view.h)
        h = ch * scale;
    evas_object_resize(clip, w, h);
    return EINA_TRUE;
}
コード例 #8
0
static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data* smartData)
{
    if (smartData->animated_zoom.zoom.current < 0.00001) {
        Evas_Object* clip = evas_object_clip_get(smartData->backing_store);

        // reset effects of zoom_weak_set()
        evas_object_image_fill_set(smartData->backing_store, 0, 0, smartData->view.w, smartData->view.h);
        evas_object_move(clip, smartData->view.x, smartData->view.y);

        Evas_Coord width = smartData->view.w;
        Evas_Coord height = smartData->view.h;

        Evas_Coord centerWidth, centerHeight;
        ewk_frame_contents_size_get(smartData->main_frame, &centerWidth, &centerHeight);
        if (width > centerWidth)
            width = centerWidth;

        if (height > centerHeight)
            height = centerHeight;

        evas_object_resize(clip, width, height);
    }

    Evas_Coord imageWidth, imageHeight;
    evas_object_image_size_get(smartData->backing_store, &imageWidth, &imageHeight);

    Eina_Tiler* tiler = eina_tiler_new(imageWidth, imageHeight);
    if (!tiler) {
        ERR("could not create tiler %dx%d", imageWidth, imageHeight);
        return false;
    }

    ewk_view_layout_if_needed_recursive(smartData->_priv);

    size_t count;
    const Eina_Rectangle* paintRequest = ewk_view_repaints_pop(smartData->_priv, &count);
    const Eina_Rectangle* paintRequestEnd = paintRequest + count;
    for (; paintRequest < paintRequestEnd; paintRequest++)
        eina_tiler_rect_add(tiler, paintRequest);

    Eina_Iterator* iterator = eina_tiler_iterator_new(tiler);
    if (!iterator) {
        ERR("could not get iterator for tiler");
        eina_tiler_free(tiler);
        return false;
    }

#if USE(TILED_BACKING_STORE)
    WebCore::Frame* mainFrame = EWKPrivate::coreFrame(smartData->main_frame);
    if (mainFrame && mainFrame->tiledBackingStore())
        mainFrame->tiledBackingStore()->coverWithTilesIfNeeded();
#endif

    Ewk_Paint_Context* context = ewk_paint_context_from_image_new(smartData->backing_store);
    ewk_paint_context_save(context);

    Eina_Rectangle* rect;
    EINA_ITERATOR_FOREACH(iterator, rect) {
        ewk_view_paint(smartData->_priv, context, rect);
        evas_object_image_data_update_add(smartData->backing_store, rect->x, rect->y, rect->w, rect->h);
    }
コード例 #9
0
/* calculates one good zoom level to fit given hit test result */
static float
_view_zoom_fits_hit(View_Smart_Data *sd, const Ewk_Hit_Test *hit_test)
{
   Evas_Coord x, y; /* hit test point */
   Evas_Coord bx, by, bw, bh, bw1, bw2, bh1, bh2; /* bounding box */
   Evas_Coord vx, vy, vw, vh, vw1, vw2, vh1, vh2; /* visible content */
   Evas_Coord cw, ch;
   float zx, zy, z, old_zoom, zx1, zx2, zy1, zy2;

   if (!hit_test)
      return 0.0;

   old_zoom = ewk_frame_page_zoom_get(sd->base.main_frame);

   /* save some typing */
   x = hit_test->x;
   y = hit_test->y;

   bx = hit_test->bounding_box.x;
   by = hit_test->bounding_box.y;
   bw = hit_test->bounding_box.w;
   bh = hit_test->bounding_box.h;

   if ((bw <= 0) || (bh <= 0))
      return 0.0;

   ewk_frame_visible_content_geometry_get
      (sd->base.main_frame, EINA_FALSE, &vx, &vy, &vw, &vh);
   if ((vw <= 0) || (vh <= 0))
      return 0.0;

   ewk_frame_contents_size_get(sd->base.main_frame, &cw, &ch);
   if ((cw <= 0) || (ch <= 0))
      return 0.0;

   /* split width of left and right parts from hit test position */
   bw1 = x - bx;
   bw2 = bw - bw1;

   /* split height of top and bottom parts from hit test position */
   bh1 = y - by;
   bh2 = bh - bh1;

   /* split size of viewport as well. We'll use this as the available space */
   vw1 = x - vx;
   vw2 = vw - vw1;

   vh1 = y - vy;
   vh2 = vh - vh1;

   /* check if we can add padding around those sizes, "adding" if possible
    * (we actually subtract as adding a pad is removing available space)
    */
   if (vw1 > ZOOM_AUTO_PADDING)
      vw1 -= ZOOM_AUTO_PADDING;

   if (vw2 > ZOOM_AUTO_PADDING)
      vw2 -= ZOOM_AUTO_PADDING;

   if (vh1 > ZOOM_AUTO_PADDING)
      vh1 -= ZOOM_AUTO_PADDING;

   if (vh2 > ZOOM_AUTO_PADDING)
      vh2 -= ZOOM_AUTO_PADDING;

   /* check individual zoom to fit each part */
   zx1 = (bw1 > 0) ? (vw1 / (float)bw1) : 0.0;
   zx2 = (bw2 > 0) ? (vw2 / (float)bw2) : 0.0;

   zy1 = (bh1 > 0) ? (vh1 / (float)bh1) : 0.0;
   zy2 = (bh2 > 0) ? (vh2 / (float)bh2) : 0.0;

   if ((zx1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zx2 >= ZOOM_AUTO_MIN_DIFFERENCE))
      zx = (zx1 < zx2) ? zx1 : zx2;
   else if (zx1 >= ZOOM_AUTO_MIN_DIFFERENCE)
      zx = zx1;
   else
      zx = zx2;

   if ((zy1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy2 >= ZOOM_AUTO_MIN_DIFFERENCE))
      zy = (zy1 < zy2) ? zy1 : zy2;
   else if (zy1 >= ZOOM_AUTO_MIN_DIFFERENCE)
      zy = zy1;
   else
      zy = zy2;

   if ((zx >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy >= ZOOM_AUTO_MIN_DIFFERENCE))
      z = (zx < zy) ? zx : zy;
   else if (zx >= ZOOM_AUTO_MIN_DIFFERENCE)
      z = zx;
   else
      z = zy;

   /* zoom will make contents be smaller than viewport, limit it */
   if (((int)(z * old_zoom * cw) < vw) || ((int)(z * old_zoom * ch) < vh))
     {
        float ac = cw / (float)ch;
        float av = vw / (float)vh;

        if (ac < av)
           z = vw / (float)cw;
        else
           z = vh / (float)ch;
     }

#if 0
   /* debug */
   printf(">>> fit: center=%3d,%3d   box=%3d,%3d+%3dx%3d\n"
          "    x:  %3d = %3d + %3d,  %3d = %3d + %3d,  %2.4f  %2.4f  -> %2.4f\n"
          "    y:  %3d = %3d + %3d,  %3d = %3d + %3d,  %2.4f  %2.4f  -> %2.4f\n"
          "    final: %2.4f   %2.4f (old=%0.3f, difference=%0.3f)\n"
          "    contents: %4dx%4d  -> %4dx%4d\n"
          "\n",
          x, y, bx, by, bw, bh,
          bw, bw1, bw2, vw, vw1, vw2, zx1, zx2, zx,
          bh, bh1, bh2, vh, vh1, vh2, zy1, zy2, zy,
          z, old_zoom * z, old_zoom, fabs(old_zoom - z),
          cw, ch, (int)(z * old_zoom * cw), (int)(z * old_zoom * ch));
#endif

   z *= old_zoom;

   if (z < ZOOM_AUTO_MIN)
      z = ZOOM_AUTO_MIN;
   else if (z > ZOOM_AUTO_MAX)
      z = ZOOM_AUTO_MAX;

   if (fabs(old_zoom - z) < ZOOM_AUTO_MIN_DIFFERENCE)
      return 0.0;

   return z;
}
コード例 #10
0
static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd)
{
    Ewk_View_Paint_Context *ctxt;
    Evas_Coord ow, oh;
    void *pixels;
    Eina_Rectangle r = {0, 0, 0, 0};
    const Eina_Rectangle *pr;
    const Eina_Rectangle *pr_end;
    Eina_Tiler *tiler;
    Eina_Iterator *itr;
    cairo_status_t status;
    cairo_surface_t *surface;
    cairo_format_t format;
    cairo_t *cairo;
    size_t count;
    Eina_Bool ret = EINA_TRUE;

    if (sd->animated_zoom.zoom.current < 0.00001) {
        Evas_Object *clip = evas_object_clip_get(sd->backing_store);
        Evas_Coord w, h, cw, ch;
        // reset effects of zoom_weak_set()
        evas_object_image_fill_set
            (sd->backing_store, 0, 0, sd->view.w, sd->view.h);
        evas_object_move(clip, sd->view.x, sd->view.y);

        w = sd->view.w;
        h = sd->view.h;

        ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
        if (w > cw)
            w = cw;
        if (h > ch)
            h = ch;
        evas_object_resize(clip, w, h);
    }

    pixels = evas_object_image_data_get(sd->backing_store, 1);
    evas_object_image_size_get(sd->backing_store, &ow, &oh);

    if (sd->bg_color.a < 255)
        format = CAIRO_FORMAT_ARGB32;
    else
        format = CAIRO_FORMAT_RGB24;

    surface = cairo_image_surface_create_for_data
        ((unsigned char*)pixels, format, ow, oh, ow * 4);
    status = cairo_surface_status(surface);
    if (status != CAIRO_STATUS_SUCCESS) {
        ERR("could not create surface from data %dx%d: %s",
            ow, oh, cairo_status_to_string(status));
        ret = EINA_FALSE;
        goto error_cairo_surface;
    }
    cairo = cairo_create(surface);
    status = cairo_status(cairo);
    if (status != CAIRO_STATUS_SUCCESS) {
        ERR("could not create cairo from surface %dx%d: %s",
            ow, oh, cairo_status_to_string(status));
        ret = EINA_FALSE;
        goto error_cairo;
    }

    ctxt = ewk_view_paint_context_new(sd->_priv, cairo);
    if (!ctxt) {
        ERR("could not create paint context");
        ret = EINA_FALSE;
        goto error_paint_context;
    }

    tiler = eina_tiler_new(ow, oh);
    if (!tiler) {
        ERR("could not create tiler %dx%d", ow, oh);
        ret = EINA_FALSE;
        goto error_tiler;
    }

    pr = ewk_view_repaints_get(sd->_priv, &count);
    pr_end = pr + count;
    for (; pr < pr_end; pr++)
        eina_tiler_rect_add(tiler, pr);

    itr = eina_tiler_iterator_new(tiler);
    if (!itr) {
        ERR("could not get iterator for tiler");
        ret = EINA_FALSE;
        goto error_iterator;
    }

    int sx, sy;
    ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy);

    EINA_ITERATOR_FOREACH(itr, r) {
        Eina_Rectangle scrolled_rect = {
            r.x + sx, r.y + sy,
            r.w, r.h
        };

        ewk_view_paint_context_save(ctxt);

        if ((sx) || (sy))
            ewk_view_paint_context_translate(ctxt, -sx, -sy);

        ewk_view_paint_context_clip(ctxt, &scrolled_rect);
        ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);

        ewk_view_paint_context_restore(ctxt);
        evas_object_image_data_update_add
            (sd->backing_store, r.x, r.y, r.w, r.h);
    }
コード例 #11
0
static Eina_Bool _ewk_view_tiled_smart_pre_render_start(Ewk_View_Smart_Data* smartData)
{
    int contentWidth, contentHeight;
    ewk_frame_contents_size_get(smartData->main_frame, &contentWidth, &contentHeight);

    int viewX, viewY, viewWidth, viewHeight;
    ewk_frame_visible_content_geometry_get(smartData->main_frame, false, &viewX, &viewY, &viewWidth, &viewHeight);

    if (viewWidth <= 0 || viewHeight <= 0 || contentWidth <= 0 || contentHeight <= 0)
        return false;

    if (viewWidth >= contentWidth && viewHeight >= contentHeight)
        return false;

    int previousViewX, previousViewY;
    previousViewX = smartData->previousView.x;
    previousViewY = smartData->previousView.y;

    if (previousViewX < 0 || previousViewX > contentWidth || previousViewY < 0 || previousViewY > contentHeight)
        previousViewX = previousViewY = 0;

    float currentViewZoom = ewk_view_zoom_get(smartData->self);

    // pre-render works when two conditions are met.
    // zoom has been changed.
    // and the view has been moved more than tile size.
    if (abs(previousViewX - viewX) < defaultTileWidth
        && abs(previousViewY - viewY) < defaultTileHeigth
        && smartData->previousView.zoom == currentViewZoom) {
        return false;
    }

    // store previous view position and zoom.
    smartData->previousView.x = viewX;
    smartData->previousView.y = viewY;
    smartData->previousView.zoom = currentViewZoom;

    // cancelling previous pre-rendering list if exists.
    ewk_view_pre_render_cancel(smartData->self);

    Ewk_Tile_Unused_Cache* tileUnusedCache = ewk_view_tiled_unused_cache_get(smartData->self);
    int maxMemory = ewk_tile_unused_cache_max_get(tileUnusedCache);
    if (maxMemory <= viewWidth * viewHeight * EWK_ARGB_BYTES_SIZE)
        return false;

    Eina_Rectangle viewRect = {viewX, viewY, viewWidth, viewHeight};
    Eina_Rectangle contentRect = {0, 0, contentWidth, contentHeight};

    // get a base render rect.
    const int contentMemory = contentWidth * contentHeight * EWK_ARGB_BYTES_SIZE;

    // get render rect's width and height.
    Eina_Rectangle renderRect;
    if (maxMemory > contentMemory)
        renderRect = contentRect;
    else {
        // Make a base rectangle as big as possible with using maxMemory.
        // and then reshape the base rectangle to fit to contents.
        const int baseSize = static_cast<int>(sqrt(maxMemory / 4.0f));
        const float widthRate = (viewRect.w + (defaultTileWidth * 2)) / static_cast<float>(baseSize);
        const float heightRate = baseSize / static_cast<float>(contentHeight);
        const float rectRate = std::max(widthRate, heightRate);

        renderRect.w = static_cast<int>(baseSize * rectRate);
        renderRect.h = static_cast<int>(baseSize / rectRate);
        renderRect.x = viewRect.x + (viewRect.w / 2) - (renderRect.w / 2);
        renderRect.y = viewRect.y + (viewRect.h / 2) - (renderRect.h / 2);

        // reposition of renderRect, if the renderRect overlapped the content rect, this code moves the renderRect inside the content rect.
        int collisionSide = _ewk_view_tiled_rect_collision_check(renderRect, contentRect);
        if (collisionSide > 0)
            _ewk_view_tiled_rect_collision_resolve(collisionSide, &renderRect, contentRect);

        // check abnormal render rect
        if (renderRect.x < 0)
            renderRect.x = 0;
        if (renderRect.y < 0)
            renderRect.y = 0;
        if (renderRect.w > contentWidth)
            renderRect.w = contentWidth;
        if (renderRect.h > contentHeight)
            renderRect.h = contentHeight;
    }

    // enqueue tiles into tiled backing store in spiral order.
    ewk_tiled_backing_store_pre_render_spiral_queue(smartData->backing_store, &viewRect, &renderRect, maxMemory, currentViewZoom);

    return true;
}
コード例 #12
0
static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data* smartData)
{
    Ewk_View_Paint_Context* context;
    Evas_Coord ow, oh;
    void* pixels;
    Eina_Rectangle* rect;
    const Eina_Rectangle* pr;
    const Eina_Rectangle* pr_end;
    Eina_Tiler* tiler;
    Eina_Iterator* iterator;
    cairo_status_t status;
    cairo_surface_t* surface;
    cairo_format_t format;
    cairo_t* cairo;
    size_t count;
    Eina_Bool result = true;

    if (smartData->animated_zoom.zoom.current < 0.00001) {
        Evas_Object* clip = evas_object_clip_get(smartData->backing_store);
        Evas_Coord width, height, centerWidth, centerHeight;
        // reset effects of zoom_weak_set()
        evas_object_image_fill_set
            (smartData->backing_store, 0, 0, smartData->view.w, smartData->view.h);
        evas_object_move(clip, smartData->view.x, smartData->view.y);

        width = smartData->view.w;
        height = smartData->view.h;

        ewk_frame_contents_size_get(smartData->main_frame, &centerWidth, &centerHeight);
        if (width > centerWidth)
            width = centerWidth;
        if (height > centerHeight)
            height = centerHeight;
        evas_object_resize(clip, width, height);
    }

    pixels = evas_object_image_data_get(smartData->backing_store, 1);
    evas_object_image_size_get(smartData->backing_store, &ow, &oh);
    format = CAIRO_FORMAT_ARGB32;

    surface = cairo_image_surface_create_for_data
                  (static_cast<unsigned char*>(pixels), format, ow, oh, ow * 4);
    status = cairo_surface_status(surface);
    if (status != CAIRO_STATUS_SUCCESS) {
        ERR("could not create surface from data %dx%d: %s",
            ow, oh, cairo_status_to_string(status));
        result = false;
        goto error_cairo_surface;
    }
    cairo = cairo_create(surface);
    status = cairo_status(cairo);
    if (status != CAIRO_STATUS_SUCCESS) {
        ERR("could not create cairo from surface %dx%d: %s",
            ow, oh, cairo_status_to_string(status));
        result = false;
        goto error_cairo;
    }

    context = ewk_view_paint_context_new(smartData->_priv, cairo);
    if (!context) {
        ERR("could not create paint context");
        result = false;
        goto error_paint_context;
    }

    tiler = eina_tiler_new(ow, oh);
    if (!tiler) {
        ERR("could not create tiler %dx%d", ow, oh);
        result = false;
        goto error_tiler;
    }

    ewk_view_layout_if_needed_recursive(smartData->_priv);

    pr = ewk_view_repaints_pop(smartData->_priv, &count);
    pr_end = pr + count;
    for (; pr < pr_end; pr++)
        eina_tiler_rect_add(tiler, pr);

    iterator = eina_tiler_iterator_new(tiler);
    if (!iterator) {
        ERR("could not get iterator for tiler");
        result = false;
        goto error_iterator;
    }

    int scrollX, scrollY;
    ewk_frame_scroll_pos_get(smartData->main_frame, &scrollX, &scrollY);

    EINA_ITERATOR_FOREACH(iterator, rect) {
        Eina_Rectangle scrolled_rect = {
            rect->x + scrollX, rect->y + scrollY,
            rect->w, rect->h
        };

        ewk_view_paint_context_save(context);

        if ((scrollX) || (scrollY))
            ewk_view_paint_context_translate(context, -scrollX, -scrollY);

        ewk_view_paint_context_clip(context, &scrolled_rect);
        ewk_view_paint_context_paint_contents(context, &scrolled_rect);

        ewk_view_paint_context_restore(context);
        evas_object_image_data_update_add
            (smartData->backing_store, rect->x, rect->y, rect->w, rect->h);
    }