/* Pango
 * silgraphite-fc.c: SILGraphite based shaper for FreeType-based backends
 * silgraphite-break.c: SILGraphite based shaper for line breaking
 *                      when a graphite font is available
 *
 * Copyright (C) 2004-2007 SIL International
 * Author: Daniel Glassey <wdg@debian.org>
 *
 * 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; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <gmodule.h>
#include <pango/pango-engine.h>
#include <pango/pango-utils.h>
#include <pango/pangofc-font.h>
#include <pango/pangoxft.h>
#include "pangographite.h"



/* No extra fields needed */
typedef PangoEngineShape      GraphiteEngineShape;
typedef PangoEngineShapeClass GraphiteEngineShapeClass;

typedef PangoEngineLang      GraphiteEngineLang;
typedef PangoEngineLangClass GraphiteEngineLangClass;

#define SCRIPT_SHAPE_ENGINE_NAME "GraphiteScriptEngineShape"
#define LANG_ENGINE_NAME "GraphiteScriptEngineLang"



static PangoEngineScriptInfo graphite_scripts[] = {
#if (PANGO_MAJOR_VERSION > 1 || PANGO_MINOR_VERSION > 18)
  {    PANGO_SCRIPT_COMMON,	"" },   	       /* Zyyy */
#else
  {    PANGO_SCRIPT_COMMON,	"*" },   	       /* Zyyy */
#endif
  {    PANGO_SCRIPT_INHERITED,	"*" },          /* Qaai */
  {    PANGO_SCRIPT_ARABIC,	"*" },             /* Arab */
  {    PANGO_SCRIPT_ARMENIAN,	"*" },           /* Armn */
  {    PANGO_SCRIPT_BENGALI,	"*" },            /* Beng */
  {    PANGO_SCRIPT_BOPOMOFO,	"*" },           /* Bopo */
  {    PANGO_SCRIPT_CHEROKEE,	"*" },           /* Cher */
  {    PANGO_SCRIPT_COPTIC,	"*" },             /* Qaac */
  {    PANGO_SCRIPT_CYRILLIC,	"*" },           /* Cyrl (Cyrs) */
  {    PANGO_SCRIPT_DESERET,	"*" },            /* Dsrt */
  {    PANGO_SCRIPT_DEVANAGARI,	"*" },         /* Deva */
  {    PANGO_SCRIPT_ETHIOPIC,	"*" },           /* Ethi */
  {    PANGO_SCRIPT_GEORGIAN,	"*" },           /* Geor (Geon, Geoa) */
  {    PANGO_SCRIPT_GOTHIC,	"*" },             /* Goth */
  {    PANGO_SCRIPT_GREEK,	"*" },              /* Grek */
  {    PANGO_SCRIPT_GUJARATI,	"*" },           /* Gujr */
  {    PANGO_SCRIPT_GURMUKHI,	"*" },           /* Guru */
  {    PANGO_SCRIPT_HAN,	"*" },                /* Hani */
  {    PANGO_SCRIPT_HANGUL,	"*" },             /* Hang */
  {    PANGO_SCRIPT_HEBREW,	"*" },             /* Hebr */
  {    PANGO_SCRIPT_HIRAGANA,	"*" },           /* Hira */
  {    PANGO_SCRIPT_KANNADA,	"*" },            /* Knda */
  {    PANGO_SCRIPT_KATAKANA,	"*" },           /* Kana */
  {    PANGO_SCRIPT_KHMER,	"*" },              /* Khmr */
  {    PANGO_SCRIPT_LAO,	"*" },                /* Laoo */
  {    PANGO_SCRIPT_LATIN,	"*" },              /* Latn (Latf, Latg) */
  {    PANGO_SCRIPT_MALAYALAM,	"*" },          /* Mlym */
  {    PANGO_SCRIPT_MONGOLIAN,	"*" },          /* Mong */
  {    PANGO_SCRIPT_MYANMAR,	"*" },            /* Mymr */
  {    PANGO_SCRIPT_OGHAM,	"*" },              /* Ogam */
  {    PANGO_SCRIPT_OLD_ITALIC,	"*" },         /* Ital */
  {    PANGO_SCRIPT_ORIYA,	"*" },              /* Orya */
  {    PANGO_SCRIPT_RUNIC,	"*" },              /* Runr */
  {    PANGO_SCRIPT_SINHALA,	"*" },            /* Sinh */
  {    PANGO_SCRIPT_SYRIAC,	"*" },             /* Syrc (Syrj, Syrn, Syre) */
  {    PANGO_SCRIPT_TAMIL,	"*" },              /* Taml */
  {    PANGO_SCRIPT_TELUGU,	"*" },             /* Telu */
  {    PANGO_SCRIPT_THAANA,	"*" },             /* Thaa */
  {    PANGO_SCRIPT_THAI,	"*" },               /* Thai */
  {    PANGO_SCRIPT_TIBETAN,	"*" },            /* Tibt */
  {    PANGO_SCRIPT_CANADIAN_ABORIGINAL,	"*" }, /* Cans */
  {    PANGO_SCRIPT_YI,		"*" },                 /* Yiii */
  {    PANGO_SCRIPT_TAGALOG,	"*" },            /* Tglg */
  {    PANGO_SCRIPT_HANUNOO,	"*" },            /* Hano */
  {    PANGO_SCRIPT_BUHID,	"*" },              /* Buhd */
  {    PANGO_SCRIPT_TAGBANWA,	"*" },           /* Tagb */
  
  	/* Unicode-4.0 additions */
  {    PANGO_SCRIPT_BRAILLE,	"*" },            /* Brai */
  {    PANGO_SCRIPT_CYPRIOT,	"*" },            /* Cprt */
  {    PANGO_SCRIPT_LIMBU,	"*" },              /* Limb */
  {    PANGO_SCRIPT_OSMANYA,	"*" },            /* Osma */
  {    PANGO_SCRIPT_SHAVIAN,	"*" },            /* Shaw */
  {    PANGO_SCRIPT_LINEAR_B,	"*" },           /* Linb */
  {    PANGO_SCRIPT_TAI_LE,	"*" },             /* Tale */
  {    PANGO_SCRIPT_UGARITIC,	"*" }            /* Ugar */
  
#if (PANGO_MAJOR_VERSION > 1) || (PANGO_MINOR_VERSION > 9)
  	/* Unicode-4.1 additions  (requires pango >= 1.9.1) */
  ,{    PANGO_SCRIPT_NEW_TAI_LUE,	"*" },            /* Talu */
  {    PANGO_SCRIPT_BUGINESE,	"*" },            /* Bugi */
  {    PANGO_SCRIPT_GLAGOLITIC,	"*" },            /* Glag */
  {    PANGO_SCRIPT_TIFINAGH,	"*" },            /* Tfng */
  {    PANGO_SCRIPT_SYLOTI_NAGRI,	"*" },            /* Sylo */
  {    PANGO_SCRIPT_OLD_PERSIAN,	"*" },            /* Xpeo */
  {    PANGO_SCRIPT_KHAROSHTHI,	"*" }            /* Khar */
#endif

#if (PANGO_MAJOR_VERSION > 1) || (PANGO_MINOR_VERSION > 12)
      /* Unicode-5.0 additions */
  ,{    PANGO_SCRIPT_UNKNOWN,   "*" },            /* Zzzz */
  {    PANGO_SCRIPT_BALINESE,   "*" },           /* Bali */
  {    PANGO_SCRIPT_CUNEIFORM,  "*" },          /* Xsux */
  {    PANGO_SCRIPT_PHOENICIAN, "*" },         /* Phnx */
  {    PANGO_SCRIPT_PHAGS_PA,   "*" },           /* Phag */
  {    PANGO_SCRIPT_NKO,        "*" }                 /* Nkoo */
#endif
};

