From abf39ed185f128c5b523c81db741c6d926b9fb7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 21 Aug 2024 01:14:16 -0700 Subject: [PATCH] =?UTF-8?q?Fixed=20character=E2=80=93section=20mapping=20d?= =?UTF-8?q?uring=20bidi=20processing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/symbol/shaping.test.ts | 12 ++++++------ src/symbol/shaping.ts | 23 ++++++++++++++++++----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/symbol/shaping.test.ts b/src/symbol/shaping.test.ts index 188fc42b33..b45c61ae4a 100644 --- a/src/symbol/shaping.test.ts +++ b/src/symbol/shaping.test.ts @@ -57,12 +57,12 @@ describe('TaggedString', () => { test('splits surrogate pairs', () => { const tagged = new TaggedString(); tagged.text = '𰻞𰻞麵𪚥𪚥'; - expect(tagged.codeUnitIndex(0)).toBe(0); - expect(tagged.codeUnitIndex(1)).toBe(2); - expect(tagged.codeUnitIndex(2)).toBe(4); - expect(tagged.codeUnitIndex(3)).toBe(5); - expect(tagged.codeUnitIndex(4)).toBe(7); - expect(tagged.codeUnitIndex(5)).toBe(9); + expect(tagged.toCodeUnitIndex(0)).toBe(0); + expect(tagged.toCodeUnitIndex(1)).toBe(2); + expect(tagged.toCodeUnitIndex(2)).toBe(4); + expect(tagged.toCodeUnitIndex(3)).toBe(5); + expect(tagged.toCodeUnitIndex(4)).toBe(7); + expect(tagged.toCodeUnitIndex(5)).toBe(9); }); }); }); diff --git a/src/symbol/shaping.ts b/src/symbol/shaping.ts index 45ecbf5c70..baeefec516 100644 --- a/src/symbol/shaping.ts +++ b/src/symbol/shaping.ts @@ -166,7 +166,7 @@ export class TaggedString { /** * Converts a UTF-16 character index to a UTF-16 code unit (JavaScript character index). */ - codeUnitIndex(unicodeIndex: number): number { + toCodeUnitIndex(unicodeIndex: number): number { return [...this.text].slice(0, unicodeIndex).join('').length; } @@ -270,7 +270,7 @@ function shapeText( // Bidi doesn't have to be style-aware lines = []; // ICU operates on code units. - lineBreaks = lineBreaks.map(index => logicalInput.codeUnitIndex(index)); + lineBreaks = lineBreaks.map(index => logicalInput.toCodeUnitIndex(index)); const untaggedLines = processBidirectionalText(logicalInput.toString(), lineBreaks); for (const line of untaggedLines) { @@ -288,14 +288,27 @@ function shapeText( // with formatting lines = []; // ICU operates on code units. - lineBreaks = lineBreaks.map(index => logicalInput.codeUnitIndex(index)); + lineBreaks = lineBreaks.map(index => logicalInput.toCodeUnitIndex(index)); + + // Convert character-based section index to be based on code units. + let i = 0; + const sectionIndex = []; + for (const char of logicalInput.text) { + sectionIndex.push(...Array(char.length).fill(logicalInput.sectionIndex[i])); + i++; + } + const processedLines = - processStyledBidirectionalText(logicalInput.text, logicalInput.sectionIndex, lineBreaks); + processStyledBidirectionalText(logicalInput.text, sectionIndex, lineBreaks); for (const line of processedLines) { const taggedLine = new TaggedString(); taggedLine.text = line[0]; - taggedLine.sectionIndex = line[1]; taggedLine.sections = logicalInput.sections; + let elapsedChars = ''; + for (const char of line[0]) { + taggedLine.sectionIndex.push(line[1][elapsedChars.length]); + elapsedChars += char; + } lines.push(taggedLine); } } else {