initial import
[vuplus_webkit] / Source / WebKit / efl / ewk / ewk_tiled_backing_store.c
1 /*
2     Copyright (C) 2009-2010 Samsung Electronics
3     Copyright (C) 2009-2010 ProFUSION embedded systems
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_tiled_backing_store.h"
23
24 #define _GNU_SOURCE
25 #include "ewk_tiled_private.h"
26 #include <Ecore.h>
27 #include <Eina.h>
28 #include <errno.h>
29 #include <math.h>
30 #include <stdio.h> // XXX REMOVE ME LATER
31 #include <stdlib.h>
32 #include <string.h>
33
34 #define IDX(col, row, rowspan) (col + (row * rowspan))
35
36 #if !defined(MIN)
37 # define MIN(a, b) ((a < b) ? a : b)
38 #endif
39
40 #if !defined(MAX)
41 # define MAX(a, b) ((a > b) ? a : b)
42 #endif
43
44 typedef enum _Ewk_Tiled_Backing_Store_Pre_Render_Priority Ewk_Tiled_Backing_Store_Pre_Render_Priority;
45 typedef struct _Ewk_Tiled_Backing_Store_Data Ewk_Tiled_Backing_Store_Data;
46 typedef struct _Ewk_Tiled_Backing_Store_Item Ewk_Tiled_Backing_Store_Item;
47 typedef struct _Ewk_Tiled_Backing_Store_Pre_Render_Request Ewk_Tiled_Backing_Store_Pre_Render_Request;
48
49 enum _Ewk_Tiled_Backing_Store_Pre_Render_Priority {
50     PRE_RENDER_PRIORITY_LOW = 0, /**< Append the request to the list */
51     PRE_RENDER_PRIORITY_HIGH     /**< Prepend the request to the list */
52 };
53
54 struct _Ewk_Tiled_Backing_Store_Item {
55     EINA_INLIST;
56     Ewk_Tile *tile;
57     struct {
58         Evas_Coord x, y, w, h;
59     } geometry;
60     Eina_Bool smooth_scale;
61 };
62
63 struct _Ewk_Tiled_Backing_Store_Pre_Render_Request {
64     EINA_INLIST;
65     unsigned long col, row;
66     float zoom;
67 };
68
69 struct _Ewk_Tiled_Backing_Store_Data {
70     Evas_Object_Smart_Clipped_Data base;
71     Evas_Object *self;
72     Evas_Object *contents_clipper;
73     struct {
74         Eina_Inlist **items;
75         Evas_Coord x, y, w, h;
76         long cols, rows;
77         struct {
78             Evas_Coord w, h;
79             float zoom;
80             Eina_Bool zoom_weak_smooth_scale:1;
81         } tile;
82         struct {
83             struct {
84                 Evas_Coord x, y;
85             } cur, old, base, zoom_center;
86         } offset;
87     } view;
88     Evas_Colorspace cspace;
89     struct {
90         Ewk_Tile_Matrix *matrix;
91         struct {
92             unsigned long col, row;
93         } base;
94         struct {
95             unsigned long cols, rows;
96         } cur, old;
97         Evas_Coord width, height;
98     } model;
99     struct {
100         Eina_Bool (*cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *area);
101         void *data;
102         Eina_Inlist *pre_render_requests;
103         Ecore_Idler *idler;
104         Eina_Bool disabled;
105         Eina_Bool suspend:1;
106     } render;
107     struct {
108         void *(*pre_cb)(void *data, Evas_Object *o);
109         void *pre_data;
110         void *(*post_cb)(void *data, void *pre_data, Evas_Object *o);
111         void *post_data;
112     } process;
113     struct {
114         Eina_Bool any:1;
115         Eina_Bool pos:1;
116         Eina_Bool size:1;
117         Eina_Bool model:1;
118         Eina_Bool offset:1;
119     } changed;
120 #ifdef DEBUG_MEM_LEAKS
121     Ecore_Event_Handler *sig_usr;
122 #endif
123 };
124
125 static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL;
126 int _ewk_tiled_log_dom = -1;
127
128 #define PRIV_DATA_GET_OR_RETURN(obj, ptr, ...)                       \
129     Ewk_Tiled_Backing_Store_Data *ptr = evas_object_smart_data_get(obj); \
130     if (!ptr) {                                                      \
131         CRITICAL("no private data in obj=%p", obj);                  \
132         return __VA_ARGS__;                                          \
133     }
134
135 static void _ewk_tiled_backing_store_fill_renderers(Ewk_Tiled_Backing_Store_Data *priv);
136 static inline void _ewk_tiled_backing_store_view_dbg(const Ewk_Tiled_Backing_Store_Data *priv);
137 static inline void _ewk_tiled_backing_store_changed(Ewk_Tiled_Backing_Store_Data *priv);
138
139 static inline void _ewk_tiled_backing_store_updates_process(Ewk_Tiled_Backing_Store_Data *priv)
140 {
141     void *data = NULL;
142
143     /* Do not process updates. Note that we still want to get updates requests
144      * in the queue in order to not miss any updates after the render is
145      * resumed.
146      */
147     if (priv->render.suspend || !evas_object_visible_get(priv->self))
148         return;
149
150     if (priv->process.pre_cb)
151         data = priv->process.pre_cb(priv->process.pre_data, priv->self);
152
153     ewk_tile_matrix_updates_process(priv->model.matrix);
154
155     if (priv->process.post_cb)
156         priv->process.post_cb(priv->process.post_data, data, priv->self);
157 }
158
159 static int _ewk_tiled_backing_store_flush(void *data)
160 {
161     Ewk_Tiled_Backing_Store_Data *priv = data;
162     Ewk_Tile_Unused_Cache *tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
163
164     if (tuc) {
165         DBG("flush unused tile cache.");
166         ewk_tile_unused_cache_auto_flush(tuc);
167     } else
168         ERR("no cache?!");
169
170     return 0;
171 }
172
173 static Ewk_Tile *_ewk_tiled_backing_store_tile_new(Ewk_Tiled_Backing_Store_Data *priv, unsigned long col, unsigned long row, float zoom)
174 {
175     Ewk_Tile *t;
176     Evas *evas = evas_object_evas_get(priv->self);
177     if (!evas) {
178         CRITICAL("evas_object_evas_get failed!");
179         return NULL;
180     }
181
182     t = ewk_tile_matrix_tile_new
183         (priv->model.matrix, evas, col, row, zoom);
184
185     if (!t) {
186         CRITICAL("ewk_tile_matrix_tile_new failed!");
187         return NULL;
188     }
189
190     return t;
191 }
192
193 static void _ewk_tiled_backing_store_item_move(Ewk_Tiled_Backing_Store_Item *it, Evas_Coord x, Evas_Coord y)
194 {
195     it->geometry.x = x;
196     it->geometry.y = y;
197
198     if (it->tile)
199         evas_object_move(it->tile->image, x, y);
200 }
201
202 static void _ewk_tiled_backing_store_item_resize(Ewk_Tiled_Backing_Store_Item *it, Evas_Coord w, Evas_Coord h)
203 {
204     it->geometry.w = w;
205     it->geometry.h = h;
206
207     if (it->tile) {
208         evas_object_resize(it->tile->image, w, h);
209         evas_object_image_fill_set(it->tile->image, 0, 0, w, h);
210     }
211 }
212
213 static void _ewk_tiled_backing_store_tile_associate(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tile *t, Ewk_Tiled_Backing_Store_Item *it)
214 {
215     if (it->tile)
216         CRITICAL("it->tile=%p, but it should be NULL!", it->tile);
217     it->tile = t;
218     evas_object_move(it->tile->image, it->geometry.x, it->geometry.y);
219     evas_object_resize(it->tile->image, it->geometry.w, it->geometry.h);
220     evas_object_image_fill_set
221         (it->tile->image, 0, 0, it->geometry.w, it->geometry.h);
222     evas_object_image_smooth_scale_set(it->tile->image, it->smooth_scale);
223
224     if (!ewk_tile_visible_get(t))
225         evas_object_smart_member_add(t->image, priv->self);
226
227     ewk_tile_show(t);
228 }
229
230 static void _ewk_tiled_backing_store_tile_dissociate(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tiled_Backing_Store_Item *it, double last_used)
231 {
232     Ewk_Tile_Unused_Cache *tuc;
233     ewk_tile_hide(it->tile);
234     if (!ewk_tile_visible_get(it->tile))
235         evas_object_smart_member_del(it->tile->image);
236     ewk_tile_matrix_tile_put(priv->model.matrix, it->tile, last_used);
237     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
238     ewk_tile_unused_cache_auto_flush(tuc);
239
240     it->tile = NULL;
241 }
242
243 static void _ewk_tiled_backing_store_tile_dissociate_all(Ewk_Tiled_Backing_Store_Data *priv)
244 {
245     Eina_Inlist *it;
246     Ewk_Tiled_Backing_Store_Item *item;
247     int i;
248     double last_used = ecore_loop_time_get();
249
250     for (i = 0; i < priv->view.rows; i++) {
251         it = priv->view.items[i];
252         EINA_INLIST_FOREACH(it, item)
253             if (item->tile)
254                 _ewk_tiled_backing_store_tile_dissociate(priv, item, last_used);
255     }
256 }
257
258 static inline Eina_Bool _ewk_tiled_backing_store_pre_render_request_add(Ewk_Tiled_Backing_Store_Data *priv, unsigned long col, unsigned long row, float zoom, Ewk_Tiled_Backing_Store_Pre_Render_Priority priority)
259 {
260     Ewk_Tiled_Backing_Store_Pre_Render_Request *r;
261
262     MALLOC_OR_OOM_RET(r, sizeof(*r), EINA_FALSE);
263
264     if (priority == PRE_RENDER_PRIORITY_HIGH)
265         priv->render.pre_render_requests = eina_inlist_prepend
266             (priv->render.pre_render_requests, EINA_INLIST_GET(r));
267     else
268         priv->render.pre_render_requests = eina_inlist_append
269             (priv->render.pre_render_requests, EINA_INLIST_GET(r));
270
271     r->col = col;
272     r->row = row;
273     r->zoom = zoom;
274
275     return EINA_TRUE;
276 }
277
278 static inline void _ewk_tiled_backing_store_pre_render_request_del(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tiled_Backing_Store_Pre_Render_Request *r)
279 {
280     priv->render.pre_render_requests = eina_inlist_remove
281         (priv->render.pre_render_requests, EINA_INLIST_GET(r));
282     free(r);
283 }
284
285 static inline Ewk_Tiled_Backing_Store_Pre_Render_Request *_ewk_tiled_backing_store_pre_render_request_first(const Ewk_Tiled_Backing_Store_Data *priv)
286 {
287     return EINA_INLIST_CONTAINER_GET(
288         priv->render.pre_render_requests,
289         Ewk_Tiled_Backing_Store_Pre_Render_Request);
290 }
291
292 static void _ewk_tiled_backing_store_pre_render_request_flush(Ewk_Tiled_Backing_Store_Data *priv)
293 {
294     Eina_Inlist **pl = &priv->render.pre_render_requests;
295     while (*pl) {
296         Ewk_Tiled_Backing_Store_Pre_Render_Request *r;
297         r = _ewk_tiled_backing_store_pre_render_request_first(priv);
298         *pl = eina_inlist_remove(*pl, *pl);
299         free(r);
300     }
301 }
302
303 static void _ewk_tiled_backing_store_pre_render_request_clear(Ewk_Tiled_Backing_Store_Data *priv)
304 {
305     Eina_Inlist **pl = &priv->render.pre_render_requests;
306     Eina_Inlist *iter = *pl, *tmp;
307     while (iter) {
308         Ewk_Tiled_Backing_Store_Pre_Render_Request *r =
309             EINA_INLIST_CONTAINER_GET(
310                 iter, Ewk_Tiled_Backing_Store_Pre_Render_Request);
311         tmp = iter->next;
312         *pl = eina_inlist_remove(*pl, iter);
313         iter = tmp;
314         free(r);
315     }
316 }
317
318 /* assumes priv->process.pre_cb was called if required! */
319 static void _ewk_tiled_backing_store_pre_render_request_process_single(Ewk_Tiled_Backing_Store_Data *priv)
320 {
321     Ewk_Tiled_Backing_Store_Pre_Render_Request *req;
322     Eina_Rectangle area;
323     Ewk_Tile_Matrix *tm = priv->model.matrix;
324     Ewk_Tile *t;
325     Ewk_Tile_Unused_Cache *tuc;
326     unsigned long col, row;
327     float zoom;
328     double last_used = ecore_loop_time_get();
329
330     req = _ewk_tiled_backing_store_pre_render_request_first(priv);
331     if (!req)
332         return;
333
334     col = req->col;
335     row = req->row;
336     zoom = req->zoom;
337
338     if (ewk_tile_matrix_tile_exact_exists(tm, col, row, zoom)) {
339         DBG("no pre-render required for tile %lu,%lu @ %f.", col, row, zoom);
340         goto end;
341     }
342
343     t = _ewk_tiled_backing_store_tile_new(priv, col, row, zoom);
344     if (!t)
345         goto end;
346
347     area.x = 0;
348     area.y = 0;
349     area.w = priv->view.tile.w;
350     area.h = priv->view.tile.h;
351
352     priv->render.cb(priv->render.data, t, &area);
353     evas_object_image_data_update_add(
354         t->image,
355         area.x, area.y, area.w, area.h);
356     ewk_tile_matrix_tile_updates_clear(tm, t);
357
358     ewk_tile_matrix_tile_put(tm, t, last_used);
359
360 end:
361     _ewk_tiled_backing_store_pre_render_request_del(priv, req);
362     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
363     ewk_tile_unused_cache_auto_flush(tuc);
364 }
365
366 static Eina_Bool _ewk_tiled_backing_store_item_process_idler_cb(void *data)
367 {
368     Ewk_Tiled_Backing_Store_Data *priv = data;
369
370     if (priv->process.pre_cb)
371         data = priv->process.pre_cb(priv->process.pre_data, priv->self);
372
373     _ewk_tiled_backing_store_pre_render_request_process_single(priv);
374
375     if (priv->process.post_cb)
376         priv->process.post_cb(priv->process.post_data, data, priv->self);
377
378     if (!priv->render.pre_render_requests) {
379         priv->render.idler = NULL;
380         return EINA_FALSE;
381     }
382
383     return EINA_TRUE;
384 }
385
386 static inline void _ewk_tiled_backing_store_item_process_idler_stop(Ewk_Tiled_Backing_Store_Data *priv)
387 {
388     if (!priv->render.idler)
389         return;
390
391     ecore_idler_del(priv->render.idler);
392     priv->render.idler = NULL;
393 }
394
395 static inline void _ewk_tiled_backing_store_item_process_idler_start(Ewk_Tiled_Backing_Store_Data *priv)
396 {
397     if (priv->render.idler)
398         return;
399     priv->render.idler = ecore_idler_add(
400         _ewk_tiled_backing_store_item_process_idler_cb, priv);
401 }
402
403 static Eina_Bool _ewk_tiled_backing_store_disable_render(Ewk_Tiled_Backing_Store_Data *priv)
404 {
405     if (priv->render.suspend)
406         return EINA_TRUE;
407
408     priv->render.suspend = EINA_TRUE;
409     _ewk_tiled_backing_store_item_process_idler_stop(priv);
410     return EINA_TRUE;
411 }
412
413 static Eina_Bool _ewk_tiled_backing_store_enable_render(Ewk_Tiled_Backing_Store_Data *priv)
414 {
415     if (!priv->render.suspend)
416         return EINA_TRUE;
417
418     priv->render.suspend = EINA_FALSE;
419
420     _ewk_tiled_backing_store_fill_renderers(priv);
421     _ewk_tiled_backing_store_item_process_idler_start(priv);
422
423     return EINA_TRUE;
424 }
425
426 static inline Eina_Bool _ewk_tiled_backing_store_item_fill(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tiled_Backing_Store_Item *it, unsigned long col, unsigned long row)
427 {
428     unsigned long m_col = priv->model.base.col + col;
429     unsigned long m_row = priv->model.base.row + row;
430     double last_used = ecore_loop_time_get();
431
432     if (m_col >= priv->model.cur.cols || m_row >= priv->model.cur.rows) {
433         if (it->tile)
434             _ewk_tiled_backing_store_tile_dissociate(priv, it, last_used);
435     } else {
436         Ewk_Tile *t;
437         const float zoom = priv->view.tile.zoom;
438
439         if (it->tile) {
440             Ewk_Tile *old = it->tile;
441             if (old->row != m_row || old->col != m_col || old->zoom != zoom)
442                 _ewk_tiled_backing_store_tile_dissociate(priv, it, last_used);
443             else if (old->row == m_row && old->col == m_col && old->zoom == zoom)
444                 goto end;
445         }
446
447         t = ewk_tile_matrix_tile_exact_get(priv->model.matrix, m_col, m_row, zoom);
448
449         if (!t) {
450             /* NOTE: it never returns NULL if it->tile was set! */
451             if (it->tile) {
452                 CRITICAL("it->tile=%p, but it should be NULL!", it->tile);
453                 _ewk_tiled_backing_store_tile_dissociate(priv, it,
454                                                          last_used);
455             }
456
457             /* Do not add new requests to the render queue */
458             if (!priv->render.suspend) {
459                 t = _ewk_tiled_backing_store_tile_new(priv, m_col, m_row, zoom);
460                 if (!t)
461                     return EINA_FALSE;
462                 _ewk_tiled_backing_store_tile_associate(priv, t, it);
463             }
464         } else if (t != it->tile) {
465             if (it->tile)
466                 _ewk_tiled_backing_store_tile_dissociate(priv,
467                                                              it, last_used);
468             _ewk_tiled_backing_store_tile_associate(priv, t, it);
469         }
470
471       end:
472
473         return EINA_TRUE;
474     }
475
476     return EINA_TRUE;
477 }
478
479 static Ewk_Tiled_Backing_Store_Item *_ewk_tiled_backing_store_item_add(Ewk_Tiled_Backing_Store_Data *priv, unsigned long col, unsigned long row)
480 {
481     Ewk_Tiled_Backing_Store_Item *it;
482     Evas_Coord x, y, tw, th;
483
484     DBG("o=%p", priv->self);
485
486     MALLOC_OR_OOM_RET(it, sizeof(*it), NULL);
487
488     tw = priv->view.tile.w;
489     th = priv->view.tile.h;
490     x = priv->view.offset.base.x + priv->view.x + tw  *col;
491     y = priv->view.offset.base.y + priv->view.y + th  *row;
492
493     it->tile = NULL;
494
495     it->smooth_scale = priv->view.tile.zoom_weak_smooth_scale;
496     _ewk_tiled_backing_store_item_move(it, x, y);
497     _ewk_tiled_backing_store_item_resize(it, tw, th);
498     if (!_ewk_tiled_backing_store_item_fill(priv, it, col, row)) {
499         free(it);
500         return NULL;
501     }
502
503     return it;
504 }
505
506 static void _ewk_tiled_backing_store_item_del(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tiled_Backing_Store_Item *it)
507 {
508     if (it->tile) {
509         double last_used = ecore_loop_time_get();
510         _ewk_tiled_backing_store_tile_dissociate(priv, it, last_used);
511     }
512
513     free(it);
514 }
515
516 static void _ewk_tiled_backing_store_item_smooth_scale_set(Ewk_Tiled_Backing_Store_Item *it, Eina_Bool smooth_scale)
517 {
518     if (it->smooth_scale == smooth_scale)
519         return;
520
521     if (it->tile)
522         evas_object_image_smooth_scale_set(it->tile->image, smooth_scale);
523 }
524
525 static inline void _ewk_tiled_backing_store_changed(Ewk_Tiled_Backing_Store_Data *priv)
526 {
527     if (priv->changed.any)
528         return;
529     evas_object_smart_changed(priv->self);
530     priv->changed.any = EINA_TRUE;
531 }
532
533 static void _ewk_tiled_backing_store_view_cols_end_del(Ewk_Tiled_Backing_Store_Data *priv, Eina_Inlist **p_row, unsigned int count)
534 {
535     Eina_Inlist *n;
536     unsigned int i;
537
538     if (!count)
539         return;
540
541     n = (*p_row)->last;
542
543     for (i = 0; i < count; i++) {
544         Ewk_Tiled_Backing_Store_Item *it;
545         it = EINA_INLIST_CONTAINER_GET(n, Ewk_Tiled_Backing_Store_Item);
546         n = n->prev;
547         *p_row = eina_inlist_remove(*p_row, EINA_INLIST_GET(it));
548         _ewk_tiled_backing_store_item_del(priv, it);
549     }
550 }
551
552 static Eina_Bool _ewk_tiled_backing_store_view_cols_end_add(Ewk_Tiled_Backing_Store_Data *priv, Eina_Inlist **p_row, unsigned int base_col, unsigned int count)
553 {
554     unsigned int i, r = p_row - priv->view.items;
555
556     for (i = 0; i < count; i++, base_col++) {
557         Ewk_Tiled_Backing_Store_Item *it;
558
559         it = _ewk_tiled_backing_store_item_add(priv, base_col, r);
560         if (!it) {
561             CRITICAL("failed to add column %u of %u in row %u.", i, count, r);
562             _ewk_tiled_backing_store_view_cols_end_del(priv, p_row, i);
563             return EINA_FALSE;
564         }
565
566         *p_row = eina_inlist_append(*p_row, EINA_INLIST_GET(it));
567     }
568     return EINA_TRUE;
569 }
570
571 static void _ewk_tiled_backing_store_view_row_del(Ewk_Tiled_Backing_Store_Data *priv, Eina_Inlist *row)
572 {
573     while (row) {
574         Ewk_Tiled_Backing_Store_Item *it;
575         it = EINA_INLIST_CONTAINER_GET(row, Ewk_Tiled_Backing_Store_Item);
576         row = row->next;
577         _ewk_tiled_backing_store_item_del(priv, it);
578     }
579 }
580
581 static void _ewk_tiled_backing_store_view_rows_range_del(Ewk_Tiled_Backing_Store_Data *priv, Eina_Inlist **start, Eina_Inlist **end)
582 {
583     for (; start < end; start++) {
584         _ewk_tiled_backing_store_view_row_del(priv, *start);
585         *start = NULL;
586     }
587 }
588
589 static void _ewk_tiled_backing_store_view_rows_all_del(Ewk_Tiled_Backing_Store_Data *priv)
590 {
591     Eina_Inlist **start;
592     Eina_Inlist **end;
593
594     start = priv->view.items;
595     end = priv->view.items + priv->view.rows;
596     _ewk_tiled_backing_store_view_rows_range_del(priv, start, end);
597
598     free(priv->view.items);
599     priv->view.items = NULL;
600     priv->view.cols = 0;
601     priv->view.rows = 0;
602 }
603
604 static void _ewk_tiled_backing_store_render(void *data, Ewk_Tile *t, const Eina_Rectangle *area)
605 {
606     Ewk_Tiled_Backing_Store_Data *priv = data;
607
608     INF("TODO %p (visible? %d) [%lu,%lu] %d,%d + %dx%d",
609         t, t->visible, t->col, t->row, area->x, area->y, area->w, area->h);
610
611     if (!t->visible)
612         return;
613
614     if (priv->view.tile.w != t->w || priv->view.tile.h != t->h)
615         return; // todo: remove me later, don't even flag as dirty!
616
617     EINA_SAFETY_ON_NULL_RETURN(priv->render.cb);
618     if (!priv->render.cb(priv->render.data, t, area))
619         return;
620
621     evas_object_image_data_update_add(t->image, area->x, area->y, area->w, area->h);
622 }
623
624 static inline void _ewk_tiled_backing_store_model_matrix_create(Ewk_Tiled_Backing_Store_Data *priv, Ewk_Tile_Unused_Cache *tuc)
625 {
626     if (priv->model.matrix) {
627         _ewk_tiled_backing_store_view_rows_all_del(priv);
628
629         priv->changed.offset = EINA_FALSE;
630         priv->changed.size = EINA_TRUE;
631
632         ewk_tile_matrix_free(priv->model.matrix);
633     }
634
635     priv->model.matrix = ewk_tile_matrix_new(tuc, priv->model.cur.cols, priv->model.cur.rows, priv->cspace, _ewk_tiled_backing_store_render, priv);
636 }
637
638 static void _ewk_tiled_backing_store_smart_member_del(Evas_Object *o, Evas_Object *member)
639 {
640     PRIV_DATA_GET_OR_RETURN(o, priv);
641     if (!priv->contents_clipper)
642         return;
643     evas_object_clip_unset(member);
644     if (!evas_object_clipees_get(priv->contents_clipper))
645         evas_object_hide(priv->contents_clipper);
646 }
647
648 static void _ewk_tiled_backing_store_smart_member_add(Evas_Object *o, Evas_Object *member)
649 {
650     PRIV_DATA_GET_OR_RETURN(o, priv);
651     if (!priv->contents_clipper)
652         return;
653     evas_object_clip_set(member, priv->contents_clipper);
654     if (evas_object_visible_get(o))
655         evas_object_show(priv->contents_clipper);
656 }
657
658 #ifdef DEBUG_MEM_LEAKS
659 static void _ewk_tiled_backing_store_mem_dbg(Ewk_Tiled_Backing_Store_Data *priv)
660 {
661     static int run = 0;
662
663     run++;
664
665     printf("\n--- BEGIN DEBUG TILED BACKING STORE MEMORY [%d] --\n"
666            "t=%0.2f, obj=%p, priv=%p, view.items=%p, matrix=%p\n",
667            run, ecore_loop_time_get(),
668            priv->self, priv, priv->view.items, priv->model.matrix);
669
670     ewk_tile_matrix_dbg(priv->model.matrix);
671     ewk_tile_accounting_dbg();
672
673     printf("--- END DEBUG TILED BACKING STORE MEMORY [%d] --\n\n", run);
674 }
675
676 static Eina_Bool _ewk_tiled_backing_store_sig_usr(void *data, int type, void *event)
677 {
678     Ecore_Event_Signal_User *sig = (Ecore_Event_Signal_User*)event;
679     Ewk_Tiled_Backing_Store_Data *priv = (Ewk_Tiled_Backing_Store_Data*)data;
680
681     if (sig->number == 2) {
682         Ewk_Tile_Unused_Cache *tuc;
683         tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
684         ewk_tile_unused_cache_auto_flush(tuc);
685     }
686
687     _ewk_tiled_backing_store_view_dbg(priv);
688     _ewk_tiled_backing_store_mem_dbg(priv);
689     return EINA_TRUE;
690 }
691 #endif
692
693 static void _ewk_tiled_backing_store_smart_add(Evas_Object *o)
694 {
695     Ewk_Tiled_Backing_Store_Data *priv;
696
697     DBG("o=%p", o);
698
699     CALLOC_OR_OOM_RET(priv, sizeof(*priv));
700
701     priv->self = o;
702     priv->view.tile.zoom = 1.0;
703     priv->view.tile.w = DEFAULT_TILE_W;
704     priv->view.tile.h = DEFAULT_TILE_H;
705     priv->view.offset.cur.x = 0;
706     priv->view.offset.cur.y = 0;
707     priv->view.offset.old.x = 0;
708     priv->view.offset.old.y = 0;
709     priv->view.offset.base.x = 0;
710     priv->view.offset.base.y = 0;
711
712     priv->model.base.col = 0;
713     priv->model.base.row = 0;
714     priv->model.cur.cols = 1;
715     priv->model.cur.rows = 1;
716     priv->model.old.cols = 0;
717     priv->model.old.rows = 0;
718     priv->model.width = 0;
719     priv->model.height = 0;
720     priv->render.suspend = EINA_FALSE;
721     priv->cspace = EVAS_COLORSPACE_ARGB8888; // TODO: detect it.
722
723     evas_object_smart_data_set(o, priv);
724     _parent_sc.add(o);
725
726     priv->contents_clipper = evas_object_rectangle_add(
727         evas_object_evas_get(o));
728     evas_object_move(priv->contents_clipper, 0, 0);
729     evas_object_resize(priv->contents_clipper,
730                        priv->model.width, priv->model.height);
731     evas_object_color_set(priv->contents_clipper, 255, 255, 255, 255);
732     evas_object_show(priv->contents_clipper);
733     evas_object_smart_member_add(priv->contents_clipper, o);
734
735     _ewk_tiled_backing_store_model_matrix_create(priv, NULL);
736     evas_object_move(priv->base.clipper, 0, 0);
737     evas_object_resize(priv->base.clipper, 0, 0);
738     evas_object_clip_set(priv->contents_clipper, priv->base.clipper);
739
740 #ifdef DEBUG_MEM_LEAKS
741     priv->sig_usr = ecore_event_handler_add
742         (ECORE_EVENT_SIGNAL_USER, _ewk_tiled_backing_store_sig_usr, priv);
743 #endif
744 }
745
746 static void _ewk_tiled_backing_store_smart_del(Evas_Object *o)
747 {
748     PRIV_DATA_GET_OR_RETURN(o, priv);
749     DBG("o=%p", o);
750     Ewk_Tile_Unused_Cache *tuc;
751
752     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
753     ewk_tile_unused_cache_unlock_area(tuc);
754
755     _ewk_tiled_backing_store_flush(priv);
756
757     _ewk_tiled_backing_store_pre_render_request_flush(priv);
758     _ewk_tiled_backing_store_item_process_idler_stop(priv);
759     _ewk_tiled_backing_store_view_rows_all_del(priv);
760
761 #ifdef DEBUG_MEM_LEAKS
762     _ewk_tiled_backing_store_mem_dbg(priv);
763     if (priv->sig_usr)
764         priv->sig_usr = ecore_event_handler_del(priv->sig_usr);
765 #endif
766
767     ewk_tile_matrix_free(priv->model.matrix);
768     evas_object_smart_member_del(priv->contents_clipper);
769     evas_object_del(priv->contents_clipper);
770
771     _parent_sc.del(o);
772
773 #ifdef DEBUG_MEM_LEAKS
774     printf("\nIMPORTANT: TILED BACKING STORE DELETED (may be real leaks)\n");
775     ewk_tile_accounting_dbg();
776 #endif
777 }
778
779 static void _ewk_tiled_backing_store_smart_move(Evas_Object *o, Evas_Coord x, Evas_Coord y)
780 {
781     DBG("o=%p, new pos: %dx%d", o, x, y);
782
783     PRIV_DATA_GET_OR_RETURN(o, priv);
784
785     if (priv->changed.pos)
786         return;
787
788     if (priv->view.x == x && priv->view.y == y)
789         return;
790
791     priv->changed.pos = EINA_TRUE;
792     _ewk_tiled_backing_store_changed(priv);
793 }
794
795 static void _ewk_tiled_backing_store_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
796 {
797     DBG("o=%p, new size: %dx%d", o, w, h);
798
799     PRIV_DATA_GET_OR_RETURN(o, priv);
800
801     if (priv->changed.size)
802         return;
803
804     if (priv->view.w == w && priv->view.h == h)
805         return;
806
807     priv->changed.size = EINA_TRUE;
808     _ewk_tiled_backing_store_changed(priv);
809 }
810
811 static void _ewk_tiled_backing_store_recalc_renderers(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord w, Evas_Coord h, Evas_Coord tw, Evas_Coord th)
812 {
813     long cols, rows, old_rows, old_cols;
814     INF("o=%p, new size: %dx%d", priv->self, w, h);
815
816     cols = 1 + (int)ceil((float)w / (float)tw);
817     rows = 1 + (int)ceil((float)h / (float)th);
818
819     INF("o=%p new grid size cols: %ld, rows: %ld, was %ld, %ld",
820         priv->self, cols, rows, priv->view.cols, priv->view.rows);
821
822     if (priv->view.cols == cols && priv->view.rows == rows)
823         return;
824
825     old_cols = priv->view.cols;
826     old_rows = priv->view.rows;
827
828     if (rows < old_rows) {
829         Eina_Inlist **start, **end;
830         start = priv->view.items + rows;
831         end = priv->view.items + old_rows;
832         _ewk_tiled_backing_store_view_rows_range_del(priv, start, end);
833     }
834     REALLOC_OR_OOM_RET(priv->view.items, sizeof(Eina_Inlist*) * (int)rows);
835     priv->view.rows = rows;
836     priv->view.cols = cols;
837     if (rows > old_rows) {
838         Eina_Inlist **start, **end;
839         start = priv->view.items + old_rows;
840         end = priv->view.items + rows;
841         for (; start < end; start++) {
842             Eina_Bool r;
843             *start = NULL;
844             r = _ewk_tiled_backing_store_view_cols_end_add
845                 (priv, start, 0, cols);
846             if (!r) {
847                 CRITICAL("failed to allocate %ld columns", cols);
848                 _ewk_tiled_backing_store_view_rows_range_del
849                     (priv, priv->view.items + old_rows, start);
850                 priv->view.rows = old_rows;
851                 return;
852             }
853         }
854     }
855
856     if (cols != old_cols) {
857         Eina_Inlist **start, **end;
858         int todo = cols - old_cols;
859         start = priv->view.items;
860         end = start + MIN(old_rows, rows);
861         if (todo > 0) {
862             for (; start < end; start++) {
863                 Eina_Bool r;
864                 r = _ewk_tiled_backing_store_view_cols_end_add
865                     (priv, start, old_cols, todo);
866                 if (!r) {
867                     CRITICAL("failed to allocate %d columns!", todo);
868
869                     for (start--; start >= priv->view.items; start--)
870                         _ewk_tiled_backing_store_view_cols_end_del(priv, start, todo);
871                     if (rows > old_rows) {
872                         start = priv->view.items + old_rows;
873                         end = priv->view.items + rows;
874                         for (; start < end; start++)
875                             _ewk_tiled_backing_store_view_cols_end_del(priv, start, todo);
876                     }
877                     return;
878                 }
879             }
880         } else if (todo < 0) {
881             todo = -todo;
882             for (; start < end; start++)
883                 _ewk_tiled_backing_store_view_cols_end_del(priv, start, todo);
884         }
885     }
886
887     _ewk_tiled_backing_store_fill_renderers(priv);
888 }
889
890 static void _ewk_tiled_backing_store_smart_calculate_size(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord w, Evas_Coord h)
891 {
892     evas_object_resize(priv->base.clipper, w, h);
893
894     priv->view.w = w;
895     priv->view.h = h;
896
897     _ewk_tiled_backing_store_recalc_renderers(
898         priv, w, h, priv->view.tile.w, priv->view.tile.h);
899 }
900
901 // TODO: remove me later.
902 static inline void _ewk_tiled_backing_store_view_dbg(const Ewk_Tiled_Backing_Store_Data *priv)
903 {
904     Eina_Inlist **start, **end;
905     printf("tiles=%2ld,%2ld  model=%2ld,%2ld [%dx%d] base=%+3ld,%+4ld offset=%+4d,%+4d old=%+4d,%+4d base=%+3d,%+3d\n",
906            priv->view.cols, priv->view.rows,
907            priv->model.cur.cols, priv->model.cur.rows,
908            priv->model.width, priv->model.height,
909            priv->model.base.col, priv->model.base.row,
910            priv->view.offset.cur.x, priv->view.offset.cur.y,
911            priv->view.offset.old.x, priv->view.offset.old.y,
912            priv->view.offset.base.x, priv->view.offset.base.y);
913
914     start = priv->view.items;
915     end = priv->view.items + priv->view.rows;
916     for (; start < end; start++) {
917         const Ewk_Tiled_Backing_Store_Item *it;
918
919         EINA_INLIST_FOREACH(*start, it) {
920             printf(" %+4d,%+4d ", it->geometry.x, it->geometry.y);
921
922             if (!it->tile)
923                 printf("            ;");
924             else
925                 printf("%8p %lu,%lu;", it->tile, it->tile->col, it->tile->row);
926         }
927         printf("\n");
928     }
929     printf("---\n");
930 }
931
932 /**
933  * @internal
934  * Move top row down as last.
935  *
936  * The final result is visually the same, but logically the top that
937  * went out of screen is now at bottom and filled with new model items.
938  *
939  * This is worth just when @a count is smaller than @c
940  * priv->view.rows, after that one is refilling the whole matrix so it
941  * is better to trigger full refill.
942  *
943  * @param count the number of times to repeat the process.
944  */
945 static void _ewk_tiled_backing_store_view_wrap_up(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y, unsigned int count)
946 {
947     unsigned int last_row = priv->view.rows - 1;
948     Evas_Coord tw = priv->view.tile.w;
949     Evas_Coord th = priv->view.tile.h;
950     Evas_Coord off_y = priv->view.offset.base.y + count * th;
951     Evas_Coord oy = y + (last_row - count + 1) * th + off_y;
952     Eina_Inlist **itr_start, **itr_end;
953
954     itr_start = priv->view.items;
955     itr_end = itr_start + last_row;
956
957     for (; count > 0; count--) {
958         Eina_Inlist **itr;
959         Eina_Inlist *tmp = *itr_start;
960         Ewk_Tiled_Backing_Store_Item *it;
961         Evas_Coord ox = x + priv->view.offset.base.x;
962         int c = 0;
963
964         for (itr = itr_start; itr < itr_end; itr++)
965             *itr = *(itr + 1);
966         *itr = tmp;
967
968         priv->model.base.row++;
969         EINA_INLIST_FOREACH(tmp, it) {
970             _ewk_tiled_backing_store_item_move(it, ox, oy);
971             ox += tw;
972             _ewk_tiled_backing_store_item_fill(priv, it, c, last_row);
973             c++;
974         }
975         oy += th;
976     }
977     priv->view.offset.base.y = off_y;
978 }
979
980 /**
981  * @internal
982  * Move bottom row up as first.
983  *
984  * The final result is visually the same, but logically the bottom that
985  * went out of screen is now at top and filled with new model items.
986  *
987  * This is worth just when @a count is smaller than @c
988  * priv->view.rows, after that one is refilling the whole matrix so it
989  * is better to trigger full refill.
990  *
991  * @param count the number of times to repeat the process.
992  */
993 static void _ewk_tiled_backing_store_view_wrap_down(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y, unsigned int count)
994 {
995     Evas_Coord tw = priv->view.tile.w;
996     Evas_Coord th = priv->view.tile.h;
997     Evas_Coord off_y = priv->view.offset.base.y - count * th;
998     Evas_Coord oy = y + off_y + (count - 1) * th;
999     Eina_Inlist **itr_start, **itr_end;
1000
1001     itr_start = priv->view.items + priv->view.rows - 1;
1002     itr_end = priv->view.items;
1003
1004     for (; count > 0; count--) {
1005         Eina_Inlist **itr;
1006         Eina_Inlist *tmp = *itr_start;
1007         Ewk_Tiled_Backing_Store_Item *it;
1008         Evas_Coord ox = x + priv->view.offset.base.x;
1009         int c = 0;
1010
1011         for (itr = itr_start; itr > itr_end; itr--)
1012             *itr = *(itr - 1);
1013         *itr = tmp;
1014
1015         priv->model.base.row--;
1016         EINA_INLIST_FOREACH(tmp, it) {
1017             _ewk_tiled_backing_store_item_move(it, ox, oy);
1018             ox += tw;
1019             _ewk_tiled_backing_store_item_fill(priv, it, c, 0);
1020             c++;
1021         }
1022         oy -= th;
1023     }
1024     priv->view.offset.base.y = off_y;
1025 }
1026
1027 /**
1028  * @internal
1029  * Move left-most (first) column right as last (right-most).
1030  *
1031  * The final result is visually the same, but logically the first col that
1032  * went out of screen is now at last and filled with new model items.
1033  *
1034  * This is worth just when @a count is smaller than @c
1035  * priv->view.cols, after that one is refilling the whole matrix so it
1036  * is better to trigger full refill.
1037  *
1038  * @param count the number of times to repeat the process.
1039  */
1040 static void _ewk_tiled_backing_store_view_wrap_left(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y, unsigned int count)
1041 {
1042     unsigned int r, last_col = priv->view.cols - 1;
1043     Evas_Coord tw = priv->view.tile.w;
1044     Evas_Coord th = priv->view.tile.h;
1045     Evas_Coord off_x = priv->view.offset.base.x + count * tw;
1046     Evas_Coord oy = y + priv->view.offset.base.y;
1047     Eina_Inlist **itr;
1048     Eina_Inlist **itr_end;
1049
1050     itr = priv->view.items;
1051     itr_end = itr + priv->view.rows;
1052     r = 0;
1053
1054     priv->model.base.col += count;
1055
1056     for (; itr < itr_end; itr++, r++) {
1057         Evas_Coord ox = x + (last_col - count + 1) * tw + off_x;
1058         unsigned int i, c = last_col - count + 1;
1059
1060         for (i = 0; i < count; i++, c++, ox += tw) {
1061             Ewk_Tiled_Backing_Store_Item *it;
1062             it = EINA_INLIST_CONTAINER_GET(*itr, Ewk_Tiled_Backing_Store_Item);
1063             *itr = eina_inlist_demote(*itr, *itr);
1064
1065             _ewk_tiled_backing_store_item_move(it, ox, oy);
1066             _ewk_tiled_backing_store_item_fill(priv, it, c, r);
1067         }
1068         oy += th;
1069     }
1070
1071     priv->view.offset.base.x = off_x;
1072 }
1073
1074 /**
1075  * @internal
1076  * Move right-most (last) column left as first (left-most).
1077  *
1078  * The final result is visually the same, but logically the last col that
1079  * went out of screen is now at first and filled with new model items.
1080  *
1081  * This is worth just when @a count is smaller than @c
1082  * priv->view.cols, after that one is refilling the whole matrix so it
1083  * is better to trigger full refill.
1084  *
1085  * @param count the number of times to repeat the process.
1086  */
1087 static void _ewk_tiled_backing_store_view_wrap_right(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y, unsigned int count)
1088 {
1089     unsigned int r;
1090     Evas_Coord tw = priv->view.tile.w;
1091     Evas_Coord th = priv->view.tile.h;
1092     Evas_Coord off_x = priv->view.offset.base.x - count * tw;
1093     Evas_Coord oy = y + priv->view.offset.base.y;
1094     Eina_Inlist **itr, **itr_end;
1095
1096     itr = priv->view.items;
1097     itr_end = itr + priv->view.rows;
1098     r = 0;
1099
1100     priv->model.base.col -= count;
1101
1102     for (; itr < itr_end; itr++, r++) {
1103         Evas_Coord ox = x + (count - 1) * tw + off_x;
1104         unsigned int i, c = count - 1;
1105
1106         for (i = 0; i < count; i++, c--, ox -= tw) {
1107             Ewk_Tiled_Backing_Store_Item *it;
1108             it = EINA_INLIST_CONTAINER_GET((*itr)->last, Ewk_Tiled_Backing_Store_Item);
1109             *itr = eina_inlist_promote(*itr, (*itr)->last);
1110
1111             _ewk_tiled_backing_store_item_move(it, ox, oy);
1112             _ewk_tiled_backing_store_item_fill(priv, it, c, r);
1113         }
1114         oy += th;
1115     }
1116
1117     priv->view.offset.base.x = off_x;
1118 }
1119
1120 static void _ewk_tiled_backing_store_view_refill(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y, int step_x, int step_y)
1121 {
1122     Eina_Inlist **itr, **itr_end;
1123     Evas_Coord base_ox, oy, tw, th;
1124     unsigned int r;
1125
1126     evas_object_move(priv->base.clipper, x, y);
1127
1128     tw = priv->view.tile.w;
1129     th = priv->view.tile.h;
1130
1131     base_ox = x + priv->view.offset.base.x;
1132     oy = y + priv->view.offset.base.y;
1133
1134     itr = priv->view.items;
1135     itr_end = itr + priv->view.rows;
1136     r = 0;
1137
1138     priv->model.base.col -= step_x;
1139     priv->model.base.row -= step_y;
1140
1141     for (; itr < itr_end; itr++, r++) {
1142         Ewk_Tiled_Backing_Store_Item *it;
1143         Evas_Coord ox = base_ox;
1144         unsigned int c = 0;
1145         EINA_INLIST_FOREACH(*itr, it) {
1146             _ewk_tiled_backing_store_item_fill(priv, it, c, r);
1147             _ewk_tiled_backing_store_item_move(it, ox, oy);
1148             c++;
1149             ox += tw;
1150         }
1151         oy += th;
1152     }
1153 }
1154
1155 static void _ewk_tiled_backing_store_view_pos_apply(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y)
1156 {
1157     Eina_Inlist **itr, **itr_end;
1158     Evas_Coord base_ox, oy, tw, th;
1159
1160     evas_object_move(priv->base.clipper, x, y);
1161
1162     tw = priv->view.tile.w;
1163     th = priv->view.tile.h;
1164
1165     base_ox = x + priv->view.offset.base.x;
1166     oy = y + priv->view.offset.base.y;
1167
1168     itr = priv->view.items;
1169     itr_end = itr + priv->view.rows;
1170     for (; itr < itr_end; itr++) {
1171         Ewk_Tiled_Backing_Store_Item *it;
1172         Evas_Coord ox = base_ox;
1173         EINA_INLIST_FOREACH(*itr, it) {
1174             _ewk_tiled_backing_store_item_move(it, ox, oy);
1175             ox += tw;
1176         }
1177         oy += th;
1178     }
1179 }
1180
1181 static void _ewk_tiled_backing_store_smart_calculate_offset_force(Ewk_Tiled_Backing_Store_Data *priv)
1182 {
1183     Evas_Coord dx = priv->view.offset.cur.x - priv->view.offset.old.x;
1184     Evas_Coord dy = priv->view.offset.cur.y - priv->view.offset.old.y;
1185     Evas_Coord tw, th;
1186     int step_y, step_x;
1187
1188     INF("o=%p, offset: %+4d, %+4d (%+4d, %+4d)",
1189         priv->self, dx, dy, priv->view.offset.cur.x, priv->view.offset.cur.y);
1190
1191     tw = priv->view.tile.w;
1192     th = priv->view.tile.h;
1193
1194     long new_col = -priv->view.offset.cur.x / tw;
1195     step_x = priv->model.base.col - new_col;
1196     long new_row = -priv->view.offset.cur.y / th;
1197     step_y = priv->model.base.row - new_row;
1198
1199     priv->view.offset.old.x = priv->view.offset.cur.x;
1200     priv->view.offset.old.y = priv->view.offset.cur.y;
1201     evas_object_move(
1202         priv->contents_clipper,
1203         priv->view.offset.cur.x + priv->view.x,
1204         priv->view.offset.cur.y + priv->view.y);
1205
1206     priv->view.offset.base.x += dx - step_x * tw;
1207     priv->view.offset.base.y += dy - step_y * th;
1208
1209     _ewk_tiled_backing_store_view_refill
1210         (priv, priv->view.x, priv->view.y, step_x, step_y);
1211 }
1212
1213 static void _ewk_tiled_backing_store_smart_calculate_offset(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y)
1214 {
1215     Evas_Coord dx = priv->view.offset.cur.x - priv->view.offset.old.x;
1216     Evas_Coord dy = priv->view.offset.cur.y - priv->view.offset.old.y;
1217     Evas_Coord tw, th;
1218     int step_y, step_x;
1219
1220     INF("o=%p, offset: %+4d, %+4d (%+4d, %+4d)",
1221         priv->self, dx, dy, priv->view.offset.cur.x, priv->view.offset.cur.y);
1222
1223     if (!dx && !dy)
1224         return;
1225
1226     tw = priv->view.tile.w;
1227     th = priv->view.tile.h;
1228
1229     long new_col = -priv->view.offset.cur.x / tw;
1230     step_x = priv->model.base.col - new_col;
1231     long new_row = -priv->view.offset.cur.y / th;
1232     step_y = priv->model.base.row - new_row;
1233
1234     priv->view.offset.old.x = priv->view.offset.cur.x;
1235     priv->view.offset.old.y = priv->view.offset.cur.y;
1236     evas_object_move(
1237         priv->contents_clipper,
1238         priv->view.offset.cur.x + priv->view.x,
1239         priv->view.offset.cur.y + priv->view.y);
1240
1241     if ((step_x < 0 && step_x <= -priv->view.cols)
1242         || (step_x > 0 && step_x >= priv->view.cols)
1243         || (step_y < 0 && step_y <= -priv->view.rows)
1244         || (step_y > 0 && step_y >= priv->view.rows)) {
1245
1246         priv->view.offset.base.x += dx - step_x * tw;
1247         priv->view.offset.base.y += dy - step_y * th;
1248
1249         _ewk_tiled_backing_store_view_refill
1250             (priv, priv->view.x, priv->view.y, step_x, step_y);
1251         return;
1252     }
1253
1254     priv->view.offset.base.x += dx;
1255     priv->view.offset.base.y += dy;
1256
1257     if (step_y < 0)
1258         _ewk_tiled_backing_store_view_wrap_up(priv, x, y, -step_y);
1259     else if (step_y > 0)
1260         _ewk_tiled_backing_store_view_wrap_down(priv, x, y, step_y);
1261
1262     if (step_x < 0)
1263         _ewk_tiled_backing_store_view_wrap_left(priv, x, y, -step_x);
1264     else if (step_x > 0)
1265         _ewk_tiled_backing_store_view_wrap_right(priv, x, y, step_x);
1266
1267     _ewk_tiled_backing_store_view_pos_apply(priv, x, y);
1268 }
1269
1270 static void _ewk_tiled_backing_store_smart_calculate_pos(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y)
1271 {
1272     _ewk_tiled_backing_store_view_pos_apply(priv, x, y);
1273     priv->view.x = x;
1274     priv->view.y = y;
1275     evas_object_move(
1276         priv->contents_clipper,
1277         priv->view.offset.cur.x + priv->view.x,
1278         priv->view.offset.cur.y + priv->view.y);
1279 }
1280
1281 static void _ewk_tiled_backing_store_fill_renderers(Ewk_Tiled_Backing_Store_Data *priv)
1282 {
1283     Eina_Inlist *it;
1284     Ewk_Tiled_Backing_Store_Item *item;
1285     int i, j;
1286
1287     for (i = 0; i < priv->view.rows; i++) {
1288         it = priv->view.items[i];
1289         j = 0;
1290         EINA_INLIST_FOREACH(it, item)
1291             _ewk_tiled_backing_store_item_fill(priv, item, j++, i);
1292     }
1293 }
1294
1295 static void _ewk_tiled_backing_store_smart_calculate(Evas_Object *o)
1296 {
1297     Evas_Coord x, y, w, h;
1298
1299     evas_object_geometry_get(o, &x, &y, &w, &h);
1300     DBG("o=%p at %d,%d + %dx%d", o, x, y, w, h);
1301
1302     PRIV_DATA_GET_OR_RETURN(o, priv);
1303
1304     priv->changed.any = EINA_FALSE;
1305
1306     ewk_tile_matrix_freeze(priv->model.matrix);
1307
1308     if (!priv->render.suspend && priv->changed.model) {
1309         unsigned long cols, rows;
1310
1311         cols = priv->model.width / priv->view.tile.w + 1;
1312         rows = priv->model.height / priv->view.tile.h + 1;
1313
1314         priv->model.old.cols = priv->model.cur.cols;
1315         priv->model.old.rows = priv->model.cur.rows;
1316         priv->model.cur.cols = cols;
1317         priv->model.cur.rows = rows;
1318         if (priv->model.old.cols > cols)
1319             cols = priv->model.old.cols;
1320         if (priv->model.old.rows > rows)
1321             rows = priv->model.old.rows;
1322         ewk_tile_matrix_resize(priv->model.matrix, cols, rows);
1323     }
1324
1325     if (priv->changed.pos && (priv->view.x != x || priv->view.y != y)) {
1326         _ewk_tiled_backing_store_smart_calculate_pos(priv, x, y);
1327         priv->changed.pos = EINA_FALSE;
1328     }
1329     if (priv->changed.offset) {
1330         _ewk_tiled_backing_store_smart_calculate_offset(priv, x, y);
1331         priv->changed.offset = EINA_FALSE;
1332     }
1333
1334     if (priv->changed.size) {
1335         _ewk_tiled_backing_store_smart_calculate_size(priv, w, h);
1336         priv->changed.size = EINA_FALSE;
1337     }
1338
1339     if (!priv->render.suspend && priv->changed.model) {
1340         Eina_Rectangle rect;
1341         rect.x = 0;
1342         rect.y = 0;
1343         rect.w = priv->model.width;
1344         rect.h = priv->model.height;
1345         _ewk_tiled_backing_store_fill_renderers(priv);
1346         ewk_tile_matrix_resize(priv->model.matrix,
1347                            priv->model.cur.cols,
1348                            priv->model.cur.rows);
1349         priv->changed.model = EINA_FALSE;
1350         evas_object_resize(priv->contents_clipper, priv->model.width, priv->model.height);
1351         _ewk_tiled_backing_store_smart_calculate_offset_force(priv);
1352
1353         /* Make sure we do not miss any important repaint by
1354          * repainting the whole viewport */
1355         const Eina_Rectangle r =
1356             { 0, 0, priv->model.width, priv->model.height };
1357         ewk_tile_matrix_update(priv->model.matrix, &r,
1358                                priv->view.tile.zoom);
1359     }
1360
1361     ewk_tile_matrix_thaw(priv->model.matrix);
1362
1363     _ewk_tiled_backing_store_updates_process(priv);
1364
1365     if (priv->view.offset.base.x > 0
1366         || priv->view.offset.base.x <= - priv->view.tile.w
1367         || priv->view.offset.base.y > 0
1368         || priv->view.offset.base.y <= - priv->view.tile.h)
1369         ERR("incorrect base offset %+4d,%+4d, tile=%dx%d, cur=%+4d,%+4d\n",
1370             priv->view.offset.base.x, priv->view.offset.base.y,
1371             priv->view.tile.w, priv->view.tile.h,
1372             priv->view.offset.cur.x, priv->view.offset.cur.y);
1373
1374 }
1375
1376 Evas_Object *ewk_tiled_backing_store_add(Evas *e)
1377 {
1378     static Evas_Smart *smart = NULL;
1379
1380     if (_ewk_tiled_log_dom < 0)
1381         _ewk_tiled_log_dom = eina_log_domain_register("Ewk_Tiled_Backing_Store", NULL);
1382
1383     if (!smart) {
1384         static Evas_Smart_Class sc =
1385             EVAS_SMART_CLASS_INIT_NAME_VERSION("Ewk_Tiled_Backing_Store");
1386
1387         evas_object_smart_clipped_smart_set(&sc);
1388         _parent_sc = sc;
1389
1390         sc.add = _ewk_tiled_backing_store_smart_add;
1391         sc.del = _ewk_tiled_backing_store_smart_del;
1392         sc.resize = _ewk_tiled_backing_store_smart_resize;
1393         sc.move = _ewk_tiled_backing_store_smart_move;
1394         sc.calculate = _ewk_tiled_backing_store_smart_calculate;
1395         sc.member_add = _ewk_tiled_backing_store_smart_member_add;
1396         sc.member_del = _ewk_tiled_backing_store_smart_member_del;
1397
1398         smart = evas_smart_class_new(&sc);
1399     }
1400
1401     return evas_object_smart_add(e, smart);
1402 }
1403
1404 void ewk_tiled_backing_store_render_cb_set(Evas_Object *o, Eina_Bool (*cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *area), const void *data)
1405 {
1406     EINA_SAFETY_ON_NULL_RETURN(cb);
1407     PRIV_DATA_GET_OR_RETURN(o, priv);
1408     priv->render.cb = cb;
1409     priv->render.data = (void*)data;
1410 }
1411
1412 Ewk_Tile_Unused_Cache *ewk_tiled_backing_store_tile_unused_cache_get(const Evas_Object *o)
1413 {
1414     PRIV_DATA_GET_OR_RETURN(o, priv, NULL);
1415     return ewk_tile_matrix_unused_cache_get(priv->model.matrix);
1416 }
1417
1418 void ewk_tiled_backing_store_tile_unused_cache_set(Evas_Object *o, Ewk_Tile_Unused_Cache *tuc)
1419 {
1420     PRIV_DATA_GET_OR_RETURN(o, priv);
1421
1422     if (ewk_tile_matrix_unused_cache_get(priv->model.matrix) == tuc)
1423         return;
1424
1425     _ewk_tiled_backing_store_model_matrix_create(priv, tuc);
1426 }
1427
1428 static Eina_Bool _ewk_tiled_backing_store_scroll_full_offset_set_internal(Ewk_Tiled_Backing_Store_Data *priv, Evas_Coord x, Evas_Coord y)
1429 {
1430     /* TODO: check offset go out of bounds, clamp */
1431     if (priv->render.disabled)
1432         return EINA_FALSE;
1433
1434     priv->view.offset.cur.x = x;
1435     priv->view.offset.cur.y = y;
1436
1437     priv->changed.offset = EINA_TRUE;
1438     _ewk_tiled_backing_store_changed(priv);
1439
1440     return EINA_TRUE;
1441 }
1442
1443 Eina_Bool ewk_tiled_backing_store_scroll_full_offset_set(Evas_Object *o, Evas_Coord x, Evas_Coord y)
1444 {
1445     DBG("o=%p, x=%d, y=%d", o, x, y);
1446
1447     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1448     if (x == priv->view.offset.cur.x && y == priv->view.offset.cur.y)
1449         return EINA_TRUE;
1450
1451     return _ewk_tiled_backing_store_scroll_full_offset_set_internal(priv, x, y);
1452 }
1453
1454 Eina_Bool ewk_tiled_backing_store_scroll_full_offset_add(Evas_Object *o, Evas_Coord dx, Evas_Coord dy)
1455 {
1456     DBG("o=%p, dx=%d, dy=%d", o, dx, dy);
1457
1458     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1459     if (!dx && !dy)
1460         return EINA_TRUE;
1461
1462     return _ewk_tiled_backing_store_scroll_full_offset_set_internal
1463         (priv, priv->view.offset.cur.x + dx, priv->view.offset.cur.y + dy);
1464 }
1465
1466 static Eina_Bool _ewk_tiled_backing_store_zoom_set_internal(Ewk_Tiled_Backing_Store_Data *priv, float *zoom, Evas_Coord cx, Evas_Coord cy, Evas_Coord *offx, Evas_Coord *offy)
1467 {
1468     *offx = priv->view.offset.cur.x;
1469     *offy = priv->view.offset.cur.y;
1470
1471     if (fabsf(priv->view.tile.zoom - *zoom) < ZOOM_STEP_MIN) {
1472         DBG("ignored as zoom difference is < %f: %f",
1473             (double)ZOOM_STEP_MIN, fabsf(priv->view.tile.zoom - *zoom));
1474         return EINA_TRUE;
1475     }
1476
1477     _ewk_tiled_backing_store_pre_render_request_flush(priv);
1478     Evas_Coord tw, th;
1479
1480     *zoom = ROUNDED_ZOOM(priv->view.tile.w, *zoom);
1481
1482     tw = priv->view.tile.w;
1483     th = priv->view.tile.h;
1484
1485     float scale = *zoom / priv->view.tile.zoom;
1486
1487     priv->view.tile.zoom = *zoom;
1488     // todo: check cx [0, w]...
1489     priv->view.offset.zoom_center.x = cx;
1490     priv->view.offset.zoom_center.y = cy;
1491
1492
1493     if (!priv->view.w || !priv->view.h) {
1494         priv->view.offset.base.x = 0;
1495         priv->view.offset.base.y = 0;
1496         return EINA_TRUE;
1497     }
1498     Eina_Inlist **itr, **itr_end;
1499     Ewk_Tiled_Backing_Store_Item *it;
1500
1501     Evas_Coord new_x = cx + (priv->view.offset.cur.x - cx) * scale;
1502     Evas_Coord new_y = cy + (priv->view.offset.cur.y - cy) * scale;
1503     Evas_Coord bx = cx + (priv->view.offset.base.x - cx) * scale;
1504     Evas_Coord by = cy + (priv->view.offset.base.y - cy) * scale;
1505
1506     Evas_Coord model_width = priv->model.width * scale;
1507     Evas_Coord model_height = priv->model.height * scale;
1508
1509     if (model_width < priv->view.w || new_x >= 0)
1510         new_x = 0;
1511     else if (-new_x + priv->view.w >= model_width)
1512         new_x = -model_width + priv->view.w;
1513
1514     if (model_height < priv->view.h || new_y >= 0)
1515         new_y = 0;
1516     else if (-new_y + priv->view.h >= model_height)
1517         new_y = -model_height + priv->view.h;
1518
1519     bx = new_x % tw;
1520     priv->model.base.col = - new_x / tw;
1521     by = new_y % th;
1522     priv->model.base.row = - new_y / th;
1523
1524     priv->changed.size = EINA_TRUE;
1525     priv->changed.model = EINA_TRUE;
1526     _ewk_tiled_backing_store_changed(priv);
1527
1528     priv->view.offset.cur.x = new_x;
1529     priv->view.offset.cur.y = new_y;
1530     priv->view.offset.base.x = bx;
1531     priv->view.offset.base.y = by;
1532
1533     priv->view.offset.old.x = priv->view.offset.cur.x;
1534     priv->view.offset.old.y = priv->view.offset.cur.y;
1535     *offx = priv->view.offset.cur.x;
1536     *offy = priv->view.offset.cur.y;
1537
1538     evas_object_move(
1539         priv->contents_clipper,
1540         new_x + priv->view.x,
1541         new_y + priv->view.y);
1542
1543     _ewk_tiled_backing_store_fill_renderers(priv);
1544
1545     Evas_Coord oy = priv->view.offset.base.y + priv->view.y;
1546     Evas_Coord base_ox = priv->view.x + priv->view.offset.base.x;
1547
1548     itr = priv->view.items;
1549     itr_end = itr + priv->view.rows;
1550
1551     for (; itr < itr_end; itr++) {
1552         Evas_Coord ox = base_ox;
1553         Eina_Inlist *lst = *itr;
1554
1555         EINA_INLIST_FOREACH(lst, it) {
1556             _ewk_tiled_backing_store_item_move(it, ox, oy);
1557             _ewk_tiled_backing_store_item_resize(it, tw, th);
1558             ox += tw;
1559         }
1560         oy += th;
1561     }
1562
1563     return EINA_TRUE;
1564 }
1565
1566 Eina_Bool ewk_tiled_backing_store_zoom_set(Evas_Object *o, float *zoom, Evas_Coord cx, Evas_Coord cy, Evas_Coord *offx, Evas_Coord *offy)
1567 {
1568     DBG("o=%p, zoom=%f", o, (double)*zoom);
1569
1570     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1571
1572     return _ewk_tiled_backing_store_zoom_set_internal(priv, zoom, cx, cy, offx, offy);
1573 }
1574
1575 Eina_Bool ewk_tiled_backing_store_zoom_weak_set(Evas_Object *o, float zoom, Evas_Coord cx, Evas_Coord cy)
1576 {
1577     DBG("o=%p, zoom=%f", o, (double)zoom);
1578     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1579     if (!priv->view.w || !priv->view.h)
1580         return EINA_FALSE;
1581     Eina_Inlist **itr, **itr_end;
1582     Ewk_Tiled_Backing_Store_Item *it;
1583     Evas_Coord tw, th;
1584     Eina_Bool recalc = EINA_FALSE;
1585
1586     float scale = zoom / priv->view.tile.zoom;
1587
1588     tw = TILE_SIZE_AT_ZOOM(priv->view.tile.w, scale);
1589     scale = TILE_ZOOM_AT_SIZE(tw, priv->view.tile.w);
1590     th = TILE_SIZE_AT_ZOOM(priv->view.tile.h, scale);
1591     zoom = scale * priv->view.tile.zoom;
1592
1593     Evas_Coord model_width = priv->model.width * scale;
1594     Evas_Coord model_height = priv->model.height * scale;
1595
1596     evas_object_resize(priv->contents_clipper, model_width, model_height);
1597
1598     int vrows = ceil((float)priv->view.h / (float)th) + 1;
1599     int vcols = ceil((float)priv->view.w / (float)tw) + 1;
1600     Evas_Coord new_x = cx + (priv->view.offset.cur.x - cx) * scale;
1601     Evas_Coord new_y = cy + (priv->view.offset.cur.y - cy) * scale;
1602     Evas_Coord bx = new_x % tw;
1603     Evas_Coord by = new_y % th;
1604     unsigned long base_row = -new_y / th;
1605     unsigned long base_col = -new_x / tw;
1606
1607     if (base_row != priv->model.base.row || base_col != priv->model.base.col) {
1608         priv->model.base.row = base_row;
1609         priv->model.base.col = base_col;
1610         recalc = EINA_TRUE;
1611     }
1612
1613     if (vrows > priv->view.rows || vcols > priv->view.cols)
1614         recalc = EINA_TRUE;
1615
1616     if (recalc) {
1617         Evas_Coord w, h;
1618         evas_object_geometry_get(o, NULL, NULL, &w, &h);
1619         _ewk_tiled_backing_store_recalc_renderers(priv, w, h, tw, th);
1620         _ewk_tiled_backing_store_fill_renderers(priv);
1621         _ewk_tiled_backing_store_updates_process(priv);
1622     }
1623
1624     Evas_Coord base_ox = bx + priv->view.x;
1625     Evas_Coord oy = by + priv->view.y;
1626
1627     evas_object_move(priv->contents_clipper,
1628                      new_x + priv->view.x,
1629                      new_y + priv->view.y);
1630
1631     itr = priv->view.items;
1632     itr_end = itr + priv->view.rows;
1633
1634     for (; itr < itr_end; itr++) {
1635         Evas_Coord ox = base_ox;
1636         Eina_Inlist *lst = *itr;
1637
1638         EINA_INLIST_FOREACH(lst, it) {
1639             _ewk_tiled_backing_store_item_move(it, ox, oy);
1640             _ewk_tiled_backing_store_item_resize(it, tw, th);
1641             ox += tw;
1642         }
1643         oy += th;
1644     }
1645
1646     return EINA_TRUE;
1647 }
1648
1649 void ewk_tiled_backing_store_fix_offsets(Evas_Object *o, Evas_Coord w, Evas_Coord h)
1650 {
1651     PRIV_DATA_GET_OR_RETURN(o, priv);
1652     Eina_Inlist **itr, **itr_end;
1653     Ewk_Tiled_Backing_Store_Item *it;
1654     Evas_Coord new_x = priv->view.offset.cur.x;
1655     Evas_Coord new_y = priv->view.offset.cur.y;
1656     Evas_Coord bx = priv->view.offset.base.x;
1657     Evas_Coord by = priv->view.offset.base.y;
1658     Evas_Coord tw = priv->view.tile.w;
1659     Evas_Coord th = priv->view.tile.h;
1660
1661     if (-new_x > w) {
1662         new_x = -w;
1663         bx = new_x % tw;
1664         priv->model.base.col = -new_x / tw;
1665     }
1666
1667     if (-new_y > h) {
1668         new_y = -h;
1669         by = new_y % th;
1670         priv->model.base.row = -new_y / th;
1671     }
1672
1673     if (bx >= 0 || bx <= -2 * priv->view.tile.w) {
1674         bx = new_x % tw;
1675         priv->model.base.col = -new_x / tw;
1676     }
1677
1678     if (by >= 0 || by <= -2 * priv->view.tile.h) {
1679         by = new_y % th;
1680         priv->model.base.row = -new_y / th;
1681     }
1682
1683     priv->view.offset.cur.x = new_x;
1684     priv->view.offset.cur.y = new_y;
1685     priv->view.offset.old.x = new_x;
1686     priv->view.offset.old.y = new_y;
1687     priv->view.offset.base.x = bx;
1688     priv->view.offset.base.y = by;
1689     evas_object_move(priv->contents_clipper,
1690                      new_x + priv->view.x,
1691                      new_y + priv->view.y);
1692
1693     Evas_Coord oy = priv->view.offset.base.y + priv->view.y;
1694     Evas_Coord base_ox = priv->view.x + priv->view.offset.base.x;
1695
1696     itr = priv->view.items;
1697     itr_end = itr + priv->view.rows;
1698
1699     for (; itr < itr_end; itr++) {
1700         Evas_Coord ox = base_ox;
1701         Eina_Inlist *lst = *itr;
1702
1703         EINA_INLIST_FOREACH(lst, it) {
1704             _ewk_tiled_backing_store_item_move(it, ox, oy);
1705             _ewk_tiled_backing_store_item_resize(it, tw, th);
1706             ox += tw;
1707         }
1708         oy += th;
1709     }
1710 }
1711
1712 void ewk_tiled_backing_store_zoom_weak_smooth_scale_set(Evas_Object *o, Eina_Bool smooth_scale)
1713 {
1714     PRIV_DATA_GET_OR_RETURN(o, priv);
1715     Eina_Inlist **itr, **itr_end;
1716
1717     itr = priv->view.items;
1718     itr_end = itr + priv->view.rows;
1719     priv->view.tile.zoom_weak_smooth_scale = smooth_scale;
1720
1721     for (; itr< itr_end; itr++) {
1722         Ewk_Tiled_Backing_Store_Item *it;
1723         EINA_INLIST_FOREACH(*itr, it)
1724             if (it->tile)
1725                 _ewk_tiled_backing_store_item_smooth_scale_set
1726                     (it, smooth_scale);
1727     }
1728 }
1729
1730 Eina_Bool ewk_tiled_backing_store_update(Evas_Object *o, const Eina_Rectangle *update)
1731 {
1732     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1733
1734     if (priv->render.disabled)
1735         return EINA_FALSE;
1736
1737     return ewk_tile_matrix_update(priv->model.matrix, update,
1738                                   priv->view.tile.zoom);
1739 }
1740
1741 void ewk_tiled_backing_store_updates_process_pre_set(Evas_Object *o, void *(*cb)(void *data, Evas_Object *o), const void *data)
1742 {
1743     PRIV_DATA_GET_OR_RETURN(o, priv);
1744     priv->process.pre_cb = cb;
1745     priv->process.pre_data = (void*)data;
1746 }
1747
1748 void ewk_tiled_backing_store_updates_process_post_set(Evas_Object *o, void *(*cb)(void *data, void *pre_data, Evas_Object *o), const void *data)
1749 {
1750     PRIV_DATA_GET_OR_RETURN(o, priv);
1751     priv->process.post_cb = cb;
1752     priv->process.post_data = (void*)data;
1753 }
1754
1755 void ewk_tiled_backing_store_updates_process(Evas_Object *o)
1756 {
1757     PRIV_DATA_GET_OR_RETURN(o, priv);
1758     _ewk_tiled_backing_store_updates_process(priv);
1759 }
1760
1761 void ewk_tiled_backing_store_updates_clear(Evas_Object *o)
1762 {
1763     PRIV_DATA_GET_OR_RETURN(o, priv);
1764
1765     ewk_tile_matrix_updates_clear(priv->model.matrix);
1766 }
1767
1768 void ewk_tiled_backing_store_contents_resize(Evas_Object *o, Evas_Coord width, Evas_Coord height)
1769 {
1770     PRIV_DATA_GET_OR_RETURN(o, priv);
1771
1772     if (width == priv->model.width && height == priv->model.height)
1773         return;
1774
1775     priv->model.width = width;
1776     priv->model.height = height;
1777     priv->changed.model = EINA_TRUE;
1778
1779     DBG("width,height=%d, %d", width, height);
1780     _ewk_tiled_backing_store_changed(priv);
1781 }
1782
1783 void ewk_tiled_backing_store_disabled_update_set(Evas_Object *o, Eina_Bool value)
1784 {
1785     PRIV_DATA_GET_OR_RETURN(o, priv);
1786
1787     if (value != priv->render.disabled)
1788         priv->render.disabled = value;
1789 }
1790
1791 void ewk_tiled_backing_store_flush(Evas_Object *o)
1792 {
1793     PRIV_DATA_GET_OR_RETURN(o, priv);
1794     Ewk_Tile_Unused_Cache *tuc = NULL;
1795
1796     priv->view.offset.cur.x = 0;
1797     priv->view.offset.cur.y = 0;
1798     priv->view.offset.old.x = 0;
1799     priv->view.offset.old.y = 0;
1800     priv->view.offset.base.x = 0;
1801     priv->view.offset.base.y = 0;
1802     priv->model.base.col = 0;
1803     priv->model.base.row = 0;
1804     priv->model.cur.cols = 1;
1805     priv->model.cur.rows = 1;
1806     priv->model.old.cols = 0;
1807     priv->model.old.rows = 0;
1808     priv->changed.size = EINA_TRUE;
1809
1810 #ifdef DEBUG_MEM_LEAKS
1811     printf("\nFLUSHED BACKING STORE, STATUS BEFORE DELETING TILE MATRIX:\n");
1812     _ewk_tiled_backing_store_mem_dbg(priv);
1813 #endif
1814
1815     _ewk_tiled_backing_store_pre_render_request_flush(priv);
1816     _ewk_tiled_backing_store_tile_dissociate_all(priv);
1817     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
1818     ewk_tile_unused_cache_clear(tuc);
1819
1820 #ifdef DEBUG_MEM_LEAKS
1821     printf("\nFLUSHED BACKING STORE, STATUS AFTER RECREATING TILE MATRIX:\n");
1822     _ewk_tiled_backing_store_mem_dbg(priv);
1823 #endif
1824 }
1825
1826 Eina_Bool ewk_tiled_backing_store_pre_render_region(Evas_Object *o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float zoom)
1827 {
1828     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1829     Eina_Tile_Grid_Slicer slicer;
1830     const Eina_Tile_Grid_Info *info;
1831     Evas_Coord tw, th;
1832     Ewk_Tile_Unused_Cache *tuc;
1833
1834     tw = priv->view.tile.w;
1835     th = priv->view.tile.h;
1836     zoom = ROUNDED_ZOOM(priv->view.tile.w, zoom);
1837
1838     if (!eina_tile_grid_slicer_setup(&slicer, x, y, w, h, tw, th)) {
1839         ERR("could not setup grid slicer for %d,%d+%dx%d tile=%dx%d",
1840             x, y, w, h, tw, th);
1841         return EINA_FALSE;
1842     }
1843
1844     while (eina_tile_grid_slicer_next(&slicer, &info)) {
1845         const unsigned long c = info->col;
1846         const unsigned long r = info->row;
1847         if (!_ewk_tiled_backing_store_pre_render_request_add(priv, c, r, zoom, PRE_RENDER_PRIORITY_LOW))
1848             break;
1849     }
1850
1851     _ewk_tiled_backing_store_item_process_idler_start(priv);
1852
1853     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
1854     ewk_tile_unused_cache_lock_area(tuc, x, y, w, h, zoom);
1855     return EINA_TRUE;
1856 }
1857
1858 Eina_Bool ewk_tiled_backing_store_pre_render_relative_radius(Evas_Object *o, unsigned int n, float zoom)
1859 {
1860     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1861     unsigned long start_row, end_row, start_col, end_col, i, j, w, h;
1862     Ewk_Tile_Unused_Cache *tuc;
1863
1864     INF("priv->model.base.row =%ld, n=%u priv->view.rows=%lu",
1865             priv->model.base.row, n, priv->view.rows);
1866     start_row = (long)priv->model.base.row - n;
1867     start_col = (long)priv->model.base.col - n;
1868     end_row = MIN(priv->model.cur.rows - 1,
1869                   priv->model.base.row + priv->view.rows + n - 1);
1870     end_col = MIN(priv->model.cur.cols - 1,
1871                   priv->model.base.col + priv->view.cols + n - 1);
1872
1873     INF("start_row=%lu, end_row=%lu, start_col=%lu, end_col=%lu",
1874          start_row, end_row, start_col, end_col);
1875
1876     zoom = ROUNDED_ZOOM(priv->view.tile.w, zoom);
1877
1878     for (i = start_row; i <= end_row; i++)
1879         for (j = start_col; j <= end_col; j++)
1880             if (!_ewk_tiled_backing_store_pre_render_request_add(priv, j, i, zoom, PRE_RENDER_PRIORITY_LOW))
1881                 goto start_processing;
1882
1883 start_processing:
1884     _ewk_tiled_backing_store_item_process_idler_start(priv);
1885
1886     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
1887     h = (end_row - start_row + 1) * TILE_SIZE_AT_ZOOM(priv->view.tile.h, zoom);
1888     w = (end_col - start_col + 1) * TILE_SIZE_AT_ZOOM(priv->view.tile.w, zoom);
1889     ewk_tile_unused_cache_lock_area(tuc,
1890             start_col * TILE_SIZE_AT_ZOOM(priv->view.tile.w, zoom),
1891             start_row * TILE_SIZE_AT_ZOOM(priv->view.tile.h, zoom), w, h, zoom);
1892
1893     return EINA_TRUE;
1894 }
1895
1896 void ewk_tiled_backing_store_pre_render_cancel(Evas_Object *o)
1897 {
1898     PRIV_DATA_GET_OR_RETURN(o, priv);
1899     Ewk_Tile_Unused_Cache *tuc;
1900
1901     _ewk_tiled_backing_store_pre_render_request_clear(priv);
1902
1903     tuc = ewk_tile_matrix_unused_cache_get(priv->model.matrix);
1904     ewk_tile_unused_cache_unlock_area(tuc);
1905 }
1906
1907 Eina_Bool ewk_tiled_backing_store_disable_render(Evas_Object *o)
1908 {
1909     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1910     return _ewk_tiled_backing_store_disable_render(priv);
1911 }
1912
1913 Eina_Bool ewk_tiled_backing_store_enable_render(Evas_Object *o)
1914 {
1915     PRIV_DATA_GET_OR_RETURN(o, priv, EINA_FALSE);
1916     _ewk_tiled_backing_store_changed(priv);
1917     return _ewk_tiled_backing_store_enable_render(priv);
1918 }