ウェブページ表示の仕組み

https://www.chromium.org/developers/design-documents/displaying-a-web-page-in-chrome

Chromiumがどのようにウェブページを表示するかをボトムアップに記述。マルチプロセスアーキテクチャも読む。マルチプロセスリソースローディングも面白い。

概念的アプリケーションレイヤー

(The original Google Doc for this illustration is http://goo.gl/MsEJX which is open for editing by any @chromium.org)

各階層は概念的アプリケーションレイヤー。下位レイヤーは上位レイヤに依存せず情報も持たない。

  • WebKit: Safari, Chromiumその他WebKitベースのブラウザで使われる共用レンダリングエンジン。PortはWebKitの一部でプラットフォーム依存のシステムサービス(リソースロードやグラフィック)を統合する。
  • Glue: WebKitの型をChromiumの型に変換する。これが我々のWebKit組み込みレイヤ。
  • Renderer / Render host: Chromiumのマルチプロセス組み込みレイヤ。相互の通知やコマンドのプロキシ。
  • WebContents: Contentモジュールのメインクラスで再利用可能なコンポーネント。マルチプロセスのHTMLレンダリングをビューへ容易に組み込み可能。コンテントモジュールのページ参照
  • Browser: ブラウザウインドウを表す。多数のWebContentsからなる。
  • Tab Helpers: 個別のオブジェクトでWebContentsと結びつく(WebContentsUserData混合)。ブラウザはこれらをWebContentsに結び付ける(faviconinfobarなど)

WebKit

我々はオープンソースのWebKitをウェブページのレイアウトに使っている。コードはアップルからプルされ、/third_party/WebKitディレクトリにある。WebKitは主にWebCoreから構成されコアレイアウト機能をもつ。Javascriptを実行するJavaScriptCoreももつ。JavaScriptCoreはテスト目的で実行する。通常これはハイパフォーマンスなV8 JavaScriptエンジンに置き換えられている。AppleがWebKitと呼ぶレイヤでSafariなどではWebCoreOS X間の組み込みAPIは実際には使っていない。我々はAppleからプルしたコードを一般にWebKitと呼んでいる。

WebKit port

最下位に我々のWebKit "port"がある。プラットフォーム固有の機能の実装でプラットフォーム独立のWebCoreとのインターフェースになる。ファイルはWebKitツリーにあり、chromiumディレクトリまたはChromiumサフィックスのファイルである。フォントレンダリングなどはプラットフォームごとに処理されなければならない。

  • ネットワークトラフィックはマルチプロセスリソースローディングで処理され、レンダープロセスからOSを利用しない。
  • グラフィックはAndroid用に開発されたSkiaグラフィックライブラリを利用する。これはクロスプラットフォームのグラフィックライブラリですべてのイメージと基本グラフィックを処理する(テキストは除く)。Skiaは/third_party/skiaにある。

WebKit glue

ChromiumWebKitは型などを含め別のコーディングルールで記述されている。WebKit glueはその間に入りChromiumにとってやりやすいインターフェースを提供する。/WebKit/glueにある。ネーミングはWebKitオブジェクトと同じようになっているが"Web"が初めにつく。例えばWebCore::FrameWebFrameになる。

"test shell"はベアボーンのウェブブラウザでWebKit portglueのテストをする。

レンダープロセス

Chromiumのレンダープロセスはglueインタフェースを使いWebKit portを組み込む。多量のコードは含んでいない。その仕事はブラウザとのIPCチャネルのレンダラーサイドになることである。

レンダラーのもっとも重要なクラスはRenderViewである。/content/renderer/render_view_impl.ccにある。これがウェブページを表す。ブラウザから、またブラウザへのナビゲーション関連のコマンドを処理する。これはRenderWidgetから継承されるがこれは描画や入力を処理する。RenderViewはブラウザとの通信に(レンダープロセスごとに)グローバルなRenderProcessを使う。

FAQ:RenderWidgetとRenderViewの違いは?

RenderWidgetWebCore::Widgetオブジェクトとマップされる。それは抽象インターフェースWebWidgetDelegateを実装することにより行う。RenderWidgetは基本的に1つのウインドウであり、入力と受け取り、描画の出力になる。RenderViewRenderWidgetから継承され、タブやポップアップウインドウのコンテンツになり、ナビゲーション関連の命令を受け取る。RenderViewなしにRenderWidgetが存在するケースが1つだけありウェブページ上のセレクトボックスである。

レンダラー内のスレッド

レンダラーは2つのスレッドを持つ。1つはRenderViewWebKitが動くものである。(途中)

ブラウザプロセス

下位レベルのブラウザプロセスのオブジェクト

ブラウザのIOスレッド上でレンダープロセスとのIPC通信が行われる。このスレッド上ですべてのネットワーク通信も扱われる。

メインスレッド(UIが動いている)でRenderProcessHostが初期化されるとき、新しくレンダラープロセスとChannelProxyというIPCオブジェクト(名前付きパイプ)がつくられる。このIPCオブジェクトはブラウザのIOスレッドで動き、名前付きパイプをリッスンし、メッセージをRenderProcessHostに返す。ResourceMessageFilterがこのチャネルにインストールされれば、メッセージをフィルタ出来る。

RenderProcessHostはビュー関連のメッセージを適切なRenderViewHostにディスパッチする責任がある。

上位レベルのブラウザプロセスのオブジェクト

ビュー固有のメッセージはRenderViewHost::OnMessageReceivedに到着する。ほとんどのメッセージはここで処理され残りはRenderWidgetHostへ回される。それぞれのプラットフォームでビュークラスがあり(RenderWidgetHostView[Aura|Gtk|Mac|Win])、ネイティブのビューシステムを実装する。

RenderView/Widgetの上位にWebContentsオブジェクトがある。ほとんどすべてのメッセージは結局のところこのオブジェクト上の関数コールに帰着する。WebContentsはウェブページのコンテンツを表す。コンテントオブジェクトの最上位モジュールである。矩形ビューにウェブページを表示する責任を持つ。詳しくはコンテントモジュールのページを参照。

WebContentsオブジェクトはTabContentsWrapperに含まれる。chromeディレクトリにありタブに責任を持つ。

イラストでの実例

ナビゲーションやスタートアップのさらなる実例はChromiumソースコードへの取り掛かりを参照。

"set cursor"メッセージの生涯

カーソルの切り替えはレンダラーからブラウザへ送られる典型的メッセージである。レンダラでは以下のことが起こる。

  • Set cursorメッセージは入力イベントへの応答として内部的にWebKitが生成する。set cursorメッセージはRenderWidget::SetCursorから始まる。
  • それはRenderWidget::Sendを呼び、メッセージをディスパッチする。このメソッドはRenderViewからもブラウザにメッセージを送るために使用される。そしてRenderThread::Sendを呼ぶ。
  • これはIPC::SyncChannelを呼びブラウザへ送られる。

そしたらブラウザは次のことを行う。

  • RenderProcessHost内にあるIPC::ChannelProxyはIOスレッドでこのメッセージを受け取る。
  • RenderProcessHost::OnMessageReceivedがメッセージを受け取る。いくつかのメッセージはここで直接処理され、残りはRenderViewHostへ送られる。
  • RenderViewHost::OnMessageReceivedにメッセージが到着する。多くのメッセージはここで処理される、我々のメッセージはここでは処理されない。
  • 処理されなかったメッセージは自動的にRenderWidgetHostに送られる。我々のメッセージもここに送られる。
  • メッセージマップがついにメッセージを受け取るりRenderWidgetHost::OnMsgSetCurorが呼ばれる。ここで適切なUI関数が呼ばれマウスカーソルがセットされる。

"mouse click"メッセージの生涯

マウスクリックメッセージはブラウザからレンダラーに送られる典型的メッセージ。

  • RederWidgetHostViewWin::OnMouseEventがブラウザのUIスレッドで呼ばれる。これはForwardMouseEventToRendererを呼ぶ。
  • このときマウス入力をプラットフォーム独立なWebMouseEventにまとめ、RenderWidgetHostに送る。
  • RenderWidgetHost::ForwardInputEventIPCメッセージViewMsg_HandleInputEventを作成、WebInputEventをその中にシリアライズする。そしてRenderWidgetHost::Sendする。
  • RenderProcessHost::Sendに送られIPC::ChannelProxyで送られる。
  • 内部的にはIPC:ChannelProxyIOスレッドへのプロキシで、そこで名前付きパイプでレンダラーに送られる。

他のタイプのメッセージはWebContentsで作成されることに注意。例えばナビゲーション関連など。WebContentsからRenderViewHostへは同じような経路をたどる。

そしてレンダラーでは:

  • メインスレッドのIPC::Channelがメッセージを受信し、IPC::ChannelProxyがレンダラースレッドでのプロキシになる。
  • RenderView::OnMessageReceivedがメッセージを受け取る。多くのメッセージはここで処理される。ただしマウスクリックは別で、RenderWidget::OnMessageReceivedに転送されその後RederWidget::OnHandleInputEventへ転送される。
  • WebWidgetImpl::HandleInputEventへ進み、WebKitPlatformMouseEvnetクラスへ変換される。その後、WebCore::Widgetへ進む。
Page last modified on July 08, 2018, at 06:13 PM
Powered by PmWiki