Chromiumのソースコードを読んでみる
この記事はSmartHR Advent Calendar 2020 10日目の記事です。
はじめに
私は、普段フロントエンドエンジニアとしてWebフロントエンドのコードを書いたりしています。 新しいHTML/CSS/JavaScriptの仕様だったり、新しいAPIのドキュメントを読んだりしていると、
この新しい仕様ってブラウザにどんな風に実装されてるんだろ?
↓
Chromiumのコードって公開されてるから見られるんじゃないかな
↓
いや、そもそもChromiumのソースコードって私でも見ても分かるのかな…
↓
公開されてるし、ちょっと覗いてみるだけでも何かいいことあるかも
と思いたってChromiumのソースコードを読んでみることにしました。
この記事はChromiumのコードを読んだことがない私がChromiumのコードを読むために行った手順と気付きを書いています。
ゴールを決める
Chromiumのソースコードを読んでみると決めたものの、Chromiumのソースコードは巨大で規模がとても大きいです。 しかも私はC++ 言語を触ったことない、全く読んだことがない、書いたことがないです...
なので、とりあえず div
タグ等のHTMLタグを生成してる辺りのコードを見つけて実装を眺めてみるっていうことをゴールにします。
Chromiumとは
Chromium オープンソースのウェブブラウザ。 主に C++ 言語で書かれています。
Chromiumを利用しているプロダクト
- Google Chrome
- Microsoft Edge
- Opera
- Brave
実際に読んで見る
ソースコードを読む準備
Chromiumのソースコードこちらを参考にgitで落としてくることが可能なようですが、Chromiumのような巨大なプロジェクトのコードを落としてくるのは、
- かなり時間がかかりそう
- C++ 言語用にエディタを整えるのが大変そう
- さくっと読んでみたい
という理由から、Chromium Code Searchを使って読んでみようと思います。
Chromium Code Search とは
Chromiumのソースコードの中から自由に検索ができ、クラスの定義や関数の呼び出し元、変数の参照元などをブラウザ上で辿ることができます。
ディレクトリ構成
コードを読む準備ができたので、さあ、読むぞ!という意気込みですが、膨大なソースコードを手当たり次第見ていっても全体像が分からないので、ざっくり全体を把握するためにディレクトリ構成を見ていきます。
src - android_webview - apps // Chrome packaged apps - base - breakpad - build - cc - chrome // GoogleChromeのオープンソースのアプリケーション層 - components - content // multi-process sandboxed browserに必要なコアコード - device - net - sandbox - skia + third_party/skia - sql - testing - third_party // 画像デコーダー、圧縮ライブラリ、WebエンジンBlinkなどの外部ライブラリ - blink // レンダリングエンジン, HTML,CSS, scriptをペイントコマンドや状態変化に変換するWebエンジン - ... - tools - ui/gfx // 共有グラフィックスクラス。これらは、ChromiumのUIグラフィックのベースを形成 - ui/views // UI開発を行うためのシンプルなフレームワーク。レンダリング、レイアウト、イベント処理を提供 - url // GoogleのオープンソースURL解析および正規化ライブラリ - v8 // V8Javascriptライブラリ
もっと詳しく知りたい方は以下に詳しく記載されているので読んでみてください。
HTMLタグが生成されているっぽいところを探す
ディレクトリ構成をざっと見たので、HTMLタグが生成されているところを探していこうと思います。
私が知っている情報は
なので、とりあえずblinkフォルダを覗いてみようと思います。
blinkフォルダ以下はこんな感じです。
このディレクトリのREADMEには
renderer/: code that runs in the renderer process (most of Blink).
と書いているので、renderer配下にいってみます。
renderer配下を見てみると renderer/core/html/
といういかにもっぽいディレクトリを見つけました。
中身を見てみると、
html_div_element.cc
, html_anchor_element.cc
, html_li_element.cc
などのHTMLタグの名前のファイルがたくさんあります。
html_div_element.cc
に div
タグの実装がありそうです。
div
の実装みたいなところ見つけた
では、html_div_element.cc の中身を見ていこうと思います。
// html_div_element.cc ... #include "third_party/blink/renderer/core/html_names.h" namespace blink { HTMLDivElement::HTMLDivElement(Document& document) : HTMLElement(html_names::kDivTag, document) {} void HTMLDivElement::CollectStyleForPresentationAttribute( const QualifiedName& name, const AtomicString& value, MutableCSSPropertyValueSet* style) { if (name == html_names::kAlignAttr) { if (EqualIgnoringASCIICase(value, "middle") || EqualIgnoringASCIICase(value, "center")) { AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kTextAlign, CSSValueID::kWebkitCenter); } else if (EqualIgnoringASCIICase(value, "left")) { AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kTextAlign, CSSValueID::kWebkitLeft); } else if (EqualIgnoringASCIICase(value, "right")) { AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kTextAlign, CSSValueID::kWebkitRight); } else { AddPropertyToPresentationAttributeStyle(style, CSSPropertyID::kTextAlign, value); } } else { HTMLElement::CollectStyleForPresentationAttribute(name, value, style); } } } // namespace blink
kAlignAttr
という型の名前や middle
, center
や left
, right
の 値で条件分岐をしていることから div
タグのalign属性の実装していることが分かります。
HTML5ではalign属性は廃止されていますが、HTML5以前の互換性を保つためにまだ実装の記述がされている?のかな(分からないです。予想です。)
html_div_element.h というファイルがincludeされているので、次はこちらを見ていきます。
// html_div_element.h ... namespace blink { class CORE_EXPORT HTMLDivElement : public HTMLElement { DEFINE_WRAPPERTYPEINFO(); public: explicit HTMLDivElement(Document&); private: void CollectStyleForPresentationAttribute( const QualifiedName&, const AtomicString&, MutableCSSPropertyValueSet*) override; }; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_HTML_DIV_ELEMENT_H_
class CORE_EXPORT HTMLDivElement : public HTMLElement
から
HTMLDivElement
が定義されていますが、HTMLElement
を継承していることが分かります。
では次に HTMLElement
を定義している html_element.h を見てみます。
// html_element.h ... namespace blink { struct AttributeTriggers; class Color; class DocumentFragment; class ElementInternals; class ExceptionState; class FormAssociated; class HTMLFormElement; class KeyboardEvent; class StringOrTrustedScript; class StringTreatNullAsEmptyStringOrTrustedScript; enum TranslateAttributeMode { kTranslateAttributeYes, kTranslateAttributeNo, kTranslateAttributeInherit }; class CORE_EXPORT HTMLElement : public Element { DEFINE_WRAPPERTYPEINFO(); ...
Color
クラス、 KeyboardEvent
クラスがあったり、読んでいくとdraggable()
, innerText()
, offsetHeightForBinding()
という名前のメソッドがあることからタグ固有のふるまいではなく共通のHTML要素のふるまいを書いているファイルのような予感です。
また、html_element.h
というファイル名、draggable()
, innerText()
というメソッドがあることからこのファイルは HTMLElement の実装をしていそうです。
HTMLElement
は Element
を継承しているので次は element.h を見てみます。
// element.h namespace blink { class AccessibleNode; class Attr; class Attribute; class CSSPropertyValueSet; class CSSStyleDeclaration; class CustomElementDefinition; class DOMRect; class DOMRectList; class DOMStringMap; class DOMTokenList; ... class CORE_EXPORT Element : public ContainerNode, public Animatable { DEFINE_WRAPPERTYPEINFO(); ...
element.h
というファイル名、AccessibleNode
, Attribute
, などのクラス、ずっと見ていくと ClassNames()
, scrollWidth()
, innerHTML()
というメソッドがあることからこのファイルは Element の実装をしていそうです。
ContainerNode
, Animatable
を継承しているのですが、このまま継承しているクラスをざっと見ていくと、
Element
→ ContainerNode
→ Node
→ EventTarget
という流れで継承していました。
ここで HTMLElement - Web API | MDN を見てみると
要素はこれを継承したインターフェイスを通して実装されています。
HTMLElement - Web API | MDN より
と書かれていて、Chromiumの実装と同じことが分かります。
合わせてMDNのHTMLElement
, Element
のページを見てみると、記載されているプロパティ名と同じ実装を見つけることできます。
また、 div
タグは HTMLDivElement
→ HTMLElement
→ Element
→ ContainerNode
, Animatable
→ Node
…
のような実装の流れだったのですが、 a
タグなど他のHTMLタグの実装をみても同じ流れでした。
このことからHTMLタグはHTMLElement
クラスから派生してできていることが分かりました。
divの実装を探してみてのまとめ
third_party/blink/renderer/core/html/
配下に、HTMLタグごとのファイルがある- HTMLタグは
HTMLElement
クラスを継承してできている HTMLElement
やElement
オブジェクトの実装が気になったらhtml_element.h
,element.h
を読んでみると分かりそうHTMLElement.XXX
やElement.XXX
とか使ったりするけど、ちょっと理解が深まった気がする
↑が実際にChromiumのソースコードを読んでみての気付きです。
見ていて気になったところ(おまけ)
accessibility
third_party/blink/renderer/core
に accessibilityフォルダがありました。
最近働いている会社でaccessibility勉強会をやっていて気になりました。
ここにARIAの実装とかAOMの実装が書いてあるのかな
potal
PortalsというWICGによって提案されているページ間の遷移をシームレスにすることができる仕組みがあるのですが、third_party/blink/renderer/core/html
にpotalディレクトリがあったので、ここでpotalタグが実装されてる気がしました。
まとめ
今回は div
タグのHTMLタグを生成してる辺りのコードを見つけて実装を眺めてみました。
C++言語がよく分かっていないので、関数名、クラス名で予測しながらでしか見ることができなかったのですが、ディレクトリ構成を眺めて全体像がなんとなく分かったり、いつも何気なく使ってるdiv
タグの実装から HTMLタグはHTMLElement
クラスから派生してできているというのが分かったり、HTMLElement
やElement
オブジェクトの実装を覗いてみたりすることができました。
使用してるライブラリの新しいバージョンのRelease Noteを読むだけではなく、変更されてるコードを読むことでより理解できることがあります。 ブラウザの新しいAPIができたとき仕様のドキュメントを読むだけではなく、実装を見てより理解を深め、ちゃんと理解してWebフロントエンドのコードが書けるになったらなあと思いました。 (C++言語何も分からなかったので何年先になるんだろう…)
Chromiumのコードって一生読めないものって勝手に思っていましたが、いざ眺めてみるとクラス名、メソッド名で予測しながらほんの少しだけ読めて少し嬉しくなりました。
参考
Chromium のソースコードの歩き方
Getting Around the Chromium Source Code Directory Structure - The Chromium Projects
HTMLElement - Web API | MDN