summaryrefslogtreecommitdiffstats
path: root/WebKit/efl/ewk/ewk_tiled_matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/efl/ewk/ewk_tiled_matrix.c')
-rw-r--r--WebKit/efl/ewk/ewk_tiled_matrix.c771
1 files changed, 771 insertions, 0 deletions
diff --git a/WebKit/efl/ewk/ewk_tiled_matrix.c b/WebKit/efl/ewk/ewk_tiled_matrix.c
new file mode 100644
index 0000000..fccbfa1
--- /dev/null
+++ b/WebKit/efl/ewk/ewk_tiled_matrix.c
@@ -0,0 +1,771 @@
+/*
+ Copyright (C) 2009-2010 Samsung Electronics
+ Copyright (C) 2009-2010 ProFUSION embedded systems
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "ewk_tiled_matrix.h"
+
+#define _GNU_SOURCE
+#include "ewk_tiled_backing_store.h"
+#include "ewk_tiled_private.h"
+#include <Eina.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h> // XXX remove me later
+#include <stdlib.h>
+#include <string.h>
+
+static const Evas_Coord TILE_MATRIX_BASE_TILE_SIZE = 256;
+
+struct _Ewk_Tile_Matrix {
+ Eina_Matrixsparse *matrix;
+ Ewk_Tile_Unused_Cache *tuc;
+ Evas_Colorspace cspace;
+ struct {
+ void (*cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *update);
+ void *data;
+ } render;
+ unsigned int frozen;
+ Eina_List *updates;
+#ifdef DEBUG_MEM_LEAKS
+ struct {
+ struct {
+ uint64_t allocated, freed;
+ } tiles, bytes;
+ } stats;
+#endif
+};
+
+#ifdef DEBUG_MEM_LEAKS
+static uint64_t tiles_leaked = 0;
+static uint64_t bytes_leaked = 0;
+#endif
+
+/* called when matrixsparse is resized or freed */
+static void _ewk_tile_matrix_cell_free(void *user_data, void *cell_data)
+{
+ Ewk_Tile_Matrix *tm = user_data;
+ Eina_Inlist *l = cell_data;
+
+ if (!l)
+ return;
+
+ ewk_tile_unused_cache_freeze(tm->tuc);
+
+ while (l) {
+ Ewk_Tile *t = (Ewk_Tile *)l;
+ l = l->next;
+
+ if (t->updates || t->stats.full_update)
+ tm->updates = eina_list_remove(tm->updates, t);
+
+ if (t->visible)
+ ERR("freeing cell that is visible, leaking tile %p", t);
+ else {
+ if (!ewk_tile_unused_cache_tile_get(tm->tuc, t))
+ ERR("tile %p was not in cache %p? leaking...", t, tm->tuc);
+ else {
+ DBG("tile cell does not exist anymore, free it %p", t);
+
+#ifdef DEBUG_MEM_LEAKS
+ tm->stats.bytes.freed += t->bytes;
+ tm->stats.tiles.freed++;
+#endif
+
+ ewk_tile_free(t);
+ }
+ }
+ }
+
+ ewk_tile_unused_cache_thaw(tm->tuc);
+}
+
+/* called when cache of unused tile is flushed */
+static void _ewk_tile_matrix_tile_free(void *data, Ewk_Tile *t)
+{
+ Ewk_Tile_Matrix *tm = data;
+ Eina_Matrixsparse_Cell *cell;
+ Eina_Inlist *l, *old;
+
+ if (!eina_matrixsparse_cell_idx_get(tm->matrix, t->row, t->col, &cell)) {
+ ERR("removing tile %p that was not in the matrix? Leaking...", t);
+ return;
+ }
+
+ if (t->updates || t->stats.full_update)
+ tm->updates = eina_list_remove(tm->updates, t);
+
+ old = eina_matrixsparse_cell_data_get(cell);
+ l = eina_inlist_remove(old, EINA_INLIST_GET(t));
+ if (!l) {
+ /* set to null to avoid double free */
+ eina_matrixsparse_cell_data_replace(cell, NULL, NULL);
+ eina_matrixsparse_cell_clear(cell);
+ } else if (old != l)
+ eina_matrixsparse_cell_data_replace(cell, l, NULL);
+
+ if (EINA_UNLIKELY(!!t->visible)) {
+ ERR("cache of unused tiles requesting deletion of used tile %p? "
+ "Leaking...", t);
+ return;
+ }
+
+#ifdef DEBUG_MEM_LEAKS
+ tm->stats.bytes.freed += t->bytes;
+ tm->stats.tiles.freed++;
+#endif
+
+ ewk_tile_free(t);
+}
+
+/**
+ * Creates a new matrix of tiles.
+ *
+ * The tile matrix is responsible for keeping tiles around and
+ * providing fast access to them. One can use it to retrieve new or
+ * existing tiles and give them back, allowing them to be
+ * freed/replaced by the cache.
+ *
+ * @param tuc cache of unused tiles or @c NULL to create one
+ * automatically.
+ * @param cols number of columns in the matrix.
+ * @param rows number of rows in the matrix.
+ * @param cspace the color space used to create tiles in this matrix.
+ * @param render_cb function used to render given tile update.
+ * @param data context to give back to @a render_cb.
+ *
+ * @return newly allocated instance on success, @c NULL on failure.
+ */
+Ewk_Tile_Matrix *ewk_tile_matrix_new(Ewk_Tile_Unused_Cache *tuc, unsigned long cols, unsigned long rows, Evas_Colorspace cspace, void (*render_cb)(void *data, Ewk_Tile *t, const Eina_Rectangle *update), const void *data)
+{
+ Ewk_Tile_Matrix *tm;
+
+ CALLOC_OR_OOM_RET(tm, sizeof(Ewk_Tile_Matrix), NULL);
+
+ tm->matrix = eina_matrixsparse_new(rows, cols, _ewk_tile_matrix_cell_free, tm);
+ if (!tm->matrix) {
+ ERR("could not create sparse matrix.");
+ free(tm);
+ return NULL;
+ }
+
+ if (tuc)
+ tm->tuc = ewk_tile_unused_cache_ref(tuc);
+ else {
+ tm->tuc = ewk_tile_unused_cache_new(40960000);
+ if (!tm->tuc) {
+ ERR("no cache of unused tile!");
+ eina_matrixsparse_free(tm->matrix);
+ free(tm);
+ return NULL;
+ }
+ }
+
+ tm->cspace = cspace;
+ tm->render.cb = render_cb;
+ tm->render.data = (void *)data;
+
+ return tm;
+}
+
+/**
+ * Destroys tiles matrix, releasing its resources.
+ *
+ * The cache instance is unreferenced, possibly freeing it.
+ */
+void ewk_tile_matrix_free(Ewk_Tile_Matrix *tm)
+{
+#ifdef DEBUG_MEM_LEAKS
+ uint64_t tiles, bytes;
+#endif
+
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+ ewk_tile_unused_cache_freeze(tm->tuc);
+
+ eina_matrixsparse_free(tm->matrix);
+
+ ewk_tile_unused_cache_thaw(tm->tuc);
+ ewk_tile_unused_cache_unref(tm->tuc);
+
+#ifdef DEBUG_MEM_LEAKS
+ tiles = tm->stats.tiles.allocated - tm->stats.tiles.freed;
+ bytes = tm->stats.bytes.allocated - tm->stats.bytes.freed;
+
+ tiles_leaked += tiles;
+ bytes_leaked += bytes;
+
+ if (tiles || bytes)
+ ERR("tiled matrix leaked: tiles[+%"PRIu64",-%"PRIu64":%"PRIu64"] "
+ "bytes[+%"PRIu64",-%"PRIu64":%"PRIu64"]",
+ tm->stats.tiles.allocated, tm->stats.tiles.freed, tiles,
+ tm->stats.bytes.allocated, tm->stats.bytes.freed, bytes);
+ else if (tiles_leaked || bytes_leaked)
+ WRN("tiled matrix had no leaks: tiles[+%"PRIu64",-%"PRIu64"] "
+ "bytes[+%"PRIu64",-%"PRIu64"], but some other leaked "
+ "%"PRIu64" tiles (%"PRIu64" bytes)",
+ tm->stats.tiles.allocated, tm->stats.tiles.freed,
+ tm->stats.bytes.allocated, tm->stats.bytes.freed,
+ tiles_leaked, bytes_leaked);
+ else
+ INF("tiled matrix had no leaks: tiles[+%"PRIu64",-%"PRIu64"] "
+ "bytes[+%"PRIu64",-%"PRIu64"]",
+ tm->stats.tiles.allocated, tm->stats.tiles.freed,
+ tm->stats.bytes.allocated, tm->stats.bytes.freed);
+#endif
+
+ free(tm);
+}
+
+/**
+ * Resize matrix to given number of rows and columns.
+ */
+void ewk_tile_matrix_resize(Ewk_Tile_Matrix *tm, unsigned long cols, unsigned long rows)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+ eina_matrixsparse_size_set(tm->matrix, rows, cols);
+}
+
+/**
+ * Get the cache of unused tiles in use by given matrix.
+ *
+ * No reference is taken to the cache.
+ */
+Ewk_Tile_Unused_Cache *ewk_tile_matrix_unused_cache_get(const Ewk_Tile_Matrix *tm)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL);
+ return tm->tuc;
+}
+
+/**
+ * Get the exact tile for the given position and zoom.
+ *
+ * If the tile was unused then it's removed from the cache.
+ *
+ * After usage, please give it back using
+ * ewk_tile_matrix_tile_put(). If you just want to check if it exists,
+ * then use ewk_tile_matrix_tile_exact_exists().
+ *
+ * @param tm the tile matrix to get tile from.
+ * @param col the column number.
+ * @param row the row number.
+ * @param zoom the exact zoom to use.
+ *
+ * @return The tile instance or @c NULL if none is found. If the tile
+ * was in the unused cache it will be @b removed (thus
+ * considered used) and one should give it back with
+ * ewk_tile_matrix_tile_put() afterwards.
+ *
+ * @see ewk_tile_matrix_tile_nearest_get()
+ * @see ewk_tile_matrix_tile_exact_get()
+ */
+Ewk_Tile *ewk_tile_matrix_tile_exact_get(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom)
+{
+ Ewk_Tile *t, *item, *item_found = NULL;
+ Eina_Inlist *inl;
+
+ t = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+ if (!t)
+ return NULL;
+
+ if (t->zoom == zoom)
+ goto end;
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) {
+ if (item->zoom != zoom)
+ continue;
+ item_found = item;
+ break;
+ }
+
+ if (!item_found)
+ return NULL;
+
+ inl = eina_inlist_promote(EINA_INLIST_GET(t), EINA_INLIST_GET(item_found));
+ eina_matrixsparse_data_idx_replace(tm->matrix, row, col, inl, NULL);
+
+ end:
+ if (!t->visible) {
+ if (!ewk_tile_unused_cache_tile_get(tm->tuc, t))
+ WRN("Ewk_Tile was unused but not in cache? bug!");
+ }
+
+ return t;
+}
+
+/**
+ * Checks if tile of given zoom exists in matrix.
+ *
+ * @param tm the tile matrix to check tile existence.
+ * @param col the column number.
+ * @param row the row number.
+ * @param zoom the exact zoom to query.
+ *
+ * @return @c EINA_TRUE if found, @c EINA_FALSE otherwise.
+ *
+ * @see ewk_tile_matrix_tile_exact_get()
+ */
+Eina_Bool ewk_tile_matrix_tile_exact_exists(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom)
+{
+ Ewk_Tile *t, *item;
+
+ t = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+ if (!t)
+ return EINA_FALSE;
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) {
+ if (item->zoom == zoom)
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+/**
+ * Get the nearest tile for given position and zoom.
+ *
+ * The nearest tile is the one at the given position but with the
+ * closest zoom, this being the division of the tile zoom by the
+ * desired zoom, the closest to 1.0 gets it.
+ *
+ * If the tile was unused then it's removed from the cache.
+ *
+ * After usage, please give it back using ewk_tile_matrix_tile_put().
+ *
+ * @param tm the tile matrix to get tile from.
+ * @param col the column number.
+ * @param row the row number.
+ * @param zoom the exact zoom to use.
+ *
+ * @return The tile instance or @c NULL if none is found. If the tile
+ * was in the unused cache it will be @b removed (thus
+ * considered used) and one should give it back with
+ * ewk_tile_matrix_tile_put() afterwards.
+ */
+Ewk_Tile *ewk_tile_matrix_tile_nearest_get(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, float zoom)
+{
+ Ewk_Tile *t, *item, *item_found = NULL;
+ Eina_Inlist *inl;
+ float zoom_found = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(zoom > 0.0, NULL);
+
+ t = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+ if (!t)
+ return NULL;
+
+ if (t->zoom == zoom) {
+ item_found = t;
+ goto end;
+ }
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(t), item) {
+ float cur_zoom = item->zoom;
+
+ if (cur_zoom == zoom) {
+ item_found = item;
+ break;
+ }
+
+ if (cur_zoom > zoom)
+ cur_zoom = zoom / cur_zoom;
+ else
+ cur_zoom = cur_zoom / zoom;
+
+ if (cur_zoom > zoom_found) {
+ item_found = item;
+ zoom_found = cur_zoom;
+ }
+ }
+
+ if (!item_found)
+ return NULL;
+
+ inl = eina_inlist_promote(EINA_INLIST_GET(t), EINA_INLIST_GET(item_found));
+ eina_matrixsparse_data_idx_replace(tm->matrix, row, col, inl, NULL);
+
+ end:
+ if (!item_found->visible) {
+ if (!ewk_tile_unused_cache_tile_get(tm->tuc, item_found))
+ WRN("Ewk_Tile was unused but not in cache? bug!");
+ }
+
+ return item_found;
+}
+
+/**
+ * Create a new tile at given position and zoom level in the matrix.
+ *
+ * The newly created tile is considered in use and not put into cache
+ * of unused tiles. After it is used one should call
+ * ewk_tile_matrix_tile_put() to give it back to matrix.
+ *
+ * @param tm the tile matrix to create tile on.
+ * @param col the column number.
+ * @param row the row number.
+ * @param zoom the level to create tile, used to determine tile size.
+ */
+Ewk_Tile *ewk_tile_matrix_tile_new(Ewk_Tile_Matrix *tm, Evas *evas, unsigned long col, unsigned int row, float zoom)
+{
+ Evas_Coord s;
+ Eina_Inlist *old;
+ Ewk_Tile *t;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(zoom > 0.0, NULL);
+
+ s = TILE_SIZE_AT_ZOOM(TILE_MATRIX_BASE_TILE_SIZE, zoom);
+ zoom = (float)s / (float)TILE_MATRIX_BASE_TILE_SIZE;
+
+ t = ewk_tile_new(evas, s, s, zoom, tm->cspace);
+ if (!t) {
+ ERR("could not create tile %dx%d at %f, cspace=%d",
+ s, s, (double)zoom, tm->cspace);
+ return NULL;
+ }
+
+ old = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+ old = eina_inlist_prepend(old, EINA_INLIST_GET(t));
+ if (!eina_matrixsparse_data_idx_replace(tm->matrix, row, col, t, NULL)) {
+ ERR("could not set matrix cell, row/col outside matrix dimensions!");
+ ewk_tile_free(t);
+ return NULL;
+ }
+
+ t->col = col;
+ t->row = row;
+ t->x = col * s;
+ t->y = row * s;
+
+ cairo_translate(t->cairo, -t->x, -t->y);
+
+ t->stats.full_update = EINA_TRUE;
+ tm->updates = eina_list_append(tm->updates, t);
+
+#ifdef DEBUG_MEM_LEAKS
+ tm->stats.bytes.allocated += t->bytes;
+ tm->stats.tiles.allocated++;
+#endif
+
+ return t;
+}
+
+/**
+ * Gives back the tile to the tile matrix.
+ *
+ * This will report the tile is no longer in use by the one that got
+ * it with ewk_tile_matrix_tile_nearest_get() or
+ * ewk_tile_matrix_tile_exact_get().
+ *
+ * Any previous reference to tile should be released
+ * (ewk_tile_hide()) before calling this function, so it will
+ * be known if it is not visibile anymore and thus can be put into the
+ * unused cache.
+ *
+ * @param tm the tile matrix to return tile to.
+ * @param t the tile instance to return, must @b not be @c NULL.
+ * @param last_used time in which tile was last used.
+ *
+ * @return #EINA_TRUE on success or #EINA_FALSE on failure.
+ */
+Eina_Bool ewk_tile_matrix_tile_put(Ewk_Tile_Matrix *tm, Ewk_Tile *t, double last_used)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(t, EINA_FALSE);
+
+ if (t->visible)
+ return EINA_TRUE;
+
+ t->stats.last_used = last_used;
+ return ewk_tile_unused_cache_tile_put(tm->tuc, t, _ewk_tile_matrix_tile_free, tm);
+}
+
+Eina_Bool ewk_tile_matrix_tile_update(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row, const Eina_Rectangle *update)
+{
+ Ewk_Tile *l, *t;
+ Eina_Rectangle new_update;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(update, EINA_FALSE);
+
+ memcpy(&new_update, update, sizeof(new_update));
+ // check update is valid, otherwise return EINA_FALSE
+ if (update->x < 0 || update->y < 0 || update->w <= 0 || update->h <= 0) {
+ ERR("invalid update region.");
+ return EINA_FALSE;
+ }
+
+ if (update->x + update->w - 1 >= TILE_MATRIX_BASE_TILE_SIZE)
+ new_update.w = TILE_MATRIX_BASE_TILE_SIZE - update->x;
+ if (update->y + update->h - 1 >= TILE_MATRIX_BASE_TILE_SIZE)
+ new_update.h = TILE_MATRIX_BASE_TILE_SIZE - update->y;
+
+ l = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+
+ if (!l)
+ return EINA_TRUE;
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) {
+ if (!t->updates && !t->stats.full_update)
+ tm->updates = eina_list_append(tm->updates, t);
+ new_update.x = roundf(t->zoom * new_update.x);
+ new_update.y = roundf(t->zoom * new_update.y);
+ new_update.w = roundf(t->zoom * new_update.w);
+ new_update.h = roundf(t->zoom * new_update.h);
+ ewk_tile_update_area(t, &new_update);
+ }
+
+ return EINA_TRUE;
+}
+
+Eina_Bool ewk_tile_matrix_tile_update_full(Ewk_Tile_Matrix *tm, unsigned long col, unsigned int row)
+{
+ Ewk_Tile *l, *t;
+ Eina_Matrixsparse_Cell *cell;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE);
+
+ if (!eina_matrixsparse_cell_idx_get(tm->matrix, row, col, &cell))
+ return EINA_FALSE;
+
+ if (!cell)
+ return EINA_TRUE;
+
+ l = eina_matrixsparse_cell_data_get(cell);
+ if (!l) {
+ CRITICAL("matrix cell with no tile!");
+ return EINA_TRUE;
+ }
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) {
+ if (!t->updates && !t->stats.full_update)
+ tm->updates = eina_list_append(tm->updates, t);
+ ewk_tile_update_full(t);
+ }
+
+ return EINA_TRUE;
+}
+
+void ewk_tile_matrix_tile_updates_clear(Ewk_Tile_Matrix *tm, Ewk_Tile *t)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+ if (!t->updates && !t->stats.full_update)
+ return;
+ ewk_tile_updates_clear(t);
+ tm->updates = eina_list_remove(tm->updates, t);
+}
+
+static Eina_Bool _ewk_tile_matrix_slicer_setup(Ewk_Tile_Matrix *tm, const Eina_Rectangle *area, float zoom, Eina_Tile_Grid_Slicer *slicer)
+{
+ unsigned long rows, cols;
+ Evas_Coord x, y, w, h, tw, th;
+
+ if (area->w <= 0 || area->h <= 0) {
+ WRN("invalid area region: %d,%d+%dx%d.",
+ area->x, area->y, area->w, area->h);
+ return EINA_FALSE;
+ }
+
+ x = area->x;
+ y = area->y;
+ w = area->w;
+ h = area->h;
+
+ tw = TILE_SIZE_AT_ZOOM(TILE_W, zoom);
+ th = TILE_SIZE_AT_ZOOM(TILE_H, zoom);
+
+ // cropping area region to fit matrix
+ eina_matrixsparse_size_get(tm->matrix, &rows, &cols);
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+
+ if (y + h - 1 > rows * th)
+ h = rows * th - y;
+ if (x + w - 1 > cols * tw)
+ w = cols * tw - x;
+
+ return eina_tile_grid_slicer_setup(slicer, x, y, w, h, tw, th);
+}
+
+
+Eina_Bool ewk_tile_matrix_update(Ewk_Tile_Matrix *tm, const Eina_Rectangle *update, float zoom)
+{
+ const Eina_Tile_Grid_Info *info;
+ Eina_Tile_Grid_Slicer slicer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tm, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(update, EINA_FALSE);
+
+ if (update->w < 1 || update->h < 1) {
+ DBG("Why we get updates with empty areas? %d,%d+%dx%d at zoom %f",
+ update->x, update->y, update->w, update->h, zoom);
+ return EINA_TRUE;
+ }
+
+ if (!_ewk_tile_matrix_slicer_setup(tm, update, zoom, &slicer)) {
+ ERR("Could not setup slicer for update %d,%d+%dx%d at zoom %f",
+ update->x, update->y, update->w, update->h, zoom);
+ return EINA_FALSE;
+ }
+
+ while (eina_tile_grid_slicer_next(&slicer, &info)) {
+ unsigned long col, row;
+ Ewk_Tile *l, *t;
+ col = info->col;
+ row = info->row;
+
+ l = eina_matrixsparse_data_idx_get(tm->matrix, row, col);
+ if (!l)
+ continue;
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(l), t) {
+ if (!t->updates && !t->stats.full_update)
+ tm->updates = eina_list_append(tm->updates, t);
+ if (info->full)
+ ewk_tile_update_full(t);
+ else {
+ if (t->zoom != zoom)
+ ewk_tile_update_full(t);
+ else
+ ewk_tile_update_area(t, &info->rect);
+ }
+ }
+ }
+
+
+ return EINA_TRUE;
+}
+
+void ewk_tile_matrix_updates_process(Ewk_Tile_Matrix *tm)
+{
+ Eina_List *l, *l_next;
+ Ewk_Tile *t;
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+
+ // process updates, unflag tiles
+ EINA_LIST_FOREACH_SAFE(tm->updates, l, l_next, t) {
+ ewk_tile_updates_process(t, tm->render.cb, tm->render.data);
+ if (t->visible) {
+ ewk_tile_updates_clear(t);
+ tm->updates = eina_list_remove_list(tm->updates, l);
+ }
+ }
+}
+
+void ewk_tile_matrix_updates_clear(Ewk_Tile_Matrix *tm)
+{
+ Ewk_Tile *t;
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+
+ EINA_LIST_FREE(tm->updates, t)
+ ewk_tile_updates_clear(t);
+ tm->updates = NULL;
+}
+
+// remove me later!
+void ewk_tile_matrix_dbg(const Ewk_Tile_Matrix *tm)
+{
+ Eina_Iterator *it = eina_matrixsparse_iterator_complete_new(tm->matrix);
+ Eina_Matrixsparse_Cell *cell;
+ Eina_Bool last_empty = EINA_FALSE;
+
+#ifdef DEBUG_MEM_LEAKS
+ printf("Ewk_Tile Matrix: tiles[+%"PRIu64",-%"PRIu64":%"PRIu64"] "
+ "bytes[+%"PRIu64",-%"PRIu64":%"PRIu64"]\n",
+ tm->stats.tiles.allocated, tm->stats.tiles.freed,
+ tm->stats.tiles.allocated - tm->stats.tiles.freed,
+ tm->stats.bytes.allocated, tm->stats.bytes.freed,
+ tm->stats.bytes.allocated - tm->stats.bytes.freed);
+#else
+ printf("Ewk_Tile Matrix:\n");
+#endif
+
+ EINA_ITERATOR_FOREACH(it, cell) {
+ unsigned long row, col;
+ Eina_Inlist *l;
+ eina_matrixsparse_cell_position_get(cell, &row, &col);
+ l = eina_matrixsparse_cell_data_get(cell);
+
+ if (!l) {
+ if (!last_empty) {
+ last_empty = EINA_TRUE;
+ printf("Empty:");
+ }
+ printf(" [%lu,%lu]", col, row);
+ } else {
+ if (last_empty) {
+ last_empty = EINA_FALSE;
+ printf("\n");
+ }
+ Ewk_Tile *t;
+
+ printf("%3lu,%3lu %10p:", col, row, l);
+ EINA_INLIST_FOREACH(l, t)
+ printf(" [%3lu,%3lu + %dx%d @ %0.3f]%c",
+ t->col, t->row, t->w, t->h, t->zoom,
+ t->visible ? '*': ' ');
+ printf("\n");
+ }
+ }
+ if (last_empty)
+ printf("\n");
+ eina_iterator_free(it);
+
+ ewk_tile_unused_cache_dbg(tm->tuc);
+}
+
+/**
+ * Freeze matrix to not do maintenance tasks.
+ *
+ * Maintenance tasks optimize usage, but maybe we know we should hold
+ * on them until we do the last operation, in this case we freeze
+ * while operating and then thaw when we're done.
+ *
+ * @see ewk_tile_matrix_thaw()
+ */
+void ewk_tile_matrix_freeze(Ewk_Tile_Matrix *tm)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+ if (!tm->frozen)
+ ewk_tile_unused_cache_freeze(tm->tuc);
+ tm->frozen++;
+}
+
+/**
+ * Unfreezes maintenance tasks.
+ *
+ * If this is the last counterpart of freeze, then maintenance tasks
+ * will run immediately.
+ */
+void ewk_tile_matrix_thaw(Ewk_Tile_Matrix *tm)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tm);
+ if (!tm->frozen) {
+ ERR("thawing more than freezing!");
+ return;
+ }
+
+ tm->frozen--;
+ if (!tm->frozen)
+ ewk_tile_unused_cache_thaw(tm->tuc);
+}