[EFL] Use standard booleand data type.
[WebKit-https.git] / Source / WebKit / efl / ewk / ewk_tiled_matrix.cpp
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 #define __STDC_FORMAT_MACROS
22 #include "config.h"
23 #include "ewk_tiled_matrix.h"
24
25 #include "ewk_tiled_backing_store.h"
26 #include "ewk_tiled_private.h"
27 #include <Eina.h>
28 #include <errno.h>
29 #include <inttypes.h>
30 #include <math.h>
31 #include <stdio.h> // XXX remove me later
32 #include <stdlib.h>
33 #include <string.h>
34
35 struct _Ewk_Tile_Matrix {
36     Eina_Matrixsparse* matrix;
37     Ewk_Tile_Unused_Cache* tilieUnusedCache;
38     Evas_Colorspace cspace;
39     struct {
40         void (*callback)(void* data, Ewk_Tile* tile, const Eina_Rectangle* update);
41         void* data;
42     } render;
43     unsigned int frozen;
44     Eina_List* updates;
45     struct {
46         Evas_Coord width, height;
47     } tile;
48 #ifdef DEBUG_MEM_LEAKS
49     struct {
50         struct {
51             uint64_t allocated, freed;
52         } tiles, bytes;
53     } stats;
54 #endif
55 };
56
57 #ifdef DEBUG_MEM_LEAKS
58 static uint64_t tiles_leaked = 0;
59 static uint64_t bytes_leaked = 0;
60 #endif
61
62 /* called when matrixsparse is resized or freed */
63 static void _ewk_tile_matrix_cell_free(void* userData, void* cellData)
64 {
65     Ewk_Tile_Matrix* tileMatrix = static_cast<Ewk_Tile_Matrix*>(userData);
66     Ewk_Tile* tile = static_cast<Ewk_Tile*>(cellData);
67
68     if (!tile)
69         return;
70
71     ewk_tile_unused_cache_freeze(tileMatrix->tilieUnusedCache);
72
73     if (tile->updates || tile->stats.full_update)
74         tileMatrix->updates = eina_list_remove(tileMatrix->updates, tile);
75
76     if (tile->visible)
77         ERR("freeing cell that is visible, leaking tile %p", tile);
78     else {
79         if (!ewk_tile_unused_cache_tile_get(tileMatrix->tilieUnusedCache, tile))
80             ERR("tile %p was not in cache %p? leaking...", tile, tileMatrix->tilieUnusedCache);
81         else {
82             DBG("tile cell does not exist anymore, free it %p", tile);
83 #ifdef DEBUG_MEM_LEAKS
84             tileMatrix->stats.bytes.freed += tile->bytes;
85             tileMatrix->stats.tiles.freed++;
86 #endif
87             ewk_tile_free(tile);
88         }
89     }
90
91     ewk_tile_unused_cache_thaw(tileMatrix->tilieUnusedCache);
92 }
93
94 /* called when cache of unused tile is flushed */
95 static void _ewk_tile_matrix_tile_free(void* data, Ewk_Tile* tile)
96 {
97     Ewk_Tile_Matrix* tileMatrix = static_cast<Ewk_Tile_Matrix*>(data);
98     Eina_Matrixsparse_Cell* cell;
99
100     if (!eina_matrixsparse_cell_idx_get(tileMatrix->matrix, tile->row, tile->col, &cell)) {
101         ERR("removing tile %p that was not in the matrix? Leaking...", tile);
102         return;
103     }
104
105     if (!cell) {
106         ERR("removing tile %p that was not in the matrix? Leaking...", tile);
107         return;
108     }
109
110     if (tile->updates || tile->stats.full_update)
111         tileMatrix->updates = eina_list_remove(tileMatrix->updates, tile);
112
113     /* set to null to avoid double free */
114     eina_matrixsparse_cell_data_replace(cell, 0, 0);
115     eina_matrixsparse_cell_clear(cell);
116
117     if (EINA_UNLIKELY(!!tile->visible)) {
118         ERR("cache of unused tiles requesting deletion of used tile %p? "
119             "Leaking...", tile);
120         return;
121     }
122
123 #ifdef DEBUG_MEM_LEAKS
124     tileMatrix->stats.bytes.freed += tile->bytes;
125     tileMatrix->stats.tiles.freed++;
126 #endif
127
128     ewk_tile_free(tile);
129 }
130
131 /**
132  * Creates a new matrix of tiles.
133  *
134  * The tile matrix is responsible for keeping tiles around and
135  * providing fast access to them. One can use it to retrieve new or
136  * existing tiles and give them back, allowing them to be
137  * freed/replaced by the cache.
138  *
139  * @param tuc cache of unused tiles or @c 0 to create one
140  *        automatically.
141  * @param columns number of columns in the matrix.
142  * @param rows number of rows in the matrix.
143  * @param cspace the color space used to create tiles in this matrix.
144  * @param render_cb function used to render given tile update.
145  * @param render_data context to give back to @a render_cb.
146  *
147  * @return newly allocated instance on success, @c 0 on failure.
148  */
149 Ewk_Tile_Matrix* ewk_tile_matrix_new(Ewk_Tile_Unused_Cache* tileUnusedCache, unsigned long columns, unsigned long rows, Evas_Colorspace colorSpace, void (*renderCallback)(void* data, Ewk_Tile* tile, const Eina_Rectangle* update), const void* renderData)
150 {
151     Ewk_Tile_Matrix* tileMatrix = static_cast<Ewk_Tile_Matrix*>(calloc(1, sizeof(Ewk_Tile_Matrix)));
152     if (!tileMatrix)
153         return 0;
154
155     tileMatrix->matrix = eina_matrixsparse_new(rows, columns, _ewk_tile_matrix_cell_free, tileMatrix);
156     if (!tileMatrix->matrix) {
157         ERR("could not create sparse matrix.");
158         free(tileMatrix);
159         return 0;
160     }
161
162     if (tileUnusedCache)
163         tileMatrix->tilieUnusedCache = ewk_tile_unused_cache_ref(tileUnusedCache);
164     else {
165         tileMatrix->tilieUnusedCache = ewk_tile_unused_cache_new(40960000);
166         if (!tileMatrix->tilieUnusedCache) {
167             ERR("no cache of unused tile!");
168             eina_matrixsparse_free(tileMatrix->matrix);
169             free(tileMatrix);
170             return 0;
171         }
172     }
173
174     tileMatrix->cspace = colorSpace;
175     tileMatrix->render.callback = renderCallback;
176     tileMatrix->render.data = (void*)renderData;
177     tileMatrix->tile.width = DEFAULT_TILE_W;
178     tileMatrix->tile.height = DEFAULT_TILE_H;
179
180     return tileMatrix;
181 }
182
183 /**
184  * Destroys tiles matrix, releasing its resources.
185  *
186  * The cache instance is unreferenced, possibly freeing it.
187  */
188 void ewk_tile_matrix_free(Ewk_Tile_Matrix* tileMatrix)
189 {
190 #ifdef DEBUG_MEM_LEAKS
191     uint64_t tiles, bytes;
192 #endif
193
194     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
195     ewk_tile_unused_cache_freeze(tileMatrix->tilieUnusedCache);
196
197     eina_matrixsparse_free(tileMatrix->matrix);
198
199     ewk_tile_unused_cache_thaw(tileMatrix->tilieUnusedCache);
200     ewk_tile_unused_cache_unref(tileMatrix->tilieUnusedCache);
201
202 #ifdef DEBUG_MEM_LEAKS
203     tiles = tileMatrix->stats.tiles.allocated - tileMatrix->stats.tiles.freed;
204     bytes = tileMatrix->stats.bytes.allocated - tileMatrix->stats.bytes.freed;
205
206     tiles_leaked += tiles;
207     bytes_leaked += bytes;
208
209     if (tiles || bytes)
210         ERR("tiled matrix leaked: tiles[+%" PRIu64 ",-%" PRIu64 ":%" PRIu64 "] "
211             "bytes[+%" PRIu64 ",-%" PRIu64 ":%" PRIu64 "]",
212             tileMatrix->stats.tiles.allocated, tileMatrix->stats.tiles.freed, tiles,
213             tileMatrix->stats.bytes.allocated, tileMatrix->stats.bytes.freed, bytes);
214     else if (tiles_leaked || bytes_leaked)
215         WRN("tiled matrix had no leaks: tiles[+%" PRIu64 ",-%" PRIu64 "] "
216             "bytes[+%" PRIu64 ",-%" PRIu64 "], but some other leaked "
217             "%" PRIu64 " tiles (%" PRIu64 " bytes)",
218             tileMatrix->stats.tiles.allocated, tileMatrix->stats.tiles.freed,
219             tileMatrix->stats.bytes.allocated, tileMatrix->stats.bytes.freed,
220             tiles_leaked, bytes_leaked);
221     else
222         INF("tiled matrix had no leaks: tiles[+%" PRIu64 ",-%" PRIu64 "] "
223             "bytes[+%" PRIu64 ",-%" PRIu64 "]",
224             tileMatrix->stats.tiles.allocated, tileMatrix->stats.tiles.freed,
225             tileMatrix->stats.bytes.allocated, tileMatrix->stats.bytes.freed);
226 #endif
227
228     free(tileMatrix);
229 }
230
231 /**
232  * Resize matrix to given number of rows and columns.
233  */
234 void ewk_tile_matrix_resize(Ewk_Tile_Matrix* tileMatrix, unsigned long cols, unsigned long rows)
235 {
236     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
237     eina_matrixsparse_size_set(tileMatrix->matrix, rows, cols);
238 }
239
240 /**
241  * Get the cache of unused tiles in use by given matrix.
242  *
243  * No reference is taken to the cache.
244  */
245 Ewk_Tile_Unused_Cache* ewk_tile_matrix_unused_cache_get(const Ewk_Tile_Matrix* tileMatrix)
246 {
247     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, 0);
248     return tileMatrix->tilieUnusedCache;
249 }
250
251 /**
252  * Get the exact tile for the given position and zoom.
253  *
254  * If the tile.widthas unused then it's removed from the cache.
255  *
256  * After usage, please give it back using
257  * ewk_tile_matrix_tile_put(). If you just want to check if it exists,
258  * then use ewk_tile_matrix_tile_exact_exists().
259  *
260  * @param tileMatrix the tile matrix to get tile from.
261  * @param column the column number.
262  * @param row the row number.
263  * @param zoom the exact zoom to use.
264  *
265  * @return The tile instance or @c 0 if none is found. If the tile
266  *         was in the unused cache it will be @b removed (thus
267  *         considered used) and one should give it back with
268  *         ewk_tile_matrix_tile_put() afterwards.
269  *
270  * @see ewk_tile_matrix_tile_exact_get()
271  */
272 Ewk_Tile* ewk_tile_matrix_tile_exact_get(Ewk_Tile_Matrix* tileMatrix, unsigned long column, unsigned long row, float zoom)
273 {
274     Ewk_Tile* tile = static_cast<Ewk_Tile*>(eina_matrixsparse_data_idx_get(tileMatrix->matrix, row, column));
275     if (!tile)
276         return 0;
277
278     if (tile->zoom == zoom)
279         goto end;
280
281 end:
282     if (!tile->visible) {
283         if (!ewk_tile_unused_cache_tile_get(tileMatrix->tilieUnusedCache, tile))
284             WRN("Ewk_Tile was unused but not in cache? bug!");
285     }
286
287     return tile;
288 }
289
290 /**
291  * Checks if tile of given zoom exists in matrix.
292  *
293  * @param tileMatrix the tile matrix to check tile existence.
294  * @param column the column number.
295  * @param row the row number.
296  * @param zoom the exact zoom to query.
297  *
298  * @return @c true if found, @c false otherwise.
299  *
300  * @see ewk_tile_matrix_tile_exact_get()
301  */
302 Eina_Bool ewk_tile_matrix_tile_exact_exists(Ewk_Tile_Matrix* tileMatrix, unsigned long column, unsigned long row, float zoom)
303 {
304     if (!eina_matrixsparse_data_idx_get(tileMatrix->matrix, row, column))
305         return false;
306
307     return true;
308 }
309
310 /**
311  * Create a new tile at given position and zoom level in the matrix.
312  *
313  * The newly created tile is considered in use and not put into cache
314  * of unused tiles. After it is used one should call
315  * ewk_tile_matrix_tile_put() to give it back to matrix.
316  *
317  * @param tileMatrix the tile matrix to create tile on.
318  * @param column the column number.
319  * @param row the row number.
320  * @param zoom the level to create tile, used to determine tile size.
321  */
322 Ewk_Tile* ewk_tile_matrix_tile_new(Ewk_Tile_Matrix* tileMatrix, Evas* canvas, unsigned long column, unsigned long row, float zoom)
323 {
324     Evas_Coord tileWidth, tileHeight;
325     Ewk_Tile* tile;
326
327     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, 0);
328     EINA_SAFETY_ON_FALSE_RETURN_VAL(zoom > 0.0, 0);
329
330     tileWidth = tileMatrix->tile.width;
331     tileHeight = tileMatrix->tile.height;
332
333     tile = ewk_tile_new(canvas, tileWidth, tileHeight, zoom, tileMatrix->cspace);
334     if (!tile) {
335         ERR("could not create tile %dx%d at %f, cspace=%d", tileWidth, tileHeight, (double)zoom, tileMatrix->cspace);
336         return 0;
337     }
338
339     if (!eina_matrixsparse_data_idx_set(tileMatrix->matrix, row, column, tile)) {
340         ERR("could not set matrix cell, row/col outside matrix dimensions!");
341         ewk_tile_free(tile);
342         return 0;
343     }
344
345     tile->col = column;
346     tile->row = row;
347     tile->x = column * tileWidth;
348     tile->y = row * tileHeight;
349
350     cairo_translate(tile->cairo, -tile->x, -tile->y);
351
352     tile->stats.full_update = true;
353     tileMatrix->updates = eina_list_append(tileMatrix->updates, tile);
354
355 #ifdef DEBUG_MEM_LEAKS
356     tileMatrix->stats.bytes.allocated += tile->bytes;
357     tileMatrix->stats.tiles.allocated++;
358 #endif
359
360     return tile;
361 }
362
363 /**
364  * Gives back the tile to the tile matrix.
365  *
366  * This will report the tile is no longer in use by the one that got
367  * it with ewk_tile_matrix_tile_exact_get().
368  *
369  * Any previous reference to tile should be released
370  * (ewk_tile.heightide()) before calling this function, so it will
371  * be known if it is not visibile anymore and thus can be put into the
372  * unused cache.
373  *
374  * @param tileMatrix the tile matrix to return tile to.
375  * @param t the tile instance to return, must @b not be @c 0.
376  * @param last_used time in which tile.widthas last used.
377  *
378  * @return #true on success or #false on failure.
379  */
380 Eina_Bool ewk_tile_matrix_tile_put(Ewk_Tile_Matrix* tileMatrix, Ewk_Tile* tile, double lastUsed)
381 {
382     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, false);
383     EINA_SAFETY_ON_NULL_RETURN_VAL(tile, false);
384
385     if (tile->visible)
386         return true;
387
388     tile->stats.last_used = lastUsed;
389     return ewk_tile_unused_cache_tile_put(tileMatrix->tilieUnusedCache, tile, _ewk_tile_matrix_tile_free, tileMatrix);
390 }
391
392 Eina_Bool ewk_tile_matrix_tile_update(Ewk_Tile_Matrix* tileMatrix, unsigned long col, unsigned long row, const Eina_Rectangle* update)
393 {
394     Eina_Rectangle newUpdate;
395     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, false);
396     EINA_SAFETY_ON_NULL_RETURN_VAL(update, false);
397
398     memcpy(&newUpdate, update, sizeof(newUpdate));
399     // check update is valid, otherwise return false
400     if (update->x < 0 || update->y < 0 || update->w <= 0 || update->h <= 0) {
401         ERR("invalid update region.");
402         return false;
403     }
404
405     if (update->x + update->w - 1 >= tileMatrix->tile.width)
406         newUpdate.w = tileMatrix->tile.width - update->x;
407     if (update->y + update->h - 1 >= tileMatrix->tile.height)
408         newUpdate.h = tileMatrix->tile.height - update->y;
409
410     Ewk_Tile* tile = static_cast<Ewk_Tile*>(eina_matrixsparse_data_idx_get(tileMatrix->matrix, row, col));
411     if (!tile)
412         return true;
413
414     if (!tile->updates && !tile->stats.full_update)
415         tileMatrix->updates = eina_list_append(tileMatrix->updates, tile);
416     ewk_tile_update_area(tile, &newUpdate);
417
418     return true;
419 }
420
421 Eina_Bool ewk_tile_matrix_tile_update_full(Ewk_Tile_Matrix* tileMatrix, unsigned long column, unsigned long row)
422 {
423     Eina_Matrixsparse_Cell* cell;
424     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, false);
425
426     if (!eina_matrixsparse_cell_idx_get(tileMatrix->matrix, row, column, &cell))
427         return false;
428
429     if (!cell)
430         return true;
431
432     Ewk_Tile* tile = static_cast<Ewk_Tile*>(eina_matrixsparse_cell_data_get(cell));
433     if (!tile) {
434         CRITICAL("matrix cell with no tile!");
435         return true;
436     }
437
438     if (!tile->updates && !tile->stats.full_update)
439         tileMatrix->updates = eina_list_append(tileMatrix->updates, tile);
440     ewk_tile_update_full(tile);
441
442     return true;
443 }
444
445 void ewk_tile_matrix_tile_updates_clear(Ewk_Tile_Matrix* tileMatrix, Ewk_Tile* tile)
446 {
447     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
448     if (!tile->updates && !tile->stats.full_update)
449         return;
450     ewk_tile_updates_clear(tile);
451     tileMatrix->updates = eina_list_remove(tileMatrix->updates, tile);
452 }
453
454 static Eina_Bool _ewk_tile_matrix_slicer_setup(Ewk_Tile_Matrix* tileMatrix, const Eina_Rectangle* area, float zoom, Eina_Tile_Grid_Slicer* slicer)
455 {
456     unsigned long rows, cols;
457     Evas_Coord x, y, width, height, tileWidth, tileHeight;
458
459     if (area->w <= 0 || area->h <= 0) {
460         WRN("invalid area region: %d,%d+%dx%d.",
461             area->x, area->y, area->w, area->h);
462         return false;
463     }
464
465     x = area->x;
466     y = area->y;
467     width = area->w;
468     height = area->h;
469
470     tileWidth = tileMatrix->tile.width;
471     tileHeight = tileMatrix->tile.height;
472
473     // cropping area region to fit matrix
474     eina_matrixsparse_size_get(tileMatrix->matrix, &rows, &cols);
475     if (x < 0) {
476         width += x;
477         x = 0;
478     }
479     if (y < 0) {
480         height += y;
481         y = 0;
482     }
483
484     if (y + height - 1 > (long)(rows * tileHeight))
485         height = rows * tileHeight - y;
486     if (x + width - 1 > (long)(cols * tileWidth))
487         width = cols * tileWidth - x;
488
489     return eina_tile_grid_slicer_setup(slicer, x, y, width, height, tileWidth, tileHeight);
490 }
491
492
493 Eina_Bool ewk_tile_matrix_update(Ewk_Tile_Matrix* tileMatrix, const Eina_Rectangle* update, float zoom)
494 {
495     const Eina_Tile_Grid_Info* info;
496     Eina_Tile_Grid_Slicer slicer;
497     EINA_SAFETY_ON_NULL_RETURN_VAL(tileMatrix, false);
498     EINA_SAFETY_ON_NULL_RETURN_VAL(update, false);
499
500     if (update->w < 1 || update->h < 1) {
501         DBG("Why we get updates with empty areas? %d,%d+%dx%d at zoom %f",
502             update->x, update->y, update->w, update->h, zoom);
503         return true;
504     }
505
506     if (!_ewk_tile_matrix_slicer_setup(tileMatrix, update, zoom, &slicer)) {
507         ERR("Could not setup slicer for update %d,%d+%dx%d at zoom %f",
508             update->x, update->y, update->w, update->h, zoom);
509         return false;
510     }
511
512     while (eina_tile_grid_slicer_next(&slicer, &info)) {
513         unsigned long col, row;
514         col = info->col;
515         row = info->row;
516
517         Ewk_Tile* tile = static_cast<Ewk_Tile*>(eina_matrixsparse_data_idx_get(tileMatrix->matrix, row, col));
518         if (!tile)
519             continue;
520
521         if (!tile->updates && !tile->stats.full_update)
522             tileMatrix->updates = eina_list_append(tileMatrix->updates, tile);
523         if (info->full)
524             ewk_tile_update_full(tile);
525         else
526             ewk_tile_update_area(tile, &info->rect);
527     }
528
529
530     return true;
531 }
532
533 void ewk_tile_matrix_updates_process(Ewk_Tile_Matrix* tileMatrix)
534 {
535     Eina_List* list, *listNext;
536     void* item;
537     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
538
539     // process updates, unflag tiles
540     EINA_LIST_FOREACH_SAFE(tileMatrix->updates, list, listNext, item) {
541         Ewk_Tile* tile = static_cast<Ewk_Tile*>(item);
542         ewk_tile_updates_process(tile, tileMatrix->render.callback, tileMatrix->render.data);
543         if (tile->visible) {
544             ewk_tile_updates_clear(tile);
545             tileMatrix->updates = eina_list_remove_list(tileMatrix->updates, list);
546         }
547     }
548 }
549
550 void ewk_tile_matrix_updates_clear(Ewk_Tile_Matrix* tileMatrix)
551 {
552     void* item;
553     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
554
555     EINA_LIST_FREE(tileMatrix->updates, item)
556         ewk_tile_updates_clear(static_cast<Ewk_Tile*>(item));
557     tileMatrix->updates = 0;
558 }
559
560 // remove me later!
561 void ewk_tile_matrix_dbg(const Ewk_Tile_Matrix* tileMatrix)
562 {
563     Eina_Iterator* iterator = eina_matrixsparse_iterator_complete_new(tileMatrix->matrix);
564     Eina_Matrixsparse_Cell* cell;
565     Eina_Bool last_empty = false;
566
567 #ifdef DEBUG_MEM_LEAKS
568     printf("Ewk_Tile Matrix: tiles[+%" PRIu64 ",-%" PRIu64 ":%" PRIu64 "] "
569            "bytes[+%" PRIu64 ",-%" PRIu64 ":%" PRIu64 "]\n",
570            tileMatrix->stats.tiles.allocated, tileMatrix->stats.tiles.freed,
571            tileMatrix->stats.tiles.allocated - tileMatrix->stats.tiles.freed,
572            tileMatrix->stats.bytes.allocated, tileMatrix->stats.bytes.freed,
573            tileMatrix->stats.bytes.allocated - tileMatrix->stats.bytes.freed);
574 #else
575     printf("Ewk_Tile Matrix:\n");
576 #endif
577
578     EINA_ITERATOR_FOREACH(iterator, cell) {
579         unsigned long row, column;
580         eina_matrixsparse_cell_position_get(cell, &row, &column);
581
582         Ewk_Tile* tile = static_cast<Ewk_Tile*>(eina_matrixsparse_cell_data_get(cell));
583         if (!tile) {
584             if (!last_empty) {
585                 last_empty = true;
586                 printf("Empty:");
587             }
588             printf(" [%lu,%lu]", column, row);
589         } else {
590             if (last_empty) {
591                 last_empty = false;
592                 printf("\n");
593             }
594             printf("%3lu,%3lu %10p:", column, row, tile);
595             printf(" [%3lu,%3lu + %dx%d @ %0.3f]%c", tile->col, tile->row, tile->width, tile->height, tile->zoom, tile->visible ? '*' : ' ');
596             printf("\n");
597         }
598     }
599     if (last_empty)
600         printf("\n");
601     eina_iterator_free(iterator);
602
603     ewk_tile_unused_cache_dbg(tileMatrix->tilieUnusedCache);
604 }
605
606 /**
607  * Freeze matrix to not do maintenance tasks.
608  *
609  * Maintenance tasks optimize usage, but maybe we know we should hold
610  * on them until we do the last operation, in this case we freeze
611  * while operating and then thaw when we're done.
612  *
613  * @see ewk_tile_matrix_thaw()
614  */
615 void ewk_tile_matrix_freeze(Ewk_Tile_Matrix* tileMatrix)
616 {
617     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
618     if (!tileMatrix->frozen)
619         ewk_tile_unused_cache_freeze(tileMatrix->tilieUnusedCache);
620     tileMatrix->frozen++;
621 }
622
623 /**
624  * Unfreezes maintenance tasks.
625  *
626  * If this is the last counterpart of freeze, then maintenance tasks
627  * will run immediately.
628  */
629 void ewk_tile_matrix_thaw(Ewk_Tile_Matrix* tileMatrix)
630 {
631     EINA_SAFETY_ON_NULL_RETURN(tileMatrix);
632     if (!tileMatrix->frozen) {
633         ERR("thawing more than freezing!");
634         return;
635     }
636
637     tileMatrix->frozen--;
638     if (!tileMatrix->frozen)
639         ewk_tile_unused_cache_thaw(tileMatrix->tilieUnusedCache);
640 }