/*
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they 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 these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/*
 * HISTORY
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#define FIX_1152

#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: XmRenderT.c /main/14 1998/10/26 20:14:42 samborn $"
#endif
#endif

#ifndef X_NOT_STDC_ENV
#include <stdlib.h>
#endif
#include <string.h>
#include <ctype.h>
#include <math.h>

#ifdef __cplusplus
extern "C" { /* some 'locale.h' do not have prototypes (sun) */
#endif
#include <X11/Xlocale.h>
#ifdef __cplusplus
} /* Close scope of 'extern "C"' declaration */
#endif /* __cplusplus */

#include <Xm/XmosP.h>		/* For ALLOCATE/DEALLOCATE_LOCAL */
#include <X11/IntrinsicP.h>
#include <X11/ShellP.h>
#include <X11/Xresource.h>
#include <Xm/Display.h>		/* For XmGetXmDisplay */
#include <Xm/DisplayP.h>	/* For direct access to callback fields */
#include "MessagesI.h"
#include "XmI.h"
#include "XmRenderTI.h"
#include "XmStringI.h"
#include "XmTabListI.h"
#ifdef USE_XFT
#include <X11/Xft/Xft.h>
#endif

/* Warning Messages */
#define NO_NULL_TAG_MSG			_XmMMsgXmRenderT_0000
#define NULL_DISPLAY_MSG      		_XmMMsgXmRenderT_0001
#define INVALID_TYPE_MSG      		_XmMMsgXmRenderT_0002
#define CONVERSION_FAILED_MSG 		_XmMMsgXmRenderT_0003
#define NULL_FONT_TYPE_MSG    		_XmMMsgXmRenderT_0004
#define NULL_LOAD_IMMEDIATE_MSG		_XmMMsgXmRenderT_0005

/* local macros */
#define GetHandle(type)		(type *)XtMalloc(sizeof(type))
#define FreeHandle(handle)	XtFree((char *)handle)
#define SetPtr(handle, ptr)	*(handle) = ptr
#define GetPtr(handle)		*(handle)
#define NameIsString(fontname) \
  (((fontname) != NULL) && ((fontname) != (String)XmAS_IS))
#define ListIsList(tablist) \
  (((tablist) != NULL) && \
   ((unsigned int)(unsigned long)(tablist) != XmAS_IS))

#define  FIX_1414
#define  FIX_1449
#define  FIX_1444
#define FIX_1451
#define FIX_1536
/**********************************************************************
 *	      IMPORTANT NOTE: IMPLEMENTATION OF SHARING
 *
 *	Instances of XmRenderTable and XmRendition are shared via a
 *	reference counting mechanism. This comment provides a general
 *	overview of how this is done.
 *
 *	First, both rendertable and renditions are indirectly
 *	referenced via a handle mechanism.  See the GetHandle,
 *	FreeHandle, SetPtr and GetPtr macros above.  This allows
 *	either the handle to change without the underlying data
 * 	structure changing, or the underlying data structure to change
 *	without the handle changing. I will indicate below where this
 *	happens.
 *
 *	Second, the real data structure for rendertable and rendition
 *	contain a reference count.  This count is incremented on copy
 *	and decremented on free.  If a decrement produces a zero
 *	refcount, the actual memory is freed.  If an increment
 *	produces a zero refcount, then the refcount has overflowed.  The
 *	refcount is decremented, and new memory is allocated for a new
 *	copy. 
 *
 *	Finally, I have defined a terminology for the different types
 *	of "copying" that can done based on allocating a new handle or
 *	not and allocating a new data structure or not.  This probably
 *	conflicts with some other existing terminology, probably in
 *	object oriented programming.  Sorry about that.
 *
 *	Function:	Clone	Copy	Renew	Duplicate
 *			(Mutate)	(Update)
 *
 *	handle		new	new	old	old
 *	structure	new	inc	new	inc
 *			(changed)	(changed)
 *
 *	(changed) indicates that the data in the new structure has
 *	been changed from the data in the old structure.
 *
 *	I will use these terms as a short hand in describing the
 *	functions below.
 **********************************************************************/


/********    Static Function Declarations    ********/

static void CopyInto(XmRendition toRend, 
		     XmRendition fromRend); 
static void MergeInto(XmRendition toRend, 
		     XmRendition fromRend); 
static XmRendition CloneRendition(XmRendition rend); 
static XmRendition CopyRendition(XmRendition rend); 
static XmRendition RenewRendition(XmRendition rend); 
static XmRendition DuplicateRendition(XmRendition rend); 
static Boolean FreeRendition(XmRendition rend); 
static void RenditionWarning(char *tag, char *type,
			     char *message, Display *dpy);
static void CleanupResources(XmRendition rend, Boolean copy);
static void ValidateTag(XmRendition rend,
			XmStringTag dflt);
static void ValidateAndLoadFont(XmRendition rend, Display *display);
static void SetRend(XmRendition to,
		    XmRendition from); 
static Boolean RendComplete(XmRendition rend);      
static void CopyFromArg(XtArgVal src,
			char *dst,
			unsigned int size);
static void CopyToArg(char *src,
		      XtArgVal *dst,
		      unsigned int size); 
static Cardinal GetNamesAndClasses(Widget w,
				   XrmNameList names,
				   XrmClassList classes); 
static XrmResourceList CompileResourceTable(XtResourceList resources,
					    Cardinal num_resources); 
static Boolean GetResources(XmRendition rend,
			    Display *dsp,
			    Widget wid,
			    String resname,
			    String resclass,
			    XmStringTag tag,
			    ArgList arglist,
			    Cardinal argcount);
static void SetDefault(XmRendition rend); 
#ifdef USE_XFT
#ifdef FIX_1536
static XftColor GetCachedXftColor(Display *display, Pixel color);
#endif
#endif

/********    End Static Function Declarations    ********/

/* Resource List. */

/************************************************************************/
/* N.B.:  The SetDefault procedure has a hardcoded list of all the	*/
/*	common resources.  Be sure to update it when adding resources.	*/
/************************************************************************/

#define DEFAULT_loadModel		XmAS_IS
#define DEFAULT_tag			XmS
#define DEFAULT_fontName		(String)XmAS_IS
#define DEFAULT_fontType		(XmFontType)XmAS_IS
#define DEFAULT_font			(XtPointer)XmAS_IS
#define DEFAULT_tabs			(XmTabList)XmAS_IS
#define DEFAULT_background		XmUNSPECIFIED_PIXEL
#define DEFAULT_foreground		XmUNSPECIFIED_PIXEL
#define DEFAULT_underlineType		XmAS_IS
#define DEFAULT_strikethruType		XmAS_IS
#define DEFAULT_backgroundState		XmAS_IS
#define DEFAULT_foregroundState		XmAS_IS
#ifdef USE_XFT
#define DEFAULT_xftFont			(XtPointer)XmAS_IS
#define DEFAULT_fontStyle		(String)NULL
#define DEFAULT_fontFoundry		(String)NULL
#define DEFAULT_fontEncoding		(String)NULL
#define DEFAULT_fontSize		0
#endif

static XtResource _XmRenditionResources[] = {
  { 
    XmNtag, XmCTag, XmRString,
    sizeof(XmStringTag), XtOffsetOf(_XmRenditionRec, tag),
    XmRImmediate, (XtPointer) DEFAULT_tag
  },
  { 
    XmNfontName, XmCFontName, XmRString,
    sizeof(String), XtOffsetOf(_XmRenditionRec, fontName),
    XmRImmediate, (XtPointer) DEFAULT_fontName
  },
  { 
    XmNfontType, XmCFontType, XmRFontType,
    sizeof(XmFontType), XtOffsetOf(_XmRenditionRec, fontType),
    XmRImmediate, (XtPointer) DEFAULT_fontType
  },
  { 
    XmNfont, XmCFont, XmRFontStruct,
    sizeof(XtPointer), XtOffsetOf(_XmRenditionRec, font),
    XmRImmediate, (XtPointer) DEFAULT_font
  },
  { 
    XmNloadModel, XmCLoadModel, XmRLoadModel,
    sizeof(unsigned char), XtOffsetOf(_XmRenditionRec, loadModel),
    XmRImmediate, (XtPointer) DEFAULT_loadModel
  },
  { 
    XmNtabList, XmCTabList, XmRTabList,
    sizeof(XmTabList), XtOffsetOf(_XmRenditionRec, tabs),
    XmRImmediate, (XtPointer) DEFAULT_tabs
  },
#if USE_XFT
  {
    XmNxftFont, XmCXftFont, XmRPointer,
    sizeof (XtPointer), XtOffsetOf (_XmRenditionRec, xftFont),
    XmRImmediate, (XtPointer) DEFAULT_xftFont
  },
  {
    XmNrenditionBackground, XmCRenditionBackground, XmRRenditionPixel,
    sizeof (Pixel), XtOffsetOf (_XmRenditionRec, xftBackground.pixel),
    XmRImmediate, (XtPointer) DEFAULT_background
  },
  {
    XmNrenditionForeground, XmCRenditionForeground, XmRRenditionPixel,
    sizeof (Pixel), XtOffsetOf (_XmRenditionRec, xftForeground.pixel),
    XmRImmediate, (XtPointer) DEFAULT_foreground
  },
  {
    XmNfontStyle, XmCFontStyle, XmRString,
    sizeof(String), XtOffsetOf (_XmRenditionRec, fontStyle),
    XmRImmediate, (XtPointer) DEFAULT_fontStyle
  },
  {
    XmNfontFoundry, XmCFontFoundry, XmRString,
    sizeof(String), XtOffsetOf (_XmRenditionRec, fontFoundry),
    XmRImmediate, (XtPointer) DEFAULT_fontFoundry
  },
  {
    XmNfontEncoding, XmCFontEncoding, XmRString,
    sizeof(String), XtOffsetOf (_XmRenditionRec, fontEncoding),
    XmRImmediate, (XtPointer) DEFAULT_fontEncoding
  },
  {
    XmNfontSize, XmCFontSize, XmRInt,
    sizeof(int), XtOffsetOf (_XmRenditionRec, fontSize),
    XmRImmediate, (XtPointer) DEFAULT_fontSize
  },
#else
  {
    XmNrenditionBackground, XmCRenditionBackground, XmRRenditionPixel,
    sizeof (Pixel), XtOffsetOf (_XmRenditionRec, background),
    XmRImmediate, (XtPointer) DEFAULT_background
  },
  {
    XmNrenditionForeground, XmCRenditionForeground, XmRRenditionPixel,
    sizeof (Pixel), XtOffsetOf (_XmRenditionRec, foreground),
    XmRImmediate, (XtPointer) DEFAULT_foreground
  },
#endif
  { 
    XmNunderlineType, XmCUnderlineType, XmRLineType,
    sizeof(unsigned char), XtOffsetOf(_XmRenditionRec, underlineType),
    XmRImmediate, (XtPointer) DEFAULT_underlineType
  },
  { 
    XmNstrikethruType, XmCStrikethruType, XmRLineType,
    sizeof(unsigned char), XtOffsetOf(_XmRenditionRec, strikethruType),
    XmRImmediate, (XtPointer) DEFAULT_strikethruType
  },
  { 
    XmNforegroundState, XmCGroundState, XmRGroundState,
    sizeof(unsigned char), XtOffsetOf(_XmRenditionRec, foregroundState),
    XmRImmediate, (XtPointer) DEFAULT_foregroundState
  },
  { 
    XmNbackgroundState, XmCGroundState, XmRGroundState,
    sizeof(unsigned char), XtOffsetOf(_XmRenditionRec, backgroundState),
    XmRImmediate, (XtPointer) DEFAULT_backgroundState
  },
};
  
static XmConst Cardinal _XmNumRenditionResources = 
	XtNumber(_XmRenditionResources);

/* Searches up widget hierarchy, quarkifying ancestor names and */
/* classes. */
static Cardinal
GetNamesAndClasses(Widget w, XrmNameList names, XrmClassList classes)
{
  Cardinal length, j;
  XrmQuark t;
  WidgetClass wc;

  /* Return null-terminated quark arrays, with length the number of
     quarks (not including NULL) */

  for (length = 0; w != NULL; w = (Widget)w->core.parent)
    {
      names[length] = w->core.xrm_name;
      wc = XtClass(w);
      /* KLUDGE KLUDGE KLUDGE KLUDGE */
      if (w->core.parent == NULL && XtIsApplicationShell(w)) {
	classes[length] =
	  ((ApplicationShellWidget) w)->application.xrm_class;
      } else classes[length] = wc->core_class.xrm_class;
      length++;
    }
  /* They're in backwards order, flop them around */
  for (j = 0; j < length/2; j++)
    {
      t = names[j];
      names[j] = names[length-j-1];
      names[length-j-1] = t;
      t = classes[j];
      classes[j] = classes[length-j-1];
      classes[length-j-1] = t;
    }
  names[length] = NULLQUARK;
  classes[length] = NULLQUARK;
  return length;
}						  /* GetNamesAndClasses */

/* Converts resource list to quarkified list. */
static XrmResourceList
CompileResourceTable(XtResourceList resources,
		     Cardinal num_resources)
{
  Cardinal		count;
  XrmResourceList	table, tPtr;
  XtResourceList	rPtr;
  
  tPtr = table = (XrmResourceList)XtMalloc(num_resources * sizeof(XrmResource));
  rPtr = resources;
  
  for (count = 0; count < num_resources; count++, tPtr++, rPtr++)
    {
      tPtr->xrm_name 		= XrmPermStringToQuark(rPtr->resource_name);
      tPtr->xrm_class 		= XrmPermStringToQuark(rPtr->resource_class);
      tPtr->xrm_type 		= XrmPermStringToQuark(rPtr->resource_type);
      tPtr->xrm_size		= rPtr->resource_size;
      tPtr->xrm_offset		= rPtr->resource_offset;
      tPtr->xrm_default_type 	= XrmPermStringToQuark(rPtr->default_type);
      tPtr->xrm_default_addr	= rPtr->default_addr;
    }
  return(table);
}

