Skip to content

Commit 711c33e

Browse files
committed
Fixed grapheme–section mapping during bidi processing
1 parent 17ebe56 commit 711c33e

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

src/symbol/shaping.test.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ describe('TaggedString', () => {
5858
test('splits surrogate pairs', () => {
5959
const tagged = new TaggedString();
6060
tagged.text = '𰻞𰻞麵𪚥𪚥';
61-
expect(tagged.codeUnitIndex(0)).toBe(0);
62-
expect(tagged.codeUnitIndex(1)).toBe(2);
63-
expect(tagged.codeUnitIndex(2)).toBe(4);
64-
expect(tagged.codeUnitIndex(3)).toBe(5);
65-
expect(tagged.codeUnitIndex(4)).toBe(7);
66-
expect(tagged.codeUnitIndex(5)).toBe(9);
61+
expect(tagged.toCodeUnitIndex(0)).toBe(0);
62+
expect(tagged.toCodeUnitIndex(1)).toBe(2);
63+
expect(tagged.toCodeUnitIndex(2)).toBe(4);
64+
expect(tagged.toCodeUnitIndex(3)).toBe(5);
65+
expect(tagged.toCodeUnitIndex(4)).toBe(7);
66+
expect(tagged.toCodeUnitIndex(5)).toBe(9);
6767
});
6868
});
6969
});

src/symbol/shaping.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export class TaggedString {
167167
/**
168168
* Converts a grapheme cluster index to a UTF-16 code unit (JavaScript character index).
169169
*/
170-
codeUnitIndex(unicodeIndex: number): number {
170+
toCodeUnitIndex(unicodeIndex: number): number {
171171
return splitByGraphemeCluster(this.text).slice(0, unicodeIndex).join('').length;
172172
}
173173

@@ -271,7 +271,7 @@ function shapeText(
271271
// Bidi doesn't have to be style-aware
272272
lines = [];
273273
// ICU operates on code units.
274-
lineBreaks = lineBreaks.map(index => logicalInput.codeUnitIndex(index));
274+
lineBreaks = lineBreaks.map(index => logicalInput.toCodeUnitIndex(index));
275275
const untaggedLines =
276276
processBidirectionalText(logicalInput.toString(), lineBreaks);
277277
for (const line of untaggedLines) {
@@ -289,9 +289,20 @@ function shapeText(
289289
// with formatting
290290
lines = [];
291291
// ICU operates on code units.
292-
lineBreaks = lineBreaks.map(index => logicalInput.codeUnitIndex(index));
292+
lineBreaks = lineBreaks.map(index => logicalInput.toCodeUnitIndex(index));
293+
294+
// Convert grapheme cluster–based section index to be based on code units.
295+
let i = 0;
296+
let elapsedCodeUnits = 0;
297+
let sectionIndex = [];
298+
for (const grapheme of splitByGraphemeCluster(logicalInput.text)) {
299+
sectionIndex.push(...Array(grapheme.length).fill(logicalInput.sectionIndex[i]));
300+
i++;
301+
elapsedCodeUnits += grapheme.length;
302+
}
303+
293304
const processedLines =
294-
processStyledBidirectionalText(logicalInput.text, logicalInput.sectionIndex, lineBreaks);
305+
processStyledBidirectionalText(logicalInput.text, sectionIndex, lineBreaks);
295306
for (const line of processedLines) {
296307
const taggedLine = new TaggedString();
297308
taggedLine.text = line[0];

0 commit comments

Comments
 (0)