以下の書籍を11章を読みました。
11章はかなり奥が深いので、1つの章のみの感想になります。
1章から10章の感想については、以下で書いています。
これまで、Tkinter とそれに付随する Canvas を使っと画面と描画を行ってきました。
図形やテキストを描画するだけであれば、これで十分です。
それ以上の視覚効果(opacityなど)を実装するには、より高度な機能を持つグラフィックライブラリが必要です。
本書では、Chromium で使用されている Skia というグラフィックライブラリを導入されます。
Tkinter の画面管理する機能が必要になるので、Simple DirectMedia Layer (SDL) の使用します。
Tkinter → SDL + Skia に置き換えるリファクタリングを行います。
SDL で画面を作成し、Skia で画面上のサーフェスへの割り当てを指示して描画します。
サーフェスは、画面上のピクセルを描画できるグラフィックバッファの表現を指します。
このサーフェスはメモリを多く消費するため、サーフェスの最適化がパフォーマンスに多く影響します。
Skia でサーフェスを構築したバイトデータを、SDLの画面サーフェスへコピーして描画します。
この描画には、Blitting と呼ばれる方式を採用し、必要箇所のみピクセルのコピーを行うことで、負荷軽減します。
Skia サーフェスを更新 → SD 画面サーフェスへコピー (画面反映) の順ですかね?
Skia への置き換えでは、各Drawクラスの execute 関数処理を Skia の canvas API を使って描画します。
サーフェスのピクセルを色付けする作業を ラスタライズ と呼ぶそうです。
Wiki によれば、ラスター形式(格子状のピクセル)に変換する意味でしょうか。
ラスタライズは、コンピュータグラフィックスにおいてラスター形式の画像(ビットマップ画像)以外のデータをラスター形式に変換して画像化すること。 ラスタライズ - Wikipedia - ja.wikipedia.org
以下のエラーになってしまったため、Docker ではなく uv run で動かすようにしました。
脱Tkinterしているので、ローカル環境で動いてくれました。
$ make docker_run
UserWarning: Using SDL2 binaries from pysdl2-dll 2.32.0
Fontconfig warning: "/usr/share/fontconfig/conf.avail/05-reset-dirs-sample.conf", line 6: unknown element "reset-dirs"
No matching fbConfigs or visuals found
glx: failed to create drisw screen
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 149 (GLX)
Minor opcode of failed request: 3 (X_GLXCreateContext)
Value in failed request: 0x0
Serial number of failed request: 162
Current serial number in output stream: 163
make: *** [docker_run] Error 1DrawRRect class のスクロール考慮が抜けいていた関係か、本書で紹介されていた角丸の確認ができませんでした。
以下のpatchファイルを生成して、動作確認できるようになりました。
※ もしかしたら、この先のコミットで直っているのかも?
diff --git a/browser/main.py b/browser/main.py
index e481dcc..fa29d8b 100644
--- a/browser/main.py
+++ b/browser/main.py
@@ -160,12 +160,17 @@ class DrawRect:
class DrawRRect:
def __init__(self, rect, radius, color):
self.rect = rect
- self.rrect = skia.RRect.MakeRectXY(rect, radius, radius)
+ self.radius = radius
self.color = color
def execute(self, scroll, canvas):
- sk_color = parse_color(self.color)
- canvas.drawRRect(self.rrect, paint=skia.Paint(Color=sk_color))
+ rect = self.rect.makeOffset(0, -scroll)
+ rrect = skia.RRect.MakeRectXY(rect, self.radius, self.radius)
+ paint = skia.Paint(
+ AntiAlias=True,
+ Color=parse_color(self.color),
+ )
+ canvas.drawRRect(rrect, paint=paint)
def getMetric(font, what):browser $ uv run main.py https://browser.engineering/examples/example11-rounded-background.htmlブラウザをスクロールするたびに再描画するのはパフォーマンスが悪いです。
そこで、ブラウザコンポジットと呼ばれるサーフェスの合成手法を実装します。
過去にブラウザのレイアウトを調べた際に、コンポジットというのがあったのでこれか!となりました。
合成なので、複数のサーフェスを用意し重ねて表示します。
例えば、クローム部分とタブ(ページ)でサーフェスを分けておいて、それぞれを非表示のサーフェスにします。
更新などでそれぞれ必要箇所のみ描画を行ったあと、画面サーフェスにそれぞれのサーフェスを適切な位置のみクリップしたりしてコピーします。
これはクローム部分とタブのサーフェスの話でしたが、タブの中でもサーフェスは分かれます。
ブラウザのレイアウトとペイントを知る | ジブンノート - silverbirder.github.io でも触れていますが、transform や opacity を使用すると、コンポジットが発生します。
それらのCSSプロパティを使用するとサーフェスが生成され合成処理が生まれます。
上記記事でも書かれている通り、paint 処理は負荷が高い(これまで話していた通り)ので left プロパティによるアニメーションはパフォーマンスに悪いです。
それを合成処理(tranform) に切り替えることで、逐次 paint ではなくサーフェス合成による最適化で滑らかなアニメーションを実現できます。
あの時学んでいた内容が、今具体的なイメージを持ててめちゃくちゃ嬉しいです。
本書の続きとしては、opacity を実装しますが省略します。
ブレンドとサーフェスのスタッキングについて解説されています。
上にあるサーフェスと下にあるサーフェスを、どのようにブレンドするのか書かれていました。
Alpha Compositing – Bartosz Ciechanowski - ciechanow.ski のページでは、サーフェスと合成について解説されていて、全部読めませんでしたが Skia の挙動について学びたい人は読んでも良いかもしれません。
Blink のグラフィカルな処理はライブラリを使われていたんですね。
なんとなく、自前で全部実装しているイメージでした。
今回はサーフェスの重ね合わせ時の色合いについてのコードを読みましたが、他にも色々ありそうです。
opacity や mix-blend-mode は奥が深そうです。
-
※ ログイン不要で投稿できます。
※ 同じブラウザから投稿を削除できます。
0
読み込み中...
タグ「書籍レビュー」の記事
以下の書籍を9章から10章まで読みました。 https://www.oreilly.co.jp/books/9784814401574/ 1章から8章の感想については、以下で書いています。 『Webブラウザエンジニアリング』第1~3章を読み
2026年03月27日
以下の書籍を7章から8章まで読みました。 https://www.oreilly.co.jp/books/9784814401574/ 1章から6章の感想については、以下で書いています。 『Webブラウザエンジニアリング』第1~3章を読みま
2026年03月25日
以下の書籍を4章から6章まで読みました。 https://www.oreilly.co.jp/books/9784814401574/ 1章から3章の感想については、以下で書いています。 https://silverbirder.githu
2026年03月22日