/* Does resource database lookup for arglist, filling in defaults from */
/* resource list as necessary. */
static Boolean
GetResources(XmRendition rend,
	     Display *dsp,
	     Widget wid,
	     String resname,
	     String resclass,
	     XmStringTag tag,
	     ArgList arglist,
	     Cardinal argcount)
{
  XrmName		names[100];
  XrmClass		classes[100];
  Cardinal		length = 0;
  static XrmQuarkList	quarks = NULL;
  static Cardinal	num_quarks = 0;
  static Boolean	*found = NULL;
  int			i, j;
  static XrmResourceList	table = NULL;
  static XrmQuark	QString;
  static XrmQuark	Qfont;
  Arg			*arg;
  XrmName		argName;
  XrmResource		*res;
  XrmDatabase		db = NULL;
  XrmHashTable   	stackSearchList[100];
  XrmHashTable    	*searchList = stackSearchList;
  unsigned int    	searchListSize = 100;
  Boolean		got_one = False;
  XrmValue		value;
  XrmQuark		rawType;
  XrmValue		convValue;
  Boolean		have_value, copied;
#ifdef XTHREADS
  XtAppContext		app=NULL;

  if (wid)
	app = XtWidgetToApplicationContext(wid);
  else if (dsp)
	app = XtDisplayToApplicationContext(dsp);
  if (app) {
      _XmAppLock(app);
  }
  _XmProcessLock();
#endif
  /* Initialize quark cache */
  if (quarks == NULL)
    {
      quarks = (XrmQuark *)XtMalloc(_XmNumRenditionResources *
				    sizeof(XrmQuark));
      num_quarks = _XmNumRenditionResources;
    }

  /* Initialize found */
  if (found == NULL)
    found = (Boolean *)XtMalloc(_XmNumRenditionResources * sizeof(Boolean));
  bzero(found, _XmNumRenditionResources * sizeof(Boolean));

  /* Compile names and classes. */
  if (wid != NULL)
    length = GetNamesAndClasses(wid, names, classes);
  
  names[length] = XrmStringToQuark(resname);
  classes[length] = XrmStringToQuark(resclass);
  length++;
  
  if (tag != NULL)
    {
      names[length] = XrmStringToQuark(tag);
      classes[length] = XrmPermStringToQuark(XmCRendition);
      length++;
    }      

  names[length] = NULLQUARK;
  classes[length] = NULLQUARK;

  /* Cache arglist */
  if (num_quarks < argcount)
    {
      quarks = (XrmQuark *)XtRealloc((char *)quarks,
				     argcount * sizeof(XrmQuark));
      num_quarks = argcount;
    }
  for (i = 0; i < argcount; i++)
    quarks[i] = XrmStringToQuark(arglist[i].name);

  /* Compile resource description into XrmResourceList if not already done. */
  if (table == NULL)
    {
      table = CompileResourceTable(_XmRenditionResources,
				   _XmNumRenditionResources);
      QString = XrmPermStringToQuark(XtCString);
      Qfont = XrmPermStringToQuark(XmNfont);
    }
  
  /* Set resources from arglist. */
  for (arg = arglist, i = 0; i < argcount; arg++, i++)
    {
      argName = quarks[i];
      
      for (j = 0, res = table; j < _XmNumRenditionResources; j++, res++)
	{
	  if (res->xrm_name == argName)
	    {
	      CopyFromArg((arg->value),
			  ((char *)GetPtr(rend) + res->xrm_offset),
			  res->xrm_size);
	      found[j] = TRUE;
	      break;
	    }
	}
    }
  
  /* DB query */
  /* Get database */
  if ((wid != NULL) || (dsp != NULL))
    {
      if (wid != NULL)
	db = XtScreenDatabase(XtScreenOfObject(wid));
      else db = XtScreenDatabase(DefaultScreenOfDisplay(dsp));

      /* Get searchlist */
      while (!XrmQGetSearchList(db, names, classes,
				searchList, searchListSize))
	{
	  if (searchList == stackSearchList)
	    searchList = NULL;
	  searchList = (XrmHashTable *)XtRealloc((char*)searchList,
						 sizeof(XrmHashTable) *
						 (searchListSize *= 2));
	}
    }
  
  /* Loop over table */
  for (j = 0, res = table; j < _XmNumRenditionResources; j++, res++)
    {
      if (!found[j])
	{
	  copied = False;
	  have_value = False;
	  
	  if ((db != NULL) &&
	      (XrmQGetSearchResource(searchList, res->xrm_name,
				     res->xrm_class, &rawType, &value)))
	    {
	      /* convert if necessary */
	      if (rawType != res->xrm_type)
		{
		  if (wid != NULL)
		    {
		      convValue.size = res->xrm_size;
		      convValue.addr = (char *)GetPtr(rend) + res->xrm_offset;
		      /*
		       * Check for special font case.
		       * Depending upon the fontType resource, try to convert
		       * to a FontSet, else to a FontStruct.
		       */
		      if ((res->xrm_name == Qfont) &&
			  (_XmRendFontType(rend) == XmFONT_IS_FONTSET))
			  copied = have_value =
			     XtConvertAndStore(wid, 
					       XrmQuarkToString(rawType),
					       &value,
					       "FontSet",
					       &convValue);
		      else
			  copied = have_value =
			     XtConvertAndStore(wid, 
					       XrmQuarkToString(rawType),
					       &value,
					       XrmQuarkToString(res->xrm_type),
					       &convValue);
		    }
		  else have_value = False;
		} 
	      else have_value = True;
		  
	      /* Check for special font case */
	      if (have_value)
		{
		  if (res->xrm_name == Qfont)
		    {
		      _XmRendFontName(rend) = value.addr;
		      copied = True;
		    }
		}
	    }
	      
	  if (!got_one && have_value) got_one = True;

	  /* Set defaults */
	  if (!have_value)
	    {
	      CopyFromArg((XtArgVal)(res->xrm_default_addr),
			  ((char *)GetPtr(rend) + res->xrm_offset),
			  res->xrm_size);
	      copied = True;
	    }

	  /* Copy if needed */
	  if (!copied)
	    {
	      if (res->xrm_type == QString)
		*((String *)((char *)GetPtr(rend) + res->xrm_offset)) =
		  value.addr;
	      else if (value.addr != NULL)
		memcpy(((char *)GetPtr(rend) + res->xrm_offset),
		       value.addr, res->xrm_size);
	      else 
		bzero(((char *)GetPtr(rend) + res->xrm_offset), res->xrm_size);
	    }
	      
	}
    }
  if (searchList != stackSearchList) XtFree((char *)searchList);

#ifdef XTHREADS
  _XmProcessUnlock();
  if (app) {
      _XmAppUnlock(app);
  }
#endif
  return(got_one);
}

/* Sets all resources to defaults from resource list. */
static void
SetDefault(XmRendition rend)
{
  /* A more robust implementation of this routine would to to loop
   * over _XmRenditionResources and use CopyFromArg to reset values
   * in rend, but to improve performance we use direct assignments. 
   */

  if (rend == NULL) return;

#ifdef	USE_XFT
  memset (&(_XmRendXftFG(rend)), 0, sizeof (XftColor));
  memset (&(_XmRendXftBG(rend)), 0, sizeof (XftColor));
#endif

  /* Leave _XmRendFontOnly unchanged.	 */
  /* Leave _XmRendRefcount unchanged.	 */
  _XmRendLoadModel(rend)      = DEFAULT_loadModel;
  _XmRendTag(rend)	      = DEFAULT_tag;
  _XmRendFontName(rend)	      = DEFAULT_fontName;
  _XmRendFontType(rend)	      = DEFAULT_fontType;
  _XmRendFont(rend)	      = DEFAULT_font;
  /* Leave _XmRendDisplay unchanged.	 */
  /* Leave _XmRendGC unchanged.		 */
  /* Leave _XmRendTags unchanged.	 */
  /* Leave _XmRendCount unchanged.	 */
  /* Leave _XmRendHadEnds unchanged.	 */
  _XmRendTabs(rend)	      = DEFAULT_tabs;
  _XmRendBG(rend)	      = DEFAULT_background;
  _XmRendFG(rend)	      = DEFAULT_foreground;
  _XmRendUnderlineType(rend)  = DEFAULT_underlineType;
  _XmRendStrikethruType(rend) = DEFAULT_strikethruType;
  _XmRendBGState(rend)	      = DEFAULT_backgroundState;
  _XmRendFGState(rend)	      = DEFAULT_foregroundState;

#ifdef	USE_XFT
  _XmRendXftFG (rend).color.alpha = 0xFFFF; /*TODO: it is really needed? (yura)*/
  _XmRendXftBG (rend).color.alpha = 0xFFFF; /*TODO: it is really needed? (yura)*/
  _XmRendXftFont(rend) = DEFAULT_xftFont;
  _XmRendPattern(rend) = NULL;
  _XmRendFontStyle(rend) = DEFAULT_fontStyle;
  _XmRendFontFoundry(rend) = DEFAULT_fontFoundry;
  _XmRendFontEncoding(rend) = DEFAULT_fontEncoding;
  _XmRendFontSize(rend) = DEFAULT_fontSize;
  _XmRendPixelSize(rend) = 0;
  _XmRendFontSlant(rend) = 0;
  _XmRendFontSpacing(rend) = 0;
  _XmRendFontWeight(rend) = 0;
#endif
}

/* Extern function to pick out display from rendertable. */
Display *
_XmRenderTableDisplay(XmRenderTable table)
{
  return(_XmRTDisplay(table));
}

/* Find a rendition in table with matching tag.  Call callback if not */
/* found and callback available.  Fail if need_font is true and */
/* rendition found does not provide font. */
XmRendition
_XmRenderTableFindRendition(XmRenderTable table, 
			    XmStringTag tag,
#if NeedWidePrototypes
			    int cached_tag,
			    int need_font,
			    int call,
#else
			    Boolean cached_tag,
			    Boolean need_font,
			    Boolean call,
#endif /* NeedWidePrototypes */
			    short *index)
{
  int				i, j;
  XmRendition			rend;
  Boolean			hit = FALSE;
  XmDisplayCallbackStruct	cb;
  XmDisplay			dsp;
  XmRenderTable			copy;
  
  if ((table == NULL) || (tag == NULL)) return(NULL);
  

  for (;;) /* May have to try twice */
    {  
      for (i = 0; i < _XmRTCount(table); i++)
	{
	  rend = _XmRTRenditions(table)[i];
      
	  if ((cached_tag) ?
	      (_XmRendTag(rend) == tag) :
	      (strcmp(_XmRendTag(rend), tag) == 0))
	    {
	      hit = TRUE;
	  
	      if ((_XmRendFont(rend) == NULL) && (_XmRendXftFont (rend) == NULL) &&
		  NameIsString(_XmRendFontName(rend)))
		{
		  if (_XmRendLoadModel(rend) == XmLOAD_DEFERRED)
		    _XmRendLoadModel(rend) = XmLOAD_IMMEDIATE;

		  ValidateAndLoadFont(rend, _XmRendDisplay(rend));
	      
		  if (need_font && (_XmRendFont(rend) == NULL &&
                      _XmRendXftFont(rend) == NULL))
		    break;
		}
	  
	      if (index != NULL) *index = i;
	      return(rend);
	    }
	}

      /* Are we done? */
      if (hit || !call) break;
      
      call = FALSE;

      /* Call callback */
      if (_XmRTDisplay(table) != NULL)
	{
	  dsp = (XmDisplay) XmGetXmDisplay(_XmRTDisplay(table));
	  
	  /* CR 7964: XtHasCallbacks is surprisingly expensive, */
	  /*	so we use a conservative approximation here. */
	  if (dsp && dsp->display.noRenditionCallback)
	    {
	      copy = XmRenderTableCopy(table, NULL, 0);
	  
	      cb.reason = XmCR_NO_RENDITION;
	      cb.event = NULL;
	      cb.render_table = copy;
	      cb.tag = tag;
      
	      XtCallCallbackList((Widget)dsp, 
				 dsp->display.noRenditionCallback, 
				 &cb);

	      if (cb.render_table != copy)
		{
		  /* Callback mutated table.  Update table with */
		  /* substitution and search again. */

		  for (j = 0; j < _XmRTCount(table); j++)
		    if (FreeRendition(_XmRTRenditions(table)[j]))
		      FreeHandle(_XmRTRenditions(table)[j]);
  
		  if (_XmRTRefcountDec(table) == 0)
		    XtFree((char *)GetPtr(table));

		  SetPtr(table, GetPtr(cb.render_table));
		  FreeHandle(cb.render_table);
		}
	      else break;
	    }
	  else break;
	}
      else break;
    } 
  
  /* Didn't find it. */
  if (index != NULL) *index = -1;
  return(NULL);
}

/* If to has resource unset and from has it set, set in to. */
static void
SetRend(XmRendition to,
	XmRendition from)
{
  if (NameIsString(_XmRendFontName(from)) &&
      !NameIsString(_XmRendFontName(to)))
    _XmRendFontName(to) = _XmRendFontName(from);
  if ((_XmRendFontType(from) != XmAS_IS) &&
      (_XmRendFontType(to) == XmAS_IS))
    _XmRendFontType(to) = _XmRendFontType(from);
  if ((_XmRendLoadModel(from) != XmAS_IS) &&
      (_XmRendLoadModel(to) == XmAS_IS))
    _XmRendLoadModel(to) = _XmRendLoadModel(from);
  if ((_XmRendFont(from) != NULL) &&
      ((unsigned int)(unsigned long)_XmRendFont(to) == XmAS_IS))
    _XmRendFont(to) = _XmRendFont(from);
  if (ListIsList(_XmRendTabs(from)) &&
      !ListIsList(_XmRendTabs(to)))
    _XmRendTabs(to) = _XmRendTabs(from);
#if USE_XFT
  if ((_XmRendFG(from) != XmUNSPECIFIED_PIXEL) &&
      (_XmRendFG(to) == XmUNSPECIFIED_PIXEL))
    {
#ifdef FIX_1536
      _XmRendFG(to) = _XmRendFG(from);
      _XmRendXftFG(to) = GetCachedXftColor(_XmRendDisplay(to), _XmRendFG(to));
#else
      XColor xcolor;
      _XmRendFG(to) = _XmRendFG(from);
      xcolor.pixel = _XmRendFG(to);
      XQueryColor(_XmRendDisplay(to), DefaultColormapOfScreen(
                  DefaultScreenOfDisplay(_XmRendDisplay(to))), &xcolor);
      /* doesn't needed  (_XmRendXftFG (to)).pixel = xcolor.pixel; */
      (_XmRendXftFG(to)).color.red = xcolor.red;
      (_XmRendXftFG(to)).color.green = xcolor.green;
      (_XmRendXftFG(to)).color.blue = xcolor.blue;
      (_XmRendXftFG(to)).color.alpha = 0xFFFF;
#endif
    }
  if ((_XmRendBG(from) != XmUNSPECIFIED_PIXEL) &&
      (_XmRendBG(to) == XmUNSPECIFIED_PIXEL))
    {
#ifdef FIX_1536
      _XmRendBG(to) = _XmRendBG (from);
      _XmRendXftBG(to) = GetCachedXftColor(_XmRendDisplay(to), _XmRendBG(to));
#else
      XColor xcolor;
      _XmRendBG(to) = _XmRendBG (from);
      xcolor.pixel = _XmRendBG (to);
      XQueryColor(_XmRendDisplay(to), DefaultColormapOfScreen(
                  DefaultScreenOfDisplay(_XmRendDisplay(to))), &xcolor);
      /* doesn't needed  (_XmRendXftBG (to)).pixel = xcolor.pixel; */
      (_XmRendXftBG(to)).color.red = xcolor.red;
      (_XmRendXftBG(to)).color.green = xcolor.green;
      (_XmRendXftBG(to)).color.blue = xcolor.blue;
      (_XmRendXftBG(to)).color.alpha = 0xFFFF;
#endif
    }
  if ((_XmRendXftFont (from) != NULL) &&
      ((unsigned int) (unsigned long) _XmRendXftFont (to) == XmAS_IS))
    _XmRendXftFont (to) = _XmRendXftFont (from);
  if ((_XmRendFontStyle (from) != NULL) && _XmRendFontStyle (to) == NULL)
    _XmRendFontStyle (to) = _XmRendFontStyle (from);
  if ((_XmRendFontFoundry (from) != NULL) && _XmRendFontFoundry (to) == NULL)
    _XmRendFontFoundry (to) = _XmRendFontFoundry (from);
  if ((_XmRendFontEncoding (from) != NULL) && _XmRendFontEncoding (to) == NULL)
    _XmRendFontEncoding (to) = _XmRendFontEncoding (from);
  if (_XmRendFontSize (to) == 0)
    _XmRendFontSize (to) = _XmRendFontSize (from);
#else
  if ((_XmRendFG(from) != XmUNSPECIFIED_PIXEL) &&
      (_XmRendFG(to) == XmUNSPECIFIED_PIXEL))
    _XmRendFG(to) = _XmRendFG (from);
  if ((_XmRendBG(from) != XmUNSPECIFIED_PIXEL) &&
      (_XmRendBG(to) == XmUNSPECIFIED_PIXEL))
    _XmRendBG(to) = _XmRendBG (from);
#endif
  if ((_XmRendUnderlineType(from) != XmAS_IS) &&
      (_XmRendUnderlineType(to) == XmAS_IS))
    _XmRendUnderlineType(to) = _XmRendUnderlineType(from);
  if ((_XmRendStrikethruType(from) != XmAS_IS) &&
      (_XmRendStrikethruType(to) == XmAS_IS))
    _XmRendStrikethruType(to) = _XmRendStrikethruType(from);
}

