chromium/components/drive/chromeos/search_metadata.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/drive/chromeos/search_metadata.h"

#include <algorithm>

#include "base/i18n/string_search.h"
#include "base/strings/escape.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"
#include "components/drive/file_system_core_util.h"

namespace drive {
namespace internal {

namespace {

// Appends substring of |original_text| to |highlighted_text| with highlight.
void AppendStringWithHighlight(const std::u16string& original_text,
                               size_t start,
                               size_t length,
                               bool highlight,
                               std::string* highlighted_text) {
  if (highlight)
    highlighted_text->append("<b>");

  highlighted_text->append(base::EscapeForHTML(
      base::UTF16ToUTF8(original_text.substr(start, length))));

  if (highlight)
    highlighted_text->append("</b>");
}

}  // namespace

bool FindAndHighlight(
    const std::string& text,
    const std::vector<std::unique_ptr<
        base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>& queries,
    std::string* highlighted_text) {
  DCHECK(highlighted_text);
  highlighted_text->clear();

  // Check text matches with all queries.
  size_t match_start = 0;
  size_t match_length = 0;

  std::u16string text16 = base::UTF8ToUTF16(text);
  std::vector<bool> highlights(text16.size(), false);
  for (const 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;
}

}  // namespace internal
}  // namespace drive