Index: components/web_view/web_view_impl.cc |
diff --git a/components/web_view/web_view_impl.cc b/components/web_view/web_view_impl.cc |
index 8992496bbc2789309aa2883afe1d67c9f21a474b..7df54d48e9a5fe500d5f1c01a0ca0f193557133f 100644 |
--- a/components/web_view/web_view_impl.cc |
+++ b/components/web_view/web_view_impl.cc |
@@ -4,6 +4,9 @@ |
#include "components/web_view/web_view_impl.h" |
+#include <queue> |
+ |
+#include "base/bind.h" |
#include "base/command_line.h" |
#include "components/devtools_service/public/cpp/switches.h" |
#include "components/mus/public/cpp/scoped_view_ptr.h" |
@@ -44,7 +47,8 @@ WebViewImpl::WebViewImpl(mojo::ApplicationImpl* app, |
binding_(this, request.Pass()), |
root_(nullptr), |
content_(nullptr), |
- navigation_controller_(this) { |
+ navigation_controller_(this), |
+ current_find_request_(-1) { |
if (EnableRemoteDebugging()) |
devtools_agent_.reset(new FrameDevToolsAgent(app_, this)); |
OnDidNavigate(); |
@@ -98,6 +102,73 @@ void WebViewImpl::OnLoad(const GURL& pending_url) { |
frame_connection.Pass(), client_properties)); |
} |
+std::deque<Frame*> WebViewImpl::GetAllFrames() { |
+ std::deque<Frame*> all_frames; |
+ std::queue<Frame*> frames_to_search; |
+ frames_to_search.push(frame_tree_->root()); |
+ while (!frames_to_search.empty()) { |
+ // TODO(erg): This is not in depth first order. I'm not actually sure how |
+ // blink does traversal though. |
+ Frame* current = frames_to_search.front(); |
+ frames_to_search.pop(); |
+ for (Frame* child : current->children()) |
+ frames_to_search.push(child); |
+ all_frames.push_back(current); |
+ } |
+ return all_frames; |
+} |
+ |
+void WebViewImpl::OnContinueFinding(int32_t request_id, |
+ const mojo::String& search_text, |
+ bool found) { |
+ if (!found && !pending_find_frames_.empty()) { |
+ // No match found, search on the next frame. |
+ Frame* next_frame = pending_find_frames_.front(); |
+ pending_find_frames_.pop_front(); |
+ next_frame->Find(request_id, search_text, |
+ base::Bind(&WebViewImpl::OnContinueFinding, |
+ base::Unretained(this))); |
+ |
+ // TODO(erg): This doesn't deal with wrapping around the document at the |
+ // end when there are multiple frames. |
+ return; |
+ } |
+ |
+ pending_find_frames_.clear(); |
+ |
+ // We either found a match or we got the final rejection. Either way, we |
+ // alert our caller. |
+ |
+ // If nothing is found, set result to "0 of 0", otherwise, set it to |
+ // "-1 of 1" to indicate that we found at least one item, but we don't know |
+ // yet what is active. |
+ int ordinal = found ? -1 : 0; // -1 here means, we might know more later. |
+ int match_count = found ? 1 : 0; // 1 here means possibly more coming. |
+ |
+ // If we find no matches then this will be our last status update. |
+ // Otherwise the scoping effort will send more results. |
+ bool final_status_update = !found; |
+ |
+ // Send priming messages. |
+ client_->ReportFindInPageSelection(request_id, ordinal); |
+ client_->ReportFindInPageMatchCount(request_id, |
+ match_count, final_status_update); |
+ |
+ // TODO(erg): This doesn't iterate in the same order as the current code |
+ // because we don't have the correct iteration primitives. |
+ std::deque<Frame*> frames = GetAllFrames(); |
+ for (Frame* f : frames) { |
+ f->CancelPendingScopingEffort(); |
+ |
+ if (found) { |
+ MatchData& match_data = returned_find_data_[f]; |
+ match_data.count = 0; |
+ match_data.final_update = false; |
+ f->ScopeStringMatches(request_id, search_text, true); |
+ } |
+ } |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// WebViewImpl, WebView implementation: |
@@ -110,6 +181,41 @@ void WebViewImpl::GetViewTreeClient( |
mus::ViewTreeConnection::Create(this, view_tree_client.Pass()); |
} |
+void WebViewImpl::Find(int32_t request_id, const mojo::String& search_text) { |
+ DCHECK(frame_tree_); |
+ |
+ // TODO(erg): While this deals with multiple frames, it does not deal with |
+ // going forward or backwards. To do that, we'll have to port all frame |
+ // traversal and focusing concepts from blink::WebFrame to mojo::Frame. |
+ |
+ // TODO(erg): This isn't great and causes flashes on character |
+ // entry. However, it's needed for now because the internals of TextFinder |
+ // still track the entire state of the blink frame tree, and if there are any |
+ // frames that have marked text, doing a find clears the results of all |
+ // frames _except_ for the first frame that it finds a result on. |
+ StopFinding(); |
+ |
+ // TODO(erg): This cheap method does not traverse in the order that blink |
+ // does. |
+ pending_find_frames_ = GetAllFrames(); |
+ |
+ current_find_request_ = request_id; |
+ returned_find_data_.clear(); |
+ |
+ // Prime the continue loop. |
+ OnContinueFinding(request_id, search_text, false); |
+} |
+ |
+void WebViewImpl::StopFinding() { |
+ DCHECK(frame_tree_); |
+ |
+ // Don't report any callbacks that we get after this. |
+ current_find_request_ = -1; |
+ |
+ for (Frame* f : GetAllFrames()) |
+ f->StopFinding(true); |
+} |
+ |
void WebViewImpl::GoBack() { |
if (!navigation_controller_.CanGoBack()) |
return; |
@@ -203,6 +309,58 @@ void WebViewImpl::DidCommitProvisionalLoad(Frame* frame) { |
navigation_controller_.FrameDidCommitProvisionalLoad(frame); |
} |
+void WebViewImpl::DidDestroyFrame(Frame* frame) { |
+ auto it = find(pending_find_frames_.begin(), pending_find_frames_.end(), |
+ frame); |
+ if (it != pending_find_frames_.end()) |
+ pending_find_frames_.erase(it); |
+} |
+ |
+void WebViewImpl::OnReportFindInFrameMatchCount(int32_t request_id, |
+ Frame* frame, |
+ int32_t count, |
+ bool final_update) { |
+ if (request_id != current_find_request_) |
+ return; |
+ |
+ auto it = returned_find_data_.find(frame); |
+ if (it == returned_find_data_.end()) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ it->second.count = count; |
+ it->second.final_update = final_update; |
+ |
+ int merged_count = 0; |
+ bool merged_final_update = true; |
+ for (auto const& data : returned_find_data_) { |
+ merged_count += data.second.count; |
+ merged_final_update = merged_final_update && data.second.final_update; |
+ } |
+ |
+ // We can now take the individual FindInFrame messages and construct a |
+ // FindInPage message. |
+ client_->ReportFindInPageMatchCount(request_id, |
+ merged_count, |
+ merged_final_update); |
+} |
+ |
+void WebViewImpl::OnReportFindInPageSelection(int32_t request_id, |
+ Frame* frame, |
+ int32_t active_match_ordinal) { |
+ if (request_id != current_find_request_) |
+ return; |
+ |
+ // TODO(erg): This is the one that's really hard. To give an accurate count |
+ // here, we need to have all the results for frames that are before the Frame |
+ // that contains the selected match so we can add their sums together. |
+ // |
+ // Thankfully, we don't have to worry about this now. Since there aren't |
+ // back/forward controls yet, active_match_ordinal will always be 1. |
+ client_->ReportFindInPageSelection(request_id, active_match_ordinal); |
+} |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// WebViewImpl, FrameDevToolsAgentDelegate implementation: |