/* Check that all resources are not default values. */
static Boolean
RendComplete(XmRendition rend)      
{
  return(((unsigned int)(unsigned long)_XmRendFontName(rend) != XmAS_IS) &&
	 (_XmRendFontType(rend) != XmAS_IS) &&
	 (_XmRendLoadModel(rend) != XmAS_IS) &&
	 (
	  ((unsigned int) (unsigned long) _XmRendFont (rend) != XmAS_IS)
#ifdef USE_XFT
            || ((unsigned int) (unsigned long) _XmRendXftFont (rend) != XmAS_IS)
#endif
         ) &&
	 ((unsigned int)(unsigned long)_XmRendTabs(rend) != XmAS_IS) &&
	 (_XmRendFG(rend) != XmUNSPECIFIED_PIXEL) &&
	 (_XmRendBG(rend) != XmUNSPECIFIED_PIXEL) &&
	 (_XmRendUnderlineType(rend) != XmAS_IS) &&
	 (_XmRendStrikethruType(rend) != XmAS_IS));
}

/* Search rt for all renditions matching tags, successively merging */
/* resource values in scr rendition. */
/*ARGSUSED*/
XmRendition
_XmRenditionMerge(Display *d,	/* unused */
		  XmRendition *scr,
		  XmRendition base_rend,
		  XmRenderTable rt,
		  XmStringTag base_tag,
		  XmStringTag *tags,
#if NeedWidePrototypes
		  unsigned int tag_count,
		  unsigned int copy
#else			
		  unsigned short tag_count,
		  Boolean copy
#endif /* NeedWidePrototypes */
		  )
{
  XmRendition 	rend, tmp;
  int 		i;
  
  if (scr == NULL)
    {
      rend = XmRenditionCreate(NULL, XmS, NULL, 0); /* Create new */
    }
  else
    {
      rend = *scr;
      if (copy)
	{
	  if (NameIsString(_XmRendFontName(rend)))
	    XtFree(_XmRendFontName(rend));
	  if (ListIsList(_XmRendTabs(rend)))
	    XmTabListFree(_XmRendTabs(rend));
	}
      SetDefault(rend);			  /* Reset state */
    }

  for (i = (tag_count - 1); i >= 0; i--)
    {
      tmp = _XmRenderTableFindRendition(rt, tags[i], TRUE, FALSE, TRUE, NULL);
      if (tmp == NULL) continue;
      
      SetRend(rend, tmp);
      if (RendComplete(rend)) break;
    }

  if (!RendComplete(rend))
    {
      short index;
      
      _XmRenderTableFindFallback(rt, base_tag, TRUE, &index, &tmp);
      if (tmp != NULL) SetRend(rend, tmp);
    }

  if (base_rend != NULL) 
    {
      SetRend(rend, base_rend);
  
      if (_XmRendFGState(base_rend) == XmFORCE_COLOR)
#if USE_XFT
	_XmRendXftFG(rend) = _XmRendXftFG(base_rend);
#else
	_XmRendFG(rend) = _XmRendFG(base_rend);
#endif
  
      if (_XmRendBGState(base_rend) == XmFORCE_COLOR)
	_XmRendBG(rend) = _XmRendBG(base_rend);
    }
  	
  CleanupResources(rend, copy);
  
  return(rend);
}


/****************
 * If the cached_tag flag is true, _XmRenderTableFindFallback assumes that the
 *   tag pointer is a pointer out of the (local) tag cache.
 *   Since XmRenditionCreate also uses tag pointers out of this cache,
 *   a string compare is avoided by simply comparing pointer values.
 ****************/
extern Boolean 
_XmRenderTableFindFallback(
        XmRenderTable rendertable,
        XmStringTag tag,
#if NeedWidePrototypes
        int cached_tag,
#else
        Boolean cached_tag,
#endif /* NeedWidePrototypes */
        short *indx,
	XmRendition *rend_ptr )
{   
  XmStringTag     search_cset = NULL;
  
  *indx = -1 ;

  if ((rendertable != NULL) && (_XmRTCount(rendertable) == 0))
    {
      *rend_ptr = NULL;
      return(FALSE);
    }
  
  if (rendertable != NULL)
    {   
      if (tag != NULL)
	{
	  if (cached_tag)			  /* No XmSTRING_DEFAULT_CHARSET */
	    {   
	      *rend_ptr = (XmRendition)
		_XmRenderTableFindRendition(rendertable, tag, TRUE, TRUE, FALSE,
					    indx);
	      if (*rend_ptr != NULL) return(TRUE);
	    }
	  else
	    {   
	      XmStringTag       curtag; 

	      if ((strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0))
		curtag = _XmStringGetCurrentCharset();
	      else curtag = tag;

	      *rend_ptr = (XmRendition)
		_XmRenderTableFindRendition(rendertable, curtag, FALSE, TRUE, FALSE,
					    indx);
	  
	      if (*rend_ptr != NULL) return(TRUE);
	    } 
      
	  /* Didn't find a match.  See if tag is one of the defaults
	     and search for the other. */
	  if (_XmStringIsCurrentCharset(tag))
	    {
	      search_cset = XmFONTLIST_DEFAULT_TAG;

	      *rend_ptr = (XmRendition)
		_XmRenderTableFindRendition(rendertable, search_cset, TRUE, 
					    TRUE, FALSE, indx);
	  
	      if (*rend_ptr != NULL) return(TRUE);
	    }
	  else if ((tag == XmFONTLIST_DEFAULT_TAG) ||
		   (strcmp(tag, XmFONTLIST_DEFAULT_TAG) == 0))
	    {
	      search_cset = _XmStringGetCurrentCharset();
	
	      *rend_ptr = (XmRendition)
		_XmRenderTableFindRendition(rendertable, search_cset, FALSE, 
					    TRUE, FALSE, indx);
	  
	      if (*rend_ptr != NULL) return(TRUE);
	    }
	}
        
      /* Otherwise pick up first font(set) if tag a default value. */
      if ((tag == NULL) ||
	  (tag == XmFONTLIST_DEFAULT_TAG) ||
	  (strcmp(tag, XmFONTLIST_DEFAULT_TAG) == 0) ||
	  _XmStringIsCurrentCharset(tag))
	return(_XmRenderTableFindFirstFont(rendertable, indx, rend_ptr));
    }
  *rend_ptr = NULL; 
  *indx = -1;
  return(FALSE);
}

extern Boolean
_XmRenderTableFindFirstFont(XmRenderTable rendertable,
			    short *indx,
			    XmRendition *rend_ptr)
{
  int i, f_idx = -1, fs_idx = -1;
#ifdef USE_XFT
  int xft_idx = -1;
#endif

  for (i = _XmRTCount(rendertable) - 1; i >= 0; i--)
    {
      *rend_ptr = _XmRTRenditions(rendertable)[i];

      if (_XmRendFont(*rend_ptr) != NULL)
      {
	if (_XmRendFontType(*rend_ptr) == XmFONT_IS_FONT) f_idx = i;
	else if (_XmRendFontType(*rend_ptr) == XmFONT_IS_FONTSET) fs_idx = i;
#ifdef USE_XFT
      } else if (_XmRendXftFont(*rend_ptr) != NULL) {
        if (_XmRendFontType(*rend_ptr) == XmFONT_IS_XFT) xft_idx = i;
#endif
      }
  }
#ifdef USE_XFT
  if (xft_idx >= 0)
    {
      *rend_ptr = _XmRTRenditions (rendertable)[xft_idx];
      *indx = xft_idx;
    }
  else
#endif
  if (fs_idx >= 0)
    {
      *rend_ptr = _XmRTRenditions(rendertable)[fs_idx];
      *indx = fs_idx;
    }
  else if (f_idx >= 0)
    {
      *rend_ptr = _XmRTRenditions(rendertable)[f_idx];
      *indx = f_idx;
    }
  else
    {
      *rend_ptr = NULL;
      *indx = -1;
      return(FALSE);
    }

  return(TRUE); 
}

/* Put value of every resource in fromRend into toRend, copying where */
/* necessary. */
static void
CopyInto(XmRendition toRend,
	 XmRendition fromRend)
{
  _XmRendTag(toRend) = _XmStringCacheTag(_XmRendTag(fromRend),
					 XmSTRING_TAG_STRLEN);
  /* CR 7890 - the fontName might be XmAS_IS here - if so, we
   ** obviously don't want to do an XtNewString (implicit strcpy)
   */
  if (!NameIsString(_XmRendFontName(fromRend)))
    _XmRendFontName(toRend) = NULL;
  else
    _XmRendFontName(toRend) = XtNewString(_XmRendFontName(fromRend));
  _XmRendFontType(toRend) = _XmRendFontType(fromRend);
  _XmRendLoadModel(toRend) = _XmRendLoadModel(fromRend);
  _XmRendFont(toRend) = _XmRendFont(fromRend);
  _XmRendDisplay(toRend) = _XmRendDisplay(fromRend);
  
  if (!ListIsList(_XmRendTabs(fromRend)))
    _XmRendTabs(toRend) = NULL;
  else
    _XmRendTabs(toRend) = XmTabListCopy(_XmRendTabs(fromRend), 0, 0);
#if USE_XFT
  _XmRendXftFont (toRend) = _XmRendXftFont (fromRend);
  _XmRendXftBG (toRend) = _XmRendXftBG (fromRend);
  _XmRendXftFG (toRend) = _XmRendXftFG (fromRend);
  _XmRendFontStyle (toRend) = _XmRendFontStyle (fromRend);
  _XmRendFontFoundry (toRend) = _XmRendFontFoundry (fromRend);
  _XmRendFontEncoding (toRend) = _XmRendFontEncoding (fromRend);
  _XmRendFontSize (toRend) = _XmRendFontSize (fromRend);
#else
  _XmRendBG (toRend) = _XmRendBG (fromRend);
  _XmRendFG (toRend) = _XmRendFG (fromRend);
#endif
  _XmRendUnderlineType(toRend) = _XmRendUnderlineType(fromRend);
  _XmRendStrikethruType(toRend) = _XmRendStrikethruType(fromRend);
}

/* As above, except only change resources in toRend that are default. */
static void
MergeInto(XmRendition toRend,
	 XmRendition fromRend)
{
  _XmRendTag(toRend) = _XmStringCacheTag(_XmRendTag(fromRend),
					 XmSTRING_TAG_STRLEN);
  if ((_XmRendFontName(toRend) == NULL) &&
      NameIsString(_XmRendFontName(fromRend)))
    _XmRendFontName(toRend) = XtNewString(_XmRendFontName(fromRend));
  if (_XmRendFontType(toRend) == XmAS_IS)
    _XmRendFontType(toRend) = _XmRendFontType(fromRend);
  if (_XmRendLoadModel(toRend) == XmAS_IS)
    _XmRendLoadModel(toRend) = _XmRendLoadModel(fromRend);
  if (_XmRendFont(toRend) == NULL)
    _XmRendFont(toRend) = _XmRendFont(fromRend);
  
  if (!ListIsList(_XmRendTabs(toRend)) && 
      ListIsList(_XmRendTabs(fromRend)))
    _XmRendTabs(toRend) = XmTabListCopy(_XmRendTabs(fromRend), 0, 0);
#if USE_XFT
  if (_XmRendXftFont(toRend) == NULL)
    _XmRendXftFont(toRend) = _XmRendXftFont(fromRend);
  if (_XmRendBG(toRend) == XmUNSPECIFIED_PIXEL)
    _XmRendXftBG(toRend) = _XmRendXftBG(fromRend);
  if (_XmRendFG(toRend) == XmUNSPECIFIED_PIXEL)
    _XmRendXftFG(toRend) = _XmRendXftFG(fromRend);
  if (_XmRendFontStyle(toRend) == NULL)
    _XmRendFontStyle(toRend) = _XmRendFontStyle(fromRend);
  if (_XmRendFontFoundry(toRend) == NULL)
    _XmRendFontFoundry(toRend) = _XmRendFontFoundry(fromRend);
  if (_XmRendFontEncoding(toRend) == NULL)
    _XmRendFontEncoding(toRend) = _XmRendFontEncoding(fromRend);
  if (_XmRendFontSize(toRend) == 0)
    _XmRendFontSize(toRend) = _XmRendFontSize(fromRend);
#else
  if (_XmRendBG(toRend) == XmUNSPECIFIED_PIXEL)
    _XmRendBG(toRend) = _XmRendBG (fromRend);
  if (_XmRendFG(toRend) == XmUNSPECIFIED_PIXEL)
    _XmRendFG(toRend) = _XmRendFG (fromRend);
#endif
  if (_XmRendUnderlineType(toRend) == XmAS_IS)
    _XmRendUnderlineType(toRend) = _XmRendUnderlineType(fromRend);
  if (_XmRendUnderlineType(toRend) == XmAS_IS)
    _XmRendStrikethruType(toRend) = _XmRendStrikethruType(fromRend);
}

