]> code.delx.au - gnu-emacs/blobdiff - src/composite.c
Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-21
[gnu-emacs] / src / composite.c
index 085458db5217eb849359e008f429eceeffbc780d..17144f25cd468beeb08e5b8b96b2c68e6c23fb9c 100644 (file)
@@ -1,6 +1,10 @@
 /* Composite sequence support.
    Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
-   Licensed to the Free Software Foundation.
+     Licensed to the Free Software Foundation.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2003
+     National Institute of Advanced Industrial Science and Technology (AIST)
+     Registration Number H13PRO009
 
 This file is part of GNU Emacs.
 
@@ -22,7 +26,7 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include "lisp.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "intervals.h"
 
 /* Emacs uses special text property `composition' to support character
@@ -91,32 +95,32 @@ Boston, MA 02111-1307, USA.  */
 
    The former is a hash table in which keys are COMPONENTS-VECs and
    values are the corresponding COMPOSITION-IDs.  This hash table is
-   weak, but as each key (COMPONENTS-VEC) is also kept as a value of
+   weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
    `composition' property, it won't be collected as garbage until all
-   text that have the same COMPONENTS-VEC are deleted.
+   bits of text that have the same COMPONENTS-VEC are deleted.
 
    The latter is a table of pointers to `struct composition' indexed
-   by COMPOSITION-ID.  This structure keep the other information (see
+   by COMPOSITION-ID.  This structure keeps the other information (see
    composite.h).
 
    In general, a text property holds information about individual
    characters.  But, a `composition' property holds information about
-   a sequence of characters (in this sense, it is like `intangible'
+   a sequence of characters (in this sense, it is like the `intangible'
    property).  That means that we should not share the property value
-   in adjacent compositions we can't distinguish them if they have the
+   in adjacent compositions -- we can't distinguish them if they have the
    same property.  So, after any changes, we call
    `update_compositions' and change a property of one of adjacent
    compositions to a copy of it.  This function also runs a proper
    composition modification function to make a composition that gets
    invalid by the change valid again.
 
-   As a value of `composition' property holds information about a
+   As the value of the `composition' property holds information about a
    specific range of text, the value gets invalid if we change the
-   text in the range.  We treat `composition' property always
+   text in the range.  We treat the `composition' property as always
    rear-nonsticky (currently by setting default-text-properties to
    (rear-nonsticky (composition))) and we never make properties of
    adjacent compositions identical.  Thus, any such changes make the
-   range just shorter.  So, we can check the validity of `composition'
+   range just shorter.  So, we can check the validity of the `composition'
    property by comparing LENGTH information with the actual length of
    the composition.
 
@@ -144,23 +148,15 @@ Lisp_Object composition_hash_table;
 /* Function to call to adjust composition.  */
 Lisp_Object Vcompose_chars_after_function;
 
+Lisp_Object Qauto_composed;
+Lisp_Object Vauto_composition_function;
+Lisp_Object Qauto_composition_function;
+
+EXFUN (Fremove_list_of_text_properties, 4);
+
 /* Temporary variable used in macros COMPOSITION_XXX.  */
 Lisp_Object composition_temp;
 \f
-/* Return how many columns C will occupy on the screen.  It always
-   returns 1 for control characters and 8-bit characters because those
-   are just ignored in a composition.  */
-#define CHAR_WIDTH(c) \
-  (SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c)))
-
-/* The following macros for hash table are copied from fns.c.  */
-/* Return the contents of vector V at index IDX.  */
-#define AREF(V, IDX)       XVECTOR (V)->contents[IDX]
-/* Value is the key part of entry IDX in hash table H.  */
-#define HASH_KEY(H, IDX)   AREF ((H)->key_and_value, 2 * (IDX))
-/* Value is the value part of entry IDX in hash table H.  */
-#define HASH_VALUE(H, IDX) AREF ((H)->key_and_value, 2 * (IDX) + 1)
-
 /* Return COMPOSITION-ID of a composition at buffer position
    CHARPOS/BYTEPOS and length NCHARS.  The `composition' property of
    the sequence is PROP.  STRING, if non-nil, is a string that
@@ -246,13 +242,13 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
         modify the cons cell of PROP because it is not shared.  */
       key = HASH_KEY (hash_table, hash_index);
       id = HASH_VALUE (hash_table, hash_index);
-      XCAR (prop) = id;
-      XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
+      XSETCAR (prop, id);
+      XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
       return XINT (id);
     }
 
   /* This composition is a new one.  We must register it.  */
