/*
 * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
 * Copyright (C) 2005, 2008
 *   National Institute of Advanced Industrial Science and Technology (AIST)
 *   Registration Number H16PRO276
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * $Id: m17n.c,v 1.11 2008/02/13 09:08:10 nishida Exp $ 
 */

#ifdef USE_M17N
#include "mgp.h"
#ifdef USE_SETLOCALE
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#endif

#ifdef HAVE_FONTCONFIG_FONTCONFIG_H
/* This is to parse Xft font name pattern.  */
#include <fontconfig/fontconfig.h>
#endif

/* Prototypes for internal functions.  They start with "M17N__".  */

static int M17N__line_break __P ((MText *, int, int, int ,int, int));
static void M17N__format_line __P ((int, int, int *, int *));
static MText *M17N__gen_mtext __P ((u_char *));
static void M17N__add_font_to_fontset __P ((MFont *));
static MFont *M17N__get_font __P ((char *, char *));

/* The following two variables are set by M17N_draw_string and
   referred by M17N__format_line ().  */

/* Width remaining for the first line of a drawning text.  */
static int first_width;
/* Width of the currently drawing area.  */
static int area_width;

static MDrawControl control;
static MFontset *fontset;
static MFace *faces[2];
static MSymbol languages[2];
/* M-text containing a single space.  It is used to get normal
   ascent/descent of an ASCII font selected for the current set of
   faces.  */
static MText *space;

static MSymbol Miso8859_1, Municode_bmp, Mjisx0208, Mgb2312, Mksc5601;
static MSymbol Mlatin, Mhan, Mhangul, Mkatakana, Mhiragana;
static MSymbol Mzh, Mja, Mko;
static MSymbol Miso_8859_1, Mutf_8, Miso_2022_7bit;

static int kinsoku_range [][2] = {
  {0x3041, 0x30FF},		/* Kana */
  {0x2E80, 0x2FDF},		/* radical */
  {0x3400, 0x4DB5},		/* CJK Ideograph Extention A */
  {0x4E00, 0x9FAF},		/* CJK Ideograph */  
  {0XF900, 0xFAFF},		/* CJK COMPATIBILITY IDEOGRAPH */
  {0X20000, 0x2A6D6},		/* CJK Ideograph Extention B */
  {0x2F800, 0x2FA1D}		/* CJK COMPATIBILITY IDEOGRAPH */		
};

static int kinsoku_list [] = {
/* UNICODE */
0x2019, 0x201A, 0x201D, 0x201E, 0x2032, 0x2033, 0x2034, 0x203A,
0x203C, 0x203D, 0x2046, 0x2047, 0x2048, 0x2049, 0x204D, 0x3000,
0x3001, 0x3002, 0x3009, 0x300B, 0x300D, 0x300F, 0x3011, 0x3015,
0x3017, 0x3018, 0x309B, 0x309C, 0x309D, 0x309E, 0x30FD, 0x30FD,
0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A, 0xFF1B, 0xFF1F, 0xFF3D,
0xFF5D, 0xFF60, 0xFF61, 0xFF63, 0xFF64,
/* JISX208 */
0x00A7, 0x00B0, 0x2018, 0x201C, 0x2032, 0x2033, 0x2103, 0x3008,
0x300A, 0x300C, 0x300E, 0x3010, 0x3014, 0x3016, 0xFF02, 0xFF08,
0xFF20, 0xFF3B, 0xFF5B
};

static MCharTable *kinsoku_table;
static MSymbol Mkinsoku;

/* Find a linebreak position.  Set in control.line_break */

static int
M17N__line_break (mt, pos, from, to, line, y)
     MText *mt;
     int pos, from, to;
     int line, y;
{
	int c, i = 0, opos = pos;
	c = mtext_ref_char(mt, pos);
	if (mchartable_lookup(kinsoku_table, c) == Mt) return pos;	
	while(pos != from){
		if (i ++ > 10) return opos; /* for stupidly long line */	
		pos --;
		c = mtext_ref_char(mt, pos);
		if (c < 256 && isspace(c)) return pos +1;	
		if (mchartable_lookup(kinsoku_table, c) == Mt) return pos;	
	}

	return pos;
}

/* Decide the width and indentation of the LINEth line.  Set in
   control.format.  */