/* Make a Clone--new handle and new data structure--of a rendition. */
static XmRendition
CloneRendition(XmRendition rend)
{
  _XmRendition 	copy;
  XmRendition	copy_handle;
  
  if (rend == NULL) return(NULL);
  
  copy = (_XmRendition)XtMalloc(sizeof(_XmRenditionRec));
  bzero((char*)copy, sizeof(_XmRenditionRec));
  copy_handle = GetHandle(_XmRendition);
  SetPtr(copy_handle, copy);
  
  _XmRendFontOnly(copy_handle) = FALSE;
  _XmRendRefcount(copy_handle) = 1;
  
  CopyInto(copy_handle, rend);
  return(copy_handle);
}

/* Set the old handle to point to a new data structure. */
static XmRendition
RenewRendition(XmRendition rend)
{
  _XmRendition copy;
  
  if (rend == NULL) return(NULL);
  
  copy = (_XmRendition)XtMalloc(sizeof(_XmRenditionRec));
  memcpy((char *)copy, (char *)GetPtr(rend), sizeof(_XmRenditionRec));
  SetPtr(rend, copy);
  
  _XmRendFontOnly(rend) = FALSE;
  _XmRendRefcount(rend) = 1;
  
  return(rend);
}

/* Allocate a new handle which points to the old data structure with */
/* an incremented refcount. */
static XmRendition
CopyRendition(XmRendition rend)
{
  XmRendition	copy;
  
  if (rend == NULL) return(NULL);

  if (_XmRendRefcountInc(rend) == 0)
    {
      _XmRendRefcountDec(rend);
      return(CloneRendition(rend));
    }
  else 
    {
      copy = GetHandle(_XmRendition);
      SetPtr(copy, GetPtr(rend));
      return(copy);
    }
}

/* Increment the refcount.  Clone if overflow. */
static XmRendition
DuplicateRendition(XmRendition rend)
{
  if (rend == NULL) return(NULL);

  if (_XmRendRefcountInc(rend) == 0)
    {
      _XmRendRefcountDec(rend);
      return(CloneRendition(rend));
    }
  else 
    {
      return(rend);
    }
}

/* Make a copy of a rendition, *including* the "scratch" info (tags,
 * GC, hadEnds).
 * Shared indicates whether or not this is a shared copy.
 */
XmRendition
_XmRenditionCopy(XmRendition rend,
		 Boolean shared)
{
  XmRendition toRend;
  int i;

  if (rend == NULL) return(NULL);

  if (shared) toRend = CopyRendition(rend);
  else toRend = CloneRendition(rend);

  /* If we had to clone, copy the 'scratch' info. */
  if (*toRend != *rend)
    {
      _XmRendGC(toRend) = _XmRendGC(rend);
      _XmRendTagCount(toRend) = _XmRendTagCount(rend);
      _XmRendHadEnds(toRend) = _XmRendHadEnds(rend);
      _XmRendTags(toRend) =
	(XmStringTag *)XtMalloc(sizeof(XmStringTag) * _XmRendTagCount(rend));
      for (i = 0; i < _XmRendTagCount(rend); i++)
	_XmRendTags(toRend)[i] = _XmRendTags(rend)[i];
    }
  
  return(toRend);
}

/* Creates new rendertable, adding any new renditions. */
/* Mutate rendertable.  Copy renditions. */
XmRenderTable
XmRenderTableAddRenditions(XmRenderTable oldtable, 
			   XmRendition *renditions,
			   Cardinal rendition_count,
			   XmMergeMode merge_mode)
{
  int			i, next;
  int			count = rendition_count;
  XmRendition		rend, match;
  _XmRenderTable	table;
  XmRenderTable		newtable, tmptable = NULL;
  Boolean		*matches;
  short			idx;
  XtAppContext		app=NULL;

  if ((renditions == NULL) || (rendition_count == 0))
    return(oldtable);

#ifdef XTHREADS
  if (_XmRendDisplay(renditions[0]))
	app = XtDisplayToApplicationContext(_XmRendDisplay(renditions[0]));
  if (app) {
     _XmAppLock(app);
  }
  else {
     _XmProcessLock();
  }
#endif
  if (oldtable == NULL)
    {
      /* Malloc new table */
      table = 
	(_XmRenderTable)XtMalloc(sizeof(_XmRenderTableRec) +
				(sizeof(XmRendition) *
				 (rendition_count -
				  RENDITIONS_IN_STRUCT)));
      oldtable = GetHandle(_XmRenderTable);
      SetPtr(oldtable, table);

      _XmRTCount(oldtable) = rendition_count;
      _XmRTDisplay(oldtable) = NULL;
      _XmRTRefcount(oldtable) = 1;
      
      /* Copy renditions */
      for (i = 0; i < rendition_count; i++)
	{
	  _XmRTRenditions(oldtable)[i] = CopyRendition(renditions[i]);
	  if (_XmRTDisplay(oldtable) == NULL)
	    _XmRTDisplay(oldtable) = _XmRendDisplay(renditions[i]);
	}
    }
  else
    {
      matches =
	(Boolean *)ALLOCATE_LOCAL(rendition_count * sizeof(Boolean));
      bzero(matches, rendition_count * sizeof(Boolean));
      
      /* May have to copy table if shared. */
      if (_XmRTRefcount(oldtable) > 1)
	{
	  /* Allocate new table */
	  table = (_XmRenderTable)
	    XtMalloc(sizeof(_XmRenderTableRec) +
		     (sizeof(XmRendition) *
		      (_XmRTCount(oldtable) - RENDITIONS_IN_STRUCT)));

	  newtable = GetHandle(_XmRenderTable);
	  SetPtr(newtable, table);

	  _XmRTDisplay(newtable) = _XmRTDisplay(oldtable);
	  _XmRTRefcount(newtable) = 1;

	  /* Move old Renditions. */
	  for (i = 0; i < _XmRTCount(oldtable); i++)
	    _XmRTRenditions(newtable)[i] = _XmRTRenditions(oldtable)[i];

	  _XmRTCount(newtable) = _XmRTCount(oldtable);
	  _XmRTRefcountDec(oldtable);

	  /* Free at end so we don't get same memory from malloc. */
	  tmptable = oldtable;
	  oldtable = newtable;
	}
      
      /* Merge matching renditions */
      for (i = 0; i < rendition_count; i++)
	{
	  rend = renditions[i];
	  
	  match =
	    _XmRenderTableFindRendition(oldtable, _XmRendTag(rend),
					TRUE, FALSE, FALSE, &idx);
	  if ((match != NULL) && (merge_mode != XmDUPLICATE))
	    {
	      /* Merge renditions. */
	      switch (merge_mode)
		{
		case XmMERGE_REPLACE:
		  if (FreeRendition(match)) FreeHandle(match);
		  _XmRTRenditions(oldtable)[idx] = 
		    CopyRendition(rend);
		  break;
		  
		case XmSKIP:
		  break;
		  
		case XmMERGE_OLD:
		  if (_XmRendRefcount(match) > 1) 
		    {
		      match = CloneRendition(match);
		      _XmRTRenditions(oldtable)[idx] = match;
		    }		      
		  MergeInto(match, rend);
		  break;
		  
		case XmMERGE_NEW:
		  rend = CloneRendition(rend);
		  MergeInto(rend, match);
		  _XmRTRenditions(oldtable)[idx] = rend;
		  if (FreeRendition(match)) FreeHandle(match);
		  break;
		  
		default:
		  printf("NYI");
		  break;
		}

	      matches[i] = TRUE;
	      --count;
	    }
	}
      
      if (count > 0)				  /* Allocate new table */
	{
	  table = (_XmRenderTable)
	    XtMalloc(sizeof(_XmRenderTableRec) +
		     (sizeof(XmRendition) *
		      (_XmRTCount(oldtable) + count - RENDITIONS_IN_STRUCT)));
	  newtable = GetHandle(_XmRenderTable);
	  SetPtr(newtable, table);

	  _XmRTDisplay(newtable) = _XmRTDisplay(oldtable);
	  _XmRTRefcount(newtable) = 1;
      
	  /* Move old Renditions. */
	  for (i = 0; i < _XmRTCount(oldtable); i++)
	    _XmRTRenditions(newtable)[i] = _XmRTRenditions(oldtable)[i];

	  /* Copy new renditions. */
	  next = _XmRTCount(oldtable);
      
	  for (i = 0; i < rendition_count; i++)
	    {
	      if (!matches[i])
		{
		  _XmRTRenditions(newtable)[next] =
		    CopyRendition(renditions[i]);
		  if (_XmRTDisplay(newtable) == NULL)
		    _XmRTDisplay(newtable) = _XmRTDisplay(oldtable);
		  ++next;
		}
	    }
	    
	  _XmRTCount(newtable) = _XmRTCount(oldtable) + count;
	  
	  /* Deallocate oldtable */
	  XtFree((char *)GetPtr(oldtable));
	  FreeHandle(oldtable);
	}
      /* Otherwise just return newhandle to oldtable */
      else					  
	{
	  table = GetPtr(oldtable);
	  newtable = GetHandle(_XmRenderTable);
	  SetPtr(newtable, table);
	  FreeHandle(oldtable);
	}
      
      DEALLOCATE_LOCAL((char *)matches);

      oldtable = newtable;
    }

  if (tmptable != NULL) FreeHandle(tmptable);
#ifdef XTHREADS
  if (app) {
      _XmAppUnlock(app);
  }
  else {
      _XmProcessUnlock();
  }
#endif
  return(oldtable);
}

/* Remove matching renditions. */
/* Mutates oldtable, decrements removed renditions. */
XmRenderTable
XmRenderTableRemoveRenditions(XmRenderTable oldtable,
			      XmStringTag *tags,
			      int tag_count)
{
  XmRenderTable ret_val;
#ifdef XTHREADS
  XtAppContext  app=NULL;

  if (_XmRTDisplay(oldtable))
	app = XtDisplayToApplicationContext(_XmRTDisplay(oldtable));
  if (app) {
    _XmAppLock(app);
  }
  else {
    _XmProcessLock();
  }
#endif
  ret_val = _XmRenderTableRemoveRenditions(oldtable, tags,tag_count,
				FALSE, XmFONT_IS_FONT, NULL);
#ifdef XTHREADS
  if (app) {
     _XmAppUnlock(app);
  }
  else {
     _XmProcessUnlock();
  }
#endif
  return ret_val;
}

/* Remove matching renditions. */
/* Mutates oldtable, decrements removed renditions. */
/* If chk_font TRUE, checks that font and type also match. */
XmRenderTable
_XmRenderTableRemoveRenditions(XmRenderTable oldtable,
			       XmStringTag *tags,
			       int tag_count,
#if NeedWidePrototypes
			       int chk_font,
#else
			       Boolean chk_font,
#endif /* NeedWidePrototypes */
			       XmFontType type,
			       XtPointer font)
{
  int			i, j;
  int			count;
  _XmRenderTable	table;
  XmRenderTable		newtable = NULL;

  if ((oldtable == NULL) || (tags == NULL) || (tag_count == 0))
    return(oldtable);
  
  count = 0;
  
  if (_XmRTRefcount(oldtable) > 1)
    {
      /* Allocate new table */
      table = (_XmRenderTable)
	XtMalloc(sizeof(_XmRenderTableRec) +
		 (sizeof(XmRendition) *
		  (_XmRTCount(oldtable) - RENDITIONS_IN_STRUCT)));

      newtable = GetHandle(_XmRenderTable);
      SetPtr(newtable, table);

      _XmRTDisplay(newtable) = _XmRTDisplay(oldtable);
      _XmRTRefcount(newtable) = 1;

      /* Move old Renditions. */
      for (i = 0; i < _XmRTCount(oldtable); i++)
	_XmRTRenditions(newtable)[i] = _XmRTRenditions(oldtable)[i];
      _XmRTCount(newtable) = _XmRTCount(oldtable);
      
      if (_XmRTRefcountDec(oldtable) == 0)
	XtFree((char *)GetPtr(oldtable));
      FreeHandle(oldtable);
      
      oldtable = newtable;
    }
  /* Iterate over renditions */
  for (i = 0; i < _XmRTCount(oldtable); i++)
    {
      /* Match against tags */
      for (j = 0; j < tag_count; j++)
	{
	  if ((strcmp(_XmRendTag(_XmRTRenditions(oldtable)[i]),
		      tags[j]) == 0) &&
	      (!chk_font ||
	       ((font == _XmRendFont(_XmRTRenditions(oldtable)[i])) &&
		(type == _XmRendFontType(_XmRTRenditions(oldtable)[i])))))
	    {
	      if (FreeRendition(_XmRTRenditions(oldtable)[i]))
		FreeHandle(_XmRTRenditions(oldtable)[i]);
	      _XmRTRenditions(oldtable)[i] = NULL;
	      break;
	    }
	}
      if (_XmRTRenditions(oldtable)[i] != NULL) 
	{
	  if (count != i)
	    _XmRTRenditions(oldtable)[count] = _XmRTRenditions(oldtable)[i];

	  count++;
	}
    }
  if (count == 0)
    /* No renditions left. Return NULL. */
    {
      XmRenderTableFree(oldtable);
      return(NULL);
    }
  else if (count < _XmRTCount(oldtable))
    {
      /* Realloc table */
      table = (_XmRenderTable)XtRealloc((char *)*oldtable,
					sizeof(_XmRenderTableRec) +
					(sizeof(XmRendition) *
					 (count - RENDITIONS_IN_STRUCT)));
      if (newtable == NULL) 
	{
	  newtable = GetHandle(_XmRenderTable);
	  FreeHandle(oldtable);
	}      
      SetPtr(newtable, table);

      _XmRTCount(newtable) = count;
  
      return(newtable);
    }
  return(oldtable);
}

static void
CopyFromArg(XtArgVal src, char *dst, unsigned int size)
{
  if (size > sizeof(XtArgVal))
    memcpy((char *)dst, (char *)src, (size_t)size);
  else {
    union {
      long	longval;
#ifdef FIX_1152
      int	intval;
#endif
      short	shortval;
      char	charval;
      char*	charptr;
      XtPointer	ptr;
    } u;
    char *p = (char*)&u;
    if      (size == sizeof(long))	    u.longval = (long)src;
#ifdef FIX_1152
    else if (size == sizeof(int))	    u.intval = (int) src;
#endif
    else if (size == sizeof(short))	    u.shortval = (short)src;
    else if (size == sizeof(char))	    u.charval = (char)src;
    else if (size == sizeof(XtPointer))	    u.ptr = (XtPointer)src;
    else if (size == sizeof(char*))	    u.charptr = (char*)src;
    else				    p = (char*)&src;

    memcpy((char *)dst, p, (size_t)size);
  }
} /* CopyFromArg */

