Open35
Flutter内部コードを探る
Flutterの実行ファイルを起動したとき何が起こるのか
Flutter for Windows のコードを読む
用語
- {app}: Flutterアプリのルートディレクトリ
 - {flutter}: flutter/flutterのルートディレクトリ
 - {engine}: flutter/engineのルートディレクトリ
 
{app}/windows/runner/main.cppにmain関数であるwWinMain()が存在
- 
in
wWinMain()- 
run_loop: RunLoopを作成 - 
project: DartProjectを作成 - 
window: FlutterWindowを作成 - ウィンドウサイズを指定してwindowにset
 - 
window.CreateAndShow()を呼ぶ - 
run_loop.Run()でメインループに入る 
 - 
 - 
FlutterWindowの定義は{app}/windows/runner/flutter_window.h
- 実装は{app}/windows/runner/flutter_window.cpp
 - FlutterWindowは
Win32Windowを継承している 
 - 
Win32Window
- コンストラクタでは特に何もしない
 - 
Win32Window::CreateAndShow- 
CreateWindowを呼び出して画面を作成 - 
Win32Window::OnCreate()を呼ぶ 
 - 
 
 - 
- 
FlutterViewControllerを作成 - 
run_loop_: RunLoopのRegisterFlutterInstance(flutter_controller_->engine())でエンジンを登録 - 
Win32Window::SetChildContent()でcontrollerの画面を登録 
 - 
 - 