static PangoEngineInfo script_engines[] = {
  {
    SCRIPT_SHAPE_ENGINE_NAME,
    PANGO_ENGINE_TYPE_SHAPE,
    PANGO_RENDER_TYPE_FC,
    graphite_scripts, G_N_ELEMENTS(graphite_scripts)
  },
  {
    LANG_ENGINE_NAME,
    PANGO_ENGINE_TYPE_LANG,
    PANGO_RENDER_TYPE_NONE,
    graphite_scripts, G_N_ELEMENTS(graphite_scripts)
  }
};


static void 
graphite_engine_script_shape (PangoEngineShape *engine,
		    PangoFont        *font,
		    const char       *text,
		    gint              length,
		    const PangoAnalysis    *analysis,
		    PangoGlyphString *glyphs)
{
    g_return_if_fail (PANGO_IS_FC_FONT (font));
    PangoFcFont *fcfont = PANGO_FC_FONT(font);
    //static GStaticMutex mutex = G_STATIC_MUTEX_INIT;

    //g_static_mutex_lock (&mutex);
    // Do Graphite Shaping
    graphite_PangoGlyphString(text, length, fcfont, glyphs, 
      pango_language_to_string(analysis->language), analysis->level % 2);

    //g_static_mutex_unlock (&mutex);
}

