From ac8cdd67597cbdc831860ec3dddd01ee133be6d4 Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Mon, 24 Sep 2018 20:37:01 +0000 Subject: [PATCH] Bug 1127855 - Handle title highlighting properly in all locales r=nalexander This patch uses a case-insensitive matcher to highlight the title of a history entry that's been typed by the user. Previously the matching substring was calculated manually as lowercase assuming that it's representation would have the same number of characters as the original mixed case. In some locales howerver this assumption is wrong leading to out-of-bound exceptions when highlighting part of the title. Differential Revision: https://phabricator.services.mozilla.com/D6661 --HG-- extra : moz-landing-system : lando --- .../org/mozilla/gecko/home/BrowserSearch.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java b/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java index e25d1067a995..0d87e8bdb025 100644 --- a/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java +++ b/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java @@ -14,6 +14,8 @@ import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import android.content.SharedPreferences; @@ -1209,29 +1211,24 @@ public class BrowserSearch extends HomeFragment private TwoLinePageRow.TitleFormatter mTwoLinePageRowTitleFormatter = new TwoLinePageRow.TitleFormatter() { @Override public CharSequence format(@NonNull CharSequence title) { - // Don't try to search for an empty string - String.indexOf will return 0, which would result - // in us iterating with lastIndexOfMatch = 0, which eventually results in an OOM. + // Don't try to search for an empty string, we would get a match for every character in the title if (TextUtils.isEmpty(mSearchTerm)) { return title; } - // Find matching substrings in title field in TwoLinePageRow, ignoring cases. - final String titleInLowerCase = title.toString().toLowerCase(); - final String pattern = mSearchTerm.toLowerCase(); - final int patternLength = pattern.length(); - final SpannableStringBuilder sb = new SpannableStringBuilder(title); - int indexOfMatch = 0; - int lastIndexOfMatch = 0; - while (indexOfMatch != -1) { - indexOfMatch = titleInLowerCase.indexOf(pattern, lastIndexOfMatch); - lastIndexOfMatch = indexOfMatch + patternLength; - if (indexOfMatch != -1) { - final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD); - sb.setSpan(boldSpan, indexOfMatch, lastIndexOfMatch, Spannable.SPAN_INCLUSIVE_INCLUSIVE); - } + // Find matching substrings in title field in TwoLinePageRow, ignoring cases. This needs + // to be done indirectly through a case-insensitive matcher because the lower-case + // version of a string might have a different number of characters than the original. + Pattern pattern = Pattern.compile(mSearchTerm, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(title.toString()); + + while (matcher.find()) { + final StyleSpan boldSpan = new StyleSpan(Typeface.BOLD); + sb.setSpan(boldSpan, matcher.start(), matcher.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); } + return sb; } }; @@ -1385,4 +1382,4 @@ public class BrowserSearch extends HomeFragment setSelector(isPrivate ? R.drawable.search_list_selector_private : R.drawable.search_list_selector); } } -} \ No newline at end of file +}