static void
CopyToArg(char *src, XtArgVal *dst, unsigned int size)
{
  if ((void *)(*dst) == NULL) {
    /* old GetValues semantics (storing directly into arglists) are bad,
     * but preserve for compatibility as long as arglist contains NULL.
     */
    if	    (size == sizeof(long))	   *dst = (XtArgVal)*(long*)src;
#ifdef FIX_1152
    else if (size == sizeof(int))	   *dst = (XtArgVal)*(int*)src;
#endif
    else if (size == sizeof(short))    *dst = (XtArgVal)*(short*)src;
    else if (size == sizeof(char))	   *dst = (XtArgVal)*(char*)src;
    else if (size == sizeof(XtPointer)) *dst = (XtArgVal)*(XtPointer*)src;
    else if (size == sizeof(char*))    *dst = (XtArgVal)*(char**)src;
    else if (size == sizeof(XtArgVal)) *dst = *(XtArgVal*)src;
    else memcpy((char*)dst, (char*)src, (size_t)size);
  }
  else {
    /* proper GetValues semantics: argval is pointer to destination */
    if	(size == sizeof(long))	   *((long*)*dst) = *(long*)src;
#ifdef FIX_1152
    else if (size == sizeof(int))	*((int*)*dst) = *(int*)src;
#endif
    else if (size == sizeof(short))    *((short*)*dst) = *(short*)src;
    else if (size == sizeof(char))	   *((char*)*dst) = *(char*)src;
    else if (size == sizeof(XtPointer)) *((XtPointer*)*dst) = *(XtPointer*)src;
    else if (size == sizeof(char*))    *((char**)*dst) = *(char**)src;
    else if (size == sizeof(XtArgVal)) *((XtArgVal*)*dst)= *(XtArgVal*)src;
    else memcpy((char *)*dst, (char *)src, (size_t)size);
  }
} /* CopyToArg */

/* Copies renditions matching tags to a new table. */
/* If all renditions copied then duplicate rendertable, duplicate */
/* renditions.  Otherwise, mutate rendertable, duplicate renditions. */
XmRenderTable
XmRenderTableCopy(XmRenderTable table,
		  XmStringTag *tags,
		  int tag_count)
{
  XmRenderTable		rt = NULL;
  _XmRenderTable	t = NULL;
  int			i, j, count;
  int			size;
  XmRendition		rend = NULL;
  XtAppContext		app = NULL;

  if (table == NULL) return((XmRenderTable)NULL);

#ifdef XTHREADS
  if (_XmRTDisplay(table))
     app = XtDisplayToApplicationContext(_XmRTDisplay(table));
  if (app) {
     _XmAppLock(app);
  }
  else {
     _XmProcessLock();
  }
#endif
  count = 0;

  if ((_XmRTRefcountInc(table) == 0) || (tags != NULL))
    {
      /* Malloc new table */
      _XmRTRefcountDec(table);
      
      if (tag_count > 0)
	size = (sizeof(_XmRendition) * (tag_count - RENDITIONS_IN_STRUCT));
      else 
	size = (sizeof(_XmRendition) *
		(_XmRTCount(table) - RENDITIONS_IN_STRUCT));
  
      size = (size < 0) ? 0 : size;

      t = (_XmRenderTable)XtMalloc(sizeof(_XmRenderTableRec) + size);
      rt = GetHandle(_XmRenderTable);
      SetPtr(rt, t);
      _XmRTRefcount(rt) = 1;
    }
  
  if (tags == NULL)
    {
      /* Increment renditions. */
      for (i = 0; i < _XmRTCount(table); i++)
	{
	  rend = DuplicateRendition(_XmRTRenditions(table)[i]);
	  /* Check for overflow. */
	  if (rend != _XmRTRenditions(table)[i]) break;
	}
      
      if (i < _XmRTCount(table))		  /* Overflow! */
	{
	  /* Malloc new table. */
	  t = (_XmRenderTable)XtMalloc(sizeof(_XmRenderTableRec) +
				       (sizeof(_XmRendition) *
					(_XmRTCount(table) - RENDITIONS_IN_STRUCT)));
	  rt = GetHandle(_XmRenderTable);
	  SetPtr(rt, t);
	  _XmRTRefcount(rt) = 1;
	    
	  _XmRTCount(rt) = _XmRTCount(table);

	  /* Move renditions done already. */
	  for (j = 0; j < i; j++)
	    _XmRTRenditions(rt)[j] = _XmRTRenditions(table)[j];
	  _XmRTRenditions(rt)[i] = rend;
	  /* Copy rest */
	  for (j = i + 1; j < _XmRTCount(rt); j++)
	    _XmRTRenditions(rt)[j] = DuplicateRendition(_XmRTRenditions(table)[j]);
	}
      else
	{
	  rt = GetHandle(_XmRenderTable);
	  SetPtr(rt, GetPtr(table));
	}
    }
  else
    {
      /* Copy matching renditions. */
      for (i = 0; i < tag_count; i++)
	{
	  XmRendition match;
	  
	  match = XmRenderTableGetRendition(table, tags[i]);

	  if (match != NULL)
	    {
	      _XmRTRenditions(rt)[i] = match;
	      ++count;
	    }
	}

      /* Realloc table */
      t = (_XmRenderTable)XtRealloc((char *)t, 
				     sizeof(_XmRenderTableRec) +
				     (sizeof(XmRendition) *
				      (count - RENDITIONS_IN_STRUCT)));
      SetPtr(rt, t);
      _XmRTCount(rt) = count;
    }

  _XmRTDisplay(rt) = _XmRTDisplay(table);

#ifdef XTHREADS
  if (app) {
	_XmAppUnlock(app);
  }
  else {
	_XmProcessUnlock();
  }
#endif
  return(rt);
}

/* Decrement rendertable, free if refcount is zero.  XmRenditionFree */
/* renditions. */
void
XmRenderTableFree(XmRenderTable table)
{
  int 		i;

  _XmProcessLock();
  for (i = 0; i < _XmRTCount(table); i++)
    if (FreeRendition(_XmRTRenditions(table)[i]))
      FreeHandle(_XmRTRenditions(table)[i]);
  
  if (_XmRTRefcountDec(table) == 0)
    XtFree((char *)GetPtr(table));

  FreeHandle(table);
  _XmProcessUnlock();
}

/* Get list of tags of all renditions in table. */
int
XmRenderTableGetTags(XmRenderTable table, 
		     XmStringTag **tag_list)
{
  int i, ret_val;
  XtAppContext          app = NULL;

  if (table == NULL)
    {
      *tag_list = NULL;
      return(0);
    }

  app = XtDisplayToApplicationContext(_XmRTDisplay(table));
  _XmAppLock(app);
  *tag_list = 
    (XmStringTag *)XtMalloc(sizeof(XmStringTag) * _XmRTCount(table));

  for (i = 0; i < _XmRTCount(table); i++)
      (*tag_list)[i] = 
	XtNewString(_XmRendTag(_XmRTRenditions(table)[i]));
      
  ret_val = _XmRTCount(table);
  _XmAppUnlock(app);
  return ret_val;
}

/* Returns copy of matching rendition. */
XmRendition
XmRenderTableGetRendition(XmRenderTable table,
			  XmStringTag tag)
{
  XmRendition ret_val;
  _XmDisplayToAppContext(_XmRTDisplay(table));

  _XmAppLock(app);
  ret_val = CopyRendition(_XmRenderTableFindRendition(table, tag,
			FALSE, FALSE, FALSE, NULL));
  _XmAppUnlock(app);
  return ret_val;
}

/* Returns array of copies of matching renditions. */
XmRendition *
XmRenderTableGetRenditions(XmRenderTable table,
			   char **tags,
			   Cardinal tag_count)
{
  XmRendition	rend, *rends;
  int		i, count;
  XtAppContext  app = NULL;

  if ((table == NULL) || (tags == NULL) || (tag_count == 0))
      return(NULL);
 
#ifdef XTHREADS
  if (_XmRTDisplay(table))
  {
     app = XtDisplayToApplicationContext(_XmRTDisplay(table));
     _XmAppLock(app);
  }
#endif
  rends = (XmRendition *)XtMalloc(tag_count * sizeof(XmRendition));
  
  count = 0;
  for (i = 0; i < tag_count; i++)
    {
      rend = _XmRenderTableFindRendition(table, tags[i],
					 FALSE, FALSE, FALSE, NULL);
      if (rend != NULL)
	{
	  rends[count] = CopyRendition(rend);
	  count++;
	}
    }
  
  if (count < tag_count)
    rends = (XmRendition *)XtRealloc((char *)rends, count * sizeof(XmRendition));
  
#ifdef XTHREADS
  if (app) {
     _XmAppUnlock(app);
  }
#endif
  return(rends);
}

/* Wrapper for calling XtWarning functions. */
static void
RenditionWarning(char *tag,
		 char *type,
		 char *message,
     		 Display *dpy)
{
  char *params[1];
  Cardinal num_params = 1 ;
  Display *d;

  /* the MotifWarningHandler installed in VendorS.c knows about
     this convention */
  params[0] = XME_WARNING;

  if (dpy)
     d = dpy;
  else
     d = _XmGetDefaultDisplay();
  if (d)
    XtAppWarningMsg (XtDisplayToApplicationContext(d),
		     tag, type, "XmRendition", 
		     message, params, &num_params);
  else XtWarning(message);
}

/* Replace XmAS_IS and copy as necessary. */
static void
CleanupResources(XmRendition rend,
		 Boolean copy)
{
  if ((unsigned int)(unsigned long)_XmRendFont(rend) == XmAS_IS) 
    _XmRendFont(rend) = NULL;
  else if (_XmRendFontType(rend) == XmAS_IS)
    _XmRendFontType(rend) = XmFONT_IS_FONT;

#ifdef USE_XFT
  if ((unsigned int)(unsigned long)_XmRendXftFont (rend) == XmAS_IS)
    _XmRendXftFont (rend) = NULL;
#endif

  if (((unsigned int)(unsigned long)_XmRendFontName(rend) == XmAS_IS) ||
      (strcmp(_XmRendFontName(rend), XmSXmAS_IS) == 0))
    _XmRendFontName(rend) = NULL;
  else if (copy)
    _XmRendFontName(rend) = XtNewString(_XmRendFontName(rend));
  
  if ((unsigned int)(unsigned long)_XmRendTabs(rend) == XmAS_IS)
    _XmRendTabs(rend) = NULL;
  else if (copy)
    _XmRendTabs(rend) = XmTabListCopy(_XmRendTabs(rend), 0, 0);
}


/* Emit warning and set default if tag is NULL. */
static void
ValidateTag(XmRendition rend,
	    XmStringTag dflt)
{
  if (_XmRendTag(rend) == NULL)
    {
      RenditionWarning(_XmRendTag(rend), "NO_NULL_TAG",
	NO_NULL_TAG_MSG, _XmRendDisplay(rend));
      _XmRendTag(rend) = _XmStringCacheTag(dflt, XmSTRING_TAG_STRLEN);
    }
}

#ifdef FIX_1414
#ifdef USE_XFT
static int
GetSameRenditions(XmRendition *rend_cache, XmRendition rend, int count_rend)
{
	int i;
	for (i=0; i<count_rend; i++){

		if ( rend_cache && (rend_cache[i])
				&& ((((_XmRendFontName(rend) 	&& _XmRendFontName(rend_cache[i]) ) && !strcmp(_XmRendFontName(rend_cache[i]), _XmRendFontName(rend)))
					|| 	(!_XmRendFontName(rend) && !_XmRendFontName(rend_cache[i])))
				&& (((_XmRendFontFoundry(rend) && _XmRendFontFoundry(rend_cache[i])) && !strcmp(_XmRendFontFoundry(rend_cache[i]), _XmRendFontFoundry(rend)))
					|| 	(!_XmRendFontFoundry(rend) && !_XmRendFontFoundry(rend_cache[i])))
				&& (((_XmRendFontEncoding(rend) && _XmRendFontEncoding(rend_cache[i])) && !strcmp(_XmRendFontEncoding(rend_cache[i]), _XmRendFontEncoding(rend)))
					|| 	(!_XmRendFontEncoding(rend) && !_XmRendFontEncoding(rend_cache[i])))
				&& (((_XmRendFontStyle(rend) && _XmRendFontStyle(rend_cache[i])) && !strcmp(_XmRendFontStyle(rend_cache[i]), _XmRendFontStyle(rend)))
					|| 	(!_XmRendFontStyle(rend) && !_XmRendFontStyle(rend_cache[i])) )
				&& _XmRendFontSize(rend) == _XmRendFontSize(rend_cache[i])
				&& _XmRendPixelSize(rend) == _XmRendPixelSize(rend_cache[i])
				&& _XmRendFontSlant(rend) == _XmRendFontSlant(rend_cache[i])
				&& _XmRendFontWeight(rend) == _XmRendFontWeight(rend_cache[i])
				&& _XmRendFontSpacing(rend) == _XmRendFontSpacing(rend_cache[i]))
	   	   )
		{
			return i;
		}

	}
	return -1;

}
#endif
#endif

