2 Copyright (C) 2009-2010 ProFUSION embedded systems
3 Copyright (C) 2009-2010 Samsung Electronics
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.
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.
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.
24 #include "ewk_frame.h"
25 #include "ewk_logging.h"
26 #include "ewk_private.h"
29 #include <eina_safety_checks.h>
32 static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL;
34 static void _ewk_view_single_on_del(void *data, Evas *e, Evas_Object *o, void *event_info)
36 Evas_Object *clip = (Evas_Object*)data;
37 evas_object_del(clip);
40 static void _ewk_view_single_smart_add(Evas_Object *o)
42 Ewk_View_Smart_Data *sd;
46 sd = (Ewk_View_Smart_Data *)evas_object_smart_data_get(o);
50 Evas_Object *clip = evas_object_rectangle_add(sd->base.evas);
51 evas_object_clip_set(sd->backing_store, clip);
52 evas_object_smart_member_add(clip, o);
53 evas_object_show(clip);
55 evas_object_event_callback_add
56 (sd->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip);
59 static Evas_Object *_ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data *sd)
61 Evas_Object *bs = evas_object_image_add(sd->base.evas);
62 evas_object_image_alpha_set(bs, EINA_FALSE);
63 evas_object_image_smooth_scale_set(bs, sd->zoom_weak_smooth_scale);
68 static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
70 Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o);
71 _parent_sc.sc.resize(o, w, h);
76 // these should be queued and processed in calculate as well!
77 evas_object_image_size_set(sd->backing_store, w, h);
78 if (sd->animated_zoom.zoom.current < 0.00001) {
79 Evas_Object *clip = evas_object_clip_get(sd->backing_store);
80 Evas_Coord x, y, cw, ch;
81 evas_object_image_fill_set(sd->backing_store, 0, 0, w, h);
82 evas_object_geometry_get(sd->backing_store, &x, &y, 0, 0);
83 evas_object_move(clip, x, y);
84 ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
89 evas_object_resize(clip, w, h);
93 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)
98 dst = image + x + y * rowsize;
99 src = dst + rows * rowsize;
102 for (; h > 0; h--, dst += rowsize, src += rowsize)
103 memcpy(dst, src, w * 4);
106 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)
112 src = image + x + (y + h - 1) * rowsize;
113 dst = src + rows * rowsize;
115 for (; h > 0; h--, dst -= rowsize, src -= rowsize)
116 memcpy(dst, src, w * 4);
119 static inline void _ewk_view_4b_move_line_left(uint32_t *dst, const uint32_t *src, size_t count)
121 uint32_t *dst_end = dst + count;
122 /* no memcpy() as it does not allow overlapping regions */
123 /* no memmove() as it will copy to a temporary buffer */
124 /* TODO: loop unrolling, copying up to quad-words would help */
125 for (; dst < dst_end; dst++, src++)
129 static inline void _ewk_view_4b_move_line_right(uint32_t *dst, uint32_t *src, size_t count)
131 uint32_t *dst_end = dst - count;
132 /* no memcpy() as it does not allow overlapping regions */
133 /* no memmove() as it will copy to a temporary buffer */
134 /* TODO: loop unrolling, copying up to quad-words would help */
135 for (; dst > dst_end; dst--, src--)
139 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)
144 dst = image + x + y * rowsize;
148 for (; h > 0; h--, dst += rowsize, src += rowsize)
149 _ewk_view_4b_move_line_left(dst, src, w);
152 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)
158 src = image + (x + w - 1) + y * rowsize;
161 for (; h > 0; h--, dst += rowsize, src += rowsize)
162 _ewk_view_4b_move_line_right(dst, src, w);
165 /* catch-all function, not as optimized as the others, but does the work. */
166 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)
173 dst = image + x + y * rowsize;
174 src = dst - dy * rowsize;
178 for (; h > 0; h--, dst += rowsize, src += rowsize)
179 _ewk_view_4b_move_line_left(dst, src, w);
184 for (; h > 0; h--, dst += rowsize, src += rowsize)
185 _ewk_view_4b_move_line_right(dst, src, w);
189 src = image + x + (y + h - 1) * rowsize;
190 dst = src + dy * rowsize;
194 for (; h > 0; h--, dst -= rowsize, src -= rowsize)
195 _ewk_view_4b_move_line_left(dst, src, w);
200 for (; h > 0; h--, dst -= rowsize, src -= rowsize)
201 _ewk_view_4b_move_line_right(dst, src, w);
206 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)
208 Evas_Coord sx, sy, sw, sh;
210 DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d",
211 sr->x, sr->y, sr->w, sr->h, sr->dx, sr->dy, pixels, ow, oh);
218 if (abs(sr->dx) >= sw || abs(sr->dy) >= sh) {
219 /* doubt webkit would be so stupid... */
220 DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
221 sr->dx, sr->dy, sx, sy, sw, sh);
222 ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh);
245 EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh);
248 DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
249 "repaint=%d,%d+%dx%d",
250 sr->dx, sr->dy, sx, sy, sw, sh + sr->dy,
251 sx, sy + sh + sr->dy, sw, -sr->dy);
253 _ewk_view_4b_move_region_up
254 ((uint32_t*)pixels, -sr->dy, sx, sy, sw, sh, ow);
255 evas_object_image_data_update_add
256 (sd->backing_store, sx, sy, sw, sh + sr->dy);
258 ewk_view_repaint_add(sd->_priv, sx, sy + sh + sr->dy, sw, -sr->dy);
259 } else if (sr->dy > 0) {
260 DBG("scroll down: %+03d,%+03d update=%d,%d+%dx%d, "
261 "repaint=%d,%d+%dx%d",
262 sr->dx, sr->dy, sx, sy + sr->dy, sw, sh - sr->dy,
265 _ewk_view_4b_move_region_down
266 ((uint32_t*)pixels, sr->dy, sx, sy, sw, sh, ow);
267 evas_object_image_data_update_add
268 (sd->backing_store, sx, sy + sr->dy, sw, sh - sr->dy);
270 ewk_view_repaint_add(sd->_priv, sx, sy, sw, sr->dy);
272 } else if (!sr->dy) {
274 DBG("scroll left: %+03d,%+03d update=%d,%d+%dx%d, "
275 "repaint=%d,%d+%dx%d",
276 sr->dx, sr->dy, sx, sy, sw + sr->dx, sh,
277 sx + sw + sr->dx, sy, -sr->dx, sh);
279 _ewk_view_4b_move_region_left
280 ((uint32_t*)pixels, -sr->dx, sx, sy, sw, sh, ow);
281 evas_object_image_data_update_add
282 (sd->backing_store, sx, sy, sw + sr->dx, sh);
284 ewk_view_repaint_add(sd->_priv, sx + sw + sr->dx, sy, -sr->dx, sh);
285 } else if (sr->dx > 0) {
286 DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
287 "repaint=%d,%d+%dx%d",
288 sr->dx, sr->dy, sx + sr->dx, sy, sw - sr->dx, sh,
291 _ewk_view_4b_move_region_right
292 ((uint32_t*)pixels, sr->dx, sx, sy, sw, sh, ow);
293 evas_object_image_data_update_add
294 (sd->backing_store, sx + sr->dx, sy, sw - sr->dx, sh);
296 ewk_view_repaint_add(sd->_priv, sx, sy, sr->dx, sh);
299 Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh;
330 DBG("scroll diagonal: %+03d,%+03d update=%d,%d+%dx%d, "
331 "repaints: h=%d,%d+%dx%d v=%d,%d+%dx%d",
332 sr->dx, sr->dy, mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh);
334 _ewk_view_4b_move_region
335 ((uint32_t*)pixels, sr->dx, sr->dy, sx, sy, sw, sh, ow);
337 evas_object_image_data_update_add(sd->backing_store, mx, my, mw, mh);
338 ewk_view_repaint_add(sd->_priv, ax, ay, aw, ah);
339 ewk_view_repaint_add(sd->_priv, bx, by, bw, bh);
343 static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data *sd)
345 const Ewk_Scroll_Request *sr;
346 const Ewk_Scroll_Request *sr_end;
349 void *pixels = evas_object_image_data_get(sd->backing_store, 1);
350 evas_object_image_size_get(sd->backing_store, &ow, &oh);
352 sr = ewk_view_scroll_requests_get(sd->_priv, &count);
354 for (; sr < sr_end; sr++)
355 _ewk_view_single_scroll_process_single(sd, pixels, ow, oh, sr);
357 evas_object_image_data_set(sd->backing_store, pixels);
362 static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd)
364 Ewk_View_Paint_Context *ctxt;
368 const Eina_Rectangle *pr;
369 const Eina_Rectangle *pr_end;
372 cairo_status_t status;
373 cairo_surface_t *surface;
374 cairo_format_t format;
377 Eina_Bool ret = EINA_TRUE;
379 if (sd->animated_zoom.zoom.current < 0.00001) {
380 Evas_Object *clip = evas_object_clip_get(sd->backing_store);
381 Evas_Coord w, h, cw, ch;
382 // reset effects of zoom_weak_set()
383 evas_object_image_fill_set
384 (sd->backing_store, 0, 0, sd->view.w, sd->view.h);
385 evas_object_move(clip, sd->view.x, sd->view.y);
390 ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
395 evas_object_resize(clip, w, h);
398 pixels = evas_object_image_data_get(sd->backing_store, 1);
399 evas_object_image_size_get(sd->backing_store, &ow, &oh);
400 format = CAIRO_FORMAT_ARGB32;
402 surface = cairo_image_surface_create_for_data
403 ((unsigned char*)pixels, format, ow, oh, ow * 4);
404 status = cairo_surface_status(surface);
405 if (status != CAIRO_STATUS_SUCCESS) {
406 ERR("could not create surface from data %dx%d: %s",
407 ow, oh, cairo_status_to_string(status));
409 goto error_cairo_surface;
411 cairo = cairo_create(surface);
412 status = cairo_status(cairo);
413 if (status != CAIRO_STATUS_SUCCESS) {
414 ERR("could not create cairo from surface %dx%d: %s",
415 ow, oh, cairo_status_to_string(status));
420 ctxt = ewk_view_paint_context_new(sd->_priv, cairo);
422 ERR("could not create paint context");
424 goto error_paint_context;
427 tiler = eina_tiler_new(ow, oh);
429 ERR("could not create tiler %dx%d", ow, oh);
434 pr = ewk_view_repaints_get(sd->_priv, &count);
436 for (; pr < pr_end; pr++)
437 eina_tiler_rect_add(tiler, pr);
439 itr = eina_tiler_iterator_new(tiler);
441 ERR("could not get iterator for tiler");
446 ewk_view_layout_if_needed_recursive(sd->_priv);
449 ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy);
451 EINA_ITERATOR_FOREACH(itr, r) {
452 Eina_Rectangle scrolled_rect = {
453 r->x + sx, r->y + sy,
457 ewk_view_paint_context_save(ctxt);
460 ewk_view_paint_context_translate(ctxt, -sx, -sy);
462 ewk_view_paint_context_clip(ctxt, &scrolled_rect);
463 ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);
465 ewk_view_paint_context_restore(ctxt);
466 evas_object_image_data_update_add
467 (sd->backing_store, r->x, r->y, r->w, r->h);
469 eina_iterator_free(itr);
472 eina_tiler_free(tiler);
474 ewk_view_paint_context_free(ctxt);
476 cairo_destroy(cairo);
478 cairo_surface_destroy(surface);
480 evas_object_image_data_set(sd->backing_store, pixels); /* dec refcount */
485 static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy)
488 float scale = zoom / sd->animated_zoom.zoom.start;
489 Evas_Coord w = sd->view.w * scale;
490 Evas_Coord h = sd->view.h * scale;
491 Evas_Coord dx, dy, cw, ch;
492 Evas_Object *clip = evas_object_clip_get(sd->backing_store);
494 ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
495 if (sd->view.w > 0 && sd->view.h > 0) {
496 dx = (w * (sd->view.w - cx)) / sd->view.w;
497 dy = (h * (sd->view.h - cy)) / sd->view.h;
503 evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h);
505 if (sd->view.w > 0 && sd->view.h > 0) {
506 dx = ((sd->view.w - w) * cx) / sd->view.w;
507 dy = ((sd->view.h - h) * cy) / sd->view.h;
512 evas_object_move(clip, sd->view.x + dx, sd->view.y + dy);
518 evas_object_resize(clip, w, h);
522 static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale)
524 evas_object_image_smooth_scale_set(sd->backing_store, smooth_scale);
527 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)
529 evas_object_image_alpha_set(sd->backing_store, a < 255);
532 Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api)
534 if (!ewk_view_base_smart_set(api))
537 if (EINA_UNLIKELY(!_parent_sc.sc.add))
538 ewk_view_base_smart_set(&_parent_sc);
540 api->sc.add = _ewk_view_single_smart_add;
541 api->sc.resize = _ewk_view_single_smart_resize;
543 api->backing_store_add = _ewk_view_single_smart_backing_store_add;
544 api->scrolls_process = _ewk_view_single_smart_scrolls_process;
545 api->repaints_process = _ewk_view_single_smart_repaints_process;
546 api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set;
547 api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set;
548 api->bg_color_set = _ewk_view_single_smart_bg_color_set;
553 static inline Evas_Smart *_ewk_view_single_smart_class_new(void)
555 static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single");
556 static Evas_Smart *smart = 0;
558 if (EINA_UNLIKELY(!smart)) {
559 ewk_view_single_smart_set(&api);
560 smart = evas_smart_class_new(&api.sc);
566 Evas_Object *ewk_view_single_add(Evas *e)
568 return evas_object_smart_add(e, _ewk_view_single_smart_class_new());