diff src/redisplay-xlike-inc.c @ 4881:a4322ac49e37

break out common separate-into-runs routines into redisplay-xlike-inc.c -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-01-18 Ben Wing <ben@xemacs.org> * redisplay-xlike-inc.c: * redisplay-xlike-inc.c (separate_textual_runs_nomule): * redisplay-xlike-inc.c (separate_textual_runs_xft_nomule): * redisplay-xlike-inc.c (separate_textual_runs_xft_mule): * redisplay-xlike-inc.c (separate_textual_runs_mule): Break separate_textual_runs_* functions from redisplay-x.c. (Code in redisplay-gtk.c should have been identical but was bit-rotted.) * redisplay-gtk.c: * redisplay-x.c: Delete code, replace with include statement. * depend: Regenerate.
author Ben Wing <ben@xemacs.org>
date Mon, 18 Jan 2010 06:21:05 -0600
parents
children eab9498ecc0e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/redisplay-xlike-inc.c	Mon Jan 18 06:21:05 2010 -0600
@@ -0,0 +1,355 @@
+/* Common code between X and GTK.
+   Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
+   Copyright (C) 1994 Lucid, Inc.
+   Copyright (C) 1995 Sun Microsystems, Inc.
+   Copyright (C) 2002, 2003, 2005 Ben Wing.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with:  Not in FSF. */
+
+     /* Note: We do not use the Xmb*() functions and XFontSets, nor the
+	Motif XFontLists and CompoundStrings.
+	Those functions are generally losing for a number of reasons.
+	Most important, they only support one locale (e.g. you could
+	display Japanese and ASCII text, but not mixed Japanese/Chinese
+	text).  You could maybe call setlocale() frequently to try to deal
+	with this, but that would generally fail because an XFontSet is
+	tied to one locale and won't have the other character sets in it.
+
+	fontconfig (the font database for Xft) has some specifier-like
+	properties, but it's not sufficient (witness the existence of
+	Pango).  Pango might do the trick, but it's not a cross-platform
+	solution; it would need significant advantages to be worth the
+	effort.
+     */
+
+struct textual_run
+{
+  Lisp_Object charset;
+  unsigned char *ptr;
+  int len;
+  int dimension;
+};
+
+/* Separate out the text in STR (an array of Ichars, not a string
+   representation) of length LEN into a series of runs, stored in
+   RUN_STORAGE.  RUN_STORAGE is guaranteed to hold enough space for all
+   runs that could be generated from this text.  Each run points to the a
+   stretch of text given simply by the position codes TEXT_STORAGE into a
+   series of textual runs of a particular charset.  Also convert the
+   characters as necessary into the format needed by XDrawImageString(),
+   XDrawImageString16(), et al.  This means converting to one or two byte
+   format, possibly tweaking the high bits, and possibly running a CCL
+   program.  You must pre-allocate the space used and pass it in. (This is
+   done so you can ALLOCA () the space.) (2 * len) bytes must be allocated
+   for TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
+   RUN_STORAGE, where LEN is the length of the dynarr.
+
+   bufchar might not be fixed width (in the case of UTF-8).
+
+   Returns the number of runs actually used. */
+
+/* Notes on Xft implementation
+
+   - With Unicode, we're no longer going to have repertoires reified as
+   charsets.  (Not that we ever really did, what with corporate variants,
+   and so on.)  So we really should be querying the face for the desired
+   font, rather than the character for the charset, and that's what would
+   determine the separation into runs.
+   - The widechar versions of fontconfig (and therefore Xft) functions
+   seem to be just bigendian Unicode.  So there's actually no need to use
+   the 8-bit versions in computing runs and runes, it would seem.
+*/
+
+#if !defined(USE_XFT) && !defined(MULE)
+static int
+separate_textual_runs_nomule (unsigned char *text_storage,
+			      struct textual_run *run_storage,
+			      const Ichar *str, Charcount len,
+			      struct face_cachel *UNUSED(cachel))
+{
+  if (!len)
+    return 0;
+
+  run_storage[0].ptr = text_storage;
+  run_storage[0].len = len;
+  run_storage[0].dimension = 1;
+  run_storage[0].charset = Qnil;
+
+  while (len--)
+    *text_storage++ = *str++;
+  return 1;
+}
+#endif
+
+#if defined(USE_XFT) && !defined(MULE)
+/*
+  Note that in this configuration the "Croatian hack" of using an 8-bit,
+  non-Latin-1 font to get localized display without Mule simply isn't
+  available.  That's by design -- Unicode does not aid or abet that kind
+  of punning.
+  This means that the cast to XftChar16 gives the correct "conversion" to
+  UCS-2.
+  #### Is there an alignment issue with text_storage?
+*/
+static int
+separate_textual_runs_xft_nomule (unsigned char *text_storage,
+				  struct textual_run *run_storage,
+				  const Ichar *str, Charcount len,
+				  struct face_cachel *UNUSED(cachel))
+{
+  int i;
+  if (!len)
+    return 0;
+
+  run_storage[0].ptr = text_storage;
+  run_storage[0].len = len;
+  run_storage[0].dimension = 2;
+  run_storage[0].charset = Qnil;
+
+  for (i = 0; i < len; i++)
+    {
+      *(XftChar16 *)text_storage = str[i];
+      text_storage += sizeof(XftChar16);
+    }
+  return 1;
+}
+#endif
+
+#if defined(USE_XFT) && defined(MULE)
+static int
+separate_textual_runs_xft_mule (unsigned char *text_storage,
+				struct textual_run *run_storage,
+				const Ichar *str, Charcount len,
+				struct face_cachel *UNUSED(cachel))
+{
+  Lisp_Object prev_charset = Qunbound;
+  int runs_so_far = 0, i;
+
+  run_storage[0].ptr = text_storage;
+  run_storage[0].len = len;
+  run_storage[0].dimension = 2;
+  run_storage[0].charset = Qnil;
+
+  for (i = 0; i < len; i++)
+    {
+      Ichar ch = str[i];
+      Lisp_Object charset = ichar_charset(ch);
+      int ucs = ichar_to_unicode(ch);
+
+      /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to
+	 REPLACMENT CHARACTER. */
+      /* That means we can't handle characters outside of the BMP for now */
+      ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs;
+
+      if (!EQ (charset, prev_charset))
+	{
+	  if (runs_so_far)
+	    run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1;
+	  run_storage[runs_so_far].ptr = text_storage;
+	  run_storage[runs_so_far].dimension = 2;
+	  run_storage[runs_so_far].charset = charset;
+	  prev_charset = charset;
+	  runs_so_far++;
+	}
+
+      *(XftChar16 *)text_storage = ucs;
+      text_storage += sizeof(XftChar16);
+    }
+
+  if (runs_so_far)
+    run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1;
+  return runs_so_far;
+}
+#endif
+
+#if !defined(USE_XFT) && defined(MULE)
+/*
+  This is the most complex function of this group, due to the various
+  indexing schemes used by different fonts.  For our purposes, they
+  fall into three classes.  Some fonts are indexed compatibly with ISO
+  2022; those fonts just use the Mule internal representation directly
+  (typically the high bit must be reset; this is determined by the `graphic'
+  flag).  Some fonts are indexed by Unicode, specifically by UCS-2.  These
+  are all translated using `ichar_to_unicode'.  Finally some fonts have
+  irregular indexes, and must be translated ad hoc.  In XEmacs ad hoc
+  translations are accomplished with CCL programs. */
+static int
+separate_textual_runs_mule (unsigned char *text_storage,
+			    struct textual_run *run_storage,
+			    const Ichar *str, Charcount len,
+			    struct face_cachel *cachel)
+{
+  Lisp_Object prev_charset = Qunbound;
+  int runs_so_far = 0, i;
+  Ibyte charset_leading_byte = LEADING_BYTE_ASCII;
+  int dimension = 1, graphic = 0, need_ccl_conversion = 0;
+  Lisp_Object ccl_prog;
+  struct ccl_program char_converter;
+
+  int translate_to_ucs_2 = 0;
+
+  for (i = 0; i < len; i++)
+    {
+      Ichar ch = str[i];
+      Lisp_Object charset;
+      int byte1, byte2;		/* BREAKUP_ICHAR dereferences the addresses
+				   of its arguments as pointer to int. */
+      BREAKUP_ICHAR (ch, charset, byte1, byte2);
+
+      if (!EQ (charset, prev_charset))
+	{
+	  /* At this point, dimension' and `prev_charset' refer to just-
+	     completed run.  `runs_so_far' and `text_storage' refer to the
+	     run about to start. */
+	  if (runs_so_far)
+	    {
+	      /* Update metadata for previous run. */
+	      run_storage[runs_so_far - 1].len =
+		text_storage - run_storage[runs_so_far - 1].ptr;
+	      if (2 == dimension) run_storage[runs_so_far - 1].len >>= 1;
+	    }
+
+	  /* Compute metadata for current run.
+	     First, classify font.
+	     If the font is indexed by UCS-2, set `translate_to_ucs_2'.
+	     Else if the charset has a CCL program, set `need_ccl_conversion'.
+	     Else if the font is indexed by an ISO 2022 "graphic register",
+	         set `graphic'.
+	     These flags are almost mutually exclusive, but we're sloppy
+	     about resetting "shadowed" flags.  So the flags must be checked
+	     in the proper order in computing byte1 and byte2, below. */
+	  charset_leading_byte = XCHARSET_LEADING_BYTE(charset);
+	  translate_to_ucs_2 =
+	    bit_vector_bit (FACE_CACHEL_FONT_FINAL_STAGE (cachel),
+			    charset_leading_byte - MIN_LEADING_BYTE);
+	  if (translate_to_ucs_2)
+	    {
+	      dimension = 2;
+	    }
+	  else
+	    {
+	      dimension = XCHARSET_DIMENSION (charset);
+
+	      /* Check for CCL charset.
+		 If setup_ccl_program fails, we'll get a garbaged display.
+		 This should never happen, and even if it does, it should
+		 be harmless (unless the X server has buggy handling of
+		 characters undefined in the font).  It may be marginally
+		 more useful to users and debuggers than substituting a
+		 fixed replacement character. */
+	      ccl_prog = XCHARSET_CCL_PROGRAM (charset);
+	      if ((!NILP (ccl_prog))
+		  && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
+		{
+		  need_ccl_conversion = 1;
+		}
+	      else 
+		{
+		  /* The charset must have an ISO 2022-compatible font index.
+		     There are 2 "registers" (what such fonts use as index).
+		     GL (graphic == 0) has the high bit of each octet reset,
+		     GR (graphic == 1) has it set. */
+		  graphic   = XCHARSET_GRAPHIC (charset);
+		  need_ccl_conversion = 0;
+		}
+	    }
+
+	  /* Initialize metadata for current run. */
+	  run_storage[runs_so_far].ptr       = text_storage;
+	  run_storage[runs_so_far].charset   = charset;
+	  run_storage[runs_so_far].dimension = dimension;
+
+	  /* Update loop variables. */
+	  prev_charset = charset;
+	  runs_so_far++;
+	} 
+
+      /* Must check flags in this order.  See comment above. */
+      if (translate_to_ucs_2)
+	{
+	  int ucs = ichar_to_unicode(ch);
+	  /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to
+	     REPLACMENT CHARACTER. */
+	  ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs;
+
+	  byte1 = ucs >> 8;
+	  byte2 = ucs;
+	}
+      else if (need_ccl_conversion)
+	{
+	  char_converter.reg[0] = charset_leading_byte;
+	  char_converter.reg[1] = byte1;
+	  char_converter.reg[2] = byte2;
+	  ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
+	  byte1 = char_converter.reg[1];
+	  byte2 = char_converter.reg[2];
+	}
+      else if (graphic == 0)
+	{
+	  byte1 &= 0x7F;
+	  byte2 &= 0x7F;
+	}
+      else
+	{
+	  byte1 |= 0x80;
+	  byte2 |= 0x80;
+	}
+
+      *text_storage++ = (unsigned char)byte1;
+
+      if (2 == dimension) *text_storage++ = (unsigned char)byte2;
+    }
+
+  if (runs_so_far)
+    {
+      run_storage[runs_so_far - 1].len =
+	text_storage - run_storage[runs_so_far - 1].ptr;
+      /* Dimension retains the relevant value for the run before it. */
+      if (2 == dimension)
+	run_storage[runs_so_far - 1].len >>= 1;
+    }
+
+  return runs_so_far;
+}
+#endif
+
+static int
+separate_textual_runs (unsigned char *text_storage,
+		       struct textual_run *run_storage,
+		       const Ichar *str, Charcount len,
+		       struct face_cachel *cachel)
+{
+#if defined(USE_XFT) && defined(MULE)
+  return separate_textual_runs_xft_mule (text_storage, run_storage,
+					 str, len, cachel);
+#endif
+#if defined(USE_XFT) && !defined(MULE)
+  return separate_textual_runs_xft_nomule (text_storage, run_storage,
+					   str, len, cachel);
+#endif
+#if !defined(USE_XFT) && defined(MULE)
+  return separate_textual_runs_mule (text_storage, run_storage,
+				     str, len, cachel);
+#endif
+#if !defined(USE_XFT) && !defined(MULE)
+  return separate_textual_runs_nomule (text_storage, run_storage,
+				       str, len, cachel);
+#endif
+}