- 
RunLoop::Run()でメインループを起動- ループ内で
RunLoop::ProcessFlutterMessages()を呼ぶ- 
FlutterEngine::ProcessMessages()を呼ぶ- これはもう使っていない...?(#24232)
 
 
 - 
 
 - ループ内で
 
 - 
 - 
FlutterViewControllerの定義は{engine}/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h
- 実装は{engine}/shell/platform/windows/client_wrapper/flutter_view_controller.cc
 - コンストラクタ内
- 
engine_: FlutterEngineを作成 - 
controller_: FlutterDesktopViewControllerRefを作成。FlutterDesktopViewControllerCreateで作る - 
view_: FlutterViewを作成 
 - 
 
 
- FlutterEngineの定義は{engine}/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h
- 実装は{engine}/shell/platform/windows/client_wrapper/flutter_engine.cc
- 
engine_: FlutterDesktopEngineRefをFlutterDesktopEngineCreateで作成- 
FlutterDesktopEngineCreate- 
FlutterWindowsEngineを作成 
 - 
 
 - 
 
 - 
 
 - 実装は{engine}/shell/platform/windows/client_wrapper/flutter_engine.cc
 - FlutterWindowsEngineの定義は{engine}/shell/platform/windows/flutter_windows_engine.h
- 実装は{engine}/shell/platform/windows/flutter_windows_engine.cc
- 
task_runner_: TaskRunner = TaskRunner::Create()でタスクランナーを作成 - 
FlutterDesktopMessengerの作成 - 
FlutterDesktopPluginRegistrarの作成 - 
BinaryMessengerImplの作成 - 
IncomingMessageDispatcherの作成 - 
FlutterWindowsTextureRegistrar::ResolveGlFunctionsの実行 - 
FlutterWindowsTextureRegistrarを作成 - 
surface_manager: AngleSurfaceManagerを作成 - 
WindowProcDelegateManagerWin32を作成 - 
BasicMessageChannelを作成 
 - 
 
 - 実装は{engine}/shell/platform/windows/flutter_windows_engine.cc
 - FlutterViewの定義は {engine}/shell/platform/windows/client_wrapper/include/flutter/flutter_view.h
- 実装どこ...?(ヘッダファイルだけで完結してる?)
 
 
- TaskRunnerの定義は {engine}/shell/platform/windows/task_runner.h
- 実装は{engine}/shell/platform/windows/task_runner_win32.cc
 - 
TaskRunner::Create()はTaskRunnerWin32(TaskRunnerを継承)を吐き出す - コンストラクタ内
- 
task_runner_window_: TaskRunnerWin32Windowを作成 - `task_runner_window_のAddDelegateにthisを入れる
 
 - 
 - 
TaskRunnerWin32::ProcessTasks()が呼ばれるとqueueに積まれたタスクを実行する 
 - TaskRunnerWin32Windowの定義は{engine}/shell/platform/windows/task_runner_win32_window.h
- 実装は{engine}/shell/platform/windows/task_runner_win32_window.cc
 - コンストラクタ内
- Windows APIを主に叩いている
 - 
CreateWindowExでウィンドウを作成(大きさはゼロ?) 
 - 
TaskRunnerWin32Window::ProcessTasks()を呼ぶとAddDelegateで登録したデリゲートを実行する 
 
- 
FlutterEngine::Run- 
FlutterDesktopEngineRun- 
FlluterWindowsEngine::RunWithEntryPoint- AOTコンパイルの場合、
FlutterProjectBundle::LoadAotData()を呼ぶ- 
Embedder::CreateAotData()を呼ぶ(Embedder::FlutterCreateAotData()が実装)- 
Dart_LoadELF()を呼んでaotデータを読み込む 
 - 
 
 - 
 - TaskRunnerの設定を
FlutterProjectArgsに乗せる- PlatformTaskRunnerの設定は
FlutterTaskRunnerDescriptionへ - 他のRunnerの設定は
FlutterCustomTaskRunnerへ - FlutterEngineProcTable.Run()
 - 
FlutterEngineGetProcAddresses(&embedder_api_);内でFlutterEngineProcTableの各メソッドを指定(RunはFlutterEngineRunが指定)- 
FlutterEngineInitializeを呼び出し- PlatformViewとかの設定
 - Textureとかの設定
 - Rasterizerとかの設定
 - 
flutter::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost()の実行 - 諸々の設定を使って
EmbedderEngineを作成 
 - 
FlutterEngineInitializedを呼ぶ- 
EmbedderEngine::LaunchShell()を呼ぶ- 
Shell::Create()を呼ぶ 
 - 
 - 
EmbedderEngine::NotifyCreated()を呼ぶ - 
EmbedderEngine::RunRootIsolate()を呼ぶ 
 - 
 - engine_outにEmbedderEngineを入れて返す
 
 - 
 
 - PlatformTaskRunnerの設定は
 - 
FlutterWindowsEngine.engine_にEmbedderEngineが入る 
 - AOTコンパイルの場合、
 
 - 
 
 - 
 - FlutterViewController()
- FlutterWindowEngineを作成
 - FlutterDesktopViewControllerCreate
- FlutterWIndowEngine::RunWithEntryPoint
- ...
 
 
 - FlutterWIndowEngine::RunWithEntryPoint
 
 
- 
EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost- 
CreateEmbedderManagedThreadHostを実行- 
CreateEmbedderTaskRunnerでPlatformTaskRunnerとRenderTaskRunnerを作成 - 
ThreadHostで残りのTaskRunner(IOとUI、前で失敗したらRasterも)を作成- 
fml::Threadで指定されたスレッドをstd::Threadで作成- MessageLoopを起動
 
 
 - 
 - 
{engine}/common/TaskRunnersに4つのTaskRunnerをセット(これはセットするだけで中では特に何もしていない) - 
EmbedderThreadHostに4つのTaskRunnerをセット?- 
EmbedderThreadHost::PostTask()を呼ぶことで指定したスレッドにタスクを流せる? 
 - 
 
 - 
 - EmbedderThreadHostをreturn
 
 - 
 
- 
FlutterDesktopViewControllerCreate(engine)- 
window_wrapper: FlutterWindowWin32を作成- 
FlutterWindowWin32- 
WindowWin32とWindowBindingHandlerを継承 - コンストラクタ内で
WindowWin32::InitializeChildを呼び出し- 
WindowWin32::InitializeChild- 
CreateWindowEx()で指定された大きさのウィンドウを作成 
 - 
 
 - 
 
 - 
 
 - 
 - 
state: FlutterDesktopViewControllerStateを作成- 
FlutterDesktopViewControllerStateはview::FlutterWindowsViewを持つだけの構造体 
 - 
 - 
state.viewにFlutterWindowsViewをwindow_wrapperを渡し作成して代入 - 
state.viewにengineをセット- engineをセット
 - 
FlutterWindowsEngine::SetView()にthisを入れる - platform_handler_とcursor_handler_を作成
 
 - 
FlutterWindowsView::CreateRenderSurfaceを呼ぶ- 
FlutterWindowsEngine.surface_manager.CreateSurfaceを呼ぶ- 
AngleSurfaceManager::CreateSurface- EGLのsurfaceを作成する
 
 
 - 
 
 - 
 - engineの
RunWithEntryPoint()が呼ばれていなければ呼ぶ - 
FlutterWindowsView::SendInitialBoundsを呼ぶ - stateを返す
 
 - 
 
- 
FlutterWindowsView- 
WindowBindingHandler::SetView()にthisを入れる- これでWindowBindingHandlerから来たイベントを
FlutterWindowsViewのメソッドで受け取れるようになる 
 - これでWindowBindingHandlerから来たイベントを
 
 - 
 
- 
DartProject- assets_path、icu_data_path、aot_library_pathを指定
 - Pathを保持しているだけのクラス
 
 
- 
Shell::Create()- 
Shell::PerformInitializationTasks()を呼ぶ- logの設定とか
 - 
SkGraphics::Init()を呼んでSkiaを初期化 - 
fml::icu::InitializeICU(settings.icu_data_path)を呼んでICU Dataを初期化 - キャッシュする
 
 - 
DartVMRef::Create()でDartVMを作成- 
DartVM::Create()を呼ぶ- 
DartVMData::Create()を呼ぶ- vmとisolateのsnapshotを読み込むor作成する
 
 - 
new DartVM()- 
SkExecutor::SetDefault()を呼ぶ - DartVMの初期化やら設定やら
dart::bin::BootstrapDartIo()- 
DartUI::InitForGlobal()- 各クラスの
RegisterNatives()を呼んでdartのメソッドとc++のメソッドを接続する- 
{engine}/lib/ui/辺りに存在 
 - 
 
 - 各クラスの
 DartVMInitializer::Initialize()
 - debugフラグの設定やら
 
 - 
 
 - 
 
 - 
 - 
Shell::CreateWithSnapshot()を呼ぶ- 
fml::TaskRunner::RunNowOrPostTaskにPlatform Task Runnerを指定して実行- Platform Task Runner上で
Shell::CreateShellOnPlatformThread()を実行 
 - Platform Task Runner上で
 - 作ったshellを返す
 
 - 
 
 - 
 
- 
Shell::CreateShellOnPlatformThread()- 
new Shell()でshell作成- 
DisplayManagerを作成 - 
serviec_protocol_handlers_を設定- ハンドラの種類は
{engine}/runtime/service_protocol.hに 
 - ハンドラの種類は
 
 - 
 - Raster Task Runnerで
Rasterizerを作成 - Platform Viewを作成
 - IO Task Runnerで
ShellIOManagerを作成 - UI Task Runnerで
Engineを作成 - 
Shell::SetUp()を呼ぶ- 
PlatformView::CreateExternalViewEmbedder()を呼んでRasterizerにセットする - UI Task Runnerで
Engine::SetupDefaultFontManager()を呼ぶ 
 - 
 
 - 
 
- 
EmbedderEngine::RunRootIsolate()- 
Shell::RunEngine()- UI Task Runnerで
Engine::Run()を実行- 
Engine::UpdateAssetManager()を実行 - 
RuntimeController::LaunchRootIsolate()を呼ぶ- 
DartIsolate::CreateRunningRootIsolate()を呼ぶ- 
DartIsolate::CreateRootIsolate()でIsolateを作成 - 
IsolateConfiguration::PrepareIsolate()を実行 - 
DartIsolate::RunFromLibrary()を実行- dartのmain関数を指定
 - 
DartIsolate::InvokeMainEntrypoint()をmain関数として実行 
 
 - 
 - 
Shell::OnRootIsolateCreated()を実行 
 - 
 
 - 
 
 - UI Task Runnerで
 
 - 
 
- main.dart
- 
runApp()を呼ぶ- 
WidgetsFlutterBinding.ensureInitialized()を呼ぶ- 
WidgetFlutterBindingのインスタンスを作成- in 
BindingBase:initInstances()を呼ぶ- 
GestureBinding.initInstances()を呼ぶ - 
SchedulerBinding.initInstances()を呼ぶ - 
ServicesBinding.initInstances()を呼ぶ - 
PaintingBinding.initInstances()を呼ぶ - 
SemanticsBinding.initInstances()を呼ぶ - 
RendererBinding.initInstances()を呼ぶ- PipelineOwnerを作成
 - 
RendererBinding.initRenderViewを呼ぶ- 
RendererBinding.createViewConfiguration()を呼びconfigurationを作る- sizeは画面サイズをdpiに変換した値
 
 - 
renderView: RenderViewを作成- Renderツリーの根
 
 - 
RendererBinding.initRenderView()呼ぶ- 
RenderView.prepareInitialFrame()呼ぶ- 
RenderObject.scheduleInitialLayout()呼ぶ- PipelineOwnerの_nodesNeedingLayoutにrenderViewを追加
 
 - 
RenderView._updateMatricesAndCreateNewRootLayer()でrootLayerを作成 - 
RenderObject.scheduleInitialPaint(rootLayer)呼ぶ- _layerHandle.layerにrootLayerをセット
 - PipelineOwnerの_nodesNeedingPaintにrenderViewを追加
 
 
 - 
 
 - 
 
 - 
 
 - 
WidgetsBinding.initInstances()を呼ぶ 
 - 
 - in 
BindingBase:initServiceExtensions()を呼ぶ- デバッグ用の諸々
 
 
 - in 
 
 - 
 - 
WidgetsBinding.scheduleAttachRootWidget() 
 - 
 
 - 
 
- 
WidgetsBinding.attachRootWidget()- 
RenderObjectToWidgetAdapterを作成- Widgetツリーの根となるObject
 - 
createElement()でRenderObjectToWidgetElementを生成 - 
createRenderObject()でrenderViewを返す 
 - 
RenderObjectToWidgetAdapter.attachToRenderTree()を呼ぶ- 
element = RenderObjectToWidgetAdapter.createElement()を呼ぶ - elementのownerにBuildOwnerを指定
 - 
BuildOwner.buildScope()呼ぶ- 渡されたcallbackを呼ぶ
- 
RenderObjectToWidgetElement.mount(null,null)呼ぶ- `RootRenderObjectElement.mount(null,null)`呼ぶ
- 
RenderObjectElement.mount(null,null)呼ぶ- `Element.mount(null,null)呼ぶ
- 
Element._updateInheritance()呼ぶ - 
Element._inheritedWidgetsを更新 
 - 
 - 
widget.createRenderObject()を呼ぶ- 
renderViewが返ってくる 
 - 
 - 
RenderObjectElement.attachRenderObject(null)を呼ぶ- slotがnullなので特に何もしないと思う
 
 
 - `Element.mount(null,null)呼ぶ
 
 - 
 - 
RenderObjectToWidgetElement._rebuild()呼ぶ- {MyApp}のツリーを作成
- ElementツリーとRenderツリーが作られる
 
 
 - {MyApp}のツリーを作成
 
 - `RootRenderObjectElement.mount(null,null)`呼ぶ
 
 - 
 
 - 渡されたcallbackを呼ぶ
 
 - 
 - 
_renderViewElement: RenderObjectToWidgetElementにセット - 
SchedulerBinding.ensureVisualUpdate()を実行- 
SchedulerBinding.scheduleFrame()呼ぶ- 
SchedulerBinding.ensureFrameCallbacksRegistered()呼ぶ- 
window.onBeginFrameとwindow.onDrawFrameをセット 
 - 
 - 
window.scheduleFrame()呼ぶ 
 - 
 
 - 
 
 - 
 
- 
window.scheduleFrame()- 
PlatformDispatcher.scheduleFrame()-> {engine}内のScheduleFrame()が呼ばれる- 
UIDartState.platform_configuration.client.ScheduleFrame()呼ぶ - 
UIDartStateはいつか作ったメインのDartIsolateだと思われる - 
platform_configuration.client: PlatformConfigurationClientはRuntimeControllerである- 
RuntimeController.ScheduleFrame()内- 
Engine.ScheduleFrame()を呼ぶ- 
Animator.requestFrame(true)を呼ぶ- UI Task Runner内で
Animator.AwaitVSync()呼ぶ- 
VSyncWaiterでVSyncを待ってからAnimator.BeginFrame()呼ぶ 
 - 
 
 - UI Task Runner内で
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
- 
PlatformConfiguration.BeginFrame()- {engine}/lib/ui/hooks.dartの
_beginFrame()を呼ぶ- 
PlatformDispatcher.onBeginFrame()呼ぶ- 
SchedulerBinding.handleBeginFrame()呼ぶ- 
SchedulerBinding._transientCallbacksを実行- 最初は登録がないはず
 
 
 - 
 
 - 
 - 
PlatformDispatcher._updateFrameData()呼ぶ- 
PlatformDispatcher.onFrameDataChanged()呼ぶ 
 - 
 
 - 
 - {engine}/lib/ui/hooks.dartの
_drawFrame()を呼ぶ- 
PlatformDispatcher.onDrawFrame()呼ぶ- 
SchedulerBinding.handleDrawFrame()呼ぶ- 
SchedulerBinding._persistendCallbacksを実行 - 
SchedulerBinding._postFrameCallbacksを実行 
 - 
 
 - 
 
 - 
 
 - {engine}/lib/ui/hooks.dartの
 
- 
RendererBinding.drawFrame()- 
PipelineOwner.flushLayout()呼ぶ- 再計算の必要があるRenderObjectのレイアウトをすべて更新する
 - RenderObject.sizeに大きさ、RenderObject.parentData.offsetにオフセットを書き込む
 - _nodesNeedingLayoutにはrenderViewがいる
 - 
renderView._layoutWithoutResize()呼ぶ -> RenderObject._layoutWithoutResize()- 
RenderView.performLayout()呼ぶ- childのRenderObject.layout({画面サイズ}.tight)呼ぶ
 
 - RenderObject.markNeedsSemanticsUpdate()呼ぶ
 - RenderObject.markNeedsPaint()呼ぶ
 
 - 
 
 - 
PipelineOwner.flushCompositingBits()呼ぶ- Renderツリーの
RenderObject.needsCompositingを更新 
 - Renderツリーの
 - 
PipelineOwner.flushPaint()呼ぶ- RenderObject._layerHandle.layerにpaint
 - 描画結果は
layer.pictureに - 
_nodesNeedingPaintごとに処理する - 
renderViewは_nodesNeedingPaint内に存在 - 
renderView._layerHandle.layer!.attachedはtrue- 
PaintingContext.repaintCompositedChild(renderView)呼ぶ 
 - 
 
 - 
RenderView.compositeFrame()呼ぶ- 
builder = ui.SceneBuilder()でSceneBuilderを作成 - 
scene = RenderView.layer.buildScene(builder)でsceneを作成 - 
_window.render(scene)でsceneをengineに送る 
 - 
 - 
PipelineOwner.flushSemantics()呼ぶ 
 - 
 
コメントメモ:
- Element.updateChild(): 子を新しい設定で更新するメソッド。このメソッドはWidgetシステムのコアである。
 
下の場合を考えよう。
runApp(Align(
  child: RichText(
    text: const TextSpan(
        children: [TextSpan(text: "Hello, "), TextSpan(text: "world!")]),
    textDirection: TextDirection.ltr,
  ),
));
- 
RenderObjectToWidgetElement._rebuild()- 
Element.updateChild(null, {MyApp}, Object())呼ぶ- 子を更新するメソッド
 - 
newChild = Element.inflateWidget({MyApp}, Object())- 
newChild = Align.createElement() - 
newChild.mount(RenderObjectToWidgetElement, Object())- これは
SingleChildRenderObjectElement.mount()- 
RenderObjectElement.mount()呼ぶ- 
Element.mount()呼ぶ- parentとnewSlotを保存
 - lifecycleStateをActiveに
 - ownerをparentから継承
 - globalKeyをownerに登録
 - Element._updateInheritance()呼ぶ
- 親の持つinheritedWidgetsを受け取る
 
 
 - 
Align.createRenderObject(this)を呼んでrenderObjectとする - 
RenderObjectElement.attachRenderObject(Object())呼ぶ- newSlotを_slotに保存
 - 親を伝って一番近いRenderObjectElementを探す
- RenderObjectToWidgetElementが見つかる
 
 - RenderObjectToWidgetElement.insertRenderObjectChild(renderObject, newSlot)呼ぶ
- renderObject[renderView]のchildにrenderObjectを保存
 
 - parentDataを更新(FlexibleやPositionedに使われている?)
 
 
 - 
 - 
Element.updateChild(null, RichText, null)呼ぶ- 
newChild = Element.inflateWidget(RichText, null)=MultiChildRenderObjectElement(widgets = TextSpan[])- 
newChild[MultiChildRenderObjectElement].mount({AlignのElement}, null)- 
RenderObjectElement.mount()Element.mount()- 
renderObject = RichText.createRenderObject(this)=RenderParagraph - 
RenderObjectElement.attachRenderObject(null)- 
{AlignのElement}[SinglechildRenderObjectElement].insertRenderObjectChild(renderObject, null)- {AlignのElement}のrenderObjectの子にrenderObjectを追加
 
 
 - 
 
 - widget.children{RichText内のTextSpanたち)それぞれを
Element.inflateWidget(children[i],IndexedSlot())で呼び出す- がTextSpanはここに入っていないので使われない
 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - これは
 
 - 
 
 
 - 
 
ここまでで以下のツリーが作成されている(parent -> child)
- RenderObjectToWidgetAdapter
- Align
- RichText
 
 
 - Align
 - RenderObjectToWidgetElement
- SingleChildRenderObjectElement
- MultiChildRenderObjectElement
 
 
 - SingleChildRenderObjectElement
 - RenderView
- RenderPositionedBox
- RenderParagraph
 
 
 - RenderPositionedBox
 
続き
- 
RenderView.performLayout()- RenderPositionedBox.layout({画面サイズ}.tight) -> 
RenderObject.layout- RenderObject._relayoutBoundaryを指定(自分)
 - RenderPositionedBox.sizedByParentはFalseのはず
 - RenderPositionedBox.performLayout()呼ぶ
- child.layout({画面サイズ}.loosen, parentUsesSize: true)呼ぶ -> RenderObject.layout
- RenderObject._relayoutBoundaryは親と同じやつ
 - visitChildren(_cleanChildRelayoutBoundary);も呼ぶんじゃないかなぁ
 - RenderBox.performResize()呼ぶ
- RenderParagraph.computeDryLayout(constraints)呼ぶ
- RenderParagraph._layoutChildren(constraints, dry: true)呼ぶ
- childrenはないので空の配列が返る?
 
 - TextPainter.setPlaceholderDimensions([])呼ぶ
- 空なのでなにもしない
 
 - RenderParagraph._layoutText()に幅の制約を与えて呼ぶ
- TextPainter.layout()に幅の制約を与えて呼ぶ
- builder = ui.ParagraphBuilder()
 - TextSpan.build(builder)呼ぶ
- childrenそれぞれのTextSpan.build(builder)呼ぶ
- ui.ParagraphBuilder.addText()呼ぶ
- {engine}: ParagraphBuilder::addText()呼ぶ
- 
ParagraphBuilderTxt::addText()呼ぶ- vectorにテキストを追加している
 
 
 - 
 
 - {engine}: ParagraphBuilder::addText()呼ぶ
 
 - ui.ParagraphBuilder.addText()呼ぶ
 
 - childrenそれぞれのTextSpan.build(builder)呼ぶ
 - ui.ParagraphBuilder.build()呼ぶ
- 
ParagraphBuilderTxt::Build()を呼んで追加されたテキストを持つtxt::Paragraphを作成 - 
Paragraph::Create()呼ぶ 
 - 
 - Paragraph.layout()を幅の制約をつけて呼ぶ
- {engine} 
Paragraph::layoutが呼ばれる 
 - {engine} 
 - newWidth = Paragraph.maxIntrinsicWidthを得る
- {engine} 
Paragraph::maxIntrinsicWidthが呼ばれる- 
txt::ParagraphTxt::getMaxIntrisicWidthが呼ばれる- max_intrisic_widthはテキストの改行を考えたときの最大幅かな
 
 
 - 
 
 - {engine} 
 - newWidthを最小最大幅でクランプ
 - newWidthに更新があればもう一度Paragraph.layout()
 
 
 - TextPainter.layout()に幅の制約を与えて呼ぶ
 
 - RenderParagraph._layoutChildren(constraints, dry: true)呼ぶ
 
 - RenderParagraph.computeDryLayout(constraints)呼ぶ
 - RenderParagraph.performLayout()呼ぶ
- RenderParagraph._layoutChildren(constraints)呼ぶ
 - RenderParagraph._layoutText()に幅の制約を与えて呼ぶ
 - _textPainter.sizeをsizeとする
 - オーバーフローしてたらその処理
 
 - RenderObject.markNeedsSemanticsUpdate()呼ぶ
 - RenderObject.markNeedsPaint()呼ぶ
 
 - shrinkWrapXはfalseなので縦横double.infinityを要求する→親の最大大きさになる
 - RenderAligningShiftedBox.alignChild()呼ぶ
- RenderAligningShiftedBox._resolve()呼ぶ
- alignmentとtextDirectionを解決する(Alignmentだとそのまま)
 
 - RenderPositionedBoxと子の左上の距離(offset)を計算してchild.parentData.offsetにセット
 
 - RenderAligningShiftedBox._resolve()呼ぶ
 
 - child.layout({画面サイズ}.loosen, parentUsesSize: true)呼ぶ -> RenderObject.layout
 - RenderObject.markNeedsSemanticsUpdate()呼ぶ
 - RenderObject.markNeedsPaint()呼ぶ
- PipelineOwner.requestVisualUpdate()呼ぶ
- SchedulerBinding.ensureVisualUpdate()呼ぶ
 
 
 - PipelineOwner.requestVisualUpdate()呼ぶ
 
 
 - RenderPositionedBox.layout({画面サイズ}.tight) -> 
 
- 
PaintingContext.repaintCompositedChild(renderView)- 
OffsetLayer? childLayer = renderView._layerHandle.layer== rootLayer - 
childLayer.removeAllChildren()呼ぶ - 
childContext = PaintingContext(childLayer, renderView.paintBounds)- paintBoundsはoffsetとsizeを合わせた矩形情報
 
 - 
renderView._paintWithContext(childContext, Offset.zero)呼ぶ- 
renderView.paint(childContext, Offset.zero)呼ぶ- 
childContext.paintChild(renderView.child, Offset.zero)呼ぶ- 
RenderPositionedBox._paintWithContext(childContext, Offset.zero)呼ぶ- 
RenderPositionedBox(=ShiftedBox).paint(childContext, Offset.zero)呼ぶ- 
childContext.paintChild(RenderPositionedBox.child, RenderPositionedBox.child.parentData.offset + Offset.zero)呼ぶ- 
RenderParagraph._paintWithContext(childContext, offset)呼ぶ- 
RenderParagraph.paint(childContext, offset)呼ぶ- 
RenderParagraph._layoutTextWithConstraints()呼ぶ- 
RenderParagraph._layoutText()に幅の制約を与えて呼ぶ- サイズ更新
 
 
 - 
 - 
_textPainter.paint(childContext.canvas, offset)でcanvasに描画 - canvasを最初に使うときに
_currentLayer=PictureLayer()を生成し、childLayerの子として追加 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 - 
childContext.stopRecordingIfNeeded()呼ぶ- 
_currentLayer.pictureに描画結果を格納 
 - 
 
 - 
 
ここまででLayerツリーは以下のようになっている
- TransformLayer
- dpiで変形する情報を持つ
 - PictureLayer
- rootの大きさで文字がかかれたpictureを持つ
 
 
 
- RenderView.isRepaintBoundary == true
 - RenderPositionedBox.isRepaintBoundary == false
 - RenderParagraph.isRepaintBoundary == false
 
- 
RenderView.layer.buildScene(builder)- {engine}/SceneBuilderがスタックを使ってlayerツリーをengineに移す
 - 
updateSubtreeNeedsAddToScene()呼ぶ- 自身とサブツリーの`_needsAddToSceneを更新する
 - 自身ないしは子の_needsAddToSceneがtrueならtrue
 - 
TransformLayerとPictureLayerは共にtrue 
 - 
TransformLayer.addToScene(builder)呼ぶ- 
builder.pushTransform()でtransform情報をengineに積む - 
ContainerLayer.addChildrenToScene()呼ぶ- 子ごとに
child.addToScene(builder)呼ぶ - 
PictureLayer.addToScene()- 
builder.addPicture(picture)で描画をengineに追加 
 - 
 
 - 子ごとに
 - 
builder.pop()呼ぶ 
 - 
 - return 
builder.build()- Sceneを作成
 - Sceneはlayerツリーの参照を持ってるだけだと思う
 
 
 
ここまででSceneが持っているツリー
- ContainerLayer (RootLayerとして追加された)
- TransformLayer
- PictureLayer
 
 
 - TransformLayer
 
- 
_window.render(scene)=FlutterView.render()- {engine}内の
Render()が呼ばれる- 
UIDartState.platform_configuration.client.Render(scene)が呼ばれる - 
RuntimeController::Render()が呼ばれる- 
Engine::Render(layer_tree)呼ぶ- 
Animator::Render(layer_tree)呼ぶ- 
Animator::producer_continuation_(キュー)にlayer_treeを追加- これでpipelineに追加されている?
 
 - 
Shell::OnAnimatorDraw(pipeline)呼ぶ- 
RasterTaskRunner内でRasterizer::Draw(pipeline)呼ぶ- 
pipeline.consume(consumer)経由でRasterizer::DoDraw(layer_tree)呼ぶ- 
Rasterizer::DrawToSurface(layer_tree)呼ぶ- 
Rasterizer::DrawToSurfaceUnsafe(layer_tree)呼ぶ- 
frame = Rasterizer::surface_.AcquireFrame(layer_tree.frame_size())でフレームを作成 - 
root_surface_canvas=frame->SkiaCanvas()でcanvasを作成 - 
compositor_frame=CompositorContext.AcquireFrame()でScopedFrameを作成- 
ScopedFrame::Raster(layer_tree)呼ぶ- 
LayerTree.Paint(ScopedFrame)呼ぶ- 
SkNWayCanvas internal_nodes_canvasを作成してframe.canvasを追加する- これが実際に書き込むcanvas
 
 - 
Layer::PaintContextをScopedFrameから作成 - 
root_layer_(=ContainerLayer).Paint(context)呼ぶ- 
ContainerLayer::Paint(context)- 
ContainerLayer::PaintChildren(context)呼ぶ- 
TransformLayer::Paint(context)呼ぶ- 
SkAutoCanvasRestore save(context.internal_nodes_canvas, true)を呼んでスコープを抜けたら変換行列を戻すようにする - 
context.internal_nodes_canvas.concat(transform_)でcanvasに変換行列を適用- 
TransformLayer::PaintChildren(context)呼ぶ- 
PictureLayer::Paint(context)呼ぶ- 
PictureLayer.picture.playback(canvas)呼ぶ- canvasにpictureを描画する
 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 - 
frame.submit()で画面に表示 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - 
 
 - {engine}内の
 
- 
Animator.requestFrame(bool regenerate_layer_tree)は基本引数がtrue- PlatformViewの関連のとき(
PlatformView::Delegate::OnPlatformViewMarkTextureFrameAvailable())だけfalseで呼んでる 
 - PlatformViewの関連のとき(
 
- LayerTreeは
あまり再利用しない- _needsPaintでマークされた場合子は再生成
- isRepaintBoundary == trueかつ_needsPaint == falseなら、layerHandleの参照から再利用する
 - RenderTransformとかもpaint()内で再利用してるわね
 
 
 - _needsPaintでマークされた場合子は再生成
 - SkPictureはRasterCacheにてPicture単位でキャッシュされる
- 再利用できると判断されればキャッシュがDrawされる
 - RepaintBoundaryの説明にもそれっぽいことが書いてある
 
 
RepaintBoundary has the further side-effect of possibly hinting to the engine that it should further optimize animation performance if the render subtree behind the RepaintBoundary is sufficiently complex and is static while the surrounding tree changes frequently.
- CacheはRasterCacheKey::Mapというstd::unordered_mapに保存される
 - キーはRasterCacheKeyで、id・type・matrixを持つ
 - 値はRasterCache::Entryで、このフレームで使われたか・アクセス回数・RasterCacheResultを持つ
 - RasterCacheResultはSkImageとSkRectを持つ
 - RasterCache::Prepare()を呼んだときにCacheを新規作成
- PictureLayerだとPreroll内で呼んでいる
 
 
- RenderObject._relayoutBoundary
- https://juejin.cn/post/6981368741653119013
 - ツリー中で再レイアウトする部分を決定
 - _relayoutBoundary != this の場合親を探索
 - _relayoutBoundary == this の場合自身で再レイアウトの伝搬を停止
- 親はrelayoutされない
 
 
 
- sizedByParent == trueの場合
- layout()内でperformResize()が呼ばれ、ここでサイズを決定する
 - performLayout()内ではサイズを変更してはいけない
 
 - sizedByParent == falseの場合
- performResize()は呼ばれない
 - performLayout()内でサイズを適宜変更する
 
 - performResize()はRenderBoxではcomputeDryLayout()で更新される
 
HitTest詳細
- hitTestではRenderObjectの左上からのローカルな座標が渡される
- 子のhitTestを呼ぶときにOffset分を引いて流している
 
 - pointerの位置から見た場合、Offsetの適用はその分を引くこと
- HitTestResultのStackには-offsetを積む
 
 - RenderTransformなどはそのままtransformをStackに積む
 - Stackに積まれた変換行列はそこまでの累積をHitTestEntryの追加時に渡す
- 根を右に置いて左から掛け合わせることで、順に変換したのと同等の変換行列になっている
 
 - EntryのtransformはGestureBinding.dispatchEventで使われる
 
- abstract class PointerEvent with Diagnosticable
 - mixin _PointerEventDescription on PointerEvent
 - abstract class _AbstractPointerEvent implements PointerEvent
 - abstract class _TransformedPointerEvent extends _AbstractPointerEvent with Diagnosticable, _PointerEventDescription
 - mixin _CopyPointerXxxEvent on PointerEvent
 - class PointerXxxEvent extends PointerEvent with _PointerEventDescription, _CopyPainterXxxEvent
 - class _TransformedPointerXxxEvent extends _TransformedPointerEvent with _CopyPointerXxxEvent implements PointerXxxEvent
 

Layerについて
- RasterではPaint前にPrerollを呼ぶ
- サイズ確定のため?
 - PictureLayer -> 持っているpictureからrectを計算
 - MutatorsStackはPlatformViewの変形用
 - TransformLayer -> context.cull_rectに逆行列を埋めて子のrectを計算
- 子のrectを変換して自分のrectとする
 
 - read_backはよくわからないけどフラグでオン・オフできるからなくてもよいのかな
 
 
- GLFWKeyCallback()
- TextInputPlugin::KeyboardHook()
 - KeyEventHandler::KeyboardHook()
- BasicMessageChannel::Send()
- BinaryMessenger::Send()
- BinaryMessengerはPluginRegistrarのBinaryMessengerImpl
- FlutterDesktopMessengerSend()
- FlutterDesktopMessengerSendWithReply()
- FlutterEngineSendPlatformMessage()
- EmbedderEngine::SendPlatformMessage()
- PlatformView::DispatchPlatformMessage()
- Shell::OnPlatformViewDispatchPlatformMessage()
- (in UI TaskRunner) Engine::DispatchPlatformMessage()
- RuntimeController::DispatchPlatformMessage()
- PlatformConfiguration::DispatchPlatformMessage()
- (hooks.dart) _dispatchPlatformMessage()
- PlatformDispatcher._dispatchPlatformMessage()
- ChannelBuffers.push()
- _Channel.push()
- "flutter/keyevent"のcallbackが設定されていれば呼び出し
- 後述
 
 - 設定されていなければqueueに保存
- これは設定されたときにdrain()で全て呼び出される
 
 
 - "flutter/keyevent"のcallbackが設定されていれば呼び出し
 
 - _Channel.push()
 
 - ChannelBuffers.push()
 
 - PlatformDispatcher._dispatchPlatformMessage()
 
 - (hooks.dart) _dispatchPlatformMessage()
 
 - PlatformConfiguration::DispatchPlatformMessage()
 
 - RuntimeController::DispatchPlatformMessage()
 
 - (in UI TaskRunner) Engine::DispatchPlatformMessage()
 
 - Shell::OnPlatformViewDispatchPlatformMessage()
 
 - PlatformView::DispatchPlatformMessage()
 
 - EmbedderEngine::SendPlatformMessage()
 
 - FlutterEngineSendPlatformMessage()
 
 - FlutterDesktopMessengerSendWithReply()
 
 - FlutterDesktopMessengerSend()
 
 - BinaryMessengerはPluginRegistrarのBinaryMessengerImpl
 
 - BinaryMessenger::Send()
 
 - BasicMessageChannel::Send()
 
 - ServicesBinding.initInstances()
- ServicesBinding._initKeyboard()
- window.onKeyData = _keyEventManager.handleKeyData
- PlatformDispatcher.setOnKeyData
- ChannelBuffers.setListener()
- _Channel.setListener()
- "flutter/keyData"にcallbackを登録
 
 
 - _Channel.setListener()
 
 - ChannelBuffers.setListener()
 
 - PlatformDispatcher.setOnKeyData
 - SystemChannels.keyEvent.setMessageHandlerにKeyEventManager.handleRawKeyMessageを指定
- _DefaultBinaryMessenger.setMessageHandler()
- ui.channelBuffers.setListener()
- "flutter/keyEvent"にcallbackを追加
 
 
 - ui.channelBuffers.setListener()
 
 - _DefaultBinaryMessenger.setMessageHandler()
 
 - window.onKeyData = _keyEventManager.handleKeyData
 
 - ServicesBinding._initKeyboard()
 - つまりcallbackはKeyEventManager.handleRawKeyMessage()
 
needsAddToSceneの調査
- trueになる時
- Layerの生成時
 - markNeedsAddToScene()が呼ばれた時
 - updateSubtreeNeedsAddToScene()でalwaysNeedsAddToSceneがtrue
 - updateSubtreeNeddsAddToScene()で子のneedsAddToSceneがtrue
 
 - falseになる時
- ContainerLayer.buildScene()が呼ばれた後
 - Layer._addToSceneWithRetainedRendering()が呼ばれた後
- ContainerLayer.addChildrenToScene()から呼ばれる
- これは各addToScene()から呼ばれる
 
 - どちらもaddToScene()が呼ばれた後である
 
 - ContainerLayer.addChildrenToScene()から呼ばれる
 
 - markNeedsAddToScene()の呼ばれるタイミング
- engineLayerが設定された時
 - layerのプロパティが変更された時
 
 - needsAddToSceneの使われるタイミング
- Layer._addToSceneWithRetainedRendering()のみ
- falseかつengineLayerがある場合addRetainedを呼び処理を省略
 - ContainerLayer.addChildrenToScene()からのみ呼ばれる
 
 
 - Layer._addToSceneWithRetainedRendering()のみ
 
SceneBuilderのoldLayerの役割
- pushXxxを呼ぶとき一緒にoldLayerを渡すことができる
 - oldLayerはインスタンスが使い回されるわけではない
- 毎回新たにLayerが生成される
 
 - 新しいLayerはoldLayerからoriginal_layer_idを継承する
 - 同じidを持つかどうかはLayer.IsReplacing()で確認される
- ContainerLayer::DiffChildren()で利用
- ContainerLayer::Diff()で利用
- ここで使い回せるかどうかを判定している?
 
 
 - ContainerLayer::Diff()で利用
 
 - ContainerLayer::DiffChildren()で利用
 - addRetained()を使うとインスタンスを使い回すことができる
- needsAddToSceneがfalseの場合