find_tab_helper.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/find_in_page/find_tab_helper.h"
  5. #include <utility>
  6. #include "base/observer_list.h"
  7. #include "base/strings/string_util.h"
  8. #include "build/build_config.h"
  9. #include "components/find_in_page/find_result_observer.h"
  10. #include "components/find_in_page/find_types.h"
  11. #include "content/public/browser/render_frame_host.h"
  12. #include "content/public/browser/web_contents.h"
  13. #include "content/public/common/stop_find_action.h"
  14. #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
  15. #include "ui/gfx/geometry/rect_f.h"
  16. using content::WebContents;
  17. namespace find_in_page {
  18. // static
  19. int FindTabHelper::find_request_id_counter_ = -1;
  20. FindTabHelper::FindTabHelper(WebContents* web_contents)
  21. : content::WebContentsUserData<FindTabHelper>(*web_contents),
  22. current_find_request_id_(find_request_id_counter_++),
  23. current_find_session_id_(current_find_request_id_) {}
  24. FindTabHelper::~FindTabHelper() {
  25. for (auto& observer : observers_)
  26. observer.OnFindTabHelperDestroyed(this);
  27. }
  28. void FindTabHelper::AddObserver(FindResultObserver* observer) {
  29. observers_.AddObserver(observer);
  30. }
  31. void FindTabHelper::RemoveObserver(FindResultObserver* observer) {
  32. observers_.RemoveObserver(observer);
  33. }
  34. void FindTabHelper::StartFinding(std::u16string search_string,
  35. bool forward_direction,
  36. bool case_sensitive,
  37. bool find_match,
  38. bool run_synchronously_for_testing) {
  39. // Remove the carriage return character, which generally isn't in web content.
  40. const char16_t kInvalidChars[] = u"\r";
  41. base::RemoveChars(search_string, kInvalidChars, &search_string);
  42. // Keep track of what the last search was across the tabs.
  43. if (delegate_)
  44. delegate_->SetLastSearchText(search_string);
  45. if (search_string.empty()) {
  46. StopFinding(find_in_page::SelectionAction::kClear);
  47. for (auto& observer : observers_)
  48. observer.OnFindEmptyText(&GetWebContents());
  49. return;
  50. }
  51. bool new_session = find_text_ != search_string ||
  52. (last_search_case_sensitive_ != case_sensitive) ||
  53. find_op_aborted_;
  54. // Continuing here would just find the same results, potentially causing
  55. // some flicker in the highlighting.
  56. if (!new_session && !find_match)
  57. return;
  58. current_find_request_id_ = find_request_id_counter_++;
  59. if (new_session)
  60. current_find_session_id_ = current_find_request_id_;
  61. previous_find_text_ = find_text_;
  62. find_text_ = search_string;
  63. last_search_case_sensitive_ = case_sensitive;
  64. find_op_aborted_ = false;
  65. should_find_match_ = find_match;
  66. auto options = blink::mojom::FindOptions::New();
  67. options->forward = forward_direction;
  68. options->match_case = case_sensitive;
  69. options->new_session = new_session;
  70. options->find_match = find_match;
  71. options->run_synchronously_for_testing = run_synchronously_for_testing;
  72. GetWebContents().Find(current_find_request_id_, find_text_,
  73. std::move(options));
  74. }
  75. void FindTabHelper::StopFinding(SelectionAction selection_action) {
  76. if (selection_action == SelectionAction::kClear) {
  77. // kClearSelection means the find string has been cleared by the user, but
  78. // the UI has not been dismissed. In that case we want to clear the
  79. // previously remembered search (http://crbug.com/42639).
  80. previous_find_text_ = std::u16string();
  81. } else {
  82. find_ui_active_ = false;
  83. if (!find_text_.empty())
  84. previous_find_text_ = find_text_;
  85. }
  86. find_text_.clear();
  87. last_completed_find_text_.clear();
  88. find_op_aborted_ = true;
  89. last_search_result_ = FindNotificationDetails();
  90. should_find_match_ = false;
  91. content::StopFindAction action;
  92. switch (selection_action) {
  93. case SelectionAction::kClear:
  94. action = content::STOP_FIND_ACTION_CLEAR_SELECTION;
  95. break;
  96. case SelectionAction::kKeep:
  97. action = content::STOP_FIND_ACTION_KEEP_SELECTION;
  98. break;
  99. case SelectionAction::kActivate:
  100. action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION;
  101. break;
  102. default:
  103. NOTREACHED();
  104. action = content::STOP_FIND_ACTION_KEEP_SELECTION;
  105. }
  106. GetWebContents().StopFinding(action);
  107. }
  108. void FindTabHelper::ActivateFindInPageResultForAccessibility() {
  109. GetWebContents()
  110. .GetPrimaryMainFrame()
  111. ->ActivateFindInPageResultForAccessibility(current_find_request_id_);
  112. }
  113. std::u16string FindTabHelper::GetInitialSearchText() {
  114. // Try the last thing we searched for in this tab.
  115. if (!previous_find_text_.empty())
  116. return previous_find_text_;
  117. // Then defer to the delegate.
  118. return delegate_ ? delegate_->GetSearchPrepopulateText() : std::u16string();
  119. }
  120. #if BUILDFLAG(IS_ANDROID)
  121. void FindTabHelper::ActivateNearestFindResult(float x, float y) {
  122. if (!find_op_aborted_ && !find_text_.empty()) {
  123. GetWebContents().ActivateNearestFindResult(x, y);
  124. }
  125. }
  126. void FindTabHelper::RequestFindMatchRects(int current_version) {
  127. if (!find_op_aborted_ && !find_text_.empty())
  128. GetWebContents().RequestFindMatchRects(current_version);
  129. }
  130. #endif
  131. void FindTabHelper::HandleFindReply(int request_id,
  132. int number_of_matches,
  133. const gfx::Rect& selection_rect,
  134. int active_match_ordinal,
  135. bool final_update) {
  136. // Ignore responses for requests that have been aborted.
  137. // Ignore responses for requests from previous sessions. That way we won't act
  138. // on stale results when the user has already typed in another query.
  139. if (!find_op_aborted_ && request_id >= current_find_session_id_) {
  140. if (number_of_matches == -1)
  141. number_of_matches = last_search_result_.number_of_matches();
  142. if (active_match_ordinal == -1)
  143. active_match_ordinal = last_search_result_.active_match_ordinal();
  144. gfx::Rect selection = selection_rect;
  145. if (final_update && active_match_ordinal == 0)
  146. selection = gfx::Rect();
  147. else if (selection_rect.IsEmpty())
  148. selection = last_search_result_.selection_rect();
  149. // Notify the UI, automation and any other observers that a find result was
  150. // found.
  151. last_search_result_ =
  152. FindNotificationDetails(request_id, number_of_matches, selection,
  153. active_match_ordinal, final_update);
  154. for (auto& observer : observers_)
  155. observer.OnFindResultAvailable(&GetWebContents());
  156. }
  157. }
  158. WEB_CONTENTS_USER_DATA_KEY_IMPL(FindTabHelper);
  159. } // namespace find_in_page