| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 | |
| 5 #include "components/web_view/find_controller.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/strings/string_util.h" | |
| 9 #include "base/trace_event/trace_event.h" | |
| 10 #include "components/web_view/find_controller_delegate.h" | |
| 11 #include "components/web_view/frame.h" | |
| 12 | |
| 13 namespace web_view { | |
| 14 | |
| 15 FindController::FindController(FindControllerDelegate* delegate) | |
| 16 : delegate_(delegate), | |
| 17 find_request_id_counter_(0), | |
| 18 current_find_request_id_(-1), | |
| 19 frame_with_selection_(0), | |
| 20 weak_ptr_factory_(this) {} | |
| 21 | |
| 22 FindController::~FindController() {} | |
| 23 | |
| 24 void FindController::Find(const std::string& in_search_string, | |
| 25 bool forward_direction) { | |
| 26 TRACE_EVENT2("web_view", "FindController::Find", | |
| 27 "search_string", in_search_string, | |
| 28 "forward_direction", forward_direction); | |
| 29 std::string search_string = in_search_string; | |
| 30 // Remove the carriage return character, which generally isn't in web content. | |
| 31 const char kInvalidChars[] = {'\r', 0}; | |
| 32 base::RemoveChars(search_string, kInvalidChars, &search_string); | |
| 33 | |
| 34 previous_find_text_ = find_text_; | |
| 35 | |
| 36 // TODO(erg): Do we need to something like |find_op_aborted_|? | |
| 37 | |
| 38 find_frames_in_order_ = delegate_->GetAllFrames(); | |
| 39 | |
| 40 uint32_t starting_frame; | |
| 41 bool continue_last_find = | |
| 42 find_text_ == search_string || search_string.empty(); | |
| 43 if (!continue_last_find) { | |
| 44 current_find_request_id_ = find_request_id_counter_++; | |
| 45 frame_with_selection_ = 0; | |
| 46 returned_find_data_.clear(); | |
| 47 starting_frame = find_frames_in_order_.front()->id(); | |
| 48 } else { | |
| 49 starting_frame = frame_with_selection_; | |
| 50 } | |
| 51 | |
| 52 if (!search_string.empty()) | |
| 53 find_text_ = search_string; | |
| 54 | |
| 55 LocalFindOptions options; | |
| 56 options.forward = forward_direction; | |
| 57 options.continue_last_find = continue_last_find; | |
| 58 // Prime the continue loop. | |
| 59 OnContinueFinding(current_find_request_id_, search_string, options, | |
| 60 starting_frame, 0u, false); | |
| 61 } | |
| 62 | |
| 63 void FindController::StopFinding() { | |
| 64 // Don't report any callbacks that we get after this. | |
| 65 current_find_request_id_ = -1; | |
| 66 frame_with_selection_ = 0; | |
| 67 | |
| 68 for (Frame* f : delegate_->GetAllFrames()) | |
| 69 f->StopFinding(true); | |
| 70 } | |
| 71 | |
| 72 void FindController::OnFindInFrameCountUpdated(int32_t request_id, | |
| 73 Frame* frame, | |
| 74 int32_t count, | |
| 75 bool final_update) { | |
| 76 if (request_id != current_find_request_id_) | |
| 77 return; | |
| 78 | |
| 79 auto it = returned_find_data_.find(frame); | |
| 80 if (it == returned_find_data_.end()) { | |
| 81 NOTREACHED(); | |
| 82 return; | |
| 83 } | |
| 84 | |
| 85 it->second.count = count; | |
| 86 it->second.final_update = final_update; | |
| 87 | |
| 88 int merged_count = 0; | |
| 89 bool merged_final_update = true; | |
| 90 for (auto const& data : returned_find_data_) { | |
| 91 merged_count += data.second.count; | |
| 92 merged_final_update = merged_final_update && data.second.final_update; | |
| 93 } | |
| 94 | |
| 95 // We can now take the individual FindInFrame messages and construct a | |
| 96 // FindInPage message. | |
| 97 delegate_->GetWebViewClient()->FindInPageMatchCountUpdated( | |
| 98 request_id, merged_count, merged_final_update); | |
| 99 } | |
| 100 | |
| 101 void FindController::OnFindInPageSelectionUpdated( | |
| 102 int32_t request_id, | |
| 103 Frame* frame, | |
| 104 int32_t active_match_ordinal) { | |
| 105 if (request_id != current_find_request_id_) | |
| 106 return; | |
| 107 | |
| 108 // TODO(erg): This is the one that's really hard. To give an accurate count | |
| 109 // here, we need to have all the results for frames that are before the Frame | |
| 110 // that contains the selected match so we can add their sums together. | |
| 111 // | |
| 112 // Thankfully, we don't have to worry about this now. Since there aren't | |
| 113 // back/forward controls yet, active_match_ordinal will always be 1. | |
| 114 delegate_->GetWebViewClient()->FindInPageSelectionUpdated( | |
| 115 request_id, active_match_ordinal); | |
| 116 } | |
| 117 | |
| 118 void FindController::DidDestroyFrame(Frame* frame) { | |
| 119 auto it = | |
| 120 find(find_frames_in_order_.begin(), find_frames_in_order_.end(), frame); | |
| 121 if (it != find_frames_in_order_.end()) | |
| 122 find_frames_in_order_.erase(it); | |
| 123 } | |
| 124 | |
| 125 void FindController::OnContinueFinding(int32_t request_id, | |
| 126 const std::string& search_string, | |
| 127 LocalFindOptions options, | |
| 128 uint32_t starting_frame, | |
| 129 uint32_t current_frame, | |
| 130 bool found) { | |
| 131 TRACE_EVENT2("web_view", "FindController::OnContinueFinding", | |
| 132 "request_id", request_id, | |
| 133 "search_string", search_string); | |
| 134 if (!found) { | |
| 135 // So we need to figure out what the next frame to search is. | |
| 136 Frame* next_frame = | |
| 137 GetNextFrameToSearch(starting_frame, current_frame, options.forward); | |
| 138 | |
| 139 // If we have one more frame to search: | |
| 140 if (next_frame) { | |
| 141 bool wrap_within_frame = find_frames_in_order_.size() == 1; | |
| 142 next_frame->Find( | |
| 143 request_id, mojo::String::From(search_string), | |
| 144 mojom::FindOptions::From(options), wrap_within_frame, | |
| 145 base::Bind(&FindController::OnContinueFinding, | |
| 146 weak_ptr_factory_.GetWeakPtr(), request_id, search_string, | |
| 147 options, starting_frame, next_frame->id())); | |
| 148 | |
| 149 // TODO(erg): This doesn't deal with wrapping around the document at the | |
| 150 // end when there are multiple frames and the last frame doesn't have a | |
| 151 // result. | |
| 152 return; | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 frame_with_selection_ = found ? current_frame : 0; | |
| 157 | |
| 158 if (!options.continue_last_find) { | |
| 159 // If nothing is found, set result to "0 of 0", otherwise, set it to | |
| 160 // "-1 of 1" to indicate that we found at least one item, but we don't know | |
| 161 // yet what is active. | |
| 162 int ordinal = found ? -1 : 0; // -1 here means, we might know more later. | |
| 163 int match_count = found ? 1 : 0; // 1 here means possibly more coming. | |
| 164 | |
| 165 // If we find no matches then this will be our last status update. | |
| 166 // Otherwise the scoping effort will send more results. | |
| 167 bool final_status_update = !found; | |
| 168 | |
| 169 // Send priming messages. | |
| 170 delegate_->GetWebViewClient()->FindInPageSelectionUpdated(request_id, | |
| 171 ordinal); | |
| 172 delegate_->GetWebViewClient()->FindInPageMatchCountUpdated( | |
| 173 request_id, match_count, final_status_update); | |
| 174 | |
| 175 std::vector<Frame*> frames = delegate_->GetAllFrames(); | |
| 176 for (Frame* f : frames) { | |
| 177 f->StopHighlightingFindResults(); | |
| 178 | |
| 179 if (found) { | |
| 180 MatchData& match_data = returned_find_data_[f]; | |
| 181 match_data.count = 0; | |
| 182 match_data.final_update = false; | |
| 183 f->HighlightFindResults(request_id, mojo::String::From(search_string), | |
| 184 mojom::FindOptions::From(options), true); | |
| 185 } | |
| 186 } | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 Frame* FindController::GetNextFrameToSearch(uint32_t starting_frame, | |
| 191 uint32_t current_frame, | |
| 192 bool forward) { | |
| 193 std::vector<Frame*>::iterator it; | |
| 194 if (current_frame == 0u) { | |
| 195 it = GetFrameIteratorById(starting_frame); | |
| 196 CHECK(it != find_frames_in_order_.end()); | |
| 197 return *it; | |
| 198 } | |
| 199 | |
| 200 Frame* candidate; | |
| 201 it = GetFrameIteratorById(current_frame); | |
| 202 if (it == find_frames_in_order_.end()) { | |
| 203 // Our current frame has been deleted. There is nothing to be done now; we | |
| 204 // will abort. | |
| 205 return nullptr; | |
| 206 } | |
| 207 | |
| 208 if (forward) { | |
| 209 ++it; | |
| 210 if (it == find_frames_in_order_.end()) | |
| 211 it = find_frames_in_order_.begin(); | |
| 212 candidate = *it; | |
| 213 } else { | |
| 214 if (it == find_frames_in_order_.begin()) { | |
| 215 candidate = find_frames_in_order_.back(); | |
| 216 } else { | |
| 217 --it; | |
| 218 candidate = *it; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 // If we've looped around the entire frame tree, then we are done and return | |
| 223 // null. | |
| 224 if (candidate->id() == starting_frame) | |
| 225 return nullptr; | |
| 226 return candidate; | |
| 227 } | |
| 228 | |
| 229 std::vector<Frame*>::iterator FindController::GetFrameIteratorById( | |
| 230 uint32_t frame_id) { | |
| 231 return find_if(find_frames_in_order_.begin(), | |
| 232 find_frames_in_order_.end(), | |
| 233 [&frame_id](Frame* f) { | |
| 234 return f->id() == frame_id; | |
| 235 }); | |
| 236 } | |
| 237 | |
| 238 } // namespace web_view | |
| OLD | NEW |