Index: components/drive/search_metadata.cc |
diff --git a/components/drive/search_metadata.cc b/components/drive/search_metadata.cc |
index 381e81fb0db9260cbd4f4a3778abfcae8c63ddfd..fcc35313fa2781e211cf67bdebc125e0ff3ecf8d 100644 |
--- a/components/drive/search_metadata.cc |
+++ b/components/drive/search_metadata.cc |
@@ -10,6 +10,9 @@ |
#include "base/bind.h" |
#include "base/i18n/string_search.h" |
#include "base/metrics/histogram.h" |
+#include "base/strings/string_piece.h" |
+#include "base/strings/string_split.h" |
+#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/time/time.h" |
#include "components/drive/drive_api_util.h" |
@@ -141,12 +144,13 @@ class HiddenEntryClassifier { |
// Used to implement SearchMetadata. |
// Adds entry to the result when appropriate. |
-// In particular, if |query| is non-null, only adds files with the name matching |
-// the query. |
+// In particular, if size of |queries| is larger than 0, only adds files with |
+// the name matching the query. |
FileError MaybeAddEntryToResult( |
ResourceMetadata* resource_metadata, |
ResourceMetadata::Iterator* it, |
- base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents* query, |
+ const ScopedVector< |
+ base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>& queries, |
const SearchMetadataPredicate& predicate, |
size_t at_most_num_matches, |
HiddenEntryClassifier* hidden_entry_classifier, |
@@ -168,7 +172,7 @@ FileError MaybeAddEntryToResult( |
// contain |query| to match the query. |
std::string highlighted; |
if (!predicate.Run(entry) || |
- (query && !FindAndHighlight(entry.base_name(), query, &highlighted))) |
+ !FindAndHighlight(entry.base_name(), queries, &highlighted)) |
return FILE_ERROR_OK; |
// Hidden entry should not be returned. |
@@ -194,8 +198,18 @@ FileError SearchMetadataOnBlockingPool(ResourceMetadata* resource_metadata, |
ResultCandidateComparator> result_candidates; |
// Prepare data structure for searching. |
- base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents query( |
- base::UTF8ToUTF16(query_text)); |
+ std::vector<base::string16> keywords = |
+ base::SplitString(base::UTF8ToUTF16(query_text), |
+ base::StringPiece16(base::kWhitespaceUTF16), |
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
+ |
+ ScopedVector<base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents> |
+ queries; |
+ for (const auto& keyword : keywords) { |
+ queries.push_back( |
+ new base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents( |
+ keyword)); |
+ } |
// Prepare an object to filter out hidden entries. |
ResourceEntry mydrive; |
@@ -210,9 +224,8 @@ FileError SearchMetadataOnBlockingPool(ResourceMetadata* resource_metadata, |
scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata->GetIterator(); |
for (; !it->IsAtEnd(); it->Advance()) { |
FileError error = MaybeAddEntryToResult( |
- resource_metadata, it.get(), query_text.empty() ? NULL : &query, |
- predicate, at_most_num_matches, &hidden_entry_classifier, |
- &result_candidates); |
+ resource_metadata, it.get(), queries, predicate, at_most_num_matches, |
+ &hidden_entry_classifier, &result_candidates); |
if (error != FILE_ERROR_OK) |
return error; |
} |
@@ -253,6 +266,22 @@ void RunSearchMetadataCallback(const SearchMetadataCallback& callback, |
base::TimeTicks::Now() - start_time); |
} |
+// Appends substring of |original_text| to |highlighted_text| with highlight. |
+void AppendStringWithHighlight(const base::string16& original_text, |
+ size_t start, |
+ size_t length, |
+ bool highlight, |
+ std::string* highlighted_text) { |
+ if (highlight) |
+ highlighted_text->append("<b>"); |
+ |
+ highlighted_text->append(net::EscapeForHTML( |
+ base::UTF16ToUTF8(original_text.substr(start, length)))); |
+ |
+ if (highlight) |
+ highlighted_text->append("</b>"); |
+} |
+ |
} // namespace |
void SearchMetadata( |
@@ -308,26 +337,45 @@ bool MatchesType(int options, const ResourceEntry& entry) { |
bool FindAndHighlight( |
const std::string& text, |
- base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents* query, |
+ const ScopedVector< |
+ base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>& queries, |
std::string* highlighted_text) { |
- DCHECK(query); |
DCHECK(highlighted_text); |
highlighted_text->clear(); |
- base::string16 text16 = base::UTF8ToUTF16(text); |
+ // Check text matches with all queries. |
size_t match_start = 0; |
size_t match_length = 0; |
- if (!query->Search(text16, &match_start, &match_length)) |
- return false; |
- base::string16 pre = text16.substr(0, match_start); |
- base::string16 match = text16.substr(match_start, match_length); |
- base::string16 post = text16.substr(match_start + match_length); |
- highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(pre))); |
- highlighted_text->append("<b>"); |
- highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(match))); |
- highlighted_text->append("</b>"); |
- highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(post))); |
+ base::string16 text16 = base::UTF8ToUTF16(text); |
+ std::vector<bool> highlights(text16.size(), false); |
+ for (auto* query : queries) { |
+ if (!query->Search(text16, &match_start, &match_length)) |
+ return false; |
+ |
+ std::fill(highlights.begin() + match_start, |
+ highlights.begin() + match_start + match_length, true); |
+ } |
+ |
+ // Generate highlighted text. |
+ size_t start_current_segment = 0; |
+ |
+ for (size_t i = 0; i < text16.size(); ++i) { |
+ if (highlights[start_current_segment] == highlights[i]) |
+ continue; |
+ |
+ AppendStringWithHighlight( |
+ text16, start_current_segment, i - start_current_segment, |
+ highlights[start_current_segment], highlighted_text); |
+ |
+ start_current_segment = i; |
+ } |
+ |
+ DCHECK_GE(text16.size(), start_current_segment); |
+ AppendStringWithHighlight( |
+ text16, start_current_segment, text16.size() - start_current_segment, |
+ highlights[start_current_segment], highlighted_text); |
+ |
return true; |
} |