static void
M17N__format_line(line, y, indent, width)
	int line, y, *indent, *width;
{
  *width = line == 0 ? first_width : area_width;
  *indent = 0;
}

/* Return an M-text generated from the byte sequence at P.  */

static MText *
M17N__gen_mtext (p)
	u_char *p;
{
	MSymbol coding;
	MText *mt = 0;
	int i, len = strlen ((char *) p);

	if (len == 0) return NULL;

	if (!mt && mgp_charset[0] != '\0') {
		coding = mconv_resolve_coding (msymbol (mgp_charset));
		if (coding) mt = mconv_decode_buffer (coding, p, len);
	}
	if (strchr ((char *) p, '\033')) {
		/* Try ISO-2022 encoding.  */
		coding = mconv_resolve_coding (Miso_2022_7bit);
		if (coding) mt = mconv_decode_buffer (coding, p, len);
		if (mt)
		  {
		    int len = mtext_len (mt);
		    int pos = 0, to;

		    for (pos = 0; pos < len; pos = to)
		      if (mtext_prop_range (mt, Mcharset, pos, NULL, &to, 0))
			{
			  MSymbol cs = mtext_get_prop (mt, pos, Mcharset);
			  char *name = msymbol_name (cs);
			  MSymbol lang
			    = (strncmp (name, "jis", 3) == 0 ? Mja
			       : strncmp (name, "gb", 2) == 0 ? Mzh
			       : strncmp (name, "ksc", 3) == 0 ? Mko
			       : Mnil);

			  if (lang != Mnil)
			    mtext_put_prop (mt, pos, to, Mlanguage, lang);
			}
		  }

	}
	if (!mt)
	  {
	    /* Check ASCII only.  */
	    for (i = 0; i < len; i++)
	      if (p[i] >= 0x80)
		break;
	    if (i == len)
	      mt = mtext_from_data (p, len, MTEXT_FORMAT_US_ASCII);
	  }
	if (!mt) {
		/* Try UTF-8.  */
		coding = mconv_resolve_coding (Mutf_8);
		if (coding) mt = mconv_decode_buffer (coding, p, len);
	}
#ifdef USE_SETLOCALE
#ifdef HAVE_LOCALE_H
	if (!mt){
		/* Try the encoding of the current locale.  */
		mt = mconv_decode_buffer (Mnil, p, len);
	}
#endif
#endif
	if (!mt) {
		/* XXX: wrong encoding, fall back to ISO-8859-1 */
		mt = mconv_decode_buffer (Miso_8859_1, p, len);
	}
	if (!mt) {
		/* Unknown encoding */
		fprintf(stderr, "unexpected byte sequence found.\n");
		fprintf(stderr, "  (expecting: %s (by %%charset), iso-2022-7bit, utf-8, default encoding of locale)\n", mgp_charset);
		exit(1);
	}

	return mt;
}


/* Return a font matching SEED and REGISTRY.  */

