initial import
[vuplus_webkit] / Source / WebKit / efl / ewk / ewk_view_single.cpp
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 #include "ewk_private.h"
27
28 #include <Evas.h>
29 #include <eina_safety_checks.h>
30 #include <string.h>
31
32 static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL;
33
34 static void _ewk_view_single_on_del(void *data, Evas *e, Evas_Object *o, void *event_info)
35 {
36     Evas_Object *clip = (Evas_Object*)data;
37     evas_object_del(clip);
38 }
39
40 static void _ewk_view_single_smart_add(Evas_Object *o)
41 {
42     Ewk_View_Smart_Data *sd;
43
44     _parent_sc.sc.add(o);
45
46     sd = (Ewk_View_Smart_Data *)evas_object_smart_data_get(o);
47     if (!sd)
48         return;
49
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);
54
55     evas_object_event_callback_add
56         (sd->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip);
57 }
58
59 static Evas_Object *_ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data *sd)
60 {
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);
64
65     return bs;
66 }
67
68 static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
69 {
70     Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o);
71     _parent_sc.sc.resize(o, w, h);
72
73     if (!sd)
74         return;
75
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);
85         if (w > cw)
86             w = cw;
87         if (h > ch)
88             h = ch;
89         evas_object_resize(clip, w, h);
90     }
91 }
92
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)
94 {
95     uint32_t *src;
96     uint32_t *dst;
97
98     dst = image + x + y * rowsize;
99     src = dst + rows * rowsize;
100     h -= rows;
101
102     for (; h > 0; h--, dst += rowsize, src += rowsize)
103         memcpy(dst, src, w * 4);
104 }
105
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)
107 {
108     uint32_t *src;
109     uint32_t *dst;
110
111     h -= rows;
112     src = image + x + (y + h - 1) * rowsize;
113     dst = src + rows * rowsize;
114
115     for (; h > 0; h--, dst -= rowsize, src -= rowsize)
116         memcpy(dst, src, w * 4);
117 }
118
119 static inline void _ewk_view_4b_move_line_left(uint32_t *dst, const uint32_t *src, size_t count)
120 {
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++)
126         *dst = *src;
127 }
128
129 static inline void _ewk_view_4b_move_line_right(uint32_t *dst, uint32_t *src, size_t count)
130 {
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--)
136         *dst = *src;
137 }
138
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)
140 {
141     uint32_t *src;
142     uint32_t *dst;
143
144     dst = image + x + y * rowsize;
145     src = dst + cols;
146     w -= cols;
147
148     for (; h > 0; h--, dst += rowsize, src += rowsize)
149         _ewk_view_4b_move_line_left(dst, src, w);
150 }
151
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)
153 {
154     uint32_t *src;
155     uint32_t *dst;
156
157     w -= cols;
158     src = image + (x + w - 1) + y * rowsize;
159     dst = src + cols;
160
161     for (; h > 0; h--, dst += rowsize, src += rowsize)
162         _ewk_view_4b_move_line_right(dst, src, w);
163 }
164
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)
167 {
168     uint32_t *src;
169     uint32_t *dst;
170
171     if (dy < 0) {
172         h += dy;
173         dst = image + x + y * rowsize;
174         src = dst - dy * rowsize;
175         if (dx <= 0) {
176             w += dx;
177             src -= dx;
178             for (; h > 0; h--, dst += rowsize, src += rowsize)
179                 _ewk_view_4b_move_line_left(dst, src, w);
180         } else {
181             w -= dx;
182             src += w - 1;
183             dst += w + dx -1;
184             for (; h > 0; h--, dst += rowsize, src += rowsize)
185                 _ewk_view_4b_move_line_right(dst, src, w);
186         }
187     } else {
188         h -= dy;
189         src = image + x + (y + h - 1) * rowsize;
190         dst = src + dy * rowsize;
191         if (dx <= 0) {
192             w += dx;
193             src -= dx;
194             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
195                 _ewk_view_4b_move_line_left(dst, src, w);
196         } else {
197             w -= dx;
198             src += w - 1;
199             dst += w + dx - 1;
200             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
201                 _ewk_view_4b_move_line_right(dst, src, w);
202         }
203     }
204 }
205
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)
207 {
208     Evas_Coord sx, sy, sw, sh;
209
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);
212
213     sx = sr->x;
214     sy = sr->y;
215     sw = sr->w;
216     sh = sr->h;
217
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);
223         return;
224     }
225
226     if (sx < 0) {
227         sw += sx;
228         sx = 0;
229     }
230     if (sy < 0) {
231         sh += sy;
232         sy = 0;
233     }
234
235     if (sx + sw > ow)
236         sw = ow - sx;
237     if (sy + sh > oh)
238         sh = oh - sy;
239
240     if (sw < 0)
241         sw = 0;
242     if (sh < 0)
243         sh = 0;
244
245     EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh);
246     if (!sr->dx) {
247         if (sr->dy < 0) {
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);
252
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);
257
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,
263                 sx, sy, sw, sr->dy);
264
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);
269
270             ewk_view_repaint_add(sd->_priv, sx, sy, sw, sr->dy);
271         }
272     } else if (!sr->dy) {
273         if (sr->dx < 0) {
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);
278
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);
283
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,
289                 sx, sy, sr->dx, sh);
290
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);
295
296             ewk_view_repaint_add(sd->_priv, sx, sy, sr->dx, sh);
297         }
298     } else {
299         Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh;
300
301         if (sr->dx < 0) {
302             mx = sx;
303             mw = sw + sr->dx;
304             ax = mx + mw;
305             aw = -sr->dx;
306         } else {
307             ax = sx;
308             aw = sr->dx;
309             mx = ax + aw;
310             mw = sw - sr->dx;
311         }
312
313         if (sr->dy < 0) {
314             my = sy;
315             mh = sh + sr->dy;
316             by = my + mh;
317             bh = -sr->dy;
318         } else {
319             by = sy;
320             bh = sr->dy;
321             my = by + bh;
322             mh = sh - sr->dy;
323         }
324
325         ay = my;
326         ah = mh;
327         bx = sx;
328         bw = sw;
329
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);
333
334         _ewk_view_4b_move_region
335             ((uint32_t*)pixels, sr->dx, sr->dy, sx, sy, sw, sh, ow);
336
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);
340     }
341 }
342
343 static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data *sd)
344 {
345     const Ewk_Scroll_Request *sr;
346     const Ewk_Scroll_Request *sr_end;
347     Evas_Coord ow, oh;
348     size_t count;
349     void *pixels = evas_object_image_data_get(sd->backing_store, 1);
350     evas_object_image_size_get(sd->backing_store, &ow, &oh);
351
352     sr = ewk_view_scroll_requests_get(sd->_priv, &count);
353     sr_end = sr + count;
354     for (; sr < sr_end; sr++)
355         _ewk_view_single_scroll_process_single(sd, pixels, ow, oh, sr);
356
357     evas_object_image_data_set(sd->backing_store, pixels);
358
359     return EINA_TRUE;
360 }
361
362 static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd)
363 {
364     Ewk_View_Paint_Context *ctxt;
365     Evas_Coord ow, oh;
366     void *pixels;
367     Eina_Rectangle *r;
368     const Eina_Rectangle *pr;
369     const Eina_Rectangle *pr_end;
370     Eina_Tiler *tiler;
371     Eina_Iterator *itr;
372     cairo_status_t status;
373     cairo_surface_t *surface;
374     cairo_format_t format;
375     cairo_t *cairo;
376     size_t count;
377     Eina_Bool ret = EINA_TRUE;
378
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);
386
387         w = sd->view.w;
388         h = sd->view.h;
389
390         ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
391         if (w > cw)
392             w = cw;
393         if (h > ch)
394             h = ch;
395         evas_object_resize(clip, w, h);
396     }
397
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;
401
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));
408         ret = EINA_FALSE;
409         goto error_cairo_surface;
410     }
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));
416         ret = EINA_FALSE;
417         goto error_cairo;
418     }
419
420     ctxt = ewk_view_paint_context_new(sd->_priv, cairo);
421     if (!ctxt) {
422         ERR("could not create paint context");
423         ret = EINA_FALSE;
424         goto error_paint_context;
425     }
426
427     tiler = eina_tiler_new(ow, oh);
428     if (!tiler) {
429         ERR("could not create tiler %dx%d", ow, oh);
430         ret = EINA_FALSE;
431         goto error_tiler;
432     }
433
434     pr = ewk_view_repaints_get(sd->_priv, &count);
435     pr_end = pr + count;
436     for (; pr < pr_end; pr++)
437         eina_tiler_rect_add(tiler, pr);
438
439     itr = eina_tiler_iterator_new(tiler);
440     if (!itr) {
441         ERR("could not get iterator for tiler");
442         ret = EINA_FALSE;
443         goto error_iterator;
444     }
445
446     ewk_view_layout_if_needed_recursive(sd->_priv);
447
448     int sx, sy;
449     ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy);
450
451     EINA_ITERATOR_FOREACH(itr, r) {
452         Eina_Rectangle scrolled_rect = {
453             r->x + sx, r->y + sy,
454             r->w, r->h
455         };
456
457         ewk_view_paint_context_save(ctxt);
458
459         if ((sx) || (sy))
460             ewk_view_paint_context_translate(ctxt, -sx, -sy);
461
462         ewk_view_paint_context_clip(ctxt, &scrolled_rect);
463         ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);
464
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);
468     }
469     eina_iterator_free(itr);
470
471 error_iterator:
472     eina_tiler_free(tiler);
473 error_tiler:
474     ewk_view_paint_context_free(ctxt);
475 error_paint_context:
476     cairo_destroy(cairo);
477 error_cairo:
478     cairo_surface_destroy(surface);
479 error_cairo_surface:
480     evas_object_image_data_set(sd->backing_store, pixels); /* dec refcount */
481
482     return ret;
483 }
484
485 static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy)
486 {
487     // TODO: review
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);
493
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;
498     } else {
499         dx = 0;
500         dy = 0;
501     }
502
503     evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h);
504
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;
508     } else {
509         dx = 0;
510         dy = 0;
511     }
512     evas_object_move(clip, sd->view.x + dx, sd->view.y + dy);
513
514     if (cw < sd->view.w)
515         w = cw * scale;
516     if (ch < sd->view.h)
517         h = ch * scale;
518     evas_object_resize(clip, w, h);
519     return EINA_TRUE;
520 }
521
522 static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale)
523 {
524     evas_object_image_smooth_scale_set(sd->backing_store, smooth_scale);
525 }
526
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)
528 {
529     evas_object_image_alpha_set(sd->backing_store, a < 255);
530 }
531
532 Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api)
533 {
534     if (!ewk_view_base_smart_set(api))
535         return EINA_FALSE;
536
537     if (EINA_UNLIKELY(!_parent_sc.sc.add))
538         ewk_view_base_smart_set(&_parent_sc);
539
540     api->sc.add = _ewk_view_single_smart_add;
541     api->sc.resize = _ewk_view_single_smart_resize;
542
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;
549
550     return EINA_TRUE;
551 }
552
553 static inline Evas_Smart *_ewk_view_single_smart_class_new(void)
554 {
555     static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single");
556     static Evas_Smart *smart = 0;
557
558     if (EINA_UNLIKELY(!smart)) {
559         ewk_view_single_smart_set(&api);
560         smart = evas_smart_class_new(&api.sc);
561     }
562
563     return smart;
564 }
565
566 Evas_Object *ewk_view_single_add(Evas *e)
567 {
568     return evas_object_smart_add(e, _ewk_view_single_smart_class_new());
569 }