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* eventType, Evas_Object* callback, void* eventInfo)
36 Evas_Object* clip = (Evas_Object*)data;
37 evas_object_del(clip);
40 static void _ewk_view_single_smart_add(Evas_Object* ewkSingle)
42 Ewk_View_Smart_Data* smartData;
44 _parent_sc.sc.add(ewkSingle);
46 smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkSingle));
50 Evas_Object* clip = evas_object_rectangle_add(smartData->base.evas);
51 evas_object_show(clip);
53 evas_object_event_callback_add
54 (smartData->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip);
57 static Evas_Object* _ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data* smartData)
59 Evas_Object* bs = evas_object_image_add(smartData->base.evas);
60 evas_object_image_alpha_set(bs, EINA_FALSE);
61 evas_object_image_smooth_scale_set(bs, smartData->zoom_weak_smooth_scale);
66 static void _ewk_view_single_smart_resize(Evas_Object* ewkSingle, Evas_Coord width, Evas_Coord height)
68 Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkSingle));
69 _parent_sc.sc.resize(ewkSingle, width, height);
74 // these should be queued and processed in calculate as well!
75 evas_object_image_size_set(smartData->backing_store, width, height);
76 if (smartData->animated_zoom.zoom.current < 0.00001) {
77 Evas_Object* clip = evas_object_clip_get(smartData->backing_store);
78 Evas_Coord x, y, cw, ch;
79 evas_object_image_fill_set(smartData->backing_store, 0, 0, width, height);
80 evas_object_geometry_get(smartData->backing_store, &x, &y, 0, 0);
81 evas_object_move(clip, x, y);
82 ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch);
87 evas_object_resize(clip, width, height);
91 static inline void _ewk_view_4b_move_region_up(uint32_t* image, size_t rows, size_t x, size_t y, size_t width, size_t height, size_t rowSize)
96 dst = image + x + y * rowSize;
97 src = dst + rows * rowSize;
100 for (; height > 0; height--, dst += rowSize, src += rowSize)
101 memcpy(dst, src, width * 4);
104 static inline void _ewk_view_4b_move_region_down(uint32_t* image, size_t rows, size_t x, size_t y, size_t width, size_t height, size_t rowSize)
110 src = image + x + (y + height - 1) * rowSize;
111 dst = src + rows * rowSize;
113 for (; height > 0; height--, dst -= rowSize, src -= rowSize)
114 memcpy(dst, src, width * 4);
117 static inline void _ewk_view_4b_move_line_left(uint32_t* dst, const uint32_t* src, size_t count)
119 uint32_t* dst_end = dst + count;
120 /* no memcpy() as it does not allow overlapping regions */
121 /* no memmove() as it will copy to a temporary buffer */
122 /* TODO: loop unrolling, copying up to quad-words would help */
123 for (; dst < dst_end; dst++, src++)
127 static inline void _ewk_view_4b_move_line_right(uint32_t* dst, uint32_t* src, size_t count)
129 uint32_t* dst_end = dst - count;
130 /* no memcpy() as it does not allow overlapping regions */
131 /* no memmove() as it will copy to a temporary buffer */
132 /* TODO: loop unrolling, copying up to quad-words would help */
133 for (; dst > dst_end; dst--, src--)
137 static inline void _ewk_view_4b_move_region_left(uint32_t* image, size_t cols, size_t x, size_t y, size_t width, size_t height, size_t rowSize)
142 dst = image + x + y * rowSize;
146 for (; height > 0; height--, dst += rowSize, src += rowSize)
147 _ewk_view_4b_move_line_left(dst, src, width);
150 static inline void _ewk_view_4b_move_region_right(uint32_t* image, size_t columns, size_t x, size_t y, size_t width, size_t height, size_t rowSize)
156 src = image + (x + width - 1) + y * rowSize;
159 for (; height > 0; height--, dst += rowSize, src += rowSize)
160 _ewk_view_4b_move_line_right(dst, src, width);
163 /* catch-all function, not as optimized as the others, but does the work. */
164 static inline void _ewk_view_4b_move_region(uint32_t* image, int deltaX, int deltaY, size_t x, size_t y, size_t width, size_t height, size_t rowSize)
171 dst = image + x + y * rowSize;
172 src = dst - deltaY * rowSize;
176 for (; height > 0; height--, dst += rowSize, src += rowSize)
177 _ewk_view_4b_move_line_left(dst, src, width);
181 dst += width + deltaX -1;
182 for (; height > 0; height--, dst += rowSize, src += rowSize)
183 _ewk_view_4b_move_line_right(dst, src, width);
187 src = image + x + (y + height - 1) * rowSize;
188 dst = src + deltaY * rowSize;
192 for (; height > 0; height--, dst -= rowSize, src -= rowSize)
193 _ewk_view_4b_move_line_left(dst, src, width);
197 dst += width + deltaX - 1;
198 for (; height > 0; height--, dst -= rowSize, src -= rowSize)
199 _ewk_view_4b_move_line_right(dst, src, width);
204 static inline void _ewk_view_single_scroll_process_single(Ewk_View_Smart_Data* smartData, void* pixels, Evas_Coord width, Evas_Coord height, const Ewk_Scroll_Request* scrollRequest)
206 Evas_Coord sx, sy, sw, sh;
208 DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d",
209 scrollRequest->x, scrollRequest->y, scrollRequest->w, scrollRequest->h, scrollRequest->dx, scrollRequest->dy, pixels, width, height);
211 sx = scrollRequest->x;
212 sy = scrollRequest->y;
213 sw = scrollRequest->w;
214 sh = scrollRequest->h;
216 if (abs(scrollRequest->dx) >= sw || abs(scrollRequest->dy) >= sh) {
217 /* doubt webkit would be so stupid... */
218 DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
219 scrollRequest->dx, scrollRequest->dy, sx, sy, sw, sh);
220 ewk_view_repaint_add(smartData->_priv, sx, sy, sw, sh);
235 if (sy + sh > height)
243 EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh);
244 if (!scrollRequest->dx) {
245 if (scrollRequest->dy < 0) {
246 DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
247 "repaint=%d,%d+%dx%d",
248 scrollRequest->dx, scrollRequest->dy, sx, sy, sw, sh + scrollRequest->dy,
249 sx, sy + sh + scrollRequest->dy, sw, -scrollRequest->dy);
251 _ewk_view_4b_move_region_up
252 (static_cast<uint32_t*>(pixels), -scrollRequest->dy, sx, sy, sw, sh, width);
253 evas_object_image_data_update_add
254 (smartData->backing_store, sx, sy, sw, sh + scrollRequest->dy);
256 ewk_view_repaint_add(smartData->_priv, sx, sy + sh + scrollRequest->dy, sw, -scrollRequest->dy);
257 } else if (scrollRequest->dy > 0) {
258 DBG("scroll down: %+03d,%+03d update=%d,%d+%dx%d, "
259 "repaint=%d,%d+%dx%d",
260 scrollRequest->dx, scrollRequest->dy, sx, sy + scrollRequest->dy, sw, sh - scrollRequest->dy,
261 sx, sy, sw, scrollRequest->dy);
263 _ewk_view_4b_move_region_down
264 (static_cast<uint32_t*>(pixels), scrollRequest->dy, sx, sy, sw, sh, width);
265 evas_object_image_data_update_add
266 (smartData->backing_store, sx, sy + scrollRequest->dy, sw, sh - scrollRequest->dy);
268 ewk_view_repaint_add(smartData->_priv, sx, sy, sw, scrollRequest->dy);
270 } else if (!scrollRequest->dy) {
271 if (scrollRequest->dx < 0) {
272 DBG("scroll left: %+03d,%+03d update=%d,%d+%dx%d, "
273 "repaint=%d,%d+%dx%d",
274 scrollRequest->dx, scrollRequest->dy, sx, sy, sw + scrollRequest->dx, sh,
275 sx + sw + scrollRequest->dx, sy, -scrollRequest->dx, sh);
277 _ewk_view_4b_move_region_left
278 (static_cast<uint32_t*>(pixels), -scrollRequest->dx, sx, sy, sw, sh, width);
279 evas_object_image_data_update_add
280 (smartData->backing_store, sx, sy, sw + scrollRequest->dx, sh);
282 ewk_view_repaint_add(smartData->_priv, sx + sw + scrollRequest->dx, sy, -scrollRequest->dx, sh);
283 } else if (scrollRequest->dx > 0) {
284 DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
285 "repaint=%d,%d+%dx%d",
286 scrollRequest->dx, scrollRequest->dy, sx + scrollRequest->dx, sy, sw - scrollRequest->dx, sh,
287 sx, sy, scrollRequest->dx, sh);
289 _ewk_view_4b_move_region_right
290 (static_cast<uint32_t*>(pixels), scrollRequest->dx, sx, sy, sw, sh, width);
291 evas_object_image_data_update_add
292 (smartData->backing_store, sx + scrollRequest->dx, sy, sw - scrollRequest->dx, sh);
294 ewk_view_repaint_add(smartData->_priv, sx, sy, scrollRequest->dx, sh);
297 Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh;
299 if (scrollRequest->dx < 0) {
301 mw = sw + scrollRequest->dx;
303 aw = -scrollRequest->dx;
306 aw = scrollRequest->dx;
308 mw = sw - scrollRequest->dx;
311 if (scrollRequest->dy < 0) {
313 mh = sh + scrollRequest->dy;
315 bh = -scrollRequest->dy;
318 bh = scrollRequest->dy;
320 mh = sh - scrollRequest->dy;
328 DBG("scroll diagonal: %+03d,%+03d update=%d,%d+%dx%d, "
329 "repaints: h=%d,%d+%dx%d v=%d,%d+%dx%d",
330 scrollRequest->dx, scrollRequest->dy, mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh);
332 _ewk_view_4b_move_region
333 (static_cast<uint32_t*>(pixels), scrollRequest->dx, scrollRequest->dy, sx, sy, sw, sh, width);
335 evas_object_image_data_update_add(smartData->backing_store, mx, my, mw, mh);
336 ewk_view_repaint_add(smartData->_priv, ax, ay, aw, ah);
337 ewk_view_repaint_add(smartData->_priv, bx, by, bw, bh);
341 static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data* smartData)
343 const Ewk_Scroll_Request* sr;
344 const Ewk_Scroll_Request* sr_end;
347 void* pixels = evas_object_image_data_get(smartData->backing_store, 1);
348 evas_object_image_size_get(smartData->backing_store, &ow, &oh);
350 sr = ewk_view_scroll_requests_get(smartData->_priv, &count);
352 for (; sr < sr_end; sr++)
353 _ewk_view_single_scroll_process_single(smartData, pixels, ow, oh, sr);
355 evas_object_image_data_set(smartData->backing_store, pixels);
360 static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data* smartData)
362 Ewk_View_Paint_Context* ctxt;
366 const Eina_Rectangle* pr;
367 const Eina_Rectangle* pr_end;
370 cairo_status_t status;
371 cairo_surface_t* surface;
372 cairo_format_t format;
375 Eina_Bool ret = EINA_TRUE;
377 if (smartData->animated_zoom.zoom.current < 0.00001) {
378 Evas_Object* clip = evas_object_clip_get(smartData->backing_store);
379 Evas_Coord w, h, cw, ch;
380 // reset effects of zoom_weak_set()
381 evas_object_image_fill_set
382 (smartData->backing_store, 0, 0, smartData->view.w, smartData->view.h);
383 evas_object_move(clip, smartData->view.x, smartData->view.y);
385 w = smartData->view.w;
386 h = smartData->view.h;
388 ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch);
393 evas_object_resize(clip, w, h);
396 pixels = evas_object_image_data_get(smartData->backing_store, 1);
397 evas_object_image_size_get(smartData->backing_store, &ow, &oh);
398 format = CAIRO_FORMAT_ARGB32;
400 surface = cairo_image_surface_create_for_data
401 (static_cast<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));
407 goto error_cairo_surface;
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));
418 ctxt = ewk_view_paint_context_new(smartData->_priv, cairo);
420 ERR("could not create paint context");
422 goto error_paint_context;
425 tiler = eina_tiler_new(ow, oh);
427 ERR("could not create tiler %dx%d", ow, oh);
432 pr = ewk_view_repaints_get(smartData->_priv, &count);
434 for (; pr < pr_end; pr++)
435 eina_tiler_rect_add(tiler, pr);
437 itr = eina_tiler_iterator_new(tiler);
439 ERR("could not get iterator for tiler");
444 ewk_view_layout_if_needed_recursive(smartData->_priv);
447 ewk_frame_scroll_pos_get(smartData->main_frame, &sx, &sy);
449 EINA_ITERATOR_FOREACH(itr, r) {
450 Eina_Rectangle scrolled_rect = {
451 r->x + sx, r->y + sy,
455 ewk_view_paint_context_save(ctxt);
458 ewk_view_paint_context_translate(ctxt, -sx, -sy);
460 ewk_view_paint_context_clip(ctxt, &scrolled_rect);
461 ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);
463 ewk_view_paint_context_restore(ctxt);
464 evas_object_image_data_update_add
465 (smartData->backing_store, r->x, r->y, r->w, r->h);
467 eina_iterator_free(itr);
470 eina_tiler_free(tiler);
472 ewk_view_paint_context_free(ctxt);
474 cairo_destroy(cairo);
476 cairo_surface_destroy(surface);
478 evas_object_image_data_set(smartData->backing_store, pixels); /* dec refcount */
483 static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data* smartData, float zoom, Evas_Coord centerX, Evas_Coord centerY)
486 float scale = zoom / smartData->animated_zoom.zoom.start;
487 Evas_Coord w = smartData->view.w * scale;
488 Evas_Coord h = smartData->view.h * scale;
489 Evas_Coord dx, dy, cw, ch;
490 Evas_Object* clip = evas_object_clip_get(smartData->backing_store);
492 ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch);
493 if (smartData->view.w > 0 && smartData->view.h > 0) {
494 dx = (w * (smartData->view.w - centerX)) / smartData->view.w;
495 dy = (h * (smartData->view.h - centerY)) / smartData->view.h;
501 evas_object_image_fill_set(smartData->backing_store, centerX + dx, centerY + dy, w, h);
503 if (smartData->view.w > 0 && smartData->view.h > 0) {
504 dx = ((smartData->view.w - w) * centerX) / smartData->view.w;
505 dy = ((smartData->view.h - h) * centerY) / smartData->view.h;
510 evas_object_move(clip, smartData->view.x + dx, smartData->view.y + dy);
512 if (cw < smartData->view.w)
514 if (ch < smartData->view.h)
516 evas_object_resize(clip, w, h);
520 static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data* smartData, Eina_Bool smooth_scale)
522 evas_object_image_smooth_scale_set(smartData->backing_store, smooth_scale);
525 static void _ewk_view_single_smart_bg_color_set(Ewk_View_Smart_Data* smartData, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
527 evas_object_image_alpha_set(smartData->backing_store, alpha < 255);
530 Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class* api)
532 if (!ewk_view_base_smart_set(api))
535 if (EINA_UNLIKELY(!_parent_sc.sc.add))
536 ewk_view_base_smart_set(&_parent_sc);
538 api->sc.add = _ewk_view_single_smart_add;
539 api->sc.resize = _ewk_view_single_smart_resize;
541 api->backing_store_add = _ewk_view_single_smart_backing_store_add;
542 api->scrolls_process = _ewk_view_single_smart_scrolls_process;
543 api->repaints_process = _ewk_view_single_smart_repaints_process;
544 api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set;
545 api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set;
546 api->bg_color_set = _ewk_view_single_smart_bg_color_set;
551 static inline Evas_Smart* _ewk_view_single_smart_class_new(void)
553 static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single");
554 static Evas_Smart* smart = 0;
556 if (EINA_UNLIKELY(!smart)) {
557 ewk_view_single_smart_set(&api);
558 smart = evas_smart_class_new(&api.sc);
564 Evas_Object* ewk_view_single_add(Evas* canvas)
566 return evas_object_smart_add(canvas, _ewk_view_single_smart_class_new());