aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenichi Handa2010-05-14 13:14:23 +0900
committerKenichi Handa2010-05-14 13:14:23 +0900
commit82ebc97b11a369303345927c98e7bc69928c9117 (patch)
tree5fc673dace42fbb438848c3c6ffda1eb47188857 /src
parent1f8162fe7761eba6a4051e242de825fdc7d7512b (diff)
downloademacs-82ebc97b11a369303345927c98e7bc69928c9117.tar.gz
emacs-82ebc97b11a369303345927c98e7bc69928c9117.zip
Fix bidi-composition interaction.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog19
-rw-r--r--src/composite.c363
-rw-r--r--src/dispextern.h4
-rw-r--r--src/xdisp.c134
4 files changed, 441 insertions, 79 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index c0e37f70c9c..084276a9f11 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
12010-05-14 Kenichi Handa <handa@m17n.org>
2
3 * dispextern.h (struct composition_it): New member reversed_p.
4
5 * composite.c (composition_compute_stop_pos): Search backward if
6 ENDPOS < CHARPOS.
7 (composition_reseat_it): Handle the case that ENDPOS < CHARPOS.
8 Set CMP_IT->reversed_p.
9 (composition_update_it): Pay attention ot CMP_IT->reversed_p.
10
11 * xdisp.c (set_iterator_to_next): Call
12 composition_compute_stop_pos with negative ENDPOS if we are
13 scanning backward. Call composition_compute_stop_pos if scan
14 direction is changed.
15 (next_element_from_buffer): Call composition_compute_stop_pos with
16 negative ENDPOS if we are scanning backward.
17 (next_element_from_composition): Pay attention to
18 IT->cmp_it.reversed_p.
19
12010-05-10 Glenn Morris <rgm@gnu.org> 202010-05-10 Glenn Morris <rgm@gnu.org>
2 21
3 * Makefile.in (LIBS_SYSTEM): Set using configure, not cpp. 22 * Makefile.in (LIBS_SYSTEM): Set using configure, not cpp.
diff --git a/src/composite.c b/src/composite.c
index 341eb371871..cbfb4aa66d3 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -1018,12 +1018,29 @@ autocmp_chars (cft_element, charpos, bytepos, limit, win, face, string)
1018 return unbind_to (count, Qnil); 1018 return unbind_to (count, Qnil);
1019} 1019}
1020 1020
1021static Lisp_Object _work_val;
1022static int _work_char;
1023
1024/* 1 iff the character C is composable. */
1025#define CHAR_COMPOSABLE_P(C) \
1026 ((C) == 0x200C || (C) == 0x200D \
1027 || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)), \
1028 (SYMBOLP (_work_val) \
1029 && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \
1030 && _work_char != 'Z')))
1021 1031
1022/* Update cmp_it->stop_pos to the next position after CHARPOS (and 1032/* Update cmp_it->stop_pos to the next position after CHARPOS (and
1023 BYTEPOS) where character composition may happen. If BYTEPOS is 1033 BYTEPOS) where character composition may happen. If BYTEPOS is
1024 negative, compute it. If it is a static composition, set 1034 negative, compute it. ENDPOS is a limit of searching. If it is
1025 cmp_it->ch to -1. Otherwise, set cmp_it->ch to the character that 1035 less than CHARPOS, search backward to ENDPOS+1 assuming that
1026 triggers a automatic composition. */ 1036 set_iterator_to_next works in reverse order. In this case, if a
1037 composition closest to CHARPOS is found, set cmp_it->stop_pos to
1038 the last character of the composition.
1039
1040 If no composition is found, set cmp_it->ch to -2. If a static
1041 composition is found, set cmp_it->ch to -1. Otherwise, set
1042 cmp_it->ch to the character that triggers the automatic
1043 composition. */
1027 1044
1028void 1045void
1029composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string) 1046composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
@@ -1036,60 +1053,200 @@ composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
1036 /* This is from forward_to_next_line_start in xdisp.c. */ 1053 /* This is from forward_to_next_line_start in xdisp.c. */
1037 const int MAX_NEWLINE_DISTANCE = 500; 1054 const int MAX_NEWLINE_DISTANCE = 500;
1038 1055
1039 if (endpos > charpos + MAX_NEWLINE_DISTANCE) 1056 if (charpos < endpos)
1040 endpos = charpos + MAX_NEWLINE_DISTANCE; 1057 {
1041 cmp_it->stop_pos = endpos; 1058 if (endpos > charpos + MAX_NEWLINE_DISTANCE)
1059 endpos = charpos + MAX_NEWLINE_DISTANCE;
1060 }
1061 else if (endpos < charpos)
1062 {
1063 /* We search backward for a position to check composition. */
1064 if (endpos < 0)
1065 {
1066 /* But we don't know where to stop the searching. */
1067 endpos = NILP (string) ? BEGV - 1 : -1;
1068 /* Usually we don't reach ENDPOS because we stop searching
1069 at an uncomposable character (NL, LRE, etc). */
1070 }
1071 }
1042 cmp_it->id = -1; 1072 cmp_it->id = -1;
1043 cmp_it->ch = -2; 1073 cmp_it->ch = -2;
1044 if (find_composition (charpos, endpos, &start, &end, &prop, string) 1074 cmp_it->reversed_p = 0;
1075 cmp_it->stop_pos = endpos;
1076 if (charpos == endpos)
1077 return;
1078 /* FIXME: Bidi is not yet handled well in static composition. */
1079 if (charpos < endpos
1080 && find_composition (charpos, endpos, &start, &end, &prop, string)
1045 && COMPOSITION_VALID_P (start, end, prop)) 1081 && COMPOSITION_VALID_P (start, end, prop))
1046 { 1082 {
1047 cmp_it->stop_pos = endpos = start; 1083 cmp_it->stop_pos = endpos = start;
1048 cmp_it->ch = -1; 1084 cmp_it->ch = -1;
1049 } 1085 }
1050 if (NILP (string) && PT > charpos && PT < endpos) 1086 if (NILP (string))
1051 cmp_it->stop_pos = PT; 1087 {
1088 /* A composition never strides over PT. */
1089 if (PT > charpos)
1090 {
1091 if (PT < endpos)
1092 cmp_it->stop_pos = endpos = PT;
1093 }
1094 else if (PT < charpos && PT > endpos)
1095 {
1096 cmp_it->stop_pos = endpos = PT - 1;
1097 }
1098 }
1052 if (NILP (current_buffer->enable_multibyte_characters) 1099 if (NILP (current_buffer->enable_multibyte_characters)
1053 || NILP (Vauto_composition_mode)) 1100 || NILP (Vauto_composition_mode))
1054 return; 1101 return;
1055 if (bytepos < 0) 1102 if (bytepos < 0)
1056 { 1103 {
1057 if (STRINGP (string)) 1104 if (NILP (string))
1058 bytepos = string_char_to_byte (string, charpos);
1059 else
1060 bytepos = CHAR_TO_BYTE (charpos); 1105 bytepos = CHAR_TO_BYTE (charpos);
1106 else
1107 bytepos = string_char_to_byte (string, charpos);
1061 } 1108 }
1062 1109
1063 start = charpos; 1110 start = charpos;
1064 while (charpos < endpos) 1111 if (charpos < endpos)
1065 { 1112 {
1066 if (STRINGP (string)) 1113 /* Forward search. */
1067 FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos); 1114 while (charpos < endpos)
1068 else
1069 FETCH_CHAR_ADVANCE (c, charpos, bytepos);
1070 if (c == '\n')
1071 { 1115 {
1072 cmp_it->ch = -2; 1116 if (STRINGP (string))
1073 break; 1117 FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
1118 else
1119 FETCH_CHAR_ADVANCE (c, charpos, bytepos);
1120 if (c == '\n')
1121 {
1122 cmp_it->ch = -2;
1123 break;
1124 }
1125 val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1126 if (! NILP (val))
1127 {
1128 Lisp_Object elt;
1129
1130 for (; CONSP (val); val = XCDR (val))
1131 {
1132 elt = XCAR (val);
1133 if (VECTORP (elt) && ASIZE (elt) == 3
1134 && NATNUMP (AREF (elt, 1))
1135 && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start)
1136 break;
1137 }
1138 if (CONSP (val))
1139 {
1140 cmp_it->lookback = XFASTINT (AREF (elt, 1));
1141 cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
1142 cmp_it->ch = c;
1143 return;
1144 }
1145 }
1074 } 1146 }
1075 val = CHAR_TABLE_REF (Vcomposition_function_table, c); 1147 }
1076 if (! NILP (val)) 1148 else
1149 {
1150 /* Search backward for a pattern that may be composed and the
1151 position of (possibly) the last character of the match is
1152 closest to (but not after) START. The reason for the last
1153 character is that set_iterator_to_next works in reverse order
1154 and, thus we must stop at the last character for composition
1155 check. */
1156 unsigned char *p;
1157 int len;
1158 /* limit byte position used in fast_looking_at. This is the
1159 byte position of the next character of START. */
1160 EMACS_INT limit;
1161
1162 if (NILP (string))
1163 p = BYTE_POS_ADDR (bytepos);
1164 else
1165 p = SDATA (string) + bytepos;
1166 c = STRING_CHAR_AND_LENGTH (p, len);
1167 limit = bytepos + len;
1168 while (CHAR_COMPOSABLE_P (c))
1077 { 1169 {
1078 Lisp_Object elt; 1170 for (val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1171 CONSP (val); val = XCDR (val))
1172 {
1173 Lisp_Object elt = XCAR (val);
1174 int back, len;
1079 1175
1080 for (; CONSP (val); val = XCDR (val)) 1176 if (VECTORP (elt) && ASIZE (elt) == 3
1177 && NATNUMP (AREF (elt, 1))
1178 && charpos - (back = XFASTINT (AREF (elt, 1))) > endpos)
1179 {
1180 EMACS_INT cpos = charpos - back, bpos;
1181
1182 if (back == 0)
1183 bpos = bytepos;
1184 else
1185 bpos = (NILP (string) ? CHAR_TO_BYTE (cpos)
1186 : string_char_to_byte (string, cpos));
1187 if (STRINGP (AREF (elt, 0)))
1188 len = fast_looking_at (AREF (elt, 0), cpos, bpos,
1189 start + 1, limit, string);
1190 else
1191 len = 1;
1192 if (len > 0)
1193 {
1194 /* Make CPOS points the last character of match.
1195 Note that LEN is byte-length. */
1196 bpos += len;
1197 if (NILP (string))
1198 cpos = BYTE_TO_CHAR (bpos) - 1;
1199 else
1200 cpos = string_byte_to_char (string, bpos) - 1;
1201 back = cpos - (charpos - back);
1202 if (cmp_it->stop_pos < cpos
1203 || (cmp_it->stop_pos == cpos
1204 && cmp_it->lookback < back))
1205 {
1206 cmp_it->stop_pos = cpos;
1207 cmp_it->ch = c;
1208 cmp_it->lookback = back;
1209 }
1210 }
1211 }
1212 }
1213 if (charpos - 1 == endpos)
1214 break;
1215 if (STRINGP (string))
1081 { 1216 {
1082 elt = XCAR (val); 1217 p--, bytepos--;
1083 if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)) 1218 while (! CHAR_HEAD_P (*p))
1084 && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start) 1219 p--, bytepos--;
1085 break; 1220 charpos--;
1221 }
1222 else
1223 {
1224 DEC_BOTH (charpos, bytepos);
1225 p = BYTE_POS_ADDR (bytepos);
1086 } 1226 }
1087 if (CONSP (val)) 1227 c = STRING_CHAR (p);
1228 }
1229 if (cmp_it->ch >= 0)
1230 /* We found a position to check. */
1231 return;
1232 /* Skip all uncomposable characters. */
1233 if (NILP (string))
1234 {
1235 while (charpos - 1 > endpos && ! CHAR_COMPOSABLE_P (c))
1236 {
1237 DEC_BOTH (charpos, bytepos);
1238 c = FETCH_MULTIBYTE_CHAR (bytepos);
1239 }
1240 }
1241 else
1242 {
1243 while (charpos - 1 > endpos && ! CHAR_COMPOSABLE_P (c))
1088 { 1244 {
1089 cmp_it->lookback = XFASTINT (AREF (elt, 1)); 1245 p--;
1090 cmp_it->stop_pos = charpos - 1 - cmp_it->lookback; 1246 while (! CHAR_HEAD_P (*p))
1091 cmp_it->ch = c; 1247 p--;
1092 return; 1248 charpos--;
1249 c = STRING_CHAR (p);
1093 } 1250 }
1094 } 1251 }
1095 } 1252 }
@@ -1104,8 +1261,8 @@ composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
1104 string. In that case, FACE must not be NULL. 1261 string. In that case, FACE must not be NULL.
1105 1262
1106 If the character is composed, setup members of CMP_IT (id, nglyphs, 1263 If the character is composed, setup members of CMP_IT (id, nglyphs,
1107 and from), and return 1. Otherwise, update CMP_IT->stop_pos, and 1264 from, to, reversed_p), and return 1. Otherwise, update
1108 return 0. */ 1265 CMP_IT->stop_pos, and return 0. */
1109 1266
1110int 1267int
1111composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string) 1268composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
@@ -1115,13 +1272,29 @@ composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
1115 struct face *face; 1272 struct face *face;
1116 Lisp_Object string; 1273 Lisp_Object string;
1117{ 1274{
1118 if (NILP (string) && charpos < PT && PT < endpos) 1275 if (endpos <= charpos)
1119 endpos = PT; 1276 {
1277 if (NILP (string))
1278 {
1279 if (endpos < 0)
1280 endpos = BEGV;
1281 if (endpos < PT && PT < charpos)
1282 endpos = PT;
1283 }
1284 else if (endpos < 0)
1285 endpos = 0;
1286 }
1287 else
1288 {
1289 if (NILP (string) && charpos < PT && PT < endpos)
1290 endpos = PT;
1291 }
1120 1292
1121 if (cmp_it->ch == -2) 1293 if (cmp_it->ch == -2)
1122 { 1294 {
1123 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string); 1295 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
1124 if (cmp_it->ch == -2) 1296 if (cmp_it->stop_pos != charpos)
1297 /* The current position is not composed. */
1125 return 0; 1298 return 0;
1126 } 1299 }
1127 1300
@@ -1145,18 +1318,46 @@ composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
1145 int i; 1318 int i;
1146 1319
1147 val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch); 1320 val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
1148 for (; CONSP (val); val = XCDR (val)) 1321 if (charpos < endpos)
1149 { 1322 {
1150 elt = XCAR (val); 1323 for (; CONSP (val); val = XCDR (val))
1151 if (cmp_it->lookback == XFASTINT (AREF (elt, 1))) 1324 {
1152 break; 1325 elt = XCAR (val);
1326 if (cmp_it->lookback == XFASTINT (AREF (elt, 1)))
1327 break;
1328 }
1329 if (NILP (val))
1330 goto no_composition;
1331
1332 val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string);
1333 if (! composition_gstring_p (val))
1334 goto no_composition;
1335 cmp_it->reversed_p = 0;
1153 } 1336 }
1154 if (NILP (val)) 1337 else
1155 goto no_composition; 1338 {
1339 EMACS_INT saved_charpos = charpos, saved_bytepos = bytepos;
1156 1340
1157 val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string); 1341 if (cmp_it->lookback > 0)
1158 if (! composition_gstring_p (val)) 1342 {
1159 goto no_composition; 1343 charpos -= cmp_it->lookback;
1344 if (charpos < endpos)
1345 goto no_composition;
1346 if (STRINGP (string))
1347 bytepos = string_char_to_byte (string, charpos);
1348 else
1349 bytepos = CHAR_TO_BYTE (charpos);
1350 }
1351 val = autocmp_chars (val, charpos, bytepos, saved_charpos + 1,
1352 w, face, string);
1353 if (! composition_gstring_p (val)
1354 || charpos + LGSTRING_CHAR_LEN (val) <= saved_charpos)
1355 {
1356 charpos = saved_charpos, bytepos = saved_bytepos;
1357 goto no_composition;
1358 }
1359 cmp_it->reversed_p = 1;
1360 }
1160 if (NILP (LGSTRING_ID (val))) 1361 if (NILP (LGSTRING_ID (val)))
1161 val = composition_gstring_put_cache (val, -1); 1362 val = composition_gstring_put_cache (val, -1);
1162 cmp_it->id = XINT (LGSTRING_ID (val)); 1363 cmp_it->id = XINT (LGSTRING_ID (val));
@@ -1164,22 +1365,40 @@ composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
1164 if (NILP (LGSTRING_GLYPH (val, i))) 1365 if (NILP (LGSTRING_GLYPH (val, i)))
1165 break; 1366 break;
1166 cmp_it->nglyphs = i; 1367 cmp_it->nglyphs = i;
1368 cmp_it->from = 0;
1369 cmp_it->to = i;
1167 } 1370 }
1168 else 1371 else
1169 goto no_composition; 1372 goto no_composition;
1170 cmp_it->from = 0;
1171 return 1; 1373 return 1;
1172 1374
1173 no_composition: 1375 no_composition:
1174 charpos++; 1376 if (charpos == endpos)
1175 if (STRINGP (string)) 1377 return 0;
1176 bytepos += MULTIBYTE_LENGTH_NO_CHECK (SDATA (string) + bytepos); 1378 if (charpos < endpos)
1379 {
1380 charpos++;
1381 if (STRINGP (string))
1382 bytepos += MULTIBYTE_LENGTH_NO_CHECK (SDATA (string) + bytepos);
1383 else
1384 INC_POS (bytepos);
1385 }
1177 else 1386 else
1178 INC_POS (bytepos); 1387 {
1388 charpos--;
1389 /* BYTEPOS is calculated in composition_compute_stop_pos */
1390 bytepos = -1;
1391 }
1179 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string); 1392 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
1180 return 0; 1393 return 0;
1181} 1394}
1182 1395
1396/* Update nchars, nbytes, and width of the current grapheme cluster
1397 which is identified by CMP_IT->from (if the composition is static
1398 or automatic in l2r context) or CMPT_IT->to (if the composition is
1399 automatic in r2l context). In addition, in the former case, update
1400 CMP_IT->to, and in the latter case, update CMP_IT->from. */
1401
1183int 1402int
1184composition_update_it (cmp_it, charpos, bytepos, string) 1403composition_update_it (cmp_it, charpos, bytepos, string)
1185 struct composition_it *cmp_it; 1404 struct composition_it *cmp_it;
@@ -1215,7 +1434,7 @@ composition_update_it (cmp_it, charpos, bytepos, string)
1215 cmp_it->nchars = LGSTRING_CHAR_LEN (gstring); 1434 cmp_it->nchars = LGSTRING_CHAR_LEN (gstring);
1216 cmp_it->width = 0; 1435 cmp_it->width = 0;
1217 } 1436 }
1218 else 1437 else if (! cmp_it->reversed_p)
1219 { 1438 {
1220 Lisp_Object glyph = LGSTRING_GLYPH (gstring, cmp_it->from); 1439 Lisp_Object glyph = LGSTRING_GLYPH (gstring, cmp_it->from);
1221 int from = LGLYPH_FROM (glyph); 1440 int from = LGLYPH_FROM (glyph);
@@ -1234,6 +1453,33 @@ composition_update_it (cmp_it, charpos, bytepos, string)
1234 cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph)); 1453 cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph));
1235 } 1454 }
1236 } 1455 }
1456 else
1457 {
1458 int from_idx = cmp_it->to - 1;
1459 Lisp_Object glyph = LGSTRING_GLYPH (gstring, from_idx);
1460 int from = LGLYPH_FROM (glyph);
1461
1462 c = XINT (LGSTRING_CHAR (gstring, from));
1463 cmp_it->nchars = LGLYPH_TO (glyph) - from + 1;
1464 cmp_it->width = (LGLYPH_WIDTH (glyph) > 0
1465 ? CHAR_WIDTH (LGLYPH_CHAR (glyph)) : 0);
1466 for (from_idx--; from_idx >= 0; from_idx--)
1467 {
1468 glyph = LGSTRING_GLYPH (gstring, from_idx);
1469 if (LGLYPH_FROM (glyph) != from)
1470 break;
1471 if (LGLYPH_WIDTH (glyph) > 0)
1472 cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph));
1473 }
1474 cmp_it->from = from_idx + 1;
1475 charpos -= cmp_it->nchars - 1;
1476 bytepos += CHAR_BYTES (c);
1477 if (STRINGP (string))
1478 cmp_it->nbytes = bytepos - string_char_to_byte (string, charpos);
1479 else
1480 cmp_it->nbytes = bytepos - CHAR_TO_BYTE (charpos);
1481 return c;
1482 }
1237 } 1483 }
1238 1484
1239 charpos += cmp_it->nchars; 1485 charpos += cmp_it->nchars;
@@ -1279,17 +1525,6 @@ struct position_record
1279 (POSITION).pos--; \ 1525 (POSITION).pos--; \
1280 } while (0) 1526 } while (0)
1281 1527
1282static Lisp_Object _work_val;
1283static int _work_char;
1284
1285/* 1 iff the character C is composable. */
1286#define CHAR_COMPOSABLE_P(C) \
1287 ((C) == 0x200C || (C) == 0x200D \
1288 || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)), \
1289 (SYMBOLP (_work_val) \
1290 && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \
1291 && _work_char != 'Z')))
1292
1293/* This is like find_composition, but find an automatic composition 1528/* This is like find_composition, but find an automatic composition
1294 instead. If found, set *GSTRING to the glyph-string representing 1529 instead. If found, set *GSTRING to the glyph-string representing
1295 the composition, and return 1. Otherwise, return 0. */ 1530 the composition, and return 1. Otherwise, return 0. */
diff --git a/src/dispextern.h b/src/dispextern.h
index 72c0b2ef414..1b631493705 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1987,6 +1987,10 @@ struct composition_it
1987 graphic display and in units of canonical characters on a 1987 graphic display and in units of canonical characters on a
1988 terminal display. */ 1988 terminal display. */
1989 int width; 1989 int width;
1990 /* Nonzero iff the composition is created while buffer is scanned in
1991 reverse order, and thus the grapheme clusters must be rendered
1992 from the last to the first. */
1993 int reversed_p;
1990}; 1994};
1991 1995
1992struct it 1996struct it
diff --git a/src/xdisp.c b/src/xdisp.c
index 1e16180f7c9..34580d22a1e 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -6281,25 +6281,96 @@ set_iterator_to_next (it, reseat_p)
6281 reseat_at_next_visible_line_start (it, 0); 6281 reseat_at_next_visible_line_start (it, 0);
6282 else if (it->cmp_it.id >= 0) 6282 else if (it->cmp_it.id >= 0)
6283 { 6283 {
6284 IT_CHARPOS (*it) += it->cmp_it.nchars; 6284 /* We are currently getting glyphs from a composition. */
6285 IT_BYTEPOS (*it) += it->cmp_it.nbytes; 6285 int i;
6286 if (it->bidi_p) 6286
6287 if (! it->bidi_p)
6287 { 6288 {
6288 if (it->bidi_it.new_paragraph) 6289 IT_CHARPOS (*it) += it->cmp_it.nchars;
6289 bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it); 6290 IT_BYTEPOS (*it) += it->cmp_it.nbytes;
6290 /* Resync the bidi iterator with IT's new position. 6291 if (it->cmp_it.to < it->cmp_it.nglyphs)
6291 FIXME: this doesn't support bidirectional text. */ 6292 {
6292 while (it->bidi_it.charpos < IT_CHARPOS (*it)) 6293 it->cmp_it.from = it->cmp_it.to;
6294 }
6295 else
6296 {
6297 it->cmp_it.id = -1;
6298 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
6299 IT_BYTEPOS (*it),
6300 it->stop_charpos, Qnil);
6301 }
6302 }
6303 else if (! it->cmp_it.reversed_p)
6304 {
6305 /* Composition created while scanning forward. */
6306 /* Update IT's char/byte positions to point the first
6307 character of the next grapheme cluster, or to the
6308 character visually after the current composition. */
6309#if 0
6310 /* Is it ok to do this directly? */
6311 IT_CHARPOS (*it) += it->cmp_it.nchars;
6312 IT_BYTEPOS (*it) += it->cmp_it.nbytes;
6313#else
6314 /* Or do we have to call bidi_get_next_char_visually
6315 repeatedly (perhaps not to confuse some internal
6316 state of bidi_it)? At least we must do this if we
6317 have consumed all grapheme clusters in the current
6318 composition because the next character will be in the
6319 different bidi level. */
6320 for (i = 0; i < it->cmp_it.nchars; i++)
6293 bidi_get_next_char_visually (&it->bidi_it); 6321 bidi_get_next_char_visually (&it->bidi_it);
6322 /* BTW, it seems that the name
6323 bidi_get_next_char_visually is confusing because
6324 it sounds like not advancing character position.
6325 How about bidi_set_iterator_to_next? */
6326 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
6327 IT_CHARPOS (*it) = it->bidi_it.charpos;
6328#endif
6329 if (it->cmp_it.to < it->cmp_it.nglyphs)
6330 {
6331 /* Proceed to the next grapheme cluster. */
6332 it->cmp_it.from = it->cmp_it.to;
6333 }
6334 else
6335 {
6336 /* No more grapheme cluster in this composition.
6337 Find the next stop position. */
6338 EMACS_INT stop = it->stop_charpos;
6339 if (it->bidi_it.scan_dir < 0)
6340 /* Now we are scanning backward and don't know
6341 where to stop. */
6342 stop = -1;
6343 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
6344 IT_BYTEPOS (*it), stop, Qnil);
6345 }
6294 } 6346 }
6295 if (it->cmp_it.to < it->cmp_it.nglyphs)
6296 it->cmp_it.from = it->cmp_it.to;
6297 else 6347 else
6298 { 6348 {
6299 it->cmp_it.id = -1; 6349 /* Composition created while scanning backward. */
6300 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it), 6350 /* Update IT's char/byte positions to point the last
6301 IT_BYTEPOS (*it), it->stop_charpos, 6351 character of the previous grapheme cluster, or the
6302 Qnil); 6352 character visually after the current composition. */
6353 bidi_get_next_char_visually (&it->bidi_it);
6354 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
6355 IT_CHARPOS (*it) = it->bidi_it.charpos;
6356
6357 if (it->cmp_it.from > 0)
6358 {
6359 /* Proceed to the previous grapheme cluster. */
6360 it->cmp_it.to = it->cmp_it.from;
6361 }
6362 else
6363 {
6364 /* No more grapheme cluster in this composition.
6365 Find the next stop position. */
6366 EMACS_INT stop = it->stop_charpos;
6367 if (it->bidi_it.scan_dir < 0)
6368 /* Now we are scanning backward and don't know
6369 where to stop. */
6370 stop = -1;
6371 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
6372 IT_BYTEPOS (*it), stop, Qnil);
6373 }
6303 } 6374 }
6304 } 6375 }
6305 else 6376 else
@@ -6313,6 +6384,7 @@ set_iterator_to_next (it, reseat_p)
6313 } 6384 }
6314 else 6385 else
6315 { 6386 {
6387 int prev_scan_dir = it->bidi_it.scan_dir;
6316 /* If this is a new paragraph, determine its base 6388 /* If this is a new paragraph, determine its base
6317 direction (a.k.a. its base embedding level). */ 6389 direction (a.k.a. its base embedding level). */
6318 if (it->bidi_it.new_paragraph) 6390 if (it->bidi_it.new_paragraph)
@@ -6320,6 +6392,16 @@ set_iterator_to_next (it, reseat_p)
6320 bidi_get_next_char_visually (&it->bidi_it); 6392 bidi_get_next_char_visually (&it->bidi_it);
6321 IT_BYTEPOS (*it) = it->bidi_it.bytepos; 6393 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
6322 IT_CHARPOS (*it) = it->bidi_it.charpos; 6394 IT_CHARPOS (*it) = it->bidi_it.charpos;
6395 if (prev_scan_dir != it->bidi_it.scan_dir)
6396 {
6397 /* As scan direction was changed, we must re-compute
6398 the stop position for composition. */
6399 EMACS_INT stop = it->stop_charpos;
6400 if (it->bidi_it.scan_dir < 0)
6401 stop = -1;
6402 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
6403 IT_BYTEPOS (*it), stop, Qnil);
6404 }
6323 } 6405 }
6324 xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it))); 6406 xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
6325 } 6407 }
@@ -6816,6 +6898,13 @@ next_element_from_buffer (it)
6816 IT_CHARPOS (*it) = it->bidi_it.charpos; 6898 IT_CHARPOS (*it) = it->bidi_it.charpos;
6817 IT_BYTEPOS (*it) = it->bidi_it.bytepos; 6899 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
6818 SET_TEXT_POS (it->position, IT_CHARPOS (*it), IT_BYTEPOS (*it)); 6900 SET_TEXT_POS (it->position, IT_CHARPOS (*it), IT_BYTEPOS (*it));
6901 {
6902 EMACS_INT stop = it->stop_charpos;
6903 if (it->bidi_it.scan_dir < 0)
6904 stop = -1;
6905 composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
6906 IT_BYTEPOS (*it), stop, Qnil);
6907 }
6819 } 6908 }
6820 6909
6821 if (IT_CHARPOS (*it) >= it->stop_charpos) 6910 if (IT_CHARPOS (*it) >= it->stop_charpos)
@@ -6893,6 +6982,7 @@ next_element_from_buffer (it)
6893 /* No face changes, overlays etc. in sight, so just return a 6982 /* No face changes, overlays etc. in sight, so just return a
6894 character from current_buffer. */ 6983 character from current_buffer. */
6895 unsigned char *p; 6984 unsigned char *p;
6985 EMACS_INT stop;
6896 6986
6897 /* Maybe run the redisplay end trigger hook. Performance note: 6987 /* Maybe run the redisplay end trigger hook. Performance note:
6898 This doesn't seem to cost measurable time. */ 6988 This doesn't seem to cost measurable time. */
@@ -6901,8 +6991,9 @@ next_element_from_buffer (it)
6901 && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos) 6991 && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
6902 run_redisplay_end_trigger_hook (it); 6992 run_redisplay_end_trigger_hook (it);
6903 6993
6994 stop = it->bidi_it.scan_dir < 0 ? -1 : it->end_charpos;
6904 if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it), 6995 if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it),
6905 it->end_charpos) 6996 stop)
6906 && next_element_from_composition (it)) 6997 && next_element_from_composition (it))
6907 { 6998 {
6908 return 1; 6999 return 1;
@@ -7028,6 +7119,19 @@ next_element_from_composition (it)
7028 it->object = it->w->buffer; 7119 it->object = it->w->buffer;
7029 it->c = composition_update_it (&it->cmp_it, IT_CHARPOS (*it), 7120 it->c = composition_update_it (&it->cmp_it, IT_CHARPOS (*it),
7030 IT_BYTEPOS (*it), Qnil); 7121 IT_BYTEPOS (*it), Qnil);
7122 if (it->cmp_it.reversed_p)
7123 {
7124 /* Now it->position points the last character of the current
7125 grapheme cluster. Adjust it to point the first one. We
7126 have to do it here so that append_composite_glyph sets
7127 correct (struct glyph)->charpos. */
7128 int i;
7129 for (i = 0; i < it->cmp_it.nchars - 1; i++)
7130 bidi_get_next_char_visually (&it->bidi_it);
7131 IT_CHARPOS (*it) = it->bidi_it.charpos;
7132 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
7133 it->position = it->current.pos;
7134 }
7031 } 7135 }
7032 return 1; 7136 return 1;
7033} 7137}