From bef691023fadfe48a51651515a638fb448dd5ef5 Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Tue, 3 Oct 2023 10:43:18 +0000 Subject: [PATCH] Bug 1848282 - Part 3. a11y's word segmenter should reference layout.word_select preferences. r=morgan We need to consider `layout.word_select.stop_at_punctuation preference` even if using new segmenter. Differential Revision: https://phabricator.services.mozilla.com/D188786 --- accessible/base/TextLeafRange.cpp | 41 +++++++++++++++++-- .../tests/browser/mac/browser_text_basics.js | 33 +++++++++++++-- .../browser/mac/doc_textmarker_test.html | 16 ++++---- .../browser/text/browser_textleafpoint.js | 39 ++++++++++++++++++ .../tests/mochitest/text/test_words.html | 20 +++++---- 5 files changed, 126 insertions(+), 23 deletions(-) diff --git a/accessible/base/TextLeafRange.cpp b/accessible/base/TextLeafRange.cpp index b437ca088b6f..9b658e12af5b 100644 --- a/accessible/base/TextLeafRange.cpp +++ b/accessible/base/TextLeafRange.cpp @@ -36,6 +36,7 @@ #include "TextAttrs.h" using mozilla::intl::WordBreaker; +using FindWordOptions = mozilla::intl::WordBreaker::FindWordOptions; namespace mozilla::a11y { @@ -826,11 +827,23 @@ TextLeafPoint TextLeafPoint::FindPrevWordStartSameAcc( if (mOffset == 0) { word.mBegin = 0; } else if (mOffset == static_cast(text.Length())) { - word = WordBreaker::FindWord(text, mOffset - 1); + word = WordBreaker::FindWord( + text, mOffset - 1, + StaticPrefs::layout_word_select_stop_at_punctuation() + ? FindWordOptions::StopAtPunctuation + : FindWordOptions::None); } else { - word = WordBreaker::FindWord(text, mOffset); + word = WordBreaker::FindWord( + text, mOffset, + StaticPrefs::layout_word_select_stop_at_punctuation() + ? FindWordOptions::StopAtPunctuation + : FindWordOptions::None); } - for (;; word = WordBreaker::FindWord(text, word.mBegin - 1)) { + for (;; word = WordBreaker::FindWord( + text, word.mBegin - 1, + StaticPrefs::layout_word_select_stop_at_punctuation() + ? FindWordOptions::StopAtPunctuation + : FindWordOptions::None)) { if (!aIncludeOrigin && static_cast(word.mBegin) == mOffset) { // A word possibly starts at the origin, but the caller doesn't want this // included. @@ -887,6 +900,7 @@ TextLeafPoint TextLeafPoint::FindNextWordStartSameAcc( } // Keep walking forward until we find an acceptable word start. intl::WordBreakIteratorUtf16 wordBreakIter(text); + int32_t previousPos = wordStart; Maybe nextBreak = wordBreakIter.Seek(wordStart); for (;;) { if (!nextBreak || *nextBreak == text.Length()) { @@ -894,6 +908,16 @@ TextLeafPoint TextLeafPoint::FindNextWordStartSameAcc( // A line start always starts a new word. return lineStart; } + if (StaticPrefs::layout_word_select_stop_at_punctuation()) { + // If layout.word_select.stop_at_punctuation is true, we have to look + // for punctuation class since it may not break state in UAX#29. + for (int32_t i = previousPos + 1; + i < static_cast(text.Length()); i++) { + if (IsAcceptableWordStart(mAcc, text, i)) { + return TextLeafPoint(mAcc, i); + } + } + } return TextLeafPoint(); } wordStart = AssertedCast(*nextBreak); @@ -904,6 +928,17 @@ TextLeafPoint TextLeafPoint::FindNextWordStartSameAcc( if (IsAcceptableWordStart(mAcc, text, wordStart)) { break; } + + if (StaticPrefs::layout_word_select_stop_at_punctuation()) { + // If layout.word_select.stop_at_punctuation is true, we have to look + // for punctuation class since it may not break state in UAX#29. + for (int32_t i = previousPos + 1; i < wordStart; i++) { + if (IsAcceptableWordStart(mAcc, text, i)) { + return TextLeafPoint(mAcc, i); + } + } + } + previousPos = wordStart; nextBreak = wordBreakIter.Next(); } return TextLeafPoint(mAcc, wordStart); diff --git a/accessible/tests/browser/mac/browser_text_basics.js b/accessible/tests/browser/mac/browser_text_basics.js index e37bb8ca45e0..156d691ca9e1 100644 --- a/accessible/tests/browser/mac/browser_text_basics.js +++ b/accessible/tests/browser/mac/browser_text_basics.js @@ -248,11 +248,14 @@ function testMarkerIntegrity(accDoc, expectedMarkerValues) { // Run tests with old word segmenter addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => { await SpecialPowers.pushPrefEnv({ - set: [["intl.icu4x.segmenter.enabled", false]], + set: [ + ["intl.icu4x.segmenter.enabled", false], + ["layout.word_select.stop_at_punctuation", true], // This is default + ], }); const expectedValues = await SpecialPowers.spawn(browser, [], async () => { - return content.wrappedJSObject.getExpected(false); + return content.wrappedJSObject.getExpected(false, true); }); testMarkerIntegrity(accDoc, expectedValues); @@ -260,13 +263,35 @@ addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => { await SpecialPowers.popPrefEnv(); }); +// new UAX#14 segmenter without stop_at_punctuation. addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => { await SpecialPowers.pushPrefEnv({ - set: [["intl.icu4x.segmenter.enabled", true]], + set: [ + ["intl.icu4x.segmenter.enabled", true], + ["layout.word_select.stop_at_punctuation", false], + ], }); const expectedValues = await SpecialPowers.spawn(browser, [], async () => { - return content.wrappedJSObject.getExpected(true); + return content.wrappedJSObject.getExpected(true, false); + }); + + testMarkerIntegrity(accDoc, expectedValues); + + await SpecialPowers.popPrefEnv(); +}); + +// new UAX#14 segmenter with stop_at_punctuation +addAccessibleTask("mac/doc_textmarker_test.html", async (browser, accDoc) => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["intl.icu4x.segmenter.enabled", true], + ["layout.word_select.stop_at_punctuation", true], // this is default + ], + }); + + const expectedValues = await SpecialPowers.spawn(browser, [], async () => { + return content.wrappedJSObject.getExpected(true, true); }); testMarkerIntegrity(accDoc, expectedValues); diff --git a/accessible/tests/browser/mac/doc_textmarker_test.html b/accessible/tests/browser/mac/doc_textmarker_test.html index 73ba380ccc72..9584d28e09f4 100644 --- a/accessible/tests/browser/mac/doc_textmarker_test.html +++ b/accessible/tests/browser/mac/doc_textmarker_test.html @@ -19,7 +19,7 @@