static PangoCoverageLevel
graphite_engine_covers (PangoEngineShape *engine,
		     PangoFont        *font,
		     PangoLanguage    *lang,
		     gunichar          wc)
{
  FcChar8 * fontcap;
  
  // First check that the font covers the lang
  PangoCoverage *coverage;
  PangoCoverageLevel result = PANGO_COVERAGE_NONE;
  PangoFcFont *fcfont;
  FcPattern *tmppat;

  if (PANGO_IS_FC_FONT (font))
  {
    coverage = pango_font_get_coverage (font, lang);
    result = pango_coverage_get (coverage, wc);
    pango_coverage_unref (coverage);

    if (result != PANGO_COVERAGE_EXACT)
    {
      result = PANGO_COVERAGE_NONE;
    }
    else
    {
      fcfont = PANGO_FC_FONT(font);
      tmppat = fcfont->font_pattern;
      if (FcPatternGetString (tmppat, FC_CAPABILITY, 0, &fontcap) != FcResultMatch)
      {
        result = PANGO_COVERAGE_NONE;
      }
      else if (strstr((char *)fontcap, "ttable:Silf"))
      {
        result = PANGO_COVERAGE_EXACT;
      }
      else
        result = PANGO_COVERAGE_NONE;
    }
  }

  // fontconfig >= 2.3.0 has fontcap for font capabilities inc silgraphite tttables   

  return result;
}







void
graphite_engine_break (PangoEngineLang *engine,
		const gchar   *text,
		gint           length,
		PangoAnalysis *analysis,
		PangoLogAttr  *attrs,
		int            attrs_len)
{
	PangoFcFont *fcfont = PANGO_FC_FONT(analysis->font);
	FcChar8 * fontcap;

#if (PANGO_MAJOR_VERSION < 2 && PANGO_MINOR_VERSION < 15)
	pango_default_break(text, length, analysis, attrs, attrs_len);
#endif

  if (fcfont)
    {
      if (FcPatternGetString (fcfont->font_pattern, FC_CAPABILITY, 0, &fontcap) != FcResultMatch)
      {
      }
      else
      {
        if (strstr((char*)fontcap, "ttable:Silf"))
        {
          //static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
      
          //g_static_mutex_lock (&mutex);
          // Do Graphite Breaking
          graphite_PangoLogAttrs(text, length, fcfont, 
            attrs, attrs_len,
            pango_language_to_string(analysis->language),
            analysis->level % 2);
          //g_static_mutex_unlock (&mutex);
          //return;
        }
      }
    }

/*
  int i;
  if (have_graphite)
    {
      const gchar *next = text;
      for (i=0; i < attrs_len; i++)
        {
          gunichar wc = g_utf8_get_char (next);
          next = g_utf8_next_char (next);
          attrs[i].backspace_deletes_character = WDG_BACKSPACE_DELETES_CHARACTER(wc);
        }
    }
*/
}

static void
graphite_engine_shape_class_init (PangoEngineShapeClass *class)
{
  class->covers = graphite_engine_covers;
  class->script_shape = graphite_engine_script_shape;
}

static void
graphite_engine_lang_class_init (PangoEngineLangClass *class)
{
  class->script_break = graphite_engine_break;
}


PANGO_ENGINE_SHAPE_DEFINE_TYPE (GraphiteEngineShape, graphite_engine_shape,
  graphite_engine_shape_class_init, NULL);
PANGO_ENGINE_LANG_DEFINE_TYPE (GraphiteEngineLang, graphite_engine_lang,
  graphite_engine_lang_class_init, NULL);



void 
PANGO_MODULE_ENTRY(init) (GTypeModule *module)
{
  graphite_engine_shape_register_type (module);
  graphite_engine_lang_register_type (module);
}

void 
PANGO_MODULE_ENTRY(exit) (void)
{
}

void 
PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines,
			  int              *n_engines)
{
  *engines = script_engines;
  *n_engines = G_N_ELEMENTS (script_engines);
}

PangoEngine *
PANGO_MODULE_ENTRY(create) (const char *id)
{
  if (!strcmp (id, LANG_ENGINE_NAME))
    return g_object_new (graphite_engine_lang_type, NULL);
  else
  if (!strcmp (id, SCRIPT_SHAPE_ENGINE_NAME))
    return g_object_new (graphite_engine_shape_type, NULL);
  else
    return NULL;
}



