赞
踩
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
继续上一次来分析LoadRequest的代码,在分析这个函数代码之前,先看看WebFrame类的继承层次关系,如下:
class WebFrame : public base::RefCounted<WebFrame> {
WebFrame是一个接口类,但它先继承引用计数类RefCounted,这样对于这个对象多次访问,就可以使用引用计数来判断对象的生命周期了。对于base::RefCounted<WebFrame>的语法,其实它是一种模板实现的多态特性,这种方案是最高效的实现方式,比使用虚函数更少占内存,并且运行的速度也更快。它就是解决如下的问题:
void Release() {
if (subtle::RefCountedBase::Release()) {
delete static_cast<T*>(this);
}
}
上面的函数里static_cast<T*>(this),它就是一种多态的实现方法,由于base::RefCounted类并没有声明为虚析构函数,如下:
template <class T>
class RefCounted : public subtle::RefCountedBase {
public:
RefCounted() { }
~RefCounted() { }
既然没有把类RefCounted声明为虚析构函数,又想在基类里调用派生类的析构函数,只好使用static_cast和类型转换了,这是一种比较好的模板使用方法,在WTL里就大量使用这种技术。
接着可以看到:
class WebFrameImpl : public WebFrame {
public:
WebFrameImpl();
~WebFrameImpl();
类WebFrameImpl是继承接口类WebFrame,这里是使用接口与实现分析的设计模式,这样更方便代码灵活地复用。可见设计Chrome的设计师和写代码的程序员,都是顶尖的模板高手,大部的思想与WTL库的设计是一脉相承。也难怪Chrome的浏览器使用WTL库来设计界面。
#001 void WebFrameImpl::LoadRequest(WebRequest* request) {
#002 SubstituteData data;
#003 InternalLoadRequest(request, data, false);
#004 }
在WebFrame里调用函数LoadRequest,实际上是调用实现类WebFrameImpl函数LoadRequest,而在这个函数又是调用InternalLoadRequest来实现的,它的代码如下:
#001 void WebFrameImpl::InternalLoadRequest(const WebRequest* request,
#002 const SubstituteData& data,
#003 bool replace) {
//转换请求参数。
#004 const WebRequestImpl* request_impl =
#005 static_cast<const WebRequestImpl*>(request);
#006
获取请求的资源。
#007 const ResourceRequest& resource_request =
#008 request_impl->frame_load_request().resourceRequest();
#009
#010 // Special-case JavaScript URLs. Do not interrupt the existing load when
#011 // asked to load a javascript URL unless the script generates a result.
#012 // We can't just use FrameLoader::executeIfJavaScriptURL because it doesn't
#013 // handle redirects properly.
获取需要下载网页的地址。
#014 const KURL& kurl = resource_request.url();
处理加载javascript的连接情况。
#015 if (!data.isValid() && kurl.protocol() == "javascript") {
#016 // Don't attempt to reload javascript URLs.
#017 if (resource_request.cachePolicy() == ReloadIgnoringCacheData)
#018 return;
#019
#020 // We can't load a javascript: URL if there is no Document!
#021 if (!frame_->document())
#022 return;
#023
#024 // TODO(darin): Is this the best API to use here? It works and seems good,
#025 // but will it change out from under us?
#026 DeprecatedString script =
#027 KURL::decode_string(kurl.deprecatedString().mid(sizeof("javascript:")-1));
#028 bool succ = false;
加载执行脚本。
#029 WebCore::String value =
#030 frame_->loader()->executeScript(script, &succ, true);
#031 if (succ && !frame_->loader()->isScheduledLocationChangePending()) {
#032 // TODO(darin): We need to figure out how to represent this in session
#033 // history. Hint: don't re-eval script when the user or script navigates
#034 // back-n-forth (instead store the script result somewhere).
#035 LoadDocumentData(kurl, value, String("text/html"), String());
#036 }
#037 return;
#038 }
#039
停止上一次没有完成的加载情况。
#040 StopLoading(); // make sure existing activity stops
#041
#042 // Keep track of the request temporarily. This is effectively a way of
#043 // passing the request to callbacks that may need it. See
#044 // WebFrameLoaderClient::createDocumentLoader.
保存当前的请求连接。
#045 currently_loading_request_ = request;
#046
#047 // If we have a current datasource, save the request info on it immediately.
#048 // This is because WebCore may not actually initiate a load on the toplevel
#049 // frame for some subframe navigations, so we want to update its request.
获取当前数据源,如果已经存在就可以保存它。
#050 WebDataSourceImpl* datasource = GetDataSourceImpl();
#051 if (datasource)
#052 CacheCurrentRequestInfo(datasource);
#053
如果数据有效就可以直接替换就行了。
#054 if (data.isValid()) {
#055 frame_->loader()->load(resource_request, data);
#056 if (replace) {
#057 // Do this to force WebKit to treat the load as replacing the currently
#058 // loaded page.
#059 frame_->loader()->setReplacing();
#060 }
如果是历史网页选择,就判断是否出错的加载处理。
#061 } else if (request_impl->history_item()) {
#062 // Use the history item if we have one, otherwise fall back to standard
#063 // load.
#064 RefPtr<HistoryItem> current_item = frame_->loader()->currentHistoryItem();
#065
#066 // If there is no current_item, which happens when we are navigating in
#067 // session history after a crash, we need to manufacture one otherwise
#068 // WebKit hoarks. This is probably the wrong thing to do, but it seems to
#069 // work.
#070 if (!current_item) {
#071 current_item = new HistoryItem(KURL("about:blank"), "");
#072 frame_->loader()->setCurrentHistoryItem(current_item);
#073 frame_->page()->backForwardList()->setCurrentItem(current_item.get());
#074
#075 // Mark the item as fake, so that we don't attempt to save its state and
#076 // end up with about:blank in the navigation history.
#077 frame_->page()->backForwardList()->setCurrentItemFake(true);
#078 }
#079
#080 frame_->loader()->goToItem(request_impl->history_item().get(),
#081 WebCore::FrameLoadTypeIndexedBackForward);
重新加载网页。
#082 } else if (resource_request.cachePolicy() == ReloadIgnoringCacheData) {
#083 frame_->loader()->reload();
下面开始调用load来加载新下载的网页资源。
#084 } else {
#085 frame_->loader()->load(resource_request);
#086 }
#087
#088 currently_loading_request_ = NULL;
#089 }
上面通过几种情况来分别实现了加载javascript网页的处理,还有历史选项处理,还有重新加载网页和加载新网页的处理。下一次再来分析加载新网页的函数frame_->loader()->load的实现。
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
#001 void FrameLoader::load(const ResourceRequest& request)
#002 {
#003 load(request, SubstituteData());
#004 }
在这个函数也只是一个中间者,它又调用函数load函数的重载函数来实现了。
#001 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
#002 {
#003 if (m_inStopAllLoaders)
#004 return;
#005
#006 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
#007 m_loadType = FrameLoadTypeStandard;
#008 load(m_client->createDocumentLoader(request, substituteData).get());
#009 }
#010
在这个函数里,第一个参数request是连接相关的信息,第二个参数substituteData是一些状态数据。然后在第7行里设置加载的类型,第8行里调用WebFrameLoaderClient::createDocumentLoader函数来创建WebDocumentLoaderImpl对象,然后再通过get函数返回来,这样就知道load函数又调用那个重载函数了,原来它是调用这个函数,如下:
#001 void FrameLoader::load(DocumentLoader* newDocumentLoader)
#002 {
#003 ResourceRequest& r = newDocumentLoader->request();
#004 addExtraFieldsToRequest(r, true, false);
#005 FrameLoadType type;
#006
#007 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
#008 r.setCachePolicy(ReloadIgnoringCacheData);
#009 type = FrameLoadTypeSame;
#010 } else
#011 type = FrameLoadTypeStandard;
#012
#013 // Do not use original encoding override since it is not loaded by user
#014 // selecting encoding.
#015 if (m_documentLoader)
#016 newDocumentLoader->setOverrideEncoding(String());
#017
#018 // When we loading alternate content for an unreachable URL that we're
#019 // visiting in the b/f list, we treat it as a reload so the b/f list
#020 // is appropriately maintained.
#021 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
#022 ASSERT(type == FrameLoadTypeStandard);
#023 type = FrameLoadTypeReload;
#024 }
#025
#026 load(newDocumentLoader, type, 0);
#027 }
上面只对newDocumentLoader做一些准备工作,并没有真正地去加载任何东西,接着又调用函数:
void FrameLoader::load(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> formState)
在上面这个函数进行安全策略的处理,然后再经过N个函数处理之后,就调用下面的函数:
void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
在这个函数开始使用类DocumentLoader来设置下载请求,主要通过函数
bool DocumentLoader::startLoadingMainResource(unsigned long identifier)
来实现的,紧跟后面调用加载函数:
bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData)
在这个函数里又开始分为两种情况处理,一种是延进加载数据,一种是立即加载数据,下面主要介绍立即加载数据函数:
bool MainResourceLoader::loadNow(ResourceRequest& r)
在类MainResourceLoader是主要资源下载的管理类,loadNow函数是把资源请求ResourceRequest变成一个IPC消息又发送给资源下载进程去处理。它的简略代码如下:
#001 bool MainResourceLoader::loadNow(ResourceRequest& r)
#002 {
......
#011 willSendRequest(r, ResourceResponse());
#012
......
#015 if (!frameLoader())
#016 return false;
#017
......
#023
#024 if (m_substituteData.isValid())
#025 handleDataLoadSoon(r);
#026 else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
#027 handleEmptyLoad(url, !shouldLoadEmpty);
#028 else
#029 m_handle = ResourceHandle::create(r, this, m_frame.get(), false, true, true);
#030
#031 return false;
#032 }
在这个函数的第29行里,就会通过ResourceHandle::create函数创建一个资源消息,并把这个消息发送出去,到底它是怎么样实现的呢?下一次再来分析它。
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
上一次说到需要把显示的网络连接地址变成一个资源的消息发送出去,它是通过函数ResourceHandle::create来实现的,但这个函数到底是怎么样实现的呢?现在就分析它的实现代码,了解它怎么样把资源变换成消息,并且通过IPC机制把消息发送到资源下载进程去。数ResourceHandle::create的代码如下:
#001 PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request,
#002 ResourceHandleClient* client,
#003 Frame* deprecated,
#004 bool defersLoading,
#005 bool shouldContentSniff,
#006 bool mightDownloadFromHandle) {
上面的参数request是把所有请求网络连接地址信息传进来了。
#007 RefPtr<ResourceHandle> newHandle(
#008 new ResourceHandle(request, client, defersLoading, shouldContentSniff,
#009 mightDownloadFromHandle));
这里创建资源类ResourceHandle对象,通过它来生成一个消息发送出去。
#010
#011 if (newHandle->start(NULL))
#012 return newHandle.release();
上面的代码里,调用函数start来处理资源请求下载。
#013
#014 return NULL;
#015 }
在这个函数里调用newHandle->start函数来处理,其实它是调用下面的函数来工作的:
bool ResourceHandle::start(Frame* deprecated) {
return d->Start(NULL);
}
那么这里的d实例是什么呢?可以通过ResourceHandle的构造函数来看到它的类,如下:
ResourceHandle::ResourceHandle(const ResourceRequest& request,
ResourceHandleClient* client,
bool defersLoading,
bool shouldContentSniff,
bool mightDownloadFromHandle)
#pragma warning(suppress: 4355) // it's okay to pass |this| here!
: d(new ResourceHandleInternal(this, request, client)) {
// TODO(darin): figure out what to do with the two bool params
}
可以看到d是类ResourceHandleInternal的实例,这就是说调用d->Start函数,其实就是调用下面的函数:
#001 bool ResourceHandleInternal::Start(
#002 ResourceLoaderBridge::SyncLoadResponse* sync_load_response) {
#003 DCHECK(!bridge_.get());
#004
#005 // The WebFrame is the Frame's FrameWinClient
#006 WebFrameImpl* webframe =
#007 request_.frame() ? WebFrameImpl::FromFrame(request_.frame()) : NULL;
......
#154
#155 if (sync_load_response) {
#156 bridge_->SyncLoad(sync_load_response);
#157 return true;
#158 }
#159
通过上面的处理,然后就调用桥连接成员bridge_来创建消息。
#160 bool rv = bridge_->Start(this);
#161 if (rv) {
#162 pending_ = true;
#163 job_->ref(); // to be released when we get a OnCompletedRequest.
#164 } else {
#165 bridge_.reset();
#166 }
#167
#168 return rv;
#169 }
在这里使用一个设计模式,叫桥连接模式。函数bridge_->Start的代码如下:
// Writes a footer on the message and sends it
bool IPCResourceLoaderBridge::Start(Peer* peer) {
if (request_id_ != -1) {
NOTREACHED() << "Starting a request twice";
return false;
}
RESOURCE_LOG("Starting request for " << url_);
保存当前接收的连接端点。
peer_ = peer;
生成请求ID,以便返回数据时可以找到相应的显示进程和窗口。
// generate the request ID, and append it to the message
request_id_ = dispatcher_->AddPendingRequest(peer_, request_.resource_type,
request_.mixed_content);
找到IPC的消息发送对象,然后创建ViewHostMsg_RequestResource消息并发送出去。
IPC::Message::Sender* sender = dispatcher_->message_sender();
bool ret = false;
if (sender)
ret = sender->Send(new ViewHostMsg_RequestResource(MSG_ROUTING_NONE,
request_id_,
request_));
return ret;
}
通过上面漫长的分析,总算搞清楚了这个过程:
从界面开始输入URL地址,然后界面把URL发送到渲染进程,渲染进程再进行处理,把这个URL连接请求再次发送到资源下载进程去处理。串起来是一个极其简单的过程,但在这个浏览器里比较复杂的,因为它是多进程的浏览器,进程之间相互消息传送,就比其它浏览器复杂,并且它还有很多安全策略的使用和优化处理,导致这个处理过程是比较复杂的。
OK,资源下载请求消息已经发送出去,那么这个消息又往何处而去呢?又怎么样通过网络连接下载回来呢?欲知后事如何,请继续看下一篇!
from:
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
上一次说到类RenderThread和类RenderView把消息处理,那么这两个类是怎么样处理消息的呢?又是怎么样处理浏览的消息呢?现在就带着这两个问题去分析它的源码,理解它处理消息的方法。类RenderThread处理消息的代码如下:
#001 void RenderThread::OnMessageReceived(const IPC::Message& msg) {
#002 // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
#003 // it seems simpler to just process any control messages that we care about
#004 // up-front and then send the rest of the messages onto router_.
#005
下面判断是控制消息,如果是控制消息就在本类里处理,否则就分发到别的地方处理,主要是转到类RenderView处理。
#006 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#007 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
#008 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
#009 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
#010 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
#011 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
#012 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
#013 OnGetCacheResourceStats)
#014 // send the rest to the router
#015 IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
#016 IPC_END_MESSAGE_MAP()
#017 } else {
这里是分发消息到别的地方处理。
#018 router_.OnMessageReceived(msg);
#019 }
#020 }
在浏览器里,消息分为两大类:控制消息和路由消息。像使用IPC_MESSAGE_CONTROL宏定义的消息,就是控制消息;使用IPC_MESSAGE_ROUTED宏定义的消息,就是路由消息。
路由消息分发是由类MessageRouter来负责的,主要处理的代码如下:
#001
#002 void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
#003 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
#004 OnControlMessageReceived(msg);
#005 } else {
#006 RouteMessage(msg);
#007 }
#008 }
在这里又分为MSG_ROUTING_CONTROL消息和其它路由消息,再一次通过函数RouteMessage分发之后,如下:
#001 bool MessageRouter::RouteMessage(const IPC::Message& msg) {
#002 IPC::Channel::Listener* listener = routes_.Lookup(msg.routing_id());
#003 if (!listener)
#004 return false;
#005
#006 listener->OnMessageReceived(msg);
#007 return true;
#008 }
上面这个函数里又把消息通过发送到listener里去,其实listener是根据消息的目标routing_id来选择的,那么就是说它是选择发送到不同的窗口里去,因为每个TAB一个窗口。消息经过这样的处理之后,就到达了终点地--- RenderView::OnMessageReceived函数。下一次再来分析RenderView::OnMessageReceived函数的代码和后继处理。
上一次说到消息转发,并分析了RenderThread类里处理消息的函数,其实大部份的消息都是在RenderView类里的OnMessageReceived函数处理,比如浏览的消息也是在这里处理。它的代码如下:
#001 void RenderView::OnMessageReceived(const IPC::Message& message) {
#002 // Let the resource dispatcher intercept resource messages first.
如果是资源消息,就直接分发去处理,以便提高效率。
#003 if (resource_dispatcher_->OnMessageReceived(message))
#004 return;
下面开始处理RenderView类里所有的消息。
#005 IPC_BEGIN_MESSAGE_MAP(RenderView, message)
#006 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
#007 IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
#008 IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
#009 IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
#010 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
#011 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
#012 IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
#013 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
#014 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
#015 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
#016 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
#017 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
#018 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
#019 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
#020 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
#021 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
#022 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
#023 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
#024 IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
#025 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
#026 IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
#027 IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
#028 IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
#029 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
#030 IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
#031 IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
#032 IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
#033 IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
#034 IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
#035 IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
#036 IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
#037 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
#038 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
#039 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
#040 IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
#041 IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
#042 OnAllowDomAutomationBindings)
#043 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
#044 IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
#045 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
#046 IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
#047 OnDragSourceSystemDragEnded)
#048 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
#049 IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
#050 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
#051 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
#052 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
#053 IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
#054 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
#055 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
#056 IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
#057 OnUpdateBackForwardListCount)
#058 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
#059 OnGetAllSavableResourceLinksForCurrentPage)
#060 IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
#061 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
#062 IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
#063 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
#064 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
#065 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
#066 #ifdef CHROME_PERSONALIZATION
#067 IPC_MESSAGE_HANDLER(ViewMsg_PersonalizationEvent, OnPersonalizationEvent)
#068 #endif
#069 IPC_MESSAGE_HANDLER(ViewMsg_HandleMessageFromExternalHost,
#070 OnMessageFromExternalHost)
这里对于没有处理的消息进行提示。
#071 // Have the super handle all other messages.
#072 IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
#073 IPC_END_MESSAGE_MAP()
#074 }
从上面这个函数可以看到,它的消息处理是非常多的,下面来分析一个浏览网络连接的消息,它就是ViewMsg_Navigate,可以看到这个消息后面响应函数是OnNavigate,也就是说,当你输入网络地址之后按回车,就会通过上说过的IPC机制把消息发送到这里,接着来看这个函数OnNavigate的代码,如下:
#001 void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
判断窗口是否关闭,如果关闭就不用去打开连接地址了。
#002 if (!webview())
#003 return;
#004
处理一些about的连接处理,比如about:crash。
#005 AboutHandler::MaybeHandle(params.url);
#006
保存是否重新加载网页。
#007 bool is_reload = params.reload;
#008
获取WEB的显示框架。
#009 WebFrame* main_frame = webview()->GetMainFrame();
判断当是重新加载时,而当前又不是历史网页的情况。
#010 if (is_reload && !main_frame->HasCurrentState()) {
#011 // We cannot reload if we do not have any history state. This happens, for
#012 // example, when recovering from a crash. Our workaround here is a bit of
#013 // a hack since it means that reload after a crashed tab does not cause an
#014 // end-to-end cache validation.
#015 is_reload = false;
#016 }
#017
下面设置缓冲策略。
#018 WebRequestCachePolicy cache_policy;
#019 if (is_reload) {
#020 cache_policy = WebRequestReloadIgnoringCacheData;
#021 } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
#022 cache_policy = WebRequestReturnCacheDataElseLoad;
#023 } else {
#024 cache_policy = WebRequestUseProtocolCachePolicy;
#025 }
#026
下面创建一个下载请求,并把相关参数设置到请求里面。
#027 scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
#028 request->SetCachePolicy(cache_policy);
#029 request->SetExtraData(new RenderViewExtraRequestData(
#030 params.page_id, params.transition, params.url));
#031
设置WEBKIT的请求状态。
#032 // If we are reloading, then WebKit will use the state of the current page.
#033 // Otherwise, we give it the state to navigate to.
#034 if (!is_reload)
#035 request->SetHistoryState(params.state);
#036
让主WEB显示框架去下载请求显示。
#037 main_frame->LoadRequest(request.get());
#038 }
分析这个函数,就可以知道处理浏览消息的过程,下一次来分析WebFrame里的接口函数LoadRequest处理过程,到底它是怎么样处理JavaScript脚本网页下载的呢?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。