find_in_page_request.mm 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2019 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. #import "ios/web/find_in_page/find_in_page_request.h"
  5. #import <Foundation/Foundation.h>
  6. #import "ios/web/public/js_messaging/web_frame.h"
  7. #if !defined(__has_feature) || !__has_feature(objc_arc)
  8. #error "This file requires ARC support."
  9. #endif
  10. namespace web {
  11. FindInPageRequest::FindInPageRequest() {}
  12. FindInPageRequest::~FindInPageRequest() {}
  13. void FindInPageRequest::Reset(NSString* new_query_,
  14. int new_pending_frame_call_count) {
  15. unique_id_++;
  16. selected_frame_id_ = frame_order_.end();
  17. selected_match_index_in_selected_frame_ = -1;
  18. query_ = [new_query_ copy];
  19. pending_frame_call_count_ = new_pending_frame_call_count;
  20. for (auto& pair : frame_match_count_) {
  21. pair.second = 0;
  22. }
  23. }
  24. int FindInPageRequest::GetTotalMatchCount() const {
  25. int matches = 0;
  26. for (auto pair : frame_match_count_) {
  27. matches += pair.second;
  28. }
  29. return matches;
  30. }
  31. int FindInPageRequest::GetRequestId() const {
  32. return unique_id_;
  33. }
  34. NSString* FindInPageRequest::GetRequestQuery() const {
  35. return query_;
  36. }
  37. bool FindInPageRequest::GoToFirstMatch() {
  38. for (auto frame_id = frame_order_.begin(); frame_id != frame_order_.end();
  39. ++frame_id) {
  40. if (frame_match_count_[*frame_id] > 0) {
  41. selected_frame_id_ = frame_id;
  42. selected_match_index_in_selected_frame_ = 0;
  43. return true;
  44. }
  45. }
  46. return false;
  47. }
  48. bool FindInPageRequest::GoToNextMatch() {
  49. if (GetTotalMatchCount() == 0) {
  50. return false;
  51. }
  52. // No currently selected match, but there are matches. Move iterator to
  53. // beginning. This can happen if a frame containing the currently selected
  54. // match is removed from the page.
  55. if (selected_frame_id_ == frame_order_.end()) {
  56. selected_frame_id_ = frame_order_.begin();
  57. }
  58. bool next_match_is_in_selected_frame =
  59. selected_match_index_in_selected_frame_ + 1 <
  60. frame_match_count_[*selected_frame_id_];
  61. if (next_match_is_in_selected_frame) {
  62. selected_match_index_in_selected_frame_++;
  63. } else {
  64. // Since the function returns early if there are no matches, an infinite
  65. // loop should not be a risk.
  66. do {
  67. if (selected_frame_id_ == --frame_order_.end()) {
  68. selected_frame_id_ = frame_order_.begin();
  69. } else {
  70. selected_frame_id_++;
  71. }
  72. } while (frame_match_count_[*selected_frame_id_] == 0);
  73. // Should have found new frame.
  74. selected_match_index_in_selected_frame_ = 0;
  75. }
  76. return true;
  77. }
  78. bool FindInPageRequest::GoToPreviousMatch() {
  79. if (GetTotalMatchCount() == 0) {
  80. return false;
  81. }
  82. // No currently selected match, but there are matches. Move iterator to
  83. // beginning. This can happen if a frame containing the currently selected
  84. // matchs is removed from the page.
  85. if (selected_frame_id_ == frame_order_.end()) {
  86. selected_frame_id_ = frame_order_.begin();
  87. }
  88. bool previous_match_is_in_selected_frame =
  89. selected_match_index_in_selected_frame_ - 1 >= 0;
  90. if (previous_match_is_in_selected_frame) {
  91. selected_match_index_in_selected_frame_--;
  92. } else {
  93. // Since the function returns early if there are no matches, an infinite
  94. // loop should not be a risk.
  95. do {
  96. if (selected_frame_id_ == frame_order_.begin()) {
  97. selected_frame_id_ = --frame_order_.end();
  98. } else {
  99. selected_frame_id_--;
  100. }
  101. } while (frame_match_count_[*selected_frame_id_] == 0);
  102. // Should have found new frame.
  103. selected_match_index_in_selected_frame_ =
  104. frame_match_count_[*selected_frame_id_] - 1;
  105. }
  106. return true;
  107. }
  108. int FindInPageRequest::GetMatchCountForFrame(const std::string& frame_id) {
  109. if (frame_match_count_.find(frame_id) == frame_match_count_.end()) {
  110. return -1;
  111. }
  112. return frame_match_count_[frame_id];
  113. }
  114. void FindInPageRequest::SetMatchCountForFrame(int match_count,
  115. const std::string& frame_id) {
  116. frame_match_count_[frame_id] = match_count;
  117. }
  118. int FindInPageRequest::GetMatchCountForSelectedFrame() {
  119. if (selected_frame_id_ == frame_order_.end()) {
  120. return -1;
  121. }
  122. return frame_match_count_[*selected_frame_id_];
  123. }
  124. void FindInPageRequest::SetMatchCountForSelectedFrame(int match_count) {
  125. if (selected_frame_id_ == frame_order_.end()) {
  126. return;
  127. }
  128. frame_match_count_[*selected_frame_id_] = match_count;
  129. }
  130. int FindInPageRequest::GetCurrentSelectedMatchPageIndex() {
  131. if (selected_match_index_in_selected_frame_ == -1) {
  132. return -1;
  133. }
  134. // Count all matches in frames that come before frame with id
  135. // |selected_frame_id|.
  136. int total_match_index = selected_match_index_in_selected_frame_;
  137. for (auto it = frame_order_.begin(); it != selected_frame_id_; ++it) {
  138. total_match_index += frame_match_count_[*it];
  139. }
  140. return total_match_index;
  141. }
  142. std::string FindInPageRequest::GetSelectedFrameId() {
  143. if (selected_frame_id_ == frame_order_.end()) {
  144. return std::string();
  145. }
  146. return *selected_frame_id_;
  147. }
  148. int FindInPageRequest::GetCurrentSelectedMatchFrameIndex() const {
  149. return selected_match_index_in_selected_frame_;
  150. }
  151. void FindInPageRequest::SetCurrentSelectedMatchFrameIndex(int index) {
  152. selected_match_index_in_selected_frame_ = index;
  153. }
  154. void FindInPageRequest::RemoveFrame(const std::string& frame_id) {
  155. if (IsSelectedFrame(frame_id)) {
  156. // If currently selecting match in frame that will become unavailable,
  157. // there will no longer be a selected match. Reset to unselected match
  158. // state.
  159. selected_frame_id_ = frame_order_.end();
  160. selected_match_index_in_selected_frame_ = -1;
  161. }
  162. frame_order_.remove(frame_id);
  163. frame_match_count_.erase(frame_id);
  164. }
  165. void FindInPageRequest::AddFrame(WebFrame* web_frame) {
  166. frame_match_count_[web_frame->GetFrameId()] = 0;
  167. if (web_frame->IsMainFrame()) {
  168. // Main frame matches should show up first.
  169. frame_order_.push_front(web_frame->GetFrameId());
  170. } else {
  171. // The order of iframes is not important.
  172. frame_order_.push_back(web_frame->GetFrameId());
  173. }
  174. }
  175. void FindInPageRequest::DidReceiveFindResponseFromOneFrame() {
  176. pending_frame_call_count_--;
  177. }
  178. bool FindInPageRequest::AreAllFindResponsesReturned() {
  179. return pending_frame_call_count_ == 0;
  180. }
  181. bool FindInPageRequest::IsSelectedFrame(const std::string& frame_id) {
  182. if (selected_frame_id_ == frame_order_.end()) {
  183. return false;
  184. }
  185. return *selected_frame_id_ == frame_id;
  186. }
  187. } // namespace web