赞
踩
#001 // Autocomplete provider for searches and suggestions from a search engine.
#002 //
#003 // After construction, the autocomplete controller repeatedly calls Start()
#004 // with some user input, each time expecting to receive a small set of the best
#005 // matches (either synchronously or asynchronously).
#006 //
#007 // Initially the provider creates a match that searches for the current input
#008 // text. It also starts a task to query the Suggest servers. When that data
#009 // comes back, the provider creates and returns matches for the best
#010 // suggestions.
SearchProvider类是继承AutocompleteProvider和URLFetcher类,AutocompleteProvider提供一个自动完成的结果,URLFetcher主要提供从URL获取数据和状态。
#011 class SearchProvider : public AutocompleteProvider,
#012 public URLFetcher::Delegate {
#013 public:
#014 SearchProvider(ACProviderListener* listener, Profile* profile)
#015 : AutocompleteProvider(listener, profile, "Search"),
#016 last_default_provider_(NULL),
#017 fetcher_(NULL),
#018 history_request_pending_(false),
#019 have_history_results_(false),
#020 suggest_results_pending_(false),
#021 have_suggest_results_(false) {
#022 }
#023
开始获取。
#024 // AutocompleteProvider
#025 virtual void Start(const AutocompleteInput& input,
#026 bool minimal_changes,
#027 bool synchronous_only);
停止查找。
#028 virtual void Stop();
#029
当获取到数据回来时响应。
#030 // URLFetcher::Delegate
#031 virtual void OnURLFetchComplete(const URLFetcher* source,
#032 const GURL& url,
#033 const URLRequestStatus& status,
#034 int response_code,
#035 const ResponseCookies& cookies,
#036 const std::string& data);
#037
#038 private:
#039 struct NavigationResult {
#040 NavigationResult(const std::wstring& url, const std::wstring& site_name)
#041 : url(url),
#042 site_name(site_name) {
#043 }
#044
#045 // The URL.
#046 std::wstring url;
#047
#048 // Name for the site.
#049 std::wstring site_name;
#050 };
#051
保存返回的结果。
#052 typedef std::vector<std::wstring> SuggestResults;
#053 typedef std::vector<NavigationResult> NavigationResults;
#054 typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
#055 typedef std::map<std::wstring, AutocompleteMatch> MatchMap;
#056
运行获取搜索引擎数据。
#057 // Called when timer_ expires.
#058 void Run();
#059
#060 // Determines whether an asynchronous subcomponent query should run for the
#061 // current input. If so, starts it if necessary; otherwise stops it.
#062 // NOTE: These functions do not update |done_|. Callers must do so.
#063 void StartOrStopHistoryQuery(bool minimal_changes, bool synchronous_only);
#064 void StartOrStopSuggestQuery(bool minimal_changes, bool synchronous_only);
#065
#066 // Functions to stop the separate asynchronous subcomponents.
#067 // NOTE: These functions do not update |done_|. Callers must do so.
#068 void StopHistory();
#069 void StopSuggest();
#070
#071 // Called back by the history system to return searches that begin with the
#072 // input text.
#073 void OnGotMostRecentKeywordSearchTerms(
#074 CancelableRequestProvider::Handle handle,
#075 HistoryResults* results);
#076
#077 // Parses the results from the Suggest server and stores up to kMaxMatches of
#078 // them in server_results_. Returns whether parsing succeeded.
#079 bool ParseSuggestResults(Value* root_val);
#080
#081 // Converts the parsed server results in server_results_ to a set of
#082 // AutocompleteMatches and adds them to |matches_|. This also sets |done_|
#083 // correctly.
#084 void ConvertResultsToAutocompleteMatches();
#085
#086 // Determines the relevance for a particular match. We use different scoring
#087 // algorithms for the different types of matches.
#088 int CalculateRelevanceForWhatYouTyped() const;
#089 // |time| is the time at which this query was last seen.
#090 int CalculateRelevanceForHistory(const Time& time) const;
#091 // |suggestion_value| is which suggestion this is in the list returned from
#092 // the server; the best suggestion is suggestion number 0.
#093 int CalculateRelevanceForSuggestion(size_t suggestion_value) const;
#094 // |suggestion_value| is same as above.
#095 int CalculateRelevanceForNavigation(size_t suggestion_value) const;
#096
#097 // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with
#098 // the supplied relevance. Adds this match to |map|; if such a match already
#099 // exists, whichever one has lower relevance is eliminated.
#100 void AddMatchToMap(const std::wstring& query_string,
#101 int relevance,
#102 int accepted_suggestion,
#103 MatchMap* map);
#104 // Returns an AutocompleteMatch for a navigational suggestion.
#105 AutocompleteMatch NavigationToMatch(const NavigationResult& query_string,
#106 int relevance);
#107
#108 // Trims "http:" and up to two subsequent slashes from |url|. Returns the
#109 // number of characters that were trimmed.
#110 // TODO(kochi): this is duplicate from history_autocomplete
#111 static size_t TrimHttpPrefix(std::wstring* url);
#112
#113 // Don't send any queries to the server until some time has elapsed after
#114 // the last keypress, to avoid flooding the server with requests we are
#115 // likely to end up throwing away anyway.
#116 static const int kQueryDelayMs;
#117
#118 // The user's input.
#119 AutocompleteInput input_;
#120
#121 TemplateURL default_provider_; // Cached across the life of a query so we
#122 // behave consistently even if the user
#123 // changes their default while the query is
#124 // running.
#125 const TemplateURL* last_default_provider_;
#126 // TODO(pkasting): http://b/1162970 We
#127 // shouldn't need this.
#128
#129 // An object we can use to cancel history requests.
#130 CancelableRequestConsumer history_request_consumer_;
#131
#132 // Searches in the user's history that begin with the input text.
#133 HistoryResults history_results_;
#134
#135 // Whether history_results_ is valid (so we can tell invalid apart from
#136 // empty).
#137 bool have_history_results_;
#138
#139 // Whether we are waiting for a history request to finish.
#140 bool history_request_pending_;
#141
#142 // True if we're expecting suggest results that haven't yet arrived. This
#143 // could be because either |timer_| or |fetcher| is still running (see below).
#144 bool suggest_results_pending_;
#145
#146 // A timer to start a query to the suggest server after the user has stopped
#147 // typing for long enough.
#148 base::OneShotTimer<SearchProvider> timer_;
#149
#150 // The fetcher that retrieves suggest results from the server.
#151 scoped_ptr<URLFetcher> fetcher_;
#152
#153 // Suggestions returned by the Suggest server for the input text.
#154 SuggestResults suggest_results_;
#155
#156 // Navigational suggestions returned by the server.
#157 NavigationResults navigation_results_;
#158
#159 // Whether suggest_results_ is valid.
#160 bool have_suggest_results_;
#161
#162 DISALLOW_EVIL_CONSTRUCTORS(SearchProvider);
#163 };
#164
在这个类里先调用函数SearchProvider::Start来获取缺省的搜索引擎,然后停止以前的搜索,接着SearchProvider::Run()函数里使用URLFetcher获取数据回来,它的代码如下:
#001 void SearchProvider::Run() {
#002 // Start a new request with the current input.
#003 DCHECK(!done_);
获取搜索的URL。
#004 const TemplateURLRef* const suggestions_url =
#005 default_provider_.suggestions_url();
建议代替的字符。
#006 DCHECK(suggestions_url->SupportsReplacement());
开始新的搜索。
#007 fetcher_.reset(new URLFetcher(GURL(suggestions_url->ReplaceSearchTerms(
#008 default_provider_, input_.text(),
#009 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring())),
#010 URLFetcher::GET, this));
#011 fetcher_->set_request_context(profile_->GetRequestContext());
#012 fetcher_->Start();
#013 }
当前上面的搜索完成时,就会通知SearchProvider::OnURLFetchComplete函数来分析返回的结果,最后调用SearchProvider::ConvertResultsToAutocompleteMatches()函数来把结果转换自动完成的列表项。
通过上面的分析,就了解通过GOOGLE搜索引擎自动完成功能的实现。
当我们根据自动提示,或者完全自己输入连接后,再按下回车键,这时浏览器就会去打开网页,或者去查找内容。那么浏览器是怎么样实现这些功能的呢?又是怎么判断去打开网页,还是去打开GOOGLE的搜索引擎的呢?下面就来分析这部份的代码,如下:
#001 bool AutocompleteEdit::OnKeyDownOnlyWritable(TCHAR key,
#002 UINT repeat_count,
#003 UINT flags) {
#004 // NOTE: Annoyingly, ctrl-alt-<key> generates WM_KEYDOWN rather than
#005 // WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places
#006 // in this function even with a WM_SYSKEYDOWN handler.
#007
#008 int count = repeat_count;
#009 switch (key) {
#010 case VK_RETURN:
#011 AcceptInput((flags & KF_ALTDOWN) ? NEW_FOREGROUND_TAB : CURRENT_TAB,
#012 false);
#013 return true;
#014
#015 case VK_UP:
#016 count = -count;
#017 // FALL THROUGH
#018 case VK_DOWN:
当用户按下回车键,就会调用上面的函数OnKeyDownOnlyWritable,并且在VK_RETURN按键处理回车的事件,接着就是调用函数AcceptInput来处理。
这个函数的代码如下:
#001 void AutocompleteEdit::AcceptInput(WindowOpenDisposition disposition,
#002 bool for_drop) {
#003 // Get the URL and transition type for the selected entry.
#004 PageTransition::Type transition;
#005 bool is_history_what_you_typed_match;
#006 std::wstring alternate_nav_url;
保存当前获取的URL连接串。
#007 const std::wstring url(GetURLForCurrentText(&transition,
#008 &is_history_what_you_typed_match,
#009 &alternate_nav_url));
#010 if (url.empty())
#011 return;
#012
判断是否重新加载当前的网页。
#013 if (url == permanent_text_) {
#014 // When the user hit enter on the existing permanent URL, treat it like a
#015 // reload for scoring purposes. We could detect this by just checking
#016 // user_input_in_progress_, but it seems better to treat "edits" that end
#017 // up leaving the URL unchanged (e.g. deleting the last character and then
#018 // retyping it) as reloads too.
#019 transition = PageTransition::RELOAD;
#020 } else if (for_drop || ((paste_state_ != NONE) &&
#021 is_history_what_you_typed_match)) {
下面是打开一个新的连接。
#022 // When the user pasted in a URL and hit enter, score it like a link click
#023 // rather than a normal typed URL, so it doesn't get inline autocompleted
#024 // as aggressively later.
#025 transition = PageTransition::LINK;
#026 }
#027
这里是调用OpenURL函数打开这个连接的内容。
#028 OpenURL(url, disposition, transition, alternate_nav_url,
#029 AutocompletePopupModel::kNoMatch,
#030 is_keyword_hint_ ? std::wstring() : keyword_);
#031 }
这段代码的流程很清楚,就是先通过判断按键输入,是否按下回车键,如果是回车键就调用函数AcceptInput处理,然后在这个函数就判断这个连接是否已经打开了,如果已经打开,只需要重新加载就行了,如果不是当前的,就是打开一个新的连接。下一次再来分析OpenURL函数是怎么样通过连接来重新加载,还是打开一个新网页。
上一次说到调用函数OpenURL来打开网络连接,这仅是网络浏览的开始,现在再来分析它怎么样去下载网页数据,然后再显示出来。
#001 void AutocompleteEdit::OpenURL(const std::wstring& url,
#002 WindowOpenDisposition disposition,
#003 PageTransition::Type transition,
#004 const std::wstring& alternate_nav_url,
#005 size_t selected_line,
#006 const std::wstring& keyword) {
#007 if (url.empty())
#008 return;
#009
#010 ScopedFreeze freeze(this, GetTextObjectModel());
#011 SendOpenNotification(selected_line, keyword);
#012
#013 if (disposition != NEW_BACKGROUND_TAB)
#014 RevertAll(); // Revert the box to its unedited state
#015 controller_->OnAutocompleteAccept(url, disposition, transition,
#016 alternate_nav_url);
#017 }
在这个函数里第一个参数url是要打开的网络连接;第二个参数disposition是显示位置,比如新添加一个TAB显示,还是在原来的TAB显示;第三个参数transition是下载的类型,比如是重新加载,还是新的连接下载;第四个参数alternate_nav_url是候选的连接;第五个参数是选择那一行提示菜单;第六个参数keyword是关键字。
第7行判断打开的连接是否为空,如果为空就不用打开连接了。
第10行锁定输入框。
第11行通知选中的关键字。
第13行,14行关闭当前输入提示,直接在当前窗口显示,清除一些状态和内容。
第15行调控制实例来打开输入的连接。
上面的代码在AutocompleteEdit类里处理完成了,然后就把打开网络连接放到别的类里来执行,这样可以提高代码的复用性,降低了代码复杂程度。那么这个controller_是何方神圣呢?一看AutocompleteEdit类有Controller类的定义,肯定就是它了,但再仔细一看它,它只是一个接口类,所有函数都是纯虚函数,真是百思不得其解时,突然想起,既然它是接口类,肯定就有其它类继承它的,那么再通过搜索,一查看,果然找到一个继承它的类LocationBarView,接着查看它的声明,如下:
#001 /
#002 //
#003 // LocationBarView class
#004 //
#005 // The LocationBarView class is a View subclass that paints the background
#006 // of the URL bar strip and contains its content.
#007 //
#008 /
#009 class LocationBarView : public ChromeViews::View,
#010 public AutocompleteEdit::Controller {
#011 public:
可见类LocationBarView是继承ChromeViews::View类,并且继承AutocompleteEdit::Controller类。说明它是一个窗口类,并且是控制类,那么就是说所有接口的功能都是在这个类里实现的,只需要分析这个类里的内容,就知道它是怎么样打开连接的了,下一次再来分析它。
上一次说到控制类的派生类LocationBarView,现在就来分析这个函数的功能,看看它又把URL连接传到那里去,立即就去看代码,在这行代码controller_->OnAutocompleteAccept里,可以看到调用函数OnAutocompleteAccept,它的代码如下:
#001 void LocationBarView::OnAutocompleteAccept(
#002 const std::wstring& url,
#003 WindowOpenDisposition disposition,
#004 PageTransition::Type transition,
#005 const std::wstring& alternate_nav_url) {
判断输入的URL连接是否为空。
#006 if (url.empty())
#007 return;
#008
保存相应的参数。
#009 location_input_ = url;
#010 disposition_ = disposition;
#011 transition_ = transition;
#012
调用控制器controller_来打开这个连接。
#013 if (controller_) {
#014 if (alternate_nav_url.empty()) {
#015 controller_->ExecuteCommand(IDC_OPENURL);
#016 return;
#017 }
#018
打开候选的连接。
#019 scoped_ptr<AlternateNavURLFetcher> fetcher(
#020 new AlternateNavURLFetcher(alternate_nav_url));
#021 // The AlternateNavURLFetcher will listen for the pending navigation
#022 // notification that will be issued as a result of the "open URL." It
#023 // will automatically install itself into that navigation controller.
#024 controller_->ExecuteCommand(IDC_OPENURL);
#025 if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
#026 // I'm not sure this should be reachable, but I'm not also sure enough
#027 // that it shouldn't to stick in a NOTREACHED(). In any case, this is
#028 // harmless; we can simply let the fetcher get deleted here and it will
#029 // clean itself up properly.
#030 } else {
#031 fetcher.release(); // The navigation controller will delete the fetcher.
#032 }
#033 }
#034 }
上面的代码主要保存传入来的参数,然后紧接着又调用了控制器controller_的函数ExecuteCommand来执行命令,这个命令是IDC_OPENURL。为什么要使用命令的方式呢?仔细地思考一下,原来这种方式是便于使用自动化测试,测试时可以自动使用程序来不断传入命令来执行。
我们再来分析这行代码:
controller_->ExecuteCommand(IDC_OPENURL);
controller_是类CommandController的实例,它主要是由MVC设计模式的控制类,可见这里可以学习怎么样把MVC设计模式应用到实际例子里,使用这种模式主要是分离面渲染、逻辑控制和不同的数据来源,这样方便维护代码。
其实所有的命令并不是CommandController来处理,它只是一个中传站,把命令发往不同的浏览器对象,如下面的代码:
#001 void CommandController::ExecuteCommand(int id) {
#002 if (IsCommandEnabled(id))
#003 handler_->ExecuteCommand(id);
#004 }
这样就把命令发送到handler_处理了,而这里的handler_是什么呢?其实它就是浏览器对象类Browser的实例,因此命令就是发送给浏览器对象来处理,它是怎么样处理命令的呢?下一次再来分析。
上一次说到发送命令给浏览器对象打开网页显示,但还没有分析它是怎么实现的,现在就来分析这方面的内容,如下:
#001 void Browser::ExecuteCommand(int id) {
#002 if (!IsCommandEnabled(id)) {
#003 NOTREACHED() << id;
#004 return;
#005 }
#006 // This might happen during QMU testing.
#007 if (!GetSelectedTabContents())
#008 return;
#009
#010 switch (id) {
#011 case IDC_BACK:
#012 UserMetrics::RecordAction(L"Back", profile_);
#013 GoBack();
#014 break;
#015
#016 ...
#017
#018
#019 case IDC_OPENURL:
#020 UserMetrics::RecordAction(L"LoadURL", profile_);
#021 {
#022 LocationBarView* lbv = GetLocationBarView();
#023 if (lbv) {
#024 OpenURL(GURL(lbv->location_input()), lbv->disposition(),
#025 lbv->transition());
#026 } else {
#027 OpenURL(GURL(), CURRENT_TAB, PageTransition::TYPED);
#028 }
#029 }
#030 break;
#031
可以看到这段代码,第19行就是处理打开网页的命令处理,当然在这个函数里不仅仅处理打开网页的连接命令,还有很多其它的命令,目前先分析这个命令的代码。
第20行里先记录当前执行的动作。
第22行里查找到当前显示BAR窗口。
如果找到LocationBarView窗口,就把当前的输入连接生成GURL对象,从窗口获取显示位置,传送的类型。否则,就是使用空的连接,并打开当前页面。
下面再来分析函数OpenURL的实现,它是调用TabContentsDelegate类里的OpenURL函数:
#001 virtual void OpenURL(const GURL& url,
#002 WindowOpenDisposition disposition,
#003 PageTransition::Type transition) {
#004 OpenURLFromTab(NULL, url, disposition, transition, std::string());
#005 }
在这个函数继续调用OpenURLFromTab函数来实现打开网页的功能,这个函数比较复杂,下一次再来分析它。
from: http://blog.csdn.net/caimouse/article/details/2999022
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。