|
15 | 15 |
|
16 | 16 | import { warn } from "../shared/util.js"; |
17 | 17 |
|
| 18 | +// Implements a subset of the Unicode Bidirectional Algorithm (UBA). |
| 19 | +// Specification: https://www.unicode.org/reports/tr9/tr9-48.html |
| 20 | + |
18 | 21 | // Character types for symbols from 0000 to 00FF. |
19 | 22 | // Source: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt |
20 | 23 | // prettier-ignore |
@@ -297,25 +300,42 @@ function bidi(str, startLevel = -1, vertical = false) { |
297 | 300 | text if the text on both sides has the same direction. European and Arabic |
298 | 301 | numbers are treated as though they were R. Start-of-level-run (sor) and |
299 | 302 | end-of-level-run (eor) are used at level run boundaries. |
| 303 | + See https://www.unicode.org/reports/tr9/tr9-48.html#N1 |
300 | 304 | */ |
301 | 305 | for (i = 0; i < strLength; ++i) { |
302 | 306 | if (types[i] === "ON") { |
303 | 307 | const end = findUnequal(types, i + 1, "ON"); |
| 308 | + |
| 309 | + // Scan left past non-strong types to find the nearest strong context |
| 310 | + // (L, R, EN, or AN), falling back to sor at the level-run boundary. |
304 | 311 | let before = sor; |
305 | | - if (i > 0) { |
306 | | - before = types[i - 1]; |
| 312 | + for (let j = i - 1; j >= 0; j--) { |
| 313 | + const tt = types[j]; |
| 314 | + if (tt === "L") { |
| 315 | + before = "L"; |
| 316 | + break; |
| 317 | + } |
| 318 | + if (tt === "R" || tt === "EN" || tt === "AN") { |
| 319 | + before = "R"; |
| 320 | + break; |
| 321 | + } |
307 | 322 | } |
308 | 323 |
|
| 324 | + // Scan right past non-strong types to find the nearest strong context, |
| 325 | + // falling back to eor at the level-run boundary. |
309 | 326 | let after = eor; |
310 | | - if (end + 1 < strLength) { |
311 | | - after = types[end + 1]; |
312 | | - } |
313 | | - if (before !== "L") { |
314 | | - before = "R"; |
315 | | - } |
316 | | - if (after !== "L") { |
317 | | - after = "R"; |
| 327 | + for (let j = end; j < strLength; j++) { |
| 328 | + const tt = types[j]; |
| 329 | + if (tt === "L") { |
| 330 | + after = "L"; |
| 331 | + break; |
| 332 | + } |
| 333 | + if (tt === "R" || tt === "EN" || tt === "AN") { |
| 334 | + after = "R"; |
| 335 | + break; |
| 336 | + } |
318 | 337 | } |
| 338 | + |
319 | 339 | if (before === after) { |
320 | 340 | types.fill(before, i, end); |
321 | 341 | } |
|
0 commit comments