谷歌chrome浏览器的源码分析(三)

上一次介绍到怎么样从其它地方返回搜索到的超级连接,现在就来分析一下使用搜索引擎去查找的类SearchProvider,它是通过搜索引擎来查找出来的,在这里是通过GOOGLE搜索引擎来查找出来。它的声明如下:

#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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值