static MFont *
M17N__get_font (seed, registry)
     char *seed;
     char *registry;
{
  static MPlist *font_list;
  MPlist *plist;
  MSymbol sym_seed, sym_registry;
  MSymbol family, weight, slant;
  MFont *font;
  char *p;

  if (! font_list)
    font_list = mplist ();

  sym_seed = msymbol (seed);
  if (strncmp (registry, "iso8859", 7) == 0)
    sym_registry = msymbol (registry);
  else if (strncmp (registry, "jisx0208", 8) == 0)
    sym_registry = Mjisx0208;
  else if (strncmp (registry, "gb2312", 6) == 0)
    sym_registry = Mgb2312;
  else if (strncmp (registry, "ksc5601", 7) == 0)
    sym_registry = Mksc5601;
  else
    sym_registry = msymbol (registry);

  for (plist = mplist_find_by_key (font_list, sym_seed); plist;
       plist = mplist_find_by_key (mplist_next (plist), sym_seed))
    {
      font = mplist_value (plist);
      if (mfont_get_prop (font, Mregistry) == sym_registry)
	return font;
    }

  family = weight = slant = Mnil;
  if ((p = strchr (seed, '-')) != NULL)
    {
      /* Should be XLFD of format FAMILY-WEIGHT[-SLANT] */
      char *copy = alloca (strlen (seed) + 1);

      strcpy (copy, seed);
      copy[p - seed] = '\0';
      family = msymbol (copy);
      copy += p + 1 - seed;
      p = strchr (copy, '-');
      if (! p)
	weight = msymbol (copy);
      else
	{
	  *p = 0;
	  weight = msymbol (copy);
	  slant = msymbol (p + 1);
	}
    }
  else if (strchr (seed, ':'))
    {
      /* Should be Xft (i.e. Fontconfig) pattern.  */
#ifdef HAVE_FONTCONFIG_FONTCONFIG_H
      FcPattern *pat = FcNameParse ((FcChar8 *) seed);
      FcChar8 *p;
      int i;

      if (pat)
	{
	  if (FcPatternGetString (pat, FC_FAMILY, 0, &p) == FcResultMatch)
	    family = msymbol ((char *) p);
	  if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &i) == FcResultMatch)
	    weight = (i < FC_WEIGHT_EXTRALIGHT ? msymbol ("ultralight")
		      : i < FC_WEIGHT_LIGHT ? msymbol ("extralight")
		      : i < FC_WEIGHT_REGULAR ? msymbol ("light")
		      : i < FC_WEIGHT_MEDIUM ? msymbol ("regular")
		      : i < FC_WEIGHT_DEMIBOLD ? msymbol ("medium")
		      : i < FC_WEIGHT_BOLD ? msymbol ("demibold")
		      : i < FC_WEIGHT_EXTRABOLD ? msymbol ("bold")
		      : i < FC_WEIGHT_ULTRABOLD ? msymbol ("extrabold")
		      : i < FC_WEIGHT_BLACK ? msymbol ("ultrabold")
		      : msymbol ("black"));
	  else
	    weight = msymbol ("medium");
	  if (FcPatternGetInteger (pat, FC_SLANT, 0, &i) == FcResultMatch)
	    slant = (i < FC_SLANT_ITALIC ? msymbol ("r")
		     : i < FC_SLANT_OBLIQUE ? msymbol ("i")
		     : msymbol ("o"));
	  else
	    slant = msymbol ("r");
	  FcPatternDestroy (pat);
	}
      else
#endif
	/* Treat the seed as family name.  */
	family = msymbol (seed);
    }
  else
    /* Treat the name as family name.  */
    family = msymbol (seed);	

  font = mfont ();
  mfont_put_prop (font, Mfamily, family);
  mfont_put_prop (font, Mweight, weight);
  mfont_put_prop (font, Mstyle, slant);
  mfont_put_prop (font, Mregistry, sym_registry);
  mplist_push (font_list, sym_seed, font);
  return font;
}

/* Pre-define the font set in CP.   */

static void
M17N__add_font_to_fontset (font)
     MFont *font;
{
  MSymbol family, registry;
  MPlist *plist, *pl;
  static MPlist *registered_list;
  
  family = mfont_get_prop (font, Mfamily);
  registry = mfont_get_prop (font, Mregistry);

  plist = NULL;
  if (! registered_list)
    registered_list = mplist ();
  else if ((plist = mplist_get (registered_list, family))
	   && (pl = mplist_get (plist, registry)))
    return;

  /* This font is not yet registered.  */
  if (! plist)
    plist = mplist ();
  mplist_push (plist, registry, Mt);
  mplist_push (registered_list, family, plist);

  if (registry == Miso8859_1)
    {
      /* This may be a TTF, in which case, we may be able to use it
	 for any scripts.  */
      plist = mfontset_lookup (fontset, Mt, Mnil, Mnil);
    }
  else
    {
      plist = mplist ();
      if (registry == Mjisx0208)
	{
	  mplist_put (plist, Mhan, NULL);
	  mplist_put (plist, Mhiragana, NULL);
	  mplist_put (plist, Mkatakana, NULL);
	}
      else if (registry == Mgb2312)
	mplist_put (plist, Mhan, NULL);
      else if (registry == Mksc5601)
	mplist_put (plist, Mhangul, NULL);
      else if (strncmp (msymbol_name (registry), "iso8859-", 8) == 0)
	mplist_put (plist, Mlatin, NULL);
    }
  font = mfont ();
  mfont_put_prop (font, Mfamily, family);
  for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
    {
      MSymbol script = mplist_key (pl);
      MPlist *p = mfontset_lookup (fontset, script, Mt, Mnil);
      MPlist *p0;
      
      for (p0 = p; mplist_key (p0) != Mnil; p0 = mplist_next (p0))
	{
	  MSymbol lang = mplist_key (p0);

	  mfont_put_prop (font, Mregistry, registry);
	  if (registry == Miso8859_1)
	    {
	      /* Add this font only for Latin script, and add
		 unicode version of this font for any scripts.  */
	      if (script == Mlatin)
		mfontset_modify_entry (fontset, script, lang, Mnil,
				       font, Mnil, 1);
	      mfont_put_prop (font, Mregistry, Municode_bmp);
	    }
	  mfontset_modify_entry (fontset, script, lang, Mnil, font, Mnil, 1);
	}
      m17n_object_unref (p);
    }
  m17n_object_unref (plist);

  mfontset_modify_entry (fontset, Mnil, Mnil, Mnil, font, Mnil, 1);
  if (registry == Miso8859_1)
    {
      mfont_put_prop (font, Mregistry, Municode_bmp);
      mfontset_modify_entry (fontset, Mnil, Mnil, Mnil, font, Mnil, 1);
    }
}