/* Make sure all the font related resources make sense together and */
/* then load the font specified by fontName if necessary. */
static void
ValidateAndLoadFont(XmRendition rend, Display *display)
{
  XrmString 		locale;
  XtPointer 		font;
  XrmValue         	args[2];
  Cardinal         	num_args = 0;
  XrmValue         	fromVal;
  XrmValue         	toVal;
  Boolean		result = False;

  _XmRendDisplay(rend) = display;
  
  if (_XmRendLoadModel(rend) != XmLOAD_DEFERRED)
    {
      XmDisplay			dsp = NULL;
      XmDisplayCallbackStruct	cb;

      if ((_XmRendFont(rend) == NULL) &&
#ifdef USE_XFT
          (_XmRendXftFont (rend) == NULL) &&
#endif
	  (_XmRendFontName(rend) != NULL))
	{
	  if (_XmRendFontType(rend) != XmAS_IS)
	    {
	      if (display == NULL)
		{
		  RenditionWarning(_XmRendTag(rend), "NULL_DISPLAY",
				   NULL_DISPLAY_MSG, NULL);
		  return;
		}
	      
	      args[0].addr = (XPointer) &display;
	      args[0].size = sizeof(Display*);
	      num_args++;

	      fromVal.addr = _XmRendFontName(rend);
	      fromVal.size = strlen(_XmRendFontName(rend));

	      toVal.addr = (XPointer) &font;
	      toVal.size = sizeof (XtPointer);

	      switch (_XmRendFontType(rend))
		{
		case XmFONT_IS_FONT:
		  result = 
		    XtCallConverter(display, XtCvtStringToFontStruct,
				    args, num_args, &fromVal, &toVal, NULL);
		  break;
		case XmFONT_IS_FONTSET:
		  locale = 
		    XrmQuarkToString(XrmStringToQuark(setlocale(LC_ALL, NULL)));
		  args[1].addr = (XPointer) &locale;
		  args[1].size = sizeof(XrmString);
		  num_args++;

		  result = XtCallConverter (display, XtCvtStringToFontSet, args,
					    num_args, &fromVal, &toVal, NULL);
		  break;
#ifdef USE_XFT
		case XmFONT_IS_XFT:
		  {
		    FcResult res;
		    FcPattern *p;
		    
#ifdef FIX_1414
						  static XmRendition *rend_cache;
						  static int count_rend=0, num_rend;
						  num_rend = GetSameRenditions(rend_cache, rend, count_rend);

						  if (num_rend>=0)
							  _XmRendXftFont(rend) = _XmRendXftFont(rend_cache[num_rend]);
						  else
						  {
#endif
		    _XmRendPattern(rend) = FcPatternCreate();
		    if (_XmRendFontName(rend))
		      FcPatternAddString(_XmRendPattern(rend), FC_FAMILY,
		                         (XftChar8 *)_XmRendFontName(rend));
		    if (_XmRendFontFoundry(rend))
		      FcPatternAddString(_XmRendPattern(rend), FC_FOUNDRY,
		                         (XftChar8 *)_XmRendFontFoundry(rend));
		    if (_XmRendFontEncoding(rend))
		      FcPatternAddString(_XmRendPattern(rend), XFT_ENCODING,
		                         (XftChar8 *)_XmRendFontEncoding(rend));
		    if (_XmRendFontStyle(rend))
		      FcPatternAddString(_XmRendPattern(rend), FC_STYLE,
		                         (XftChar8 *)_XmRendFontStyle(rend));
		    if (_XmRendFontSize(rend))
		      FcPatternAddInteger(_XmRendPattern(rend), FC_SIZE,
		                         _XmRendFontSize(rend));
		    if (_XmRendPixelSize(rend))
		      FcPatternAddInteger(_XmRendPattern(rend), FC_PIXEL_SIZE,
		                         _XmRendPixelSize(rend));
		    if (_XmRendFontSlant(rend))
		      FcPatternAddInteger(_XmRendPattern(rend), FC_SLANT,
		                         _XmRendFontSlant(rend));
		    if (_XmRendFontWeight(rend))
		      FcPatternAddInteger(_XmRendPattern(rend), FC_WEIGHT,
		                         _XmRendFontWeight(rend));
		    if (_XmRendFontSpacing(rend))
		      FcPatternAddInteger(_XmRendPattern(rend), FC_SPACING,
		                         _XmRendFontSpacing(rend));
                    p = XftFontMatch(display, 0, _XmRendPattern(rend), &res);
#ifdef FIX_1414
                    _XmRendXftFont(rend) = XftFontOpenPattern(display, p);
					    		  rend_cache = (XmRendition *) XtRealloc((char *)rend_cache, 
					    		    (Cardinal)(sizeof(XmRendition) * (count_rend + 1)));
							  rend_cache[count_rend] =_XmRenditionCopy(rend, TRUE);
							  count_rend++;
						  }

#else
						  _XmRendXftFont(rend) = XftFontOpenPattern(display, p);
#endif
		  }
		  result = _XmRendXftFont(rend) != NULL;
		  break;
#endif
		default:
		  RenditionWarning(_XmRendTag(rend), "INVALID_TYPE",
				   INVALID_TYPE_MSG,
				   _XmRendDisplay(rend));
		  break;
		}

	      /* NoFontCallback. */
	      if (!result)
		{
		  if (display != NULL) 
		    {
		      dsp = (XmDisplay) XmGetXmDisplay(display);
		      cb.reason = XmCR_NO_FONT;
		      cb.event = NULL;
		      cb.rendition = rend;
		      cb.font_name = _XmRendFontName(rend);
      
		      /* We must know for sure whether there are any */
		      /* callbacks, so we have to use XtHasCallbacks. */
		      if (XtHasCallbacks((Widget)dsp, XmNnoFontCallback) ==
			  XtCallbackHasSome)
			{
			  XtCallCallbackList((Widget)dsp,
					     dsp->display.noFontCallback, 
					     &cb);
			  return;
			}
		    }
	  
		  RenditionWarning(_XmRendTag(rend), "CONVERSION_FAILED",
				   CONVERSION_FAILED_MSG,
				   _XmRendDisplay(rend));
		}
	      else
		{
#ifdef USE_XFT
		  if (_XmRendFontType(rend) != XmFONT_IS_XFT)
#endif
		    _XmRendFont(rend) = font;
		}
	    }
	  else
	    {
	      RenditionWarning(_XmRendTag(rend), "NULL_FONT_TYPE",
			       NULL_FONT_TYPE_MSG,
				_XmRendDisplay(rend));
	    }
	}
      else if ((_XmRendLoadModel(rend) == XmLOAD_IMMEDIATE) &&
	       (_XmRendFont(rend) == NULL) &&
#ifdef USE_XFT
	       (_XmRendXftFont (rend) == NULL) &&
#endif
	       (_XmRendFontName(rend) == NULL))
	{
	  RenditionWarning(_XmRendTag(rend), "NULL_LOAD_IMMEDIATE",
			   NULL_LOAD_IMMEDIATE_MSG,
			   _XmRendDisplay(rend));
	}
    }
}

/* Create new rendition. */
XmRendition
XmRenditionCreate(Widget widget,
		  XmStringTag tag,
		  ArgList arglist,
		  Cardinal argcount)
{
  XmRendition  ret_val;
  XtAppContext app=NULL;

  /* If cannot applock, assume its an internal call (from
   *	fontlist code, etc.) and already process locked.
   */
  if (widget)
	app = XtWidgetToApplicationContext(widget);
  if (app) {
	_XmAppLock(app);
  }
  else {
	_XmProcessLock();
  }
  ret_val = _XmRenditionCreate(NULL, widget, XmS, XmCRenderTable,
			    tag, arglist, argcount, NULL);
  if (app) {
	_XmAppUnlock(app);
  }
  else {
	_XmProcessUnlock();
  }

  return ret_val;
}

/* Internal function.  Called from XmRenditionCreate, resource */
/* converter, and Mrm create function. */
XmRendition
_XmRenditionCreate(Display *display,
		   Widget widget,
		   String resname,
		   String resclass,
		   XmStringTag tag,
		   ArgList arglist,
		   Cardinal argcount,
		   Boolean *in_db)
{
  XmRendition	rend;
  _XmRendition	rend_int;
  Boolean 	result;
  
  if ((display == NULL) && (widget != NULL))
    display = XtDisplayOfObject(widget);

 if ((tag != NULL) &&
     (tag != XmFONTLIST_DEFAULT_TAG) &&
     (strcmp(tag, XmSTRING_DEFAULT_CHARSET) == 0))
   tag = _XmStringGetCurrentCharset();

  /* Allocate rendition. */
  rend_int = (_XmRendition)XtMalloc(sizeof(_XmRenditionRec));
  bzero((char*)rend_int, sizeof(_XmRenditionRec));
  rend = GetHandle(_XmRendition);
  SetPtr(rend, rend_int);
  
  _XmRendRefcount(rend) = 1;
  
  /* For now, FontOnly renditions aren't implemented. */
  _XmRendFontOnly(rend) = FALSE;

  /* X resource DB query */
  result =
    GetResources(rend, display, widget, resname, resclass, tag,
		 arglist, argcount);
  
  if (in_db != NULL) *in_db = result;
  
  if (tag == NULL)
    {
      if (result == FALSE)
	{
	  XtFree((char *)rend_int);
	  FreeHandle(rend);
	  return(NULL);
	}
      else tag = _MOTIF_DEFAULT_LOCALE;
    }
  
  _XmRendTag(rend) = _XmStringCacheTag(tag, XmSTRING_TAG_STRLEN);
  
  /* Cleanup and validate resources. */

  CleanupResources(rend, TRUE);

  ValidateTag(rend, XmS);
  
  ValidateAndLoadFont(rend, display);

  return(rend);
}

/* Mrm create function for rendertables. */
/*ARGSUSED*/
Widget
_XmCreateRenderTable(Widget parent,
		     String name, /* unused */
		     ArgList arglist, /* unused */
		     Cardinal argcount)	/* unused */
{
  XmRenderTable 	newtable;
  _XmRenderTable	table;
  
  /* Malloc new table */
  table = (_XmRenderTable)XtMalloc(sizeof(_XmRenderTableRec));
  newtable = GetHandle(_XmRenderTable);
  SetPtr(newtable, table);
  _XmRTCount(newtable) = 0;
  _XmRTRefcount(newtable) = 1;
  _XmRTDisplay(newtable) = XtDisplay(parent);
  
  return((Widget)newtable);
}

/* Mrm create function for renditions. */
Widget
_XmCreateRendition(Widget parent,
		   String name,
		   ArgList arglist,
		   Cardinal argcount)
{
  XmRenderTable		rt = (XmRenderTable)parent;
  _XmRenderTable	table;
  XmRendition		rend;
  
  table = GetPtr(rt);
  
  rend = _XmRenditionCreate(_XmRTDisplay(rt), NULL, XmS, XmCRenderTable,
			    name, arglist, argcount, NULL);
  
  /* Ignore repeats */
  if (_XmRenderTableFindRendition(rt, _XmRendTag(rend),
				  TRUE, FALSE, FALSE, NULL) 
      != NULL)
    {
      if (FreeRendition(rend)) FreeHandle(rend);
      return((Widget)NULL);
    }
  
  table = (_XmRenderTable)
    XtRealloc((char *)table,
	      sizeof(_XmRenderTableRec) +
	      (sizeof(XmRendition) *
	       ((_XmRTCount(rt) + 1) - RENDITIONS_IN_STRUCT)));
  SetPtr(rt, table);

  /* Copy new rendition. */
  _XmRTRenditions(rt)[_XmRTCount(rt)] = CopyRendition(rend);
  _XmRTCount(rt)++;

  return((Widget)rend);
}

/* Free data structure and any copied values. */
/* TRUE return -> freed.  FALSE -> just decremented. */
static Boolean
FreeRendition(XmRendition rendition)
{
  if (rendition == NULL) return(FALSE);
  
  if (_XmRendRefcountDec(rendition) == 0)
    {
      /* CR 7890 - the fontName might be XmAS_IS here */
      if (NameIsString(_XmRendFontName(rendition)))
	XtFree(_XmRendFontName(rendition));
      if (ListIsList(_XmRendTabs(rendition)))
	XmTabListFree(_XmRendTabs(rendition));
      if (_XmRendTagCount(rendition) != 0)
	XtFree((char *)_XmRendTags(rendition));
#ifdef USE_XFT
      if (_XmRendXftFont(rendition))
        {
          XftFontClose(_XmRendDisplay(rendition),
              _XmRendXftFont(rendition));
          _XmRendXftFont(rendition) = NULL;
        }
      if (_XmRendPattern(rendition))
        {
          FcPatternDestroy(_XmRendPattern(rendition));
          _XmRendPattern(rendition) = NULL;
        }
#endif
  
      XtFree((char *)GetPtr(rendition));
      return(TRUE);
    }
  return(FALSE);
}

void
XmRenditionFree(XmRendition rendition)
{
  XtAppContext app;

  if (rendition == NULL) return;

  _XmProcessLock();
  FreeRendition(rendition);
  FreeHandle(rendition);
  _XmProcessUnlock();
}

/* Get resource values from rendition. */
void
XmRenditionRetrieve(XmRendition rendition,
		    ArgList arglist,
		    Cardinal argcount)
{
  int			i, j;
  Arg			*arg;
  XtResource		*res;
  char			*as_is = (char *)XmAS_IS;
  
  if (rendition == NULL) return;

  _XmProcessLock();
  /* Get resources */
  for (i = 0; i < argcount; i++)
    {
      arg = &(arglist[i]);
      
      for (j = 0; j < _XmNumRenditionResources; j++)
	{
	  res = &(_XmRenditionResources[j]);

	  if (strcmp(res->resource_name, arg->name) == 0)
	    {
	      /* CR 7890: Font hook - if there's a fontName but the 
	      ** font hasn't been fetched yet, now's a good time to 
	      ** get it - if the caller wants to use the font to, say, 
	      ** compute font metrics for layout (as CSText does), it won't
	      ** like to get NULL back
	      */
	      if (strcmp(res->resource_name, XmNfont) == 0)
		{
		  if ((_XmRendFont(rendition) == NULL) &&
#ifdef USE_XFT
		      (_XmRendXftFont (rendition) == NULL) &&
#endif
		      (_XmRendFontName(rendition) != NULL))
		    {
		      if (_XmRendLoadModel(rendition) == XmLOAD_DEFERRED)
			_XmRendLoadModel(rendition) = XmLOAD_IMMEDIATE;
		      ValidateAndLoadFont(rendition, _XmRendDisplay(rendition));
		    }
		  if (_XmRendFont (rendition) == NULL
#ifdef USE_XFT
		      && _XmRendXftFont (rendition) == NULL
#endif
		     )
		    CopyToArg((char*)&as_is, &(arg->value), sizeof(char*));
		  else CopyToArg(((char *)GetPtr(rendition) + 
				  res->resource_offset),
				 &(arg->value),
				 res->resource_size);
		}
	      else if (((strcmp(res->resource_name, XmNfontName) == 0) &&
		       (_XmRendFontName(rendition) == NULL)) ||
		       ((strcmp(res->resource_name, XmNtabList) == 0) &&
		       (_XmRendTabs(rendition) == NULL)))
		CopyToArg((char*)&as_is, &(arg->value), sizeof(char*));
	      else CopyToArg(((char *)GetPtr(rendition) + res->resource_offset),
			     &(arg->value),
			     res->resource_size);
	      break;
	    }
	}
    }
    _XmProcessUnlock();
}

