Blob Blame History Raw
/* This file is part of GEGL.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2006, 2007 Øyvind Kolås <pippin@gimp.org>
 */

#include "config.h"

#include <glib.h>

#include "glib-object.h"
#include "gegl-buffer-types.h"
#include "gegl-tile-handler-chain.h"
#include "gegl-tile-handler-cache.h"


G_DEFINE_TYPE (GeglTileHandlerChain, gegl_tile_handler_chain, GEGL_TYPE_TILE_HANDLER)

static void
gegl_tile_handler_chain_nuke_cache (GeglTileHandlerChain *tile_handler_chain)
{
  GSList *iter;

  while (gegl_tile_handler_chain_get_first (tile_handler_chain, GEGL_TYPE_TILE_HANDLER_CACHE))
    {
      iter = tile_handler_chain->chain;
      while (iter)
        {
          if (GEGL_IS_TILE_HANDLER_CACHE (iter->data))
            {
              g_object_unref (iter->data);
              tile_handler_chain->chain = g_slist_remove (tile_handler_chain->chain, iter->data);
              break;
            }
          iter = iter->next;
        }
    }
}

static void
gegl_tile_handler_chain_dispose (GObject *object)
{
  GeglTileHandlerChain *tile_handler_chain = GEGL_TILE_HANDLER_CHAIN (object);
  GSList       *iter;
  GSList       *chain;

  /* Get rid of the cache before any further parts of the deconstruction of the
   * TileStore chain, unwritten tiles need a living TileStore for their
   * deconstruction.
   */
  gegl_tile_handler_chain_nuke_cache (tile_handler_chain);

  /* While we destroy tile_handler_chain->chain, don't have
   * tile_handler_chain->chain set, because it might otherwise be used
   * by other objects in the dispose phase
   */
  chain = tile_handler_chain->chain;
  tile_handler_chain->chain = NULL;

  iter = chain;
  while (iter)
    {
      if (iter->data)
        {
          if (G_IS_OBJECT (iter->data))
            g_object_unref (iter->data);
          else
            g_free (iter->data);
        }
      iter = iter->next;
    }

  if (chain)
    g_slist_free (chain);
  chain = NULL;

  G_OBJECT_CLASS (gegl_tile_handler_chain_parent_class)->dispose (object);
}


static void
gegl_tile_handler_chain_finalize (GObject *object)
{
  G_OBJECT_CLASS (gegl_tile_handler_chain_parent_class)->finalize (object);
}

static gpointer
gegl_tile_handler_chain_command (GeglTileSource *tile_store,
                                 GeglTileCommand command,
                                 gint            x,
                                 gint            y,
                                 gint            z,
                                 gpointer        data)
{
  GeglTileHandlerChain *tile_handler_chain = (GeglTileHandlerChain *) tile_store;
  GeglTileSource *source = ((GeglTileHandler *) tile_store)->source;

  if (tile_handler_chain->chain != NULL)
    return gegl_tile_source_command ((GeglTileSource *)(tile_handler_chain->chain->data),
                                  command, x, y, z, data);
  else if (source)
    return gegl_tile_source_command (source, command, x, y, z, data);
  else
    g_assert (0);

  return FALSE;
}

static void
gegl_tile_handler_chain_class_init (GeglTileHandlerChainClass *class)
{
  GObjectClass      *gobject_class;
  gobject_class    = (GObjectClass *) class;

  gobject_class->finalize = gegl_tile_handler_chain_finalize;
  gobject_class->dispose  = gegl_tile_handler_chain_dispose;
}

static void
gegl_tile_handler_chain_init (GeglTileHandlerChain *self)
{
  ((GeglTileSource*)self)->command = gegl_tile_handler_chain_command;
  self->chain = NULL;
}

void
gegl_tile_handler_chain_bind (GeglTileHandlerChain *tile_handler_chain)
{
  GSList *iter;

  iter = tile_handler_chain->chain;
  while (iter)
    {
      GeglTileHandler  *handler;
      GeglTileSource *source = NULL;

      handler = iter->data;
      if (iter->next)
        {
          source = iter->next->data;
        }
      else
        {
          source = gegl_tile_handler_get_source (tile_handler_chain);
        }
      gegl_tile_handler_set_source (handler, source);
      iter = iter->next;
    }
}

GeglTileHandler *
gegl_tile_handler_chain_add (GeglTileHandlerChain *tile_handler_chain,
                             GeglTileHandler      *handler)
{
  tile_handler_chain->chain = g_slist_prepend (tile_handler_chain->chain, handler);
  /*gegl_tile_handler_chain_bind (tile_handler_chain);*/
  return handler;
}

/*
 * return the first handler of a given type
 */
GeglTileHandler *
gegl_tile_handler_chain_get_first (GeglTileHandlerChain *tile_handler_chain,
                                   GType                 type)
{
  GSList *iter;

  iter = tile_handler_chain->chain;
  while (iter)
    {
      if ((G_TYPE_CHECK_INSTANCE_TYPE ((iter->data), type)))
        {
          return iter->data;
        }
      iter = iter->next;
    }
  return NULL;
}