changeset 97982:59bcf1726f2c

(autocmp_chars): Check lookback count. (composition_compute_stop_pos): Set cmp_it->lookback. (composition_reseat_it): Check lookback count. (struct position_record): New struct. (FORWARD_CHAR, BACKWARD_CHAR, CHAR_COMPOSABLE_P): New macros. (find_automatic_composition): New function. (composition_adjust_point): Use find_automatic_composition.
author Kenichi Handa <handa@m17n.org>
date Fri, 05 Sep 2008 00:46:57 +0000
parents 4ca1e7cb50ea
children b5a42c692791
files src/composite.c
diffstat 1 files changed, 252 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/src/composite.c	Fri Sep 05 00:40:53 2008 +0000
+++ b/src/composite.c	Fri Sep 05 00:46:57 2008 +0000
@@ -402,8 +402,8 @@
 }
 
 
-/* Find a composition at or nearest to position POS of OBJECT (buffer
-   or string).
+/* Find a static composition at or nearest to position POS of OBJECT
+   (buffer or string).
 
    OBJECT defaults to the current buffer.  If there's a composition at
    POS, set *START and *END to the start and end of the sequence,
@@ -916,9 +916,10 @@
   FRAME_PTR f = XFRAME (win->frame);
   Lisp_Object pos = make_number (charpos);
   EMACS_INT pt = PT, pt_byte = PT_BYTE;
+  int lookback;
   
   record_unwind_save_match_data ();
-  for (; CONSP (cft_element); cft_element = XCDR (cft_element))
+  for (lookback = -1; CONSP (cft_element); cft_element = XCDR (cft_element))
     {
       Lisp_Object elt = XCAR (cft_element);
       Lisp_Object re;
@@ -927,6 +928,10 @@
 
       if (! VECTORP (elt) || ASIZE (elt) != 3)
 	continue;
+      if (lookback < 0)
+	lookback = XFASTINT (AREF (elt, 1));
+      else if (lookback != XFASTINT (AREF (elt, 1)))
+	break;
       re = AREF (elt, 0);
       if (NILP (string))
 	TEMP_SET_PT_BOTH (charpos, bytepos);
@@ -1029,7 +1034,8 @@
 	    }
 	  if (CONSP (val))
 	    {
-	      cmp_it->stop_pos = charpos - 1 - XFASTINT (AREF (elt, 1));
+	      cmp_it->lookback = XFASTINT (AREF (elt, 1));
+	      cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
 	      cmp_it->ch = c;
 	      break;
 	    }
@@ -1072,12 +1078,19 @@
     }
   else
     {
-      Lisp_Object val;
+      Lisp_Object val, elt;
       int i;
 
       val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
+      for (; CONSP (val); val = XCDR (val))
+	{
+	  elt = XCAR (val);
+	  if (cmp_it->lookback == XFASTINT (AREF (elt, 1)))
+	    break;
+	}
       if (NILP (val))
 	goto no_composition;
+
       val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string);
       if (! composition_gstring_p (val))
 	goto no_composition;
@@ -1167,19 +1180,214 @@
 }
 
 
+struct position_record
+{
+  EMACS_INT pos, pos_byte;
+  unsigned char *p;
+};
+
+/* Update the members of POSTION to the next character boundary.  */
+#define FORWARD_CHAR(POSITION, STOP)					\
+  do {									\
+    if ((POSITION).pos == (STOP))					\
+      (POSITION).p = GAP_END_ADDR;					\
+    (POSITION).pos++;							\
+    (POSITION).pos_byte += BYTES_BY_CHAR_HEAD (*((POSITION).p));	\
+    (POSITION).p += BYTES_BY_CHAR_HEAD (*((POSITION).p));		\
+  } while (0)
+
+/* Update the members of POSTION to the previous character boundary.  */
+#define BACKWARD_CHAR(POSITION, STOP)		\
+  do {						\
+    if ((POSITION).pos == STOP)			\
+      (POSITION).p = GPT_ADDR;			\
+    do {					\
+      (POSITION).pos_byte--;			\
+      (POSITION).p--;				\
+    } while (! CHAR_HEAD_P (*((POSITION).p)));	\
+    (POSITION).pos--;				\
+  } while (0)
+
+static Lisp_Object _work_val;
+static int _work_char;
+
+/* 1 iff the character C is composable.  */
+#define CHAR_COMPOSABLE_P(C)					\
+  (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)),	\
+   (SYMBOLP (_work_val)						\
+    && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C'	\
+    && _work_char != 'Z'))
+
+/* This is like find_composition, but find an automatic composition
+   instead.  If found, set *GSTRING to the glyph-string representing
+   the composition, and return 1.  Otherwise, return 0.  */
+
+static int
+find_automatic_composition (pos, limit, start, end, gstring, string)
+     EMACS_INT pos, limit, *start, *end;
+     Lisp_Object *gstring, string;
+{
+  EMACS_INT head, tail, stop;
+  struct position_record orig, cur, check, prev;
+  Lisp_Object check_val, val, elt;
+  int check_lookback;
+  int c;
+  struct window *w;
+
+  orig.pos = pos;
+  if (NILP (string))
+    {
+      head = BEGV, tail = ZV, stop = GPT;
+      orig.pos_byte = CHAR_TO_BYTE (orig.pos);
+      orig.p = BYTE_POS_ADDR (orig.pos_byte);
+    }
+  else
+    {
+      head = 0, tail = SCHARS (string), stop = -1;
+      orig.pos_byte = string_char_to_byte (string, orig.pos);
+      orig.p = SDATA (string) + orig.pos_byte;
+    }
+  if (limit < pos)
+    {
+      head = max (head, limit);
+      tail = min (tail, pos + 3);
+    }
+  else
+    {
+      tail = min (tail, limit + 3);
+    }
+  w = XWINDOW (selected_window);
+  cur = orig;
+
+ retry:
+  check_val = Qnil;
+  /* At first, check if POS is compoable.  */
+  c = STRING_CHAR (cur.p, 0);
+  if (! CHAR_COMPOSABLE_P (c))
+    {
+      if (limit < 0)
+	return 0;
+      if (limit >= cur.pos)
+	goto search_forward;
+    }
+  else
+    {
+      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+      if (! NILP (val))
+	check_val = val, check = cur;
+      else
+	while (cur.pos + 1 < tail)
+	  {
+	    FORWARD_CHAR (cur, stop);
+	    c = STRING_CHAR (cur.p, 0);
+	    if (! CHAR_COMPOSABLE_P (c))
+	      break;
+	    val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+	    if (NILP (val))
+	      continue;
+	    check_val = val, check = cur;
+	    break;
+	  }
+      cur = orig;
+    }
+  /* Rewind back to the position where we can safely search forward
+     for compositions.  */
+  while (cur.pos > head)
+    {
+      BACKWARD_CHAR (cur, stop);
+      c = STRING_CHAR (cur.p, 0);
+      if (! CHAR_COMPOSABLE_P (c))
+	break;
+      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+      if (! NILP (val))
+	check_val = val, check = cur;
+    }
+  prev = cur;
+  /* Now search forward.  */
+ search_forward:  
+  *gstring = Qnil;
+  if (! NILP (check_val) || limit >= orig.pos)
+    {
+      if (NILP (check_val))
+	cur = orig;
+      else
+	cur = check;
+      while (cur.pos < tail)
+	{
+	  int need_adjustment = 0;
+
+	  if (NILP (check_val))
+	    {
+	      c = STRING_CHAR (cur.p, 0);
+	      check_val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+	    }
+	  for (; CONSP (check_val); check_val = XCDR (check_val))
+	    {
+	      elt = XCAR (check_val);
+	      if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
+		  && cur.pos - XFASTINT (AREF (elt, 1)) >= head)
+		{
+		  check.pos = cur.pos - XFASTINT (AREF (elt, 1));
+		  if (check.pos == cur.pos)
+		    check.pos_byte = cur.pos_byte;
+		  else
+		    check.pos_byte = CHAR_TO_BYTE (check.pos);
+		  val = autocmp_chars (check_val, check.pos, check.pos_byte,
+				       tail, w, NULL, string);
+		  need_adjustment = 1;
+		  if (! NILP (val))
+		    {
+		      *gstring = val;
+		      *start = check.pos;
+		      *end = check.pos + LGSTRING_CHAR_LEN (*gstring);
+		      if (*start <= orig.pos ? *end > orig.pos
+			  : limit >= orig.pos)
+			return 1;
+		      cur.pos = *end;
+		      cur.pos_byte = CHAR_TO_BYTE (cur.pos);
+		      break;
+		    }
+		}
+	    }
+	  if (need_adjustment)
+	    {
+	      /* As we have called Lisp, there's a possibilily that
+		 buffer/string is relocated.  */
+	      if (NILP (string))
+		cur.p  = BYTE_POS_ADDR (cur.pos_byte);
+	      else
+		cur.p = SDATA (string) + cur.pos_byte;
+	    }
+	  if (! CONSP (check_val))
+	    FORWARD_CHAR (cur, stop);
+	  check_val = Qnil;
+	}
+    }
+  if (! NILP (*gstring))
+    return (limit >= 0 || (*start <= orig.pos && *end > orig.pos));
+  if (limit >= 0 && limit < orig.pos && prev.pos > head)
+    {
+      cur = prev;
+      BACKWARD_CHAR (cur, stop);
+      orig = cur;
+      tail = orig.pos;
+      goto retry;
+    }
+  return 0;
+}
+
 int
 composition_adjust_point (last_pt)
      EMACS_INT last_pt;
 {
-  /* Now check the automatic composition. */
   EMACS_INT charpos, bytepos, startpos, beg, end, pos;
-  Lisp_Object val, cat;
-  EMACS_INT limit;
-  int c;
+  Lisp_Object val;
+  int i;
 
   if (PT == BEGV || PT == ZV)
     return PT;
 
+  /* At first check the static composition. */
   if (get_property_and_range (PT, Qcomposition, &val, &beg, &end, Qnil)
       && COMPOSITION_VALID_P (beg, end, val)
       && beg < PT /* && end > PT   <- It's always the case.  */
@@ -1190,97 +1398,22 @@
       || ! FUNCTIONP (Vauto_composition_function))
     return PT;
 
-  c = FETCH_MULTIBYTE_CHAR (PT_BYTE);
-  cat = CHAR_TABLE_REF (Vunicode_category_table, c);
-  if (SYMBOLP (cat)
-      && ((c = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || c == 'Z'))
-    /* A control character is never composed.  */
+  /* Next check the automatic composition.  */
+  if (! find_automatic_composition (PT, -1, &beg, &end, &val, Qnil)
+      || beg == PT)
     return PT;
-
-  charpos = PT;
-  bytepos = PT_BYTE;
-  limit = (last_pt < PT ? last_pt : BEGV);
-  do {
-    DEC_BOTH (charpos, bytepos);
-    c = FETCH_MULTIBYTE_CHAR (bytepos);
-    cat = CHAR_TABLE_REF (Vunicode_category_table, c);
-    if (SYMBOLP (cat)
-	&& ((c = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || c == 'Z'))
-      {
-	INC_BOTH (charpos, bytepos);
-	break;
-      }
-  } while (charpos > limit);
-
-
-  limit = (last_pt < PT ? ZV : last_pt);
-  if (limit > PT + 3)
-    limit = PT + 3;
-  startpos = charpos;
-  while (charpos < limit)
+  for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++)
     {
-      c = FETCH_MULTIBYTE_CHAR (bytepos);
-      if (charpos > PT)
-	{
-	  int ch;
+      Lisp_Object glyph = LGSTRING_GLYPH (val, i);
 
-	  cat = CHAR_TABLE_REF (Vunicode_category_table, c);
-	  if (SYMBOLP (cat)
-	      && ((ch = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || ch == 'Z'))
-	    return PT;
-	}
-      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
-      if (! CONSP (val))
-	{
-	  INC_BOTH (charpos, bytepos);
-	  continue;
-	}
-      for (; CONSP (val); val = XCDR (val))
-	{
-	  Lisp_Object elt = XCAR (val);
-
-	  if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
-	      && (pos = charpos - XFASTINT (AREF (elt, 1))) < PT
-	      && pos >= startpos)
-	    {
-	      Lisp_Object gstring;
-	      EMACS_INT pos_byte;
-
-	      if (XFASTINT (AREF (elt, 1)) == 0)
-		pos_byte = bytepos;
-	      else
-		pos_byte = CHAR_TO_BYTE (pos);
-	      gstring = autocmp_chars (val, pos, pos_byte, Z,
-				       XWINDOW (selected_window), NULL, Qnil);
-	      if (composition_gstring_p (gstring))
-		{
-		  if (pos + LGSTRING_CHAR_LEN (gstring) > PT)
-		    {
-		      int i;
-
-		      for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
-			{
-			  Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
-
-			  if (NILP (glyph))
-			    break;
-			  if (pos + LGLYPH_FROM (glyph) == PT)
-			    return PT;
-			  if (pos + LGLYPH_TO (glyph) + 1 > PT)
-			    return (PT < last_pt
-				    ? pos + LGLYPH_FROM (glyph)
-				    : pos + LGLYPH_TO (glyph) + 1);
-			}
-		      return PT;
-		    }
-		  charpos = startpos = pos + LGSTRING_CHAR_LEN (gstring);
-		  bytepos = CHAR_TO_BYTE (charpos);
-		  break;
-		}
-	    }
-	}
-      if (! CONSP (val))
-	INC_BOTH (charpos, bytepos);
+      if (NILP (glyph))
+	break;
+      if (beg + LGLYPH_FROM (glyph) == PT)
+	return PT;
+      if (beg + LGLYPH_TO (glyph) >= PT)
+	return (PT < last_pt
+		? beg + LGLYPH_FROM (glyph)
+		: beg + LGLYPH_TO (glyph) + 1);
     }
   return PT;
 }
@@ -1395,19 +1528,19 @@
      (pos, limit, string, detail_p)
      Lisp_Object pos, limit, string, detail_p;
 {
-  Lisp_Object prop, tail;
-  EMACS_INT start, end;
+  Lisp_Object prop, tail, gstring;
+  EMACS_INT start, end, from, to;
   int id;
 
   CHECK_NUMBER_COERCE_MARKER (pos);
-  start = XINT (pos);
+  from = XINT (pos);
   if (!NILP (limit))
     {
       CHECK_NUMBER_COERCE_MARKER (limit);
-      end = XINT (limit);
+      to = XINT (limit);
     }
   else
-    end = -1;
+    to = -1;
 
   if (!NILP (string))
     {
@@ -1421,8 +1554,23 @@
 	args_out_of_range (Fcurrent_buffer (), pos);
     }
 
-  if (!find_composition (start, end, &start, &end, &prop, string))
-    return Qnil;
+  if (!find_composition (from, to, &start, &end, &prop, string))
+    {
+      if (!NILP (current_buffer->enable_multibyte_characters)
+	  && FUNCTIONP (Vauto_composition_function)
+	  && find_automatic_composition (from, to, &start, &end, &gstring,
+					 string))
+	return list3 (make_number (start), make_number (end), gstring);
+      return Qnil;
+    }
+  if ((end <= XINT (pos) || start > XINT (pos)))
+    {
+      EMACS_INT s, e;
+
+      if (find_automatic_composition (from, to, &s, &e, &gstring, string)
+	  && (e <= XINT (pos) ? e > end : s < start))
+	return list3 (make_number (start), make_number (end), gstring);
+    }
   if (!COMPOSITION_VALID_P (start, end, prop))
     return Fcons (make_number (start), Fcons (make_number (end),
 					      Fcons (Qnil, Qnil)));