-         
+
   /* Check if we have sufficient memory to store this information.  */
   if (composition_table_size == 0)
     {
@@ -294,8 +290,8 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
   /* Change PROP from Form-A above to Form-B.  We can directly modify
      the cons cell of PROP because it is not shared.  */
   XSETFASTINT (id, n_compositions);
-  XCAR (prop) = id;
-  XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
+  XSETCAR (prop, id);
+  XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
 
   /* Register the composition in composition_hash_table.  */
   hash_index = hash_put (hash_table, key, id, hash_code);
@@ -340,7 +336,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
 
       for (i = 1; i < glyph_len; i += 2)
        {
-         int rule, gref, nref;
+         int rule, gref, nref, xoff, yoff;
          int this_width;
          float this_left;
 
@@ -362,7 +358,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
                |       |
                6---7---8 -- descent
          */
-         COMPOSITION_DECODE_RULE (rule, gref, nref);
+         COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
          this_left = (leftmost
                       + (gref % 3) * (rightmost - leftmost) / 2.0
                       - (nref % 3) * this_width / 2.0);
@@ -408,7 +404,8 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
 
 int
 find_composition (pos, limit, start, end, prop, object)
-     int pos, limit, *start, *end;
+     int pos, limit;
+     EMACS_INT *start, *end;
      Lisp_Object *prop, object;
 {
   Lisp_Object val;
@@ -420,14 +417,25 @@ find_composition (pos, limit, start, end, prop, object)
     return 0;
 
   if (limit > pos)             /* search forward */
-    val = Fnext_single_property_change (make_number (pos), Qcomposition,
-                                       object, make_number (limit));
+    {
+      val = Fnext_single_property_change (make_number (pos), Qcomposition,
+                                         object, make_number (limit));
+      pos = XINT (val);
+      if (pos == limit)
+       return 0;
+    }
   else                         /* search backward */
-    val = Fprevious_single_property_change (make_number (pos), Qcomposition,
-                                           object, make_number (limit));
-  pos = XINT (val);
-  if (pos == limit)
-    return 0;
+    {
+      if (get_property_and_range (pos - 1, Qcomposition, prop, start, end,
+                                 object))
+       return 1;
+      val = Fprevious_single_property_change (make_number (pos), Qcomposition,
+                                             object, make_number (limit));
+      pos = XINT (val);
+      if (pos == limit)
+       return 0;
+      pos--;
+    }
   get_property_and_range (pos, Qcomposition, prop, start, end, object);
   return 1;
 }
@@ -440,8 +448,8 @@ run_composition_function (from, to, prop)
      int from, to;
      Lisp_Object prop;
 {
-  Lisp_Object func, val;
-  int start, end;
+  Lisp_Object func;
+  EMACS_INT start, end;
 
   func = COMPOSITION_MODIFICATION_FUNC (prop);
   /* If an invalid composition precedes or follows, try to make them
@@ -454,26 +462,34 @@ run_composition_function (from, to, prop)
       && find_composition (to, -1, &start, &end, &prop, Qnil)
       && !COMPOSITION_VALID_P (start, end, prop))
     to = end;
-  if (!NILP (func))
+  if (!NILP (Ffboundp (func)))
     call2 (func, make_number (from), make_number (to));
-  else if (!NILP (Ffboundp (Vcompose_chars_after_function)))
-    call2 (Vcompose_chars_after_function,
-          make_number (from), make_number (to));
 }
 
 /* Make invalid compositions adjacent to or inside FROM and TO valid.
    CHECK_MASK is bitwise `or' of mask bits defined by macros
    CHECK_XXX (see the comment in composite.h).
 
+   It also resets the text-property `auto-composed' to a proper region
+   so that automatic character composition works correctly later while
+   displaying the region.
+
    This function is called when a buffer text is changed.  If the
    change is deletion, FROM == TO.  Otherwise, FROM < TO.  */
 
 void
 update_compositions (from, to, check_mask)
-     int from, to;
+     EMACS_INT from, to;
+     int check_mask;
 {
-  Lisp_Object prop, hook;
-  int start, end;
+  Lisp_Object prop;
+  EMACS_INT start, end;
+  /* The beginning and end of the region to set the property
+     `auto-composed' to nil.  */
+  EMACS_INT min_pos = from, max_pos = to;
+
+  if (inhibit_modification_hooks)
+    return;
 
   /* If FROM and TO are not in a valid range, do nothing.  */
   if (! (BEGV <= from && from <= to && to <= ZV))
@@ -489,6 +505,9 @@ update_compositions (from, to, check_mask)
       if (from > BEGV
          && find_composition (from - 1, -1, &start, &end, &prop, Qnil))
        {
+         min_pos = start;
+         if (end > to)
+           max_pos = end;
          if (from < end)
            Fput_text_property (make_number (from), make_number (end),
                                Qcomposition,
@@ -496,9 +515,13 @@ update_compositions (from, to, check_mask)
          run_composition_function (start, end, prop);
          from = end;
        }
-      else if (from < end
+      else if (from < ZV
               && find_composition (from, -1, &start, &from, &prop, Qnil))
-       run_composition_function (start, from, prop);
+       {
+         if (from > to)
+           max_pos = from;
+         run_composition_function (start, from, prop);
+       }
     }
 
   if (check_mask & CHECK_INSIDE)
@@ -523,17 +546,60 @@ update_compositions (from, to, check_mask)
             To avoid it, in such a case, we change the property of
             the former to the copy of it.  */
          if (to < end)
-           Fput_text_property (make_number (start), make_number (to),
-                               Qcomposition,
-                               Fcons (XCAR (prop), XCDR (prop)), Qnil);
+           {
+             Fput_text_property (make_number (start), make_number (to),
+                                 Qcomposition,
+                                 Fcons (XCAR (prop), XCDR (prop)), Qnil);
+             max_pos = end;
+           }
          run_composition_function (start, end, prop);
        }
       else if (to < ZV
               && find_composition (to, -1, &start, &end, &prop, Qnil))
-       run_composition_function (start, end, prop);
+       {
+         run_composition_function (start, end, prop);
+         max_pos = end;
+       }
+    }
+  if (min_pos < max_pos)
+    {
+      int count = SPECPDL_INDEX ();
+
+      specbind (Qinhibit_read_only, Qt);
+      specbind (Qinhibit_modification_hooks, Qt);
+      specbind (Qinhibit_point_motion_hooks, Qt);
+      Fremove_list_of_text_properties (make_number (min_pos),
+                                      make_number (max_pos),
+                                      Fcons (Qauto_composed, Qnil), Qnil);
+      unbind_to (count, Qnil);
+    }
+}
+
+
+/* Modify composition property values in LIST destructively.  LIST is
+   a list as returned from text_property_list.  Change values to the
+   top-level copies of them so that none of them are `eq'.  */
+
+void
+make_composition_value_copy (list)
+     Lisp_Object list;
+{
+  Lisp_Object plist, val;
+
+  for (; CONSP (list); list = XCDR (list))
+    {
+      plist = XCAR (XCDR (XCDR (XCAR (list))));
+      while (CONSP (plist) && CONSP (XCDR (plist)))
+       {
+         if (EQ (XCAR (plist), Qcomposition)
+             && (val = XCAR (XCDR (plist)), CONSP (val)))
+           XSETCAR (XCDR (plist), Fcons (XCAR (val), XCDR (val)));
+         plist = XCDR (XCDR (plist));
+       }
     }
 }
 
+
 /* Make text in the region between START and END a composition that
    has COMPONENTS and MODIFICATION-FUNC.
 
@@ -552,18 +618,17 @@ compose_text (start, end, components, modification_func, string)
   Fput_text_property  (make_number (start), make_number (end),
                       Qcomposition, prop, string);
 }
-
 \f
 /* Emacs Lisp APIs.  */
 
 DEFUN ("compose-region-internal", Fcompose_region_internal,
        Scompose_region_internal, 2, 4, 0,
-  "Internal use only.\n\
-\n\
-Compose text in the region between START and END.\n\
-Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC\n\
-for the composition.   See `compose-region' for more detial.")
-  (start, end, components, mod_func)
+       doc: /* Internal use only.
+
+Compose text in the region between START and END.
+Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
+for the composition.  See `compose-region' for more detail.  */)
+     (start, end, components, mod_func)
      Lisp_Object start, end, components, mod_func;
 {
   validate_region (&start, &end);
@@ -571,7 +636,7 @@ for the composition.   See `compose-region' for more detial.")
       && !INTEGERP (components)
       && !CONSP (components)
       && !STRINGP (components))
-    CHECK_VECTOR (components, 2);
+    CHECK_VECTOR (components);
 
   compose_text (XINT (start), XINT (end), components, mod_func, Qnil);
   return Qnil;
@@ -579,21 +644,21 @@ for the composition.   See `compose-region' for more detial.")
 
 DEFUN ("compose-string-internal", Fcompose_string_internal,
        Scompose_string_internal, 3, 5, 0,
-  "Internal use only.\n\
-\n\
-Compose text between indices START and END of STRING.\n\
-Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC\n\
-for the composition.   See `compose-string' for more detial.")
-  (string, start, end, components, mod_func)
+       doc: /* Internal use only.
+
+Compose text between indices START and END of STRING.
+Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
+for the composition.  See `compose-string' for more detail.  */)
+     (string, start, end, components, mod_func)
      Lisp_Object string, start, end, components, mod_func;
 {
-  CHECK_STRING (string, 0);
-  CHECK_NUMBER (start, 1);
-  CHECK_NUMBER (end, 2);
+  CHECK_STRING (string);
+  CHECK_NUMBER (start);
+  CHECK_NUMBER (end);
 
   if (XINT (start) < 0 ||
       XINT (start) > XINT (end)
-      || XINT (end) > XSTRING (string)->size)
+      || XINT (end) > SCHARS (string))
     args_out_of_range (start, end);
 
   compose_text (XINT (start), XINT (end), components, mod_func, string);
@@ -601,29 +666,39 @@ for the composition.   See `compose-string' for more detial.")
 }
 
 DEFUN ("find-composition-internal", Ffind_composition_internal,
-       Sfind_composition_internal, 4, 4, 0, 
-  "Internal use only.\n\
-\n\
-Return information about composition at or nearest to position POS.\n\
-See `find-composition' for more detail.")
-  (pos, limit, string, detail_p)
+       Sfind_composition_internal, 4, 4, 0,
+       doc: /* Internal use only.
+
+Return information about composition at or nearest to position POS.
+See `find-composition' for more detail.  */)
+     (pos, limit, string, detail_p)
      Lisp_Object pos, limit, string, detail_p;
 {
   Lisp_Object prop, tail;
-  int start, end;
+  EMACS_INT start, end;
   int id;
 
-  CHECK_NUMBER_COERCE_MARKER (pos, 0);
+  CHECK_NUMBER_COERCE_MARKER (pos);
   start = XINT (pos);
   if (!NILP (limit))
     {
-      CHECK_NUMBER_COERCE_MARKER (limit, 1);
+      CHECK_NUMBER_COERCE_MARKER (limit);
       end = XINT (limit);
     }
   else
     end = -1;
+
   if (!NILP (string))
-    CHECK_STRING (string, 2);
+    {
+      CHECK_STRING (string);
+      if (XINT (pos) < 0 || XINT (pos) > SCHARS (string))
+       args_out_of_range (string, pos);
+    }
+  else
+    {
+      if (XINT (pos) < BEGV || XINT (pos) > ZV)
+       args_out_of_range (Fcurrent_buffer (), pos);
+    }
 
   if (!find_composition (start, end, &start, &end, &prop, string))
     return Qnil;
@@ -676,10 +751,15 @@ syms_of_composite ()
   {
     Lisp_Object args[6];
     extern Lisp_Object QCsize;
-    
+
     args[0] = QCtest;
     args[1] = Qequal;
     args[2] = QCweakness;
+    /* We used to make the hash table weak so that unreferenced
+       compostions can be garbage-collected.  But, usually once
+       created compositions are repeatedly used in an Emacs session,
+       and thus it's not worth to save memory in such a way.  So, we
+       make the table not weak.  */
     args[3] = Qnil;
     args[4] = QCsize;
     args[5] = make_number (311);
@@ -692,19 +772,42 @@ syms_of_composite ()
     = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky);
 
   DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function,
-    "Function to adjust composition of buffer text.\n\
-\n\
-This function is called after a text with `composition' property is\n\
-inserted or deleted to keep `composition' property of buffer text\n\
-valid.\n\
-\n\
-The function is called with two arguments FROM and TO.  They specify\n\
-the range of text of which composition should be adjusted.\n\
-\n\
-The default value is the function `compose-chars-after'.");
+              doc: /* Function to adjust composition of buffer text.
+
+The function is called with three arguments FROM, TO, and OBJECT.
+FROM and TO specify the range of text of which composition should be
+adjusted.  OBJECT, if non-nil, is a string that contains the text.
+
+This function is called after a text with `composition' property is
+inserted or deleted to keep `composition' property of buffer text
+valid.
+
+The default value is the function `compose-chars-after'.  */);
   Vcompose_chars_after_function = intern ("compose-chars-after");
 
+  Qauto_composed = intern ("auto-composed");
+  staticpro (&Qauto_composed);
+
+  Qauto_composition_function = intern ("auto-composition-function");
+  staticpro (&Qauto_composition_function);
+
+  DEFVAR_LISP ("auto-composition-function", &Vauto_composition_function,
+              doc: /* Function to call to compose characters automatically.
+The function is called from the display routine with two arguments,
+POS and STRING.
+
+If STRING is nil, the function must compose characters following POS
+in the current buffer.
+
+Otherwise, STRING is a string, and POS is an index to the string.  In
+this case, the function must compose characters following POS in
+the string.  */);
+  Vauto_composition_function = Qnil;
+
   defsubr (&Scompose_region_internal);
   defsubr (&Scompose_string_internal);
   defsubr (&Sfind_composition_internal);
 }
+
+/* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272
+   (do not change this comment) */