/* Composite sequence support.
- Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ Copyright (C) 2001-2014 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H14PRO021
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include <setjmp.h>
+
#include "lisp.h"
#include "character.h"
#include "buffer.h"
auto-compositions. */
#define MAX_AUTO_COMPOSITION_LOOKBACK 3
-/* Temporary variable used in macros COMPOSITION_XXX. */
-Lisp_Object composition_temp;
-
-\f
/* 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
key = components;
else if (NILP (components))
{
- key = Fmake_vector (make_number (nchars), Qnil);
+ key = make_uninit_vector (nchars);
if (STRINGP (string))
for (i = 0; i < nchars; i++)
{
This doesn't check the validity of composition. */
-int
+bool
find_composition (ptrdiff_t pos, ptrdiff_t limit,
ptrdiff_t *start, ptrdiff_t *end,
Lisp_Object *prop, Lisp_Object object)
valid too. */
if (from > BEGV
&& find_composition (from - 1, -1, &start, &end, &prop, Qnil)
- && !COMPOSITION_VALID_P (start, end, prop))
+ && !composition_valid_p (start, end, prop))
from = start;
if (to < ZV
&& find_composition (to, -1, &start, &end, &prop, Qnil)
- && !COMPOSITION_VALID_P (start, end, prop))
+ && !composition_valid_p (start, end, prop))
to = end;
if (!NILP (Ffboundp (func)))
call2 (func, make_number (from), make_number (to));
latter to the copy of it. */
if (from > BEGV
&& find_composition (from - 1, -1, &start, &end, &prop, Qnil)
- && COMPOSITION_VALID_P (start, end, prop))
+ && composition_valid_p (start, end, prop))
{
min_pos = start;
if (end > to)
}
else if (from < ZV
&& find_composition (from, -1, &start, &from, &prop, Qnil)
- && COMPOSITION_VALID_P (start, from, prop))
+ && composition_valid_p (start, from, prop))
{
if (from > to)
max_pos = from;
(to - 1). */
while (from < to - 1
&& find_composition (from, to, &start, &from, &prop, Qnil)
- && COMPOSITION_VALID_P (start, from, prop)
+ && composition_valid_p (start, from, prop)
&& from < to - 1)
run_composition_function (start, from, prop);
}
{
if (from < to
&& find_composition (to - 1, -1, &start, &end, &prop, Qnil)
- && COMPOSITION_VALID_P (start, end, prop))
+ && composition_valid_p (start, end, prop))
{
/* TO should be also at composition boundary. But,
insertion or deletion will make two compositions adjacent
}
else if (to < ZV
&& find_composition (to, -1, &start, &end, &prop, Qnil)
- && COMPOSITION_VALID_P (start, end, prop))
+ && composition_valid_p (start, end, prop))
{
run_composition_function (start, end, prop);
max_pos = end;
specbind (Qinhibit_point_motion_hooks, Qt);
Fremove_list_of_text_properties (make_number (min_pos),
make_number (max_pos),
- Fcons (Qauto_composed, Qnil), Qnil);
+ list1 (Qauto_composed), Qnil);
unbind_to (count, Qnil);
}
}
Qcomposition, prop, string);
}
-
-static Lisp_Object autocmp_chars (Lisp_Object, ptrdiff_t, ptrdiff_t,
- ptrdiff_t, struct window *,
- struct face *, Lisp_Object);
-
-\f
-/* Lisp glyph-string handlers */
+/* Lisp glyph-string handlers. */
/* Hash table for automatic composition. The key is a header of a
lgstring (Lispy glyph-string), and the value is a body of a
ptrdiff_t i;
header = LGSTRING_HEADER (gstring);
- hash = h->hashfn (h, header);
+ hash = h->test.hashfn (&h->test, header);
if (len < 0)
{
ptrdiff_t j, glyph_len = LGSTRING_GLYPH_LEN (gstring);
len = j;
}
- lint_assume (len <= TYPE_MAXIMUM (ptrdiff_t) - 2);
copy = Fmake_vector (make_number (len + 2), Qnil);
LGSTRING_SET_HEADER (copy, Fcopy_sequence (header));
for (i = 0; i < len; i++)
return HASH_VALUE (h, id);
}
-static Lisp_Object fill_gstring_header (Lisp_Object, Lisp_Object,
- Lisp_Object, Lisp_Object,
- Lisp_Object);
-
-int
+bool
composition_gstring_p (Lisp_Object gstring)
{
Lisp_Object header;
}
metrics->width = metrics->lbearing = metrics->rbearing = 0;
}
- for (glyph = &LGSTRING_GLYPH (gstring, from); from < to; from++, glyph++)
+ for (glyph = lgstring_glyph_addr (gstring, from); from < to; from++, glyph++)
{
int x;
static Lisp_Object gstring_work_headers;
static Lisp_Object
-fill_gstring_header (Lisp_Object header, Lisp_Object start, Lisp_Object end, Lisp_Object font_object, Lisp_Object string)
+fill_gstring_header (Lisp_Object header, ptrdiff_t from, ptrdiff_t from_byte,
+ ptrdiff_t to, Lisp_Object font_object, Lisp_Object string)
{
- ptrdiff_t from, to, from_byte;
- ptrdiff_t len, i;
+ ptrdiff_t len = to - from, i;
- if (NILP (string))
- {
- if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
- error ("Attempt to shape unibyte text");
- validate_region (&start, &end);
- from = XFASTINT (start);
- to = XFASTINT (end);
- from_byte = CHAR_TO_BYTE (from);
- }
- else
- {
- CHECK_STRING (string);
- if (! STRING_MULTIBYTE (string))
- error ("Attempt to shape unibyte text");
- /* The caller checks that START and END are nonnegative integers. */
- if (! (XINT (start) <= XINT (end) && XINT (end) <= SCHARS (string)))
- args_out_of_range_3 (string, start, end);
- from = XINT (start);
- to = XINT (end);
- from_byte = string_char_to_byte (string, from);
- }
-
- len = to - from;
if (len == 0)
error ("Attempt to shape zero-length text");
if (VECTORP (header))
if (len <= 8)
header = AREF (gstring_work_headers, len - 1);
else
- header = Fmake_vector (make_number (len + 1), Qnil);
+ header = make_uninit_vector (len + 1);
}
ASET (header, 0, font_object);
object. Otherwise return nil. */
static Lisp_Object
-autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t limit, struct window *win, struct face *face, Lisp_Object string)
+autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
+ ptrdiff_t limit, struct window *win, struct face *face,
+ Lisp_Object string)
{
ptrdiff_t count = SPECPDL_INDEX ();
- FRAME_PTR f = XFRAME (win->frame);
+ struct frame *f = XFRAME (win->frame);
Lisp_Object pos = make_number (charpos);
ptrdiff_t to;
ptrdiff_t pt = PT, pt_byte = PT_BYTE;
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f))
{
- font_object = font_range (charpos, &to, win, face, string);
+ font_object = font_range (charpos, bytepos, &to, win, face, string);
if (! FONT_OBJECT_P (font_object)
|| (! NILP (re)
&& to < limit
string);
if (NILP (LGSTRING_ID (lgstring)))
{
- Lisp_Object args[6];
-
/* Save point as marker before calling out to lisp. */
if (NILP (string))
- {
- Lisp_Object m = Fmake_marker ();
- set_marker_both (m, Qnil, pt, pt_byte);
- record_unwind_protect (restore_point_unwind, m);
- }
-
- args[0] = Vauto_composition_function;
- args[1] = AREF (rule, 2);
- args[2] = pos;
- args[3] = make_number (to);
- args[4] = font_object;
- args[5] = string;
- lgstring = safe_call (6, args);
+ record_unwind_protect (restore_point_unwind,
+ build_marker (current_buffer, pt, pt_byte));
+ lgstring = safe_call (6, Vauto_composition_function, AREF (rule, 2),
+ pos, make_number (to), font_object, string);
}
return unbind_to (count, lgstring);
}
if (charpos < endpos
&& find_composition (charpos, endpos, &start, &end, &prop, string)
&& start >= charpos
- && COMPOSITION_VALID_P (start, end, prop))
+ && composition_valid_p (start, end, prop))
{
cmp_it->stop_pos = endpos = start;
cmp_it->ch = -1;
/* Check if the character at CHARPOS (and BYTEPOS) is composed
(possibly with the following characters) on window W. ENDPOS limits
- characters to be composed. FACE, in non-NULL, is a base face of
+ characters to be composed. FACE, if non-NULL, is a base face of
the character. If STRING is not nil, it is a string containing the
character to check, and CHARPOS and BYTEPOS are indices in the
string. In that case, FACE must not be NULL.
If the character is composed, setup members of CMP_IT (id, nglyphs,
- from, to, reversed_p), and return 1. Otherwise, update
- CMP_IT->stop_pos, and return 0. */
+ from, to, reversed_p), and return true. Otherwise, update
+ CMP_IT->stop_pos, and return false. */
-int
-composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t endpos, struct window *w, struct face *face, Lisp_Object string)
+bool
+composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
+ ptrdiff_t bytepos, ptrdiff_t endpos, struct window *w,
+ struct face *face, Lisp_Object string)
{
- if (endpos < 0)
- endpos = NILP (string) ? BEGV : 0;
-
if (cmp_it->ch == -2)
{
composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
return 0;
}
+ if (endpos < 0)
+ endpos = NILP (string) ? BEGV : 0;
+
if (cmp_it->ch < 0)
{
/* We are looking at a static composition. */
{
ptrdiff_t cpos = charpos, bpos = bytepos;
- while (1)
+ cmp_it->reversed_p = 1;
+ elt = XCAR (val);
+ if (cmp_it->lookback > 0)
{
- elt = XCAR (val);
- if (cmp_it->lookback > 0)
- {
- cpos = charpos - cmp_it->lookback;
- if (STRINGP (string))
- bpos = string_char_to_byte (string, cpos);
- else
- bpos = CHAR_TO_BYTE (cpos);
- }
- lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
- string);
- if (composition_gstring_p (lgstring)
- && cpos + LGSTRING_CHAR_LEN (lgstring) - 1 == charpos)
- break;
- /* Composition failed or didn't cover the current
- character. */
- if (cmp_it->lookback == 0)
- goto no_composition;
- lgstring = Qnil;
- /* Try to find a shorter composition that starts after CPOS. */
- composition_compute_stop_pos (cmp_it, charpos, bytepos, cpos,
- string);
- if (cmp_it->ch == -2 || cmp_it->stop_pos < charpos)
- goto no_composition;
- val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
- for (i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val));
+ cpos = charpos - cmp_it->lookback;
+ if (STRINGP (string))
+ bpos = string_char_to_byte (string, cpos);
+ else
+ bpos = CHAR_TO_BYTE (cpos);
}
- cmp_it->reversed_p = 1;
+ lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
+ string);
+ if (! composition_gstring_p (lgstring)
+ || cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos)
+ /* Composition failed or didn't cover the current
+ character. */
+ goto no_composition;
}
if (NILP (lgstring))
goto no_composition;
/* BYTEPOS is calculated in composition_compute_stop_pos */
bytepos = -1;
}
+ if (cmp_it->reversed_p)
+ endpos = -1;
composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
return 0;
}
}
else
{
- /* automatic composition */
+ /* Automatic composition. */
Lisp_Object gstring = composition_gstring_from_id (cmp_it->id);
Lisp_Object glyph;
ptrdiff_t from;
cmp_it->width = 0;
for (i = cmp_it->nchars - 1; i >= 0; i--)
{
- c = XINT (LGSTRING_CHAR (gstring, i));
+ c = XINT (LGSTRING_CHAR (gstring, from + i));
cmp_it->nbytes += CHAR_BYTES (c);
cmp_it->width += CHAR_WIDTH (c);
}
/* This is like find_composition, but find an automatic composition
instead. It is assured that POS is not within a static
composition. If found, set *GSTRING to the glyph-string
- representing the composition, and return 1. Otherwise, *GSTRING to
- Qnil, and return 0. */
+ representing the composition, and return true. Otherwise, *GSTRING to
+ Qnil, and return false. */
-static int
+static bool
find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
ptrdiff_t *start, ptrdiff_t *end,
Lisp_Object *gstring, Lisp_Object string)
int c;
Lisp_Object window;
struct window *w;
- int need_adjustment = 0;
+ bool need_adjustment = 0;
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
if (NILP (window))
/* At first check the static composition. */
if (get_property_and_range (new_pt, Qcomposition, &val, &beg, &end, Qnil)
- && COMPOSITION_VALID_P (beg, end, val))
+ && composition_valid_p (beg, end, val))
{
if (beg < new_pt /* && end > new_pt <- It's always the case. */
&& (last_pt <= beg || last_pt >= end))
If the optional 4th argument STRING is not nil, it is a string
containing the target characters between indices FROM and TO.
+Otherwise FROM and TO are character positions in current buffer;
+they can be in either order, and can be integers or markers.
A glyph-string is a vector containing information about how to display
a specific character sequence. The format is:
(Lisp_Object from, Lisp_Object to, Lisp_Object font_object, Lisp_Object string)
{
Lisp_Object gstring, header;
- ptrdiff_t frompos, topos;
+ ptrdiff_t frompos, frombyte, topos;
- CHECK_NATNUM (from);
- CHECK_NATNUM (to);
if (! FONT_OBJECT_P (font_object))
{
struct coding_system *coding;
font_object = CODING_ID_NAME (coding->id);
}
- header = fill_gstring_header (Qnil, from, to, font_object, string);
+ if (NILP (string))
+ {
+ if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
+ error ("Attempt to shape unibyte text");
+ validate_region (&from, &to);
+ frompos = XFASTINT (from);
+ topos = XFASTINT (to);
+ frombyte = CHAR_TO_BYTE (frompos);
+ }
+ else
+ {
+ CHECK_NATNUM (from);
+ CHECK_NATNUM (to);
+ CHECK_STRING (string);
+ if (! STRING_MULTIBYTE (string))
+ error ("Attempt to shape unibyte text");
+ if (! (XINT (from) <= XINT (to) && XINT (to) <= SCHARS (string)))
+ args_out_of_range_3 (string, from, to);
+ frompos = XFASTINT (from);
+ topos = XFASTINT (to);
+ frombyte = string_char_to_byte (string, frompos);
+ }
+
+ header = fill_gstring_header (Qnil, frompos, frombyte,
+ topos, font_object, string);
gstring = gstring_lookup_cache (header);
if (! NILP (gstring))
return gstring;
- frompos = XINT (from);
- topos = XINT (to);
if (LGSTRING_GLYPH_LEN (gstring_work) < topos - frompos)
gstring_work = Fmake_vector (make_number (topos - frompos + 2), Qnil);
LGSTRING_SET_HEADER (gstring_work, header);
&& (e <= XINT (pos) ? e > end : s < start))
return list3 (make_number (s), make_number (e), gstring);
}
- if (!COMPOSITION_VALID_P (start, end, prop))
- return Fcons (make_number (start), Fcons (make_number (end),
- Fcons (Qnil, Qnil)));
+ if (!composition_valid_p (start, end, prop))
+ return list3 (make_number (start), make_number (end), Qnil);
if (NILP (detail_p))
- return Fcons (make_number (start), Fcons (make_number (end),
- Fcons (Qt, Qnil)));
+ return list3 (make_number (start), make_number (end), Qt);
- if (COMPOSITION_REGISTERD_P (prop))
+ if (composition_registered_p (prop))
id = COMPOSITION_ID (prop);
else
{
if (id >= 0)
{
Lisp_Object components, relative_p, mod_func;
- enum composition_method method = COMPOSITION_METHOD (prop);
+ enum composition_method method = composition_method (prop);
int width = composition_table[id]->width;
components = Fcopy_sequence (COMPOSITION_COMPONENTS (prop));
relative_p = (method == COMPOSITION_WITH_RULE_ALTCHARS
? Qnil : Qt);
mod_func = COMPOSITION_MODIFICATION_FUNC (prop);
- tail = Fcons (components,
- Fcons (relative_p,
- Fcons (mod_func,
- Fcons (make_number (width), Qnil))));
+ tail = list4 (components, relative_p, mod_func, make_number (width));
}
else
tail = Qnil;
}
staticpro (&gstring_work_headers);
- gstring_work_headers = Fmake_vector (make_number (8), Qnil);
+ gstring_work_headers = make_uninit_vector (8);
for (i = 0; i < 8; i++)
ASET (gstring_work_headers, i, Fmake_vector (make_number (i + 2), Qnil));
staticpro (&gstring_work);