diff options
| author | Kenichi Handa | 2010-05-14 13:14:23 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2010-05-14 13:14:23 +0900 |
| commit | 82ebc97b11a369303345927c98e7bc69928c9117 (patch) | |
| tree | 5fc673dace42fbb438848c3c6ffda1eb47188857 /src | |
| parent | 1f8162fe7761eba6a4051e242de825fdc7d7512b (diff) | |
| download | emacs-82ebc97b11a369303345927c98e7bc69928c9117.tar.gz emacs-82ebc97b11a369303345927c98e7bc69928c9117.zip | |
Fix bidi-composition interaction.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 19 | ||||
| -rw-r--r-- | src/composite.c | 363 | ||||
| -rw-r--r-- | src/dispextern.h | 4 | ||||
| -rw-r--r-- | src/xdisp.c | 134 |
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 @@ | |||
| 1 | 2010-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 | |||
| 1 | 2010-05-10 Glenn Morris <rgm@gnu.org> | 20 | 2010-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 | ||
| 1021 | static Lisp_Object _work_val; | ||
| 1022 | static 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 | ||
| 1028 | void | 1045 | void |
| 1029 | composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string) | 1046 | composition_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 | ||
| 1110 | int | 1267 | int |
| 1111 | composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string) | 1268 | composition_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 | |||
| 1183 | int | 1402 | int |
| 1184 | composition_update_it (cmp_it, charpos, bytepos, string) | 1403 | composition_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 | ||
| 1282 | static Lisp_Object _work_val; | ||
| 1283 | static 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 | ||
| 1992 | struct it | 1996 | struct 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 | } |