/* Set resources in rendition. */
/* Renew rendition if necessary, then update resources. */
void
XmRenditionUpdate(XmRendition rendition,
		  ArgList arglist,
		  Cardinal argcount)
{
  XmStringTag	oldtag;
  char		*oldname;
  XtPointer	oldfont;
  XmTabList	oldtabs;
  int		i, j;
  XtResource	*res;
  Arg		*arg;
  Display	*display = _XmGetDefaultDisplay();
  Boolean	can_free;
  XtAppContext	app = NULL;
  
  if (rendition == NULL) return;
  
#ifdef XTHREADS
  if (_XmRendDisplay(rendition))
  {
     app = XtDisplayToApplicationContext(_XmRendDisplay(rendition));
     _XmAppLock(app);
  }
  if (_XmRendDisplay(rendition) && (_XmRendDisplay(rendition) !=
			display) )
 	display = _XmRendDisplay(rendition);
#endif
  /* Save old values to check for dependencies and free memory. */
  oldtag = _XmRendTag(rendition);
  oldname = _XmRendFontName(rendition);
  oldfont = _XmRendFont(rendition);
  oldtabs = _XmRendTabs(rendition);
  can_free = TRUE;
  
  /* New memory if needed. */
  if (_XmRendRefcount(rendition) > 1)
    {
      _XmRendRefcountDec(rendition);
      RenewRendition(rendition);
      can_free = FALSE;
    }
      
  for (i = 0; i < argcount; i++)
    {
      arg = &(arglist[i]);
      
      for (j = 0; j < _XmNumRenditionResources; j++)
	{
	  res = &(_XmRenditionResources[j]);

	  if (strcmp(res->resource_name, arg->name) == 0)
	    {
	      CopyFromArg((arg->value),
			  ((char *)GetPtr(rendition) + res->resource_offset),
			  res->resource_size);
	      break;
	    }
	}
    }
  
  CopyInto(rendition, rendition);

  /** Validate resources **/

  /* CR 7890 - handle cases of fontName == NULL and fontName == XmAS_IS */

  /* If fontName changed but not font, NULL font so it's updated. 
   ** (first make sure we won't crash on the strcmp) */

  if (NameIsString(oldname) && NameIsString(_XmRendFontName(rendition)))    {
    if (strcmp(oldname, _XmRendFontName(rendition)) != 0)
      {
	if (oldfont == _XmRendFont(rendition))
	  _XmRendFont(rendition) = NULL;
      }
    if (can_free) XtFree(oldname);
  }
  /* Also handle the case where we started with a NULL fontName and
   ** had a real fontName specified */
  else if ((oldname == NULL) && NameIsString(_XmRendFontName(rendition)))
    {
      if (oldfont == _XmRendFontName(rendition))
	_XmRendFont(rendition) = NULL;
    }

  if (_XmRendFont(rendition) == (XtPointer)XmAS_IS)
    _XmRendFont(rendition) = NULL;

  if ((oldtabs != _XmRendTabs(rendition)) && can_free) XmTabListFree(oldtabs);
  
  ValidateTag(rendition, oldtag);
  
  ValidateAndLoadFont(rendition, display);
#ifdef XTHREADS
  if (app) {
     _XmAppUnlock(app);
  }
#endif
}

/*****************************************************************************/
/* XmRenderTableCvtToProp takes a rendertable and converts it to             */
/* an ascii string in the following format:				     */
/* tag : char*								     */
/* font : either fontid (integer) or [ fontid, fontid ... fontid ] or -1     */
/* tablist : [ tab1, ... tabn ] or -1					     */
/* background : pixel or -1						     */
/* foreground : pixel or -1						     */
/* underlineType : integer (from enum in Xm.h ) or -1			     */
/* strikethruType : integer (from enum in Xm.h ) or -1			     */
/* 									     */
/* example:								     */
/* "tag, font, tablist, background, foreground, underlineType, 		     */
/*  strikethruType\n							     */
/* bold, 10000031, -1, -1, -1, -1, -1\n					     */
/* underline, 10000029, -1, -1, -1, -1, -1\n				     */
/* default, 10000029, [ 1.234 1 0 0, 2.43 2 0 2], 1, 2, 0, 0\n		     */
/* japanese, [10000029, 10000030], -1, -1, -1, -1, -1"			     */
/* 									     */
/* The first line gives a complete list of the attributes by name.	     */
/* on the destination side,  attributes which are not understood	     */
/* or are outdated can be ignored.  The conversion of each rendition	     */
/* passes a single "line" which contains the fields in order.		     */
/*****************************************************************************/

/* Note that this MUST be in the same order as the output conversion
   below!! */
static XmConst char *CVTproperties[] = {
  XmNtag,
  XmNfont,
  XmNtabList,
  XmNbackground,
  XmNforeground,
  XmNunderlineType,
  XmNstrikethruType,
  NULL,
  };

/* Must be big enough to take all the above strings concatenated with
   commas separating them */
static char CVTtransfervector[256];
static int CVTtvinited = 0;

/* Use this macro to encapsulate the code that extends the output
   buffer as needed */
#define CVTaddString(dest, src, srcsize)\
{\
   if ((chars_used + srcsize) > allocated_size) {\
     allocated_size *= 2;\
     buffer = XtRealloc(buffer, allocated_size);\
   }\
   strcat(buffer, src);\
   chars_used += srcsize;\
}

/*ARGSUSED*/
unsigned int
XmRenderTableCvtToProp(Widget widget, /* unused */
		       XmRenderTable table,
		       char **prop_return)
{
  int i;
  int allocated_size = 256;
  int chars_used = 0, size;
  char *buffer;
  char *str;
  XmRendition rendition;
  _XmWidgetToAppContext(widget);

  _XmAppLock(app);
  buffer = XtMalloc(allocated_size);

  _XmProcessLock();
  if (CVTtvinited == 0) {
    CVTtvinited = 1;
    strcpy(CVTtransfervector, "");
    for(i = 0; CVTproperties[i] != NULL; i++) {
      strcat(CVTtransfervector, CVTproperties[i]);
      strcat(CVTtransfervector, ",");
    }
    strcat(CVTtransfervector, "\n");
  }
  
  /* Copy the transfer vector into the output buffer. */
  strcpy(buffer, CVTtransfervector);
  chars_used = strlen(buffer);
  _XmProcessUnlock();

  /* Now iterate over the list of renditions */
  for(i = 0; i < _XmRTCount(table); i++) {
    char temp[2048];

    rendition = _XmRTRenditions(table)[i];
    sprintf(temp, "\"%s\", ", _XmRendTag(rendition));
    size = strlen(temp);
    CVTaddString(buffer, temp, size);

    if (_XmRendFontType(rendition) == XmAS_IS)
      str = "-1, ";
    else {
      sprintf(temp, "%d \"%s\" %d,", _XmRendFontType(rendition),
	      _XmRendFontName(rendition), _XmRendLoadModel(rendition));
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);

    if ((unsigned int)(unsigned long)_XmRendTabs(rendition) == XmAS_IS ||
	_XmRendTabs(rendition) == NULL)
      str = "-1, ";
    else {
      _XmTab tab;
      _XmTabList tlist;
      int number;
      strcpy(temp, "[ ");
      tlist = (_XmTabList) _XmRendTabs(rendition);
      number = tlist -> count;
      tab = (_XmTab) tlist -> start;
      while(number > 0) {
	sprintf(temp, "%s %f %d %d %d, ", temp, tab -> value, 
		tab -> units, tab -> alignment, tab -> offsetModel);
	tab = (_XmTab) tab -> next;
	number--;
      }
      strcat(temp, " ], ");
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);

    if (_XmRendBG(rendition) == XmAS_IS)
      str = "-1, ";
    else {
      sprintf(temp, "%ld, ", _XmRendBG(rendition));
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);

    if (_XmRendFG(rendition) == XmAS_IS)
      str = "-1, ";
    else {
      sprintf(temp, "%ld, ", _XmRendFG(rendition));
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);

    if (_XmRendUnderlineType(rendition) == XmAS_IS)
      str = "-1, ";
    else {
      sprintf(temp, "%d, ", _XmRendUnderlineType(rendition));
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);

    if (_XmRendStrikethruType(rendition) == XmAS_IS)
      str = "-1, ";
    else {
      sprintf(temp, "%d, ", _XmRendStrikethruType(rendition));
      str = temp;
    }
    size = strlen(str);
    CVTaddString(buffer, str, size);
    CVTaddString(buffer, "\n", size);
  }

  /* Return the converted rendertable string */
  *prop_return = buffer;

  _XmAppUnlock(app);
  /* chars_used is always the size - the NULL terminator */
  return(chars_used + 1);
}

typedef enum {   T_NL, T_INT, T_FLOAT, T_SEP, 
		 T_OPEN, T_CLOSE, T_STR, T_EOF } TokenType;

typedef struct _TokenRec {
  TokenType	type;
  int		integer;
  float		real;
  char		*string;
} TokenRec, *Token;


#ifndef XTHREADS
static TokenRec reusetoken;
#endif

static Token
ReadToken(char *string, int *position)
{
#ifdef XTHREADS
  TokenRec reusetoken;
  Token new_token = &reusetoken;
#else
  Token new_token = &reusetoken;
#endif
  int pos = *position;
  int count;

  /* Skip whitespace but not newlines */
  while (isspace(string[pos]) && ! (string[pos] == '\n'))
    pos++;

  /* Select token type */
  switch(string[pos]) {
  case '\0':
    new_token -> type = T_EOF;
    break;
  case '\n': 
    new_token -> type = T_NL;
    pos++;
    break;
  case ',':
    new_token -> type = T_SEP;
    pos++;
    break;
  case '[':
    new_token -> type = T_OPEN;
    pos++;
    break;
  case ']':
    new_token -> type = T_CLOSE;
    pos++;
    break;
  case '"': /* String result */
    count = 1;
    while (string[pos + count] != '"' &&
	   string[pos + count] != '\0')
      count++; /* Scan for end of string */
    new_token -> type = T_STR;
    new_token -> string = NULL;
    count -= 1;
    if (count > 0) {
      new_token -> string = (char*) XtMalloc(count + 1);
      strncpy(new_token -> string, &string[pos + 1], count);
      pos += count + 2; /* Move past end quote */
      new_token -> string[count] = 0; /* Null terminate */
    }
    break;
  default:
    if (isalpha(string[pos])) /* String result */
      {
	char temp[80];
	int count;
	for(count = 0; 
	    isalpha(string[pos + count]) && count < 79;
	    count++) temp[count] = string[pos + count];
	temp[count] = 0;
	pos += count;
	new_token -> type = T_STR;
	new_token -> string = XtNewString(temp);
      }
    else
      {
	/* start converting a float number.  If it is exactly integer
	   then we return an int,  otherwise return a float */
	double result;
	int intresult;
	char *newpos;
	result=strtod(&(string[pos]), &newpos);
	intresult= (int) result;
	pos = newpos - string;
	if (((double) intresult) == result) /* Integer result */
	  {
	    new_token -> type = T_INT;
	    new_token -> integer = intresult;
	  }
	else
	  {
	    new_token -> type = T_FLOAT;
	    new_token -> real = (float) result;
	  }
      }
  }

  *position = pos;
  return(new_token);
}

#ifdef	USE_XFT
static struct _XmXftDrawCacheStruct {
	Display	*display;
	Window	window;
	XftDraw	*draw;
} *_XmXftDrawCache = NULL;
static int _XmXftDrawCacheSize = 0;

static XErrorHandler           oldErrorHandler;
static int xft_error;

static int 
_XmXftErrorHandler(
        Display *display,
        XErrorEvent *error )
{
   (void) fprintf(stderr,
   "Ignoring Xlib error: error code %d request code %d\n",
   error->error_code,
   error->request_code) ;
   xft_error = BadWindow;

    /* No exit! - but keep lint happy */

    return 0 ;
}

XftDraw *
_XmXftDrawCreate(Display *display, Window window)
{
	XftDraw			*draw;
	XWindowAttributes	wa;
	int			i;
	Status status;

	for (i=0; i<_XmXftDrawCacheSize; i++) {
		if (_XmXftDrawCache[i].display == display &&
		    _XmXftDrawCache[i].window == window) {
			return _XmXftDrawCache[i].draw;
		}
	}

#ifdef FIX_1444
	if (!(draw = XftDrawCreate(display, window,
	    DefaultVisual(display, DefaultScreen(display)),
	    DefaultColormap(display, DefaultScreen(display))))) 
            	draw = XftDrawCreateBitmap(display, window);
#else
	oldErrorHandler = XSetErrorHandler (_XmXftErrorHandler);	
	xft_error = 0;
	XGetWindowAttributes(display, window, &wa);
	XSetErrorHandler(oldErrorHandler);
	if (xft_error != BadWindow) {
	    draw = XftDrawCreate(display, window,
	        DefaultVisual(display, DefaultScreen(display)),
	        DefaultColormap(display, DefaultScreen(display)));
	} else {
            draw = XftDrawCreateBitmap(display, window);
        }
#endif
	/* Store it in the cache. Look for an empty slot first */
	for (i=0; i<_XmXftDrawCacheSize; i++)
		if (_XmXftDrawCache[i].display == NULL) {
			_XmXftDrawCache[i].display = display;
			_XmXftDrawCache[i].draw = draw;
			_XmXftDrawCache[i].window = window;
			return draw;
		}
	i = _XmXftDrawCacheSize;	/* Next free index */
	_XmXftDrawCacheSize = _XmXftDrawCacheSize * 2 + 8;
	_XmXftDrawCache = (struct _XmXftDrawCacheStruct *)
		XtRealloc((char *)_XmXftDrawCache,
		sizeof(struct _XmXftDrawCacheStruct) * _XmXftDrawCacheSize);
#ifdef FIX_1449
	memset(_XmXftDrawCache + i, 0, (_XmXftDrawCacheSize - i) * sizeof(*_XmXftDrawCache));
#endif

	_XmXftDrawCache[i].display = display;
	_XmXftDrawCache[i].draw = draw;
	_XmXftDrawCache[i].window = window;
	
	return draw;
}

void
_XmXftDrawDestroy(Display *display, Window window, XftDraw *draw)
{
    int i;

    for (i=0; i<_XmXftDrawCacheSize; i++)
	if (_XmXftDrawCache[i].display == display &&
	    _XmXftDrawCache[i].window == window) {
	        _XmXftDrawCache[i].display = NULL;
	        _XmXftDrawCache[i].draw = NULL;
	        _XmXftDrawCache[i].window = None;
	        XftDrawDestroy(draw);
	        return;
        }
    XmeWarning(NULL, "_XmXftDrawDestroy() this should not happen\n");
}

void
_XmXftDrawString2(Display *display, Window window, GC gc, XftFont *font, int bpc,
#if NeedWidePrototypes
                int x, int y,
#else
                Position x, Position y,
#endif
                char *s, int len)
{
    XftDraw	*draw = _XmXftDrawCreate(display, window);
    XGCValues gc_val;
    XColor xcol;
    XftColor xftcol;
    
    XGetGCValues(display, gc, GCForeground, &gc_val);

    xcol.pixel = gc_val.foreground;
    XQueryColor(display, DefaultColormap(display,
        DefaultScreen(display)), &xcol);
    xftcol.color.red = xcol.red;
    xftcol.color.blue = xcol.blue;
    xftcol.color.green = xcol.green;
    xftcol.color.alpha = 0xFFFF;

    switch (bpc)
    {
	case 1:
		XftDrawStringUtf8(draw, &xftcol, font,
			x, y, (XftChar8 *)s, len);
		break;
	case 2:
		XftDrawString16(draw, &xftcol, font,
			x, y, (XftChar16 *)s, len);
		break;
	case 4:
		XftDrawString32(draw, &xftcol, font,
			x, y, (XftChar32 *)s, len);
		break;
	default:
		XmeWarning(NULL, "_XmXftDrawString(unsupported bpc)\n");
    }
}

