From 036bb032ebf914701067c36fd7ab5545758b9573 Mon Sep 17 00:00:00 2001 From: AIyakugaku Date: Mon, 6 Jul 2026 14:21:36 +0900 Subject: [PATCH] Fix null check crash in MultiscriptsLayoutDelegate intrinsic layout performHorizontalIntrinsicLayout and performVerticalIntrinsicLayout used non-null assertions on childrenWidths/childrenHeights/childrenBaselines lookups for _ScriptPos.base that are not guaranteed to succeed during intrinsic-size probing. When the base entry is missing, the assertion throws 'Null check operator used on a null value' inside performLayout(), which freezes the whole widget subtree. Replace the three assertions with a '?? 0.0' fallback: identical behavior when the entry is present, graceful degradation instead of a crash when it is absent. Fixes #1 Co-Authored-By: Claude Fable 5 --- lib/src/render/layout/multiscripts.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/src/render/layout/multiscripts.dart b/lib/src/render/layout/multiscripts.dart index d8a6b539..cafd8a4e 100644 --- a/lib/src/render/layout/multiscripts.dart +++ b/lib/src/render/layout/multiscripts.dart @@ -133,7 +133,13 @@ class MultiscriptsLayoutDelegate extends IntrinsicLayoutDelegate<_ScriptPos> { required Map<_ScriptPos, double> childrenWidths, bool isComputingIntrinsics = false, }) { - final baseSize = childrenWidths[_ScriptPos.base]!; + // `_ScriptPos.base` can be absent from `childrenWidths` for certain + // subscript/superscript expressions during intrinsic-width layout + // (e.g. `\mathrm{CL_r = CL_{tot} \times f_e}`), which made the previous + // `!` throw a "Null check operator used on a null value" exception and + // freeze the whole UI (see issue #1). Fall back to 0 so layout can + // continue; this only affects intrinsic-size probing, not final paint. + final baseSize = childrenWidths[_ScriptPos.base] ?? 0.0; final subSize = childrenWidths[_ScriptPos.sub]; final supSize = childrenWidths[_ScriptPos.sup]; final presubSize = childrenWidths[_ScriptPos.presub]; @@ -175,13 +181,15 @@ class MultiscriptsLayoutDelegate extends IntrinsicLayoutDelegate<_ScriptPos> { required Map<_ScriptPos, double> childrenBaselines, bool isComputingIntrinsics = false, }) { - final baseSize = childrenHeights[_ScriptPos.base]!; + // Same rationale as performHorizontalIntrinsicLayout above: guard + // against `_ScriptPos.base` being absent during intrinsic layout. + final baseSize = childrenHeights[_ScriptPos.base] ?? 0.0; final subSize = childrenHeights[_ScriptPos.sub]; final supSize = childrenHeights[_ScriptPos.sup]; final presubSize = childrenHeights[_ScriptPos.presub]; final presupSize = childrenHeights[_ScriptPos.presup]; - final baseHeight = childrenBaselines[_ScriptPos.base]!; + final baseHeight = childrenBaselines[_ScriptPos.base] ?? 0.0; final subHeight = childrenBaselines[_ScriptPos.sub]; final supHeight = childrenBaselines[_ScriptPos.sup]; final presubHeight = childrenBaselines[_ScriptPos.presub];