/* Internal API (functions called from the other files) */

void
M17N_init()
{
	int i;

	M17N_INIT();
#ifdef USE_SETLOCALE
#ifdef HAVE_LOCALE_H
	mlocale_set (LC_CTYPE, NULL);
#endif
#endif
	space = mtext_from_data (" ", 1, MTEXT_FORMAT_US_ASCII);
	fontset = mfontset ("default");
	memset (&control, 0, sizeof control);
	control.two_dimensional = 1;
	control.enable_bidi = 1;
	control.ignore_formatting_char = 1;
	control.disable_caching = 0;
	control.max_line_width = 0;
	control.anti_alias = 1;
	control.format = M17N__format_line; 
	control.line_break = M17N__line_break; 

	/* Generate kinsoku_char_table.  */
	Mkinsoku = msymbol ("kinsoku");
	kinsoku_table = mchartable (Msymbol, Mnil);
	for (i = 0; i < (sizeof(kinsoku_range) / sizeof(kinsoku_range[0])); i++)
		mchartable_set_range (kinsoku_table, kinsoku_range[i][0],
			kinsoku_range[i][1], Mt);
	for (i = 0; i < (sizeof kinsoku_list / sizeof (int)); i++)
		mchartable_set (kinsoku_table, kinsoku_list[i], Mkinsoku);

	Miso8859_1 = msymbol ("iso8859-1");
	Municode_bmp = msymbol ("unicode-bmp");
	Mjisx0208 = msymbol ("jisx0208.1983-0");
	Mgb2312 = msymbol ("gb2312.1980-0");
	Mksc5601 = msymbol ("ksc5601.1987-0");

	Mlatin = msymbol ("latin");
	Mhan = msymbol ("han");
	Mhangul = msymbol ("hangul");
	Mkatakana = msymbol ("katakana");
	Mhiragana = msymbol ("hiragana");
	Mzh = msymbol ("zh");
	Mja = msymbol ("ja");
	Mko = msymbol ("ko");

	Mutf_8 = msymbol ("utf-8");
	Miso_8859_1 = msymbol ("iso-8859-1");
	Miso_2022_7bit = msymbol ("iso-2022-7bit");
}

void
M17N_fini(void)
{
  m17n_object_unref (kinsoku_table);
  if (fontset)
    m17n_object_unref (fontset);
  if (faces[0])
    m17n_object_unref (faces[0]);
  if (faces[1])
    m17n_object_unref (faces[1]);
  if (space)
    m17n_object_unref (space);
  M17N_FINI ();
}


/* Set font-oriented properties (family, weight, slant) of the current
   face to what specified in SEED.  */