void
_XmXftDrawString(Display *display, Window window, XmRendition rend, int bpc,
#if NeedWidePrototypes
                int x, int y,
#else
                Position x, Position y,
#endif
                char *s, int len,
#if NeedWidePrototypes
		int image
#else
		Boolean image
#endif
		)
{
    XftDraw	*draw = _XmXftDrawCreate(display, window);
    XftColor    fg_color = _XmRendXftFG(rend);

    if (image)
    {
        XftColor bg_color = _XmRendXftBG(rend);
	XGlyphInfo ext;
	ext.xOff = 0;
	
	switch (bpc)
	{
	    case 1:
	        XftTextExtentsUtf8(display, _XmRendXftFont(rend),
		                (FcChar8*)s, len, &ext);
		break;
	    case 2:
	        XftTextExtents16(display, _XmRendXftFont(rend),
		                 (FcChar16*)s, len, &ext);
		break;
	    case 4:
	        XftTextExtents32(display, _XmRendXftFont(rend),
		                 (FcChar32*)s, len, &ext);
		break;
	}
	
	if (_XmRendBG(rend) == XmUNSPECIFIED_PIXEL)
	{
	    XGCValues gc_val;
	    XColor xcol;

	    XGetGCValues(display, _XmRendGC(rend), GCBackground, &gc_val);
	    xcol.pixel = gc_val.background;
            XQueryColor(display, DefaultColormapOfScreen(
                  DefaultScreenOfDisplay(display)), &xcol);
	    bg_color.pixel = xcol.pixel;
	    bg_color.color.red = xcol.red;
	    bg_color.color.green = xcol.green;
	    bg_color.color.blue = xcol.blue;
	    bg_color.color.alpha = 0xFFFF;
	}
#ifdef FIX_1451
        XftDrawRect(draw, &bg_color, x, y - _XmRendXftFont(rend)->ascent,
	            ext.xOff,
		    _XmRendXftFont(rend)->ascent +
		    _XmRendXftFont(rend)->descent);
#else
        XftDrawRect(draw, &bg_color, x - 10, y - _XmRendXftFont(rend)->ascent - 10,
	            ext.xOff +20,
		    _XmRendXftFont(rend)->ascent +
		    _XmRendXftFont(rend)->descent + 20);
#endif
    }

    if (_XmRendFG(rend) == XmUNSPECIFIED_PIXEL)
    {
        XGCValues gc_val;
	XColor xcol;
	XGetGCValues(display, _XmRendGC(rend), GCForeground, &gc_val);
	xcol.pixel = gc_val.foreground;
        XQueryColor(display, DefaultColormapOfScreen(
              DefaultScreenOfDisplay(display)), &xcol);
	fg_color.pixel = xcol.pixel;
	fg_color.color.red = xcol.red;
	fg_color.color.green = xcol.green;
	fg_color.color.blue = xcol.blue;
	fg_color.color.alpha = 0xFFFF;
    }

    switch (bpc)
    {
	case 1:
		XftDrawStringUtf8(draw, &fg_color, _XmRendXftFont(rend),
			x, y, (XftChar8 *)s, len);
		break;
	case 2:
		XftDrawString16(draw, &fg_color, _XmRendXftFont(rend),
			x, y, (XftChar16 *)s, len);
		break;
	case 4:
		XftDrawString32(draw, &fg_color, _XmRendXftFont(rend),
			x, y, (XftChar32 *)s, len);
		break;
	default:
		XmeWarning(NULL, "_XmXftDrawString(unsupported bpc)\n");
    }
}

void
_XmXftSetClipRectangles(Display *display, Window window, Position x, Position y, XRectangle *rects, int n)
{
	XftDraw	*d = _XmXftDrawCreate(display, window);

	XftDrawSetClipRectangles(d, x, y, rects, n);
}

#ifdef FIX_1536
static XftColor
GetCachedXftColor(Display *display, Pixel color)
{
  static XftColor *color_cache = NULL;
  static int colors_count = 0;

  XftColor xftcol = {0, {0,0,0,0xFFFF}};
  XColor xcol;
  Boolean color_exist = FALSE;
  int i;

  if (color_cache != NULL)
  {
    for (i = 0; i < colors_count; ++i)
    {
      if (color_cache[i].pixel == color)
      {
        xftcol = color_cache[i];
        color_exist = TRUE;
        break;
      }
    }
  }

  if (!color_exist)
  {
    xcol.pixel = color;
    XQueryColor(display, DefaultColormap(display,
      DefaultScreen(display)), &xcol);
    xftcol.pixel = color;
    xftcol.color.red = xcol.red;
    xftcol.color.blue = xcol.blue;
    xftcol.color.green = xcol.green;
    xftcol.color.alpha = 0xFFFF;

    color_cache = (XftColor *) XtRealloc((char *) color_cache,
      (Cardinal) (sizeof(XftColor) * (colors_count + 1)));
    if (color_cache != NULL)
      color_cache[colors_count++] = xftcol;
  }

  return xftcol;
}
#endif

XftColor
_XmXftGetXftColor(Display *display, Pixel color)
{
#ifdef FIX_1536
    return GetCachedXftColor(display, color);
#else
    XColor xcol;
    XftColor xftcol;
    
    xcol.pixel = color;
    XQueryColor(display, DefaultColormap(display,
        DefaultScreen(display)), &xcol);
    xftcol.pixel = color;
    xftcol.color.red = xcol.red;
    xftcol.color.blue = xcol.blue;
    xftcol.color.green = xcol.green;
    xftcol.color.alpha = 0xFFFF;
    return xftcol;
#endif
}

#ifdef FIX_1415
void _XmXftFontAverageWidth(Widget w, XtPointer f, int *width)
{
	XftFont *fp = (XftFont *)f;
	static char	*s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	int l = 62; /* strlen(s) */
	XGlyphInfo	ext;

	XftTextExtents8(XtDisplay(w), fp, (unsigned char *)s, l, &ext);
    if (width) 
    	*width = ext.width / l;
}
#endif

#endif

/*ARGSUSED*/
XmRenderTable
XmRenderTableCvtFromProp(Widget w, 
			 char *prop,
			 unsigned int len) /* unused */
{
  XmRenderTable new_rt;
  XmRendition rendition;
  XmRendition *rarray;
  int rarray_count, rarray_max;
  /* These must both be big enough for the number of passed parameters */
  char *items[20];
  char *name;
  Arg args[20];
  /* This must be big enough to hold all the strings returned by
     readtoken */
  char *freelater[5];
  int scanpointer, j, count, freecount, i;
  Token token;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  new_rt = NULL;
  scanpointer = 0;
  rarray_max = 10;
  rarray_count = 0;
  rarray = (XmRendition *) XtMalloc(sizeof(XmRendition) * rarray_max);
  name = "";

  for(j = 0; j < 20; j++) items[j] = NULL;
  /* Read the list of items */
  for(j = 0; j < 20; ) {
    token = ReadToken(prop, &scanpointer);
    if (token -> type == T_NL) break;
    if (token -> type == T_STR) {
      items[j] = token -> string;
      j++;
    }
  }
  
  j = -1;
  count = 0;
  freecount = 0;
  while(True) {
    token = ReadToken(prop, &scanpointer);
    /* We skip the separators */
    while(token -> type == T_SEP &&
	  token -> type != T_EOF)
      token = ReadToken(prop, &scanpointer);
    if (token -> type == T_EOF) goto finish;

    j++; /* Go to next item in items array */
	  
    if (items[j] == NULL) {
      /* End of line processing.  Scan for NewLine */
      while(token -> type != T_NL &&
	    token -> type != T_EOF)
	token = ReadToken(prop, &scanpointer);
      /* Store rendition */
      rendition = XmRenditionCreate(w, name, args, count);
      name = "";
      count = 0;
      /* Reset index into namelist */
      j = -1;
      /* Free temp strings returned by ReadToken */
      for(i = 0; i < freecount; i++) XtFree(freelater[i]);
      freecount = 0;
      /* Record rendition in array */
      if (rarray_count >= rarray_max) {
	/* Extend array if necessary */
	rarray_max += 10;
	rarray = (XmRendition *) XtRealloc((char*) rarray, 
					   sizeof(XmRendition) * rarray_max);
      }
      if (token -> type == T_EOF) goto finish;
      rarray[rarray_count] = rendition;
      rarray_count++;
    } else if (strcmp(items[j], XmNtag) == 0) {
      /* Next item should be a string with the name of the new
	 rendition to create */
      if (token -> type == T_STR) {
	name = token -> string;
	freelater[freecount] = token -> string; freecount++;
      } else {
	goto error;
      }
    } else if (strcmp(items[j], XmNfont) == 0) {
      /* If the next item is a number then we have a font
	 id,  otherwise we are reading in a fontset */
      if (token -> type != T_INT) goto error;
      if (token -> integer != -1) { /* AS IS */ 
	XtSetArg(args[count], XmNfontType, token -> integer); count++;
	token = ReadToken(prop, &scanpointer);
	if (token -> type != T_STR) goto error;
	XtSetArg(args[count], XmNfontName, token -> string); count++;
	freelater[freecount] = token -> string; freecount++;
	token = ReadToken(prop, &scanpointer);
	if (token -> type != T_INT) goto error;
	XtSetArg(args[count], XmNloadModel, token -> integer); count++;
      }
    } else if (strcmp(items[j], XmNtabList) == 0) {
      /* This starts with an OPEN then a number of
	 FLOAT INT INT INT then CLOSE and SEP */
      if (token -> type == T_INT) { /* Should be AS IS */
	if (token -> integer != -1) goto error;
      } else if (token -> type == T_OPEN) {
	float value;
	int units, align;
	XmOffsetModel model;
	XmTabList tablist;
	XmTab tabs[1];

	tablist = NULL;
	token = ReadToken(prop, &scanpointer);
	while(token -> type != T_CLOSE) {
	  if (token -> type != T_FLOAT &&
	      token -> type != T_INT) goto error;
	  if (token -> type == T_FLOAT)
	    value = token -> real;
	  else
	    value = (float) token -> integer;
	  token = ReadToken(prop, &scanpointer);
	  if (token -> type != T_INT) goto error;
	  units = token -> integer;
	  token = ReadToken(prop, &scanpointer);
	  if (token -> type != T_INT) goto error;
	  align = token -> integer;
	  token = ReadToken(prop, &scanpointer);
	  if (token -> type != T_INT) goto error;
	  model = (XmOffsetModel) token -> integer;
	  tabs[0] = XmTabCreate(value, units, model, align, NULL);
	  tablist = XmTabListInsertTabs(tablist, tabs, 1, 1000);
	  XtFree((char*) tabs[0]);
	  /* Go to next separator to skip unknown future values */
	  while(token -> type != T_SEP) 
	    token = ReadToken(prop, &scanpointer);
	  if (token -> type == T_SEP)
	    token = ReadToken(prop, &scanpointer);
	}
	XtSetArg(args[count], XmNtabList, tablist); count++;
      } else 
	goto error;
    } else if (strcmp(items[j], XmNbackground) == 0) {
      if (token -> type != T_INT) goto error;
      if (token -> type != -1) {
	XtSetArg(args[count], XmNrenditionBackground, token -> integer); count++;
      }
    } else if (strcmp(items[j], XmNforeground) == 0) {
      if (token -> type != T_INT) goto error;
      if (token -> type != -1) {
	XtSetArg(args[count], XmNrenditionForeground, token -> integer); count++;
      }
    } else if (strcmp(items[j], XmNunderlineType) == 0) {
      if (token -> type != T_INT) goto error;
      if (token -> type != -1) {
	XtSetArg(args[count], XmNunderlineType, token -> integer); count++;
      }
    } else if (strcmp(items[j], XmNstrikethruType) == 0) {
      if (token -> type != T_INT) goto error;
      if (token -> type != -1) {
	XtSetArg(args[count], XmNstrikethruType, token -> integer); count++;
      }
    }
  }

 finish:
  new_rt = XmRenderTableAddRenditions(new_rt, rarray, rarray_count, XmMERGE_REPLACE);
  for (i = 0; i < rarray_count; i++) XmRenditionFree(rarray[i]);
  _XmAppUnlock(app);
  return(new_rt);

 error:
  /* Free temp strings returned by ReadToken */
  for(i = 0; i < freecount; i++) XtFree((char*) freelater[i]);
  freecount = 0;
  goto finish;
}

void
XmRenderTableGetDefaultFontExtents(XmRenderTable rendertable,
                                    int *height,
				    int *ascent,
				    int *descent)
{
    XmStringTag	    tag = XmFONTLIST_DEFAULT_TAG;
    XmRendition     rend;
    Boolean         success;
    short           indx;
    int             h,a,d;
  
#ifdef XTHREADS
  XtAppContext	       app=NULL;

  if ( _XmRTDisplay(rendertable) )
    app = XtDisplayToApplicationContext(_XmRTDisplay(rendertable));

  if (app)
    _XmAppLock(app);
  else
    _XmProcessLock();
#endif

    a = d = h = 0;
    /* Get default rendition */
    success = _XmRenderTableFindFallback(rendertable, tag, FALSE, &indx, &rend);

    /* For backward compatibility we must try to return something for */
    /* any non-null charset, not just XmFONTLIST_DEFAULT_TAG. */
    if (rendertable && tag && !success)
      success = _XmRenderTableFindFirstFont(rendertable, &indx, &rend);

    if (success) {
        /* Find font height */
        switch (_XmRendFontType(rend)) {
            case XmFONT_IS_FONT:
                if (_XmRendFont(rend)) {
                    a = ((XFontStruct*)_XmRendFont(rend))->ascent;
                    d = ((XFontStruct*)_XmRendFont(rend))->descent;
                    h = a + d;
                }
                break;
            case XmFONT_IS_FONTSET:
                if (_XmRendFont(rend)) {
                    XFontStruct **font_struct_list;
                    char **font_name_list;

                    if (XFontsOfFontSet((XFontSet)_XmRendFont(rend),
                                &font_struct_list, &font_name_list)) {
                        a = font_struct_list[0]->ascent;
                        d = font_struct_list[0]->descent;
                        h = a + d;
                    }
                }
                break;
#ifdef USE_XFT
                case XmFONT_IS_XFT:
                    if (_XmRendXftFont(rend)) {
                        a = _XmRendXftFont(rend)->ascent;
                        d = _XmRendXftFont(rend)->descent;
                        h = a + d;
                    }
                    break;
#endif
        }
    }

#ifdef XTHREADS
  if (app)
    _XmAppUnlock(app);
  else
    _XmProcessUnlock();
#endif

  if (ascent) *ascent = a;
  if (descent) *descent = d;
  if (height) *height = h;
}
