<rdar://problem/10071256> Retain retired custom fonts until the next style recalc
[WebKit-https.git] / Source / WebKit / efl / ewk / ewk_view_single.c
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     if (!sd)
47         return;
48
49     Evas_Object *clip = evas_object_rectangle_add(sd->base.evas);
50     evas_object_clip_set(sd->backing_store, clip);
51     evas_object_smart_member_add(clip, o);
52     evas_object_show(clip);
53
54     evas_object_event_callback_add
55         (sd->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip);
56 }
57
58 static Evas_Object *_ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data *sd)
59 {
60     Evas_Object *bs = evas_object_image_add(sd->base.evas);
61     evas_object_image_alpha_set(bs, EINA_FALSE);
62     evas_object_image_smooth_scale_set(bs, sd->zoom_weak_smooth_scale);
63
64     return bs;
65 }
66
67 static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
68 {
69     Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o);
70     _parent_sc.sc.resize(o, w, h);
71
72     if (!sd)
73         return;
74
75     // these should be queued and processed in calculate as well!
76     evas_object_image_size_set(sd->backing_store, w, h);
77     if (sd->animated_zoom.zoom.current < 0.00001) {
78         Evas_Object *clip = evas_object_clip_get(sd->backing_store);
79         Evas_Coord x, y, cw, ch;
80         evas_object_image_fill_set(sd->backing_store, 0, 0, w, h);
81         evas_object_geometry_get(sd->backing_store, &x, &y, 0, 0);
82         evas_object_move(clip, x, y);
83         ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
84         if (w > cw)
85             w = cw;
86         if (h > ch)
87             h = ch;
88         evas_object_resize(clip, w, h);
89     }
90 }
91
92 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)
93 {
94     uint32_t *src;
95     uint32_t *dst;
96
97     dst = image + x + y * rowsize;
98     src = dst + rows * rowsize;
99     h -= rows;
100
101     for (; h > 0; h--, dst += rowsize, src += rowsize)
102         memcpy(dst, src, w * 4);
103 }
104
105 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)
106 {
107     uint32_t *src;
108     uint32_t *dst;
109
110     h -= rows;
111     src = image + x + (y + h - 1) * rowsize;
112     dst = src + rows * rowsize;
113
114     for (; h > 0; h--, dst -= rowsize, src -= rowsize)
115         memcpy(dst, src, w * 4);
116 }
117
118 static inline void _ewk_view_4b_move_line_left(uint32_t *dst, const uint32_t *src, size_t count)
119 {
120     uint32_t *dst_end = dst + count;
121     /* no memcpy() as it does not allow overlapping regions */
122     /* no memmove() as it will copy to a temporary buffer */
123     /* TODO: loop unrolling, copying up to quad-words would help */
124     for (; dst < dst_end; dst++, src++)
125         *dst = *src;
126 }
127
128 static inline void _ewk_view_4b_move_line_right(uint32_t *dst, uint32_t *src, size_t count)
129 {
130     uint32_t *dst_end = dst - count;
131     /* no memcpy() as it does not allow overlapping regions */
132     /* no memmove() as it will copy to a temporary buffer */
133     /* TODO: loop unrolling, copying up to quad-words would help */
134     for (; dst > dst_end; dst--, src--)
135         *dst = *src;
136 }
137
138 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)
139 {
140     uint32_t *src;
141     uint32_t *dst;
142
143     dst = image + x + y * rowsize;
144     src = dst + cols;
145     w -= cols;
146
147     for (; h > 0; h--, dst += rowsize, src += rowsize)
148         _ewk_view_4b_move_line_left(dst, src, w);
149 }
150
151 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)
152 {
153     uint32_t *src;
154     uint32_t *dst;
155
156     w -= cols;
157     src = image + (x + w - 1) + y * rowsize;
158     dst = src + cols;
159
160     for (; h > 0; h--, dst += rowsize, src += rowsize)
161         _ewk_view_4b_move_line_right(dst, src, w);
162 }
163
164 /* catch-all function, not as optimized as the others, but does the work. */
165 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)
166 {
167     uint32_t *src;
168     uint32_t *dst;
169
170     if (dy < 0) {
171         h += dy;
172         dst = image + x + y * rowsize;
173         src = dst - dy * rowsize;
174         if (dx <= 0) {
175             w += dx;
176             src -= dx;
177             for (; h > 0; h--, dst += rowsize, src += rowsize)
178                 _ewk_view_4b_move_line_left(dst, src, w);
179         } else {
180             w -= dx;
181             src += w - 1;
182             dst += w + dx -1;
183             for (; h > 0; h--, dst += rowsize, src += rowsize)
184                 _ewk_view_4b_move_line_right(dst, src, w);
185         }
186     } else {
187         h -= dy;
188         src = image + x + (y + h - 1) * rowsize;
189         dst = src + dy * rowsize;
190         if (dx <= 0) {
191             w += dx;
192             src -= dx;
193             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
194                 _ewk_view_4b_move_line_left(dst, src, w);
195         } else {
196             w -= dx;
197             src += w - 1;
198             dst += w + dx - 1;
199             for (; h > 0; h--, dst -= rowsize, src -= rowsize)
200                 _ewk_view_4b_move_line_right(dst, src, w);
201         }
202     }
203 }
204
205 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)
206 {
207     Evas_Coord sx, sy, sw, sh;
208
209     DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d",
210         sr->x, sr->y, sr->w, sr->h, sr->dx, sr->dy, pixels, ow, oh);
211
212     sx = sr->x;
213     sy = sr->y;
214     sw = sr->w;
215     sh = sr->h;
216
217     if (abs(sr->dx) >= sw || abs(sr->dy) >= sh) {
218         /* doubt webkit would be so stupid... */
219         DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d",
220             sr->dx, sr->dy, sx, sy, sw, sh);
221         ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh);
222         return;
223     }
224
225     if (sx < 0) {
226         sw += sx;
227         sx = 0;
228     }
229     if (sy < 0) {
230         sh += sy;
231         sy = 0;
232     }
233
234     if (sx + sw > ow)
235         sw = ow - sx;
236     if (sy + sh > oh)
237         sh = oh - sy;
238
239     if (sw < 0)
240         sw = 0;
241     if (sh < 0)
242         sh = 0;
243
244     EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh);
245     if (!sr->dx) {
246         if (sr->dy < 0) {
247             DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
248                 "repaint=%d,%d+%dx%d",
249                 sr->dx, sr->dy, sx, sy, sw, sh + sr->dy,
250                 sx, sy + sh + sr->dy, sw, -sr->dy);
251
252             _ewk_view_4b_move_region_up
253                 ((uint32_t*)pixels, -sr->dy, sx, sy, sw, sh, ow);
254             evas_object_image_data_update_add
255                 (sd->backing_store, sx, sy, sw, sh + sr->dy);
256
257             ewk_view_repaint_add(sd->_priv, sx, sy + sh + sr->dy, sw, -sr->dy);
258         } else if (sr->dy > 0) {
259             DBG("scroll down: %+03d,%+03d update=%d,%d+%dx%d, "
260                 "repaint=%d,%d+%dx%d",
261                 sr->dx, sr->dy, sx, sy + sr->dy, sw, sh - sr->dy,
262                 sx, sy, sw, sr->dy);
263
264             _ewk_view_4b_move_region_down
265                 ((uint32_t*)pixels, sr->dy, sx, sy, sw, sh, ow);
266             evas_object_image_data_update_add
267                 (sd->backing_store, sx, sy + sr->dy, sw, sh - sr->dy);
268
269             ewk_view_repaint_add(sd->_priv, sx, sy, sw, sr->dy);
270         }
271     } else if (!sr->dy) {
272         if (sr->dx < 0) {
273             DBG("scroll left: %+03d,%+03d update=%d,%d+%dx%d, "
274                 "repaint=%d,%d+%dx%d",
275                 sr->dx, sr->dy, sx, sy, sw + sr->dx, sh,
276                 sx + sw + sr->dx, sy, -sr->dx, sh);
277
278             _ewk_view_4b_move_region_left
279                 ((uint32_t*)pixels, -sr->dx, sx, sy, sw, sh, ow);
280             evas_object_image_data_update_add
281                 (sd->backing_store, sx, sy, sw + sr->dx, sh);
282
283             ewk_view_repaint_add(sd->_priv, sx + sw + sr->dx, sy, -sr->dx, sh);
284         } else if (sr->dx > 0) {
285             DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, "
286                 "repaint=%d,%d+%dx%d",
287                 sr->dx, sr->dy, sx + sr->dx, sy, sw - sr->dx, sh,
288                 sx, sy, sr->dx, sh);
289
290             _ewk_view_4b_move_region_right
291                 ((uint32_t*)pixels, sr->dx, sx, sy, sw, sh, ow);
292             evas_object_image_data_update_add
293                 (sd->backing_store, sx + sr->dx, sy, sw - sr->dx, sh);
294
295             ewk_view_repaint_add(sd->_priv, sx, sy, sr->dx, sh);
296         }
297     } else {
298         Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh;
299
300         if (sr->dx < 0) {
301             mx = sx;
302             mw = sw + sr->dx;
303             ax = mx + mw;
304             aw = -sr->dx;
305         } else {
306             ax = sx;
307             aw = sr->dx;
308             mx = ax + aw;
309             mw = sw - sr->dx;
310         }
311
312         if (sr->dy < 0) {
313             my = sy;
314             mh = sh + sr->dy;
315             by = my + mh;
316             bh = -sr->dy;
317         } else {
318             by = sy;
319             bh = sr->dy;
320             my = by + bh;
321             mh = sh - sr->dy;
322         }
323
324         ay = my;
325         ah = mh;
326         bx = sx;
327         bw = sw;
328
329         DBG("scroll diagonal: %+03d,%+03d update=%d,%d+%dx%d, "
330             "repaints: h=%d,%d+%dx%d v=%d,%d+%dx%d",
331             sr->dx, sr->dy, mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh);
332
333         _ewk_view_4b_move_region
334             ((uint32_t*)pixels, sr->dx, sr->dy, sx, sy, sw, sh, ow);
335
336         evas_object_image_data_update_add(sd->backing_store, mx, my, mw, mh);
337         ewk_view_repaint_add(sd->_priv, ax, ay, aw, ah);
338         ewk_view_repaint_add(sd->_priv, bx, by, bw, bh);
339     }
340 }
341
342 static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data *sd)
343 {
344     const Ewk_Scroll_Request *sr;
345     const Ewk_Scroll_Request *sr_end;
346     Evas_Coord ow, oh;
347     size_t count;
348     void *pixels = evas_object_image_data_get(sd->backing_store, 1);
349     evas_object_image_size_get(sd->backing_store, &ow, &oh);
350
351     sr = ewk_view_scroll_requests_get(sd->_priv, &count);
352     sr_end = sr + count;
353     for (; sr < sr_end; sr++)
354         _ewk_view_single_scroll_process_single(sd, pixels, ow, oh, sr);
355
356     evas_object_image_data_set(sd->backing_store, pixels);
357
358     return EINA_TRUE;
359 }
360
361 static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd)
362 {
363     Ewk_View_Paint_Context *ctxt;
364     Evas_Coord ow, oh;
365     void *pixels;
366     Eina_Rectangle *r;
367     const Eina_Rectangle *pr;
368     const Eina_Rectangle *pr_end;
369     Eina_Tiler *tiler;
370     Eina_Iterator *itr;
371     cairo_status_t status;
372     cairo_surface_t *surface;
373     cairo_format_t format;
374     cairo_t *cairo;
375     size_t count;
376     Eina_Bool ret = EINA_TRUE;
377
378     if (sd->animated_zoom.zoom.current < 0.00001) {
379         Evas_Object *clip = evas_object_clip_get(sd->backing_store);
380         Evas_Coord w, h, cw, ch;
381         // reset effects of zoom_weak_set()
382         evas_object_image_fill_set
383             (sd->backing_store, 0, 0, sd->view.w, sd->view.h);
384         evas_object_move(clip, sd->view.x, sd->view.y);
385
386         w = sd->view.w;
387         h = sd->view.h;
388
389         ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
390         if (w > cw)
391             w = cw;
392         if (h > ch)
393             h = ch;
394         evas_object_resize(clip, w, h);
395     }
396
397     pixels = evas_object_image_data_get(sd->backing_store, 1);
398     evas_object_image_size_get(sd->backing_store, &ow, &oh);
399     format = CAIRO_FORMAT_ARGB32;
400
401     surface = cairo_image_surface_create_for_data
402         ((unsigned char*)pixels, format, ow, oh, ow * 4);
403     status = cairo_surface_status(surface);
404     if (status != CAIRO_STATUS_SUCCESS) {
405         ERR("could not create surface from data %dx%d: %s",
406             ow, oh, cairo_status_to_string(status));
407         ret = EINA_FALSE;
408         goto error_cairo_surface;
409     }
410     cairo = cairo_create(surface);
411     status = cairo_status(cairo);
412     if (status != CAIRO_STATUS_SUCCESS) {
413         ERR("could not create cairo from surface %dx%d: %s",
414             ow, oh, cairo_status_to_string(status));
415         ret = EINA_FALSE;
416         goto error_cairo;
417     }
418
419     ctxt = ewk_view_paint_context_new(sd->_priv, cairo);
420     if (!ctxt) {
421         ERR("could not create paint context");
422         ret = EINA_FALSE;
423         goto error_paint_context;
424     }
425
426     tiler = eina_tiler_new(ow, oh);
427     if (!tiler) {
428         ERR("could not create tiler %dx%d", ow, oh);
429         ret = EINA_FALSE;
430         goto error_tiler;
431     }
432
433     pr = ewk_view_repaints_get(sd->_priv, &count);
434     pr_end = pr + count;
435     for (; pr < pr_end; pr++)
436         eina_tiler_rect_add(tiler, pr);
437
438     itr = eina_tiler_iterator_new(tiler);
439     if (!itr) {
440         ERR("could not get iterator for tiler");
441         ret = EINA_FALSE;
442         goto error_iterator;
443     }
444
445     ewk_view_layout_if_needed_recursive(sd->_priv);
446
447     int sx, sy;
448     ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy);
449
450     EINA_ITERATOR_FOREACH(itr, r) {
451         Eina_Rectangle scrolled_rect = {
452             r->x + sx, r->y + sy,
453             r->w, r->h
454         };
455
456         ewk_view_paint_context_save(ctxt);
457
458         if ((sx) || (sy))
459             ewk_view_paint_context_translate(ctxt, -sx, -sy);
460
461         ewk_view_paint_context_clip(ctxt, &scrolled_rect);
462         ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect);
463
464         ewk_view_paint_context_restore(ctxt);
465         evas_object_image_data_update_add
466             (sd->backing_store, r->x, r->y, r->w, r->h);
467     }
468     eina_iterator_free(itr);
469
470 error_iterator:
471     eina_tiler_free(tiler);
472 error_tiler:
473     ewk_view_paint_context_free(ctxt);
474 error_paint_context:
475     cairo_destroy(cairo);
476 error_cairo:
477     cairo_surface_destroy(surface);
478 error_cairo_surface:
479     evas_object_image_data_set(sd->backing_store, pixels); /* dec refcount */
480
481     return ret;
482 }
483
484 static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy)
485 {
486     // TODO: review
487     float scale = zoom / sd->animated_zoom.zoom.start;
488     Evas_Coord w = sd->view.w * scale;
489     Evas_Coord h = sd->view.h * scale;
490     Evas_Coord dx, dy, cw, ch;
491     Evas_Object *clip = evas_object_clip_get(sd->backing_store);
492
493     ewk_frame_contents_size_get(sd->main_frame, &cw, &ch);
494     if (sd->view.w > 0 && sd->view.h > 0) {
495         dx = (w * (sd->view.w - cx)) / sd->view.w;
496         dy = (h * (sd->view.h - cy)) / sd->view.h;
497     } else {
498         dx = 0;
499         dy = 0;
500     }
501
502     evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h);
503
504     if (sd->view.w > 0 && sd->view.h > 0) {
505         dx = ((sd->view.w - w) * cx) / sd->view.w;
506         dy = ((sd->view.h - h) * cy) / sd->view.h;
507     } else {
508         dx = 0;
509         dy = 0;
510     }
511     evas_object_move(clip, sd->view.x + dx, sd->view.y + dy);
512
513     if (cw < sd->view.w)
514         w = cw * scale;
515     if (ch < sd->view.h)
516         h = ch * scale;
517     evas_object_resize(clip, w, h);
518     return EINA_TRUE;
519 }
520
521 static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale)
522 {
523     evas_object_image_smooth_scale_set(sd->backing_store, smooth_scale);
524 }
525
526 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)
527 {
528     evas_object_image_alpha_set(sd->backing_store, a < 255);
529 }
530
531 Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api)
532 {
533     if (!ewk_view_base_smart_set(api))
534         return EINA_FALSE;
535
536     if (EINA_UNLIKELY(!_parent_sc.sc.add))
537         ewk_view_base_smart_set(&_parent_sc);
538
539     api->sc.add = _ewk_view_single_smart_add;
540     api->sc.resize = _ewk_view_single_smart_resize;
541
542     api->backing_store_add = _ewk_view_single_smart_backing_store_add;
543     api->scrolls_process = _ewk_view_single_smart_scrolls_process;
544     api->repaints_process = _ewk_view_single_smart_repaints_process;
545     api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set;
546     api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set;
547     api->bg_color_set = _ewk_view_single_smart_bg_color_set;
548
549     return EINA_TRUE;
550 }
551
552 static inline Evas_Smart *_ewk_view_single_smart_class_new(void)
553 {
554     static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single");
555     static Evas_Smart *smart = 0;
556
557     if (EINA_UNLIKELY(!smart)) {
558         ewk_view_single_smart_set(&api);
559         smart = evas_smart_class_new(&api.sc);
560     }
561
562     return smart;
563 }
564
565 Evas_Object *ewk_view_single_add(Evas *e)
566 {
567     return evas_object_smart_add(e, _ewk_view_single_smart_class_new());
568 }