void
M17N_set_font (seed, registry)
     char *seed;
     char *registry;
{
  MFont *font = M17N__get_font (seed, registry);
  MSymbol reg;
  MFace *face;

  M17N__add_font_to_fontset (font);
  reg = mfont_get_prop (font, Mregistry);
  if (reg != Miso8859_1)
    return;
  face = faces[caching];
  if (! face)
    face = faces[caching] = mface ();
  mface_put_prop (face, Mfoundry, (MSymbol)  mfont_get_prop (font, Mfoundry));
  mface_put_prop (face, Mfamily, (MSymbol)  mfont_get_prop (font, Mfamily));
  mface_put_prop (face, Mweight, mfont_get_prop (font, Mweight));
  mface_put_prop (face, Mstyle, mfont_get_prop (font, Mstyle));
  mface_put_prop (face, Mstretch, mfont_get_prop (font, Mstretch));
  mface_put_prop (face, Madstyle, mfont_get_prop (font, Madstyle));
}

void
M17N_set_color (color)
     u_long color;
{
  MFace *face = faces[caching];
  char color_string[20];
  XColor xcolor;

  if (! faces[caching])
    face = faces[caching] = mface ();

  xcolor.pixel = color;  
  XQueryColor (display, colormap, &xcolor);
  sprintf (color_string, "#%04X%04X%04X",
	   xcolor.red, xcolor.green, xcolor.blue); 
  mface_put_prop (face, Mforeground, msymbol (color_string));
}

/* Calculate the extents of text pointed by CP and update STATE.  */

void
M17N_draw_string (state, cp)
	struct render_state *state;
	struct ctrl *cp;
{
  MText *mt;
  static MFrame *drawframe;
  static MPlist *plist;
  MDrawGlyphInfo info;
  MDrawMetric rect_sp, rect;
  int ascent = 0, descent = 0;
  int nchars;
  int i, c;
  int leftfillpos = state->leftfillpos;

  if (cp->ct_flag == 0)
    {
      /* cp->ctc_value points a raw byte sequence.  */
      mt = M17N__gen_mtext ((u_char *) cp->ctc_value);
      if (mt)
	mtext_put_prop (mt, 0, 1, msymbol ("leftfillpos"),
			(void *) leftfillpos);
      cp->ctc_value = (char *) mt;
      cp->ct_flag = 1;
    }
  else
    {
      /* cp->ctc_valus points an M-text. */
      mt = (MText *) cp->ctc_value;
      if (mt)
	leftfillpos = (int) mtext_get_prop (mt, 0, msymbol ("leftfillpos"));
    }
  if (! mt)
    return;

  nchars = mtext_len (mt);
  if (! plist)
    {
      plist = mplist ();
      mplist_add (plist, Mdisplay, display);
      drawframe = mframe (plist);
    }

  if (! mtext_get_prop (mt, 0, Mface))
    {
      MFace *face;

      if (! faces[caching])
	faces[caching] = mface ();
      face = mface_copy (faces[caching]);
      mface_put_prop (face, Msize, (void *) (char_size[caching] * 10));
      mtext_push_prop (mt, 0, nchars, Mface, face);
      if (languages[caching])
	mtext_push_prop (mt, 0, nchars, Mlanguage, languages[caching]);
      m17n_object_unref (face);
    }

  /* Compare the normal ascent/descent and the physical ascent/descent
     of this M-text, and use the bigger ones.  */
  mdraw_text_extents(drawframe, space, 0, 1, &control, NULL, NULL, &rect_sp);
  rect_sp.height += rect_sp.y;	/* calculate descent */

  area_width = state->width - leftfillpos;
  first_width = area_width - state->linewidth;
  mdraw_glyph_info (drawframe, mt, 0, 0, &control, &info);
  if (info.line_to == nchars)
    {
      /* All text can be drawn on the current line.  */
      mdraw_text_extents (drawframe, mt, 0, nchars, &control,
			  NULL, NULL, &rect);
      rect.height += rect.y; /* calculate descent */
      ascent = rect_sp.y < rect.y ? - rect_sp.y : - rect.y;
      descent = rect_sp.height > rect.height ? rect_sp.height : rect.height;
      for (i = 0; state->brankline && i < nchars; i++)
	if ((c = mtext_ref_char (mt, i)) != ' ' && c != '\t')
	  state->brankline = 0;
      draw_line_itemsize(state, ascent, descent, 0);
      obj_new_mtext (state, state->linewidth, state->charoff,
		     mt, 0, nchars, drawframe, ascent, descent);
      state->linewidth += rect.width;
    }
  else
    {    
      int i, c;
      MDrawGlyphInfo info2;
      /* We need a line break.  Check if there's a room for at least
	 one fragment on the current line.  */

      /* Skip the leading spaces.  */
      for (i = 0; i < nchars && mtext_ref_char (mt, 0) == ' '; i++);
      for (; i < nchars; i++)
	{
	  if ((c = mtext_ref_char (mt, i)) == ' ')
	    break;
	  else if (mchartable_lookup (kinsoku_table, c) == Mt)
	    {
	      i++;
	      break;
	    }
	}
      mdraw_glyph_info (drawframe, mt, 0, i - 1, &control, &info2);
      if (info2.line_from > 0)
	{
	  /* No room even for one fragment.  Break the line before
	     drawing anything.  */
	  draw_line_end (state);
	  draw_line_start (state);
	  state->linewidth = leftfillpos;
	  first_width = area_width;
	  mdraw_clear_cache (mt);
	  mdraw_glyph_info (drawframe, mt, 0, 0, &control, &info);
	}

      while (1)
	{
	  for (i = info.line_to; i > info.line_from; i--)
	    if ((c = mtext_ref_char (mt, i - 1)) != ' ' && c != '\t')
	      {
		state->brankline = 0;
		break;
	      }
	  if (i == info.line_from)
	    i = info.line_to;

	  mdraw_text_extents (drawframe, mt, info.line_from, i,
			      &control, NULL, NULL, &rect);
	  rect.height += rect.y; /* calculate descent */
	  ascent = rect_sp.y < rect.y ? - rect_sp.y : - rect.y;
	  descent = rect_sp.height > rect.height ? rect_sp.height : rect.height;
	  draw_line_itemsize (state, ascent, descent, 0);
	  obj_new_mtext (state, state->linewidth, state->charoff,
			 mt, info.line_from, i, drawframe, ascent, descent);
	  state->linewidth += rect.width;
	  if (info.line_to >= nchars)
	    break;
	  draw_line_end (state);
	  draw_line_start (state);
	  state->linewidth = leftfillpos;
	  mdraw_glyph_info (drawframe, mt, info.line_to, info.line_to,
			    &control, &info);
	}
    }
}

/* Draw the M-text stored in OBJ on TARGET at the coordinate (X Y).  */

void
M17N_draw_object(obj, target, x, y)
	struct render_object *obj;
	Drawable target;	
	int x, y;
{
	control.format = NULL;
	mdraw_text_with_control (
		obj->data.m17ntext.drawframe, 
		(MDrawWindow) target, x, y,
		obj->data.m17ntext.mt,
		obj->data.m17ntext.from, obj->data.m17ntext.to, &control);
	control.format = M17N__format_line;
}


/* Update faces[caching] or languages[caching] according to KEY and
   VALUE.  */

void
M17N_process_direc(key, value)
	char *key, *value;
{
  MSymbol key_sym = msymbol (key);
  MFace *face = faces[caching];

  if (! faces[caching])
    face = faces[caching] = mface ();

  if (key_sym == Mfoundry || key_sym == Mfamily || key_sym == Mweight
      || key_sym == Mstyle || key_sym == Mstretch || key_sym == Madstyle)
    mface_put_prop (face, key_sym, value ? msymbol (value) : Mnil);
  else if (key_sym == Mfontset)
    mface_put_prop (face, key_sym, value ? mfontset (value) : fontset);
  else if (key_sym == Mratio)
    mface_put_prop (face, key_sym, value ? (void *) atoi (value) : (void *) 1); 
  else if (key_sym == Mlanguage)
    languages[caching] = value ? msymbol (value) : Mnil;
}

void
M17N_write_text (txt, cp)
     FILE *txt;
     struct ctrl *cp;
{
  MText *mt;

  if (! cp->ctc_value)
    return;
  if (cp->ct_flag == 0)
    {
      /* cp->ctc_value points a raw byte sequence.  */
      mt = M17N__gen_mtext ((u_char *) cp->ctc_value);
      cp->ctc_value = (char *) mt;
      cp->ct_flag =1;
    }
  else
    {
      /* cp->ctc_valus points an M-text. */
      mt = (MText *) cp->ctc_value;
    }
  if (mt)
    mconv_encode_stream (Mcoding_utf_8, mt, txt);
}

#endif	/* USE_M17N */
