Expand characters temporarily skipped in spellchecking
An earlier patch (I4d09576a31df551c96f820242fd2cbc675506dae) special-cased apostrophe as a character to defer spellchecking on, since it could cause a word break which could later get removed. This patch updates that earlier patch to include all characters that could cause such a behavior according the Unicode word breaking algorithm defined in UAX #29. Bug: 17641350 Bug: 17673522 Test: manual Change-Id: I4029e3d91dfcf96665b003f6fdd30d1208b0ac7c
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
package android.text.method;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.icu.lang.UCharacter;
|
||||
import android.icu.lang.UProperty;
|
||||
import android.icu.text.BreakIterator;
|
||||
import android.text.CharSequenceCharacterIterator;
|
||||
import android.text.Selection;
|
||||
@@ -321,6 +323,27 @@ public class WordIterator implements Selection.PositionIterator {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the codepoint is a mid-word-only punctuation.
|
||||
*
|
||||
* At the moment, this is locale-independent, and includes all the characters in
|
||||
* the MidLetter, MidNumLet, and Single_Quote class of Unicode word breaking algorithm (see
|
||||
* UAX #29 "Unicode Text Segmentation" at http://unicode.org/reports/tr29/). These are all the
|
||||
* characters that according to the rules WB6 and WB7 of UAX #29 prevent word breaks if they are
|
||||
* in the middle of a word, but they become word breaks if they happen at the end of a word
|
||||
* (accroding to rule WB999 that breaks word in any place that is not prohibited otherwise).
|
||||
*
|
||||
* @param locale the locale to consider the codepoint in. Presently ignored.
|
||||
* @param codePoint the codepoint to check.
|
||||
* @return True if the codepoint is a mid-word punctuation.
|
||||
*/
|
||||
public static boolean isMidWordPunctuation(Locale locale, int codePoint) {
|
||||
final int wb = UCharacter.getIntPropertyValue(codePoint, UProperty.WORD_BREAK);
|
||||
return (wb == UCharacter.WordBreak.MIDLETTER
|
||||
|| wb == UCharacter.WordBreak.MIDNUMLET
|
||||
|| wb == UCharacter.WordBreak.SINGLE_QUOTE);
|
||||
}
|
||||
|
||||
private boolean isPunctuationStartBoundary(int offset) {
|
||||
return isOnPunctuation(offset) && !isAfterPunctuation(offset);
|
||||
}
|
||||
@@ -331,13 +354,13 @@ public class WordIterator implements Selection.PositionIterator {
|
||||
|
||||
private static boolean isPunctuation(int cp) {
|
||||
final int type = Character.getType(cp);
|
||||
return (type == Character.CONNECTOR_PUNCTUATION ||
|
||||
type == Character.DASH_PUNCTUATION ||
|
||||
type == Character.END_PUNCTUATION ||
|
||||
type == Character.FINAL_QUOTE_PUNCTUATION ||
|
||||
type == Character.INITIAL_QUOTE_PUNCTUATION ||
|
||||
type == Character.OTHER_PUNCTUATION ||
|
||||
type == Character.START_PUNCTUATION);
|
||||
return (type == Character.CONNECTOR_PUNCTUATION
|
||||
|| type == Character.DASH_PUNCTUATION
|
||||
|| type == Character.END_PUNCTUATION
|
||||
|| type == Character.FINAL_QUOTE_PUNCTUATION
|
||||
|| type == Character.INITIAL_QUOTE_PUNCTUATION
|
||||
|| type == Character.OTHER_PUNCTUATION
|
||||
|| type == Character.START_PUNCTUATION);
|
||||
}
|
||||
|
||||
private boolean isAfterLetterOrDigit(int offset) {
|
||||
|
||||
@@ -277,18 +277,19 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
||||
// Do not check this word if the user is currently editing it
|
||||
final boolean isEditing;
|
||||
|
||||
// Defer spell check when typing a word with an interior apostrophe.
|
||||
// TODO: a better solution to this would be to make the word
|
||||
// iterator locale-sensitive and include the apostrophe in
|
||||
// languages that use it (such as English).
|
||||
final boolean apostrophe = (selectionStart == end + 1 && editable.charAt(end) == '\'');
|
||||
if (mIsSentenceSpellCheckSupported) {
|
||||
// Defer spell check when typing a word ending with a punctuation like an apostrophe
|
||||
// which could end up being a mid-word punctuation.
|
||||
if (selectionStart == end + 1
|
||||
&& WordIterator.isMidWordPunctuation(
|
||||
mCurrentLocale, Character.codePointBefore(editable, end + 1))) {
|
||||
isEditing = false;
|
||||
} else if (mIsSentenceSpellCheckSupported) {
|
||||
// Allow the overlap of the cursor and the first boundary of the spell check span
|
||||
// no to skip the spell check of the following word because the
|
||||
// following word will never be spell-checked even if the user finishes composing
|
||||
isEditing = !apostrophe && (selectionEnd <= start || selectionStart > end);
|
||||
isEditing = selectionEnd <= start || selectionStart > end;
|
||||
} else {
|
||||
isEditing = !apostrophe && (selectionEnd < start || selectionStart > end);
|
||||
isEditing = selectionEnd < start || selectionStart > end;
|
||||
}
|
||||
if (start >= 0 && end > start && isEditing) {
|
||||
spellCheckSpan.setSpellCheckInProgress(true);
|
||||
|
||||
Reference in New Issue
Block a user