diff --git a/lib/model/katex.dart b/lib/model/katex.dart index 8a793f663a..3efb5eafec 100644 --- a/lib/model/katex.dart +++ b/lib/model/katex.dart @@ -386,6 +386,7 @@ class _KatexParser { final spanClasses = element.className != '' ? List.unmodifiable(element.className.split(' ')) : const []; + double? widthEm; String? fontFamily; double? fontSizeEm; KatexSpanFontWeight? fontWeight; @@ -576,7 +577,11 @@ class _KatexParser { _ => throw _KatexHtmlParseError(), }; - // TODO handle .nulldelimiter and .delimcenter . + case 'nulldelimiter': + // .nulldelimiter { display: inline-block; width: 0.12em; } + widthEm = 0.12; + + // TODO .delimcenter . case 'op-symbol': // .op-symbol { ... } @@ -621,6 +626,7 @@ class _KatexParser { final inlineStyles = _parseInlineStyles(element); final styles = KatexSpanStyles( + widthEm: widthEm, fontFamily: fontFamily, fontSizeEm: fontSizeEm, fontWeight: fontWeight, @@ -810,6 +816,8 @@ class KatexSpanColor { @immutable class KatexSpanStyles { + final double? widthEm; + // TODO(#1674) does height actually appear on generic spans? // In a corpus, the only occurrences that we don't already handle separately // (i.e. occurrences other than on struts, vlists, etc) seem to be within @@ -834,6 +842,7 @@ class KatexSpanStyles { final KatexSpanColor? color; const KatexSpanStyles({ + this.widthEm, this.heightEm, this.topEm, this.marginRightEm, @@ -849,6 +858,7 @@ class KatexSpanStyles { @override int get hashCode => Object.hash( 'KatexSpanStyles', + widthEm, heightEm, topEm, marginRightEm, @@ -864,6 +874,7 @@ class KatexSpanStyles { @override bool operator ==(Object other) { return other is KatexSpanStyles && + other.widthEm == widthEm && other.heightEm == heightEm && other.topEm == topEm && other.marginRightEm == marginRightEm && @@ -879,6 +890,7 @@ class KatexSpanStyles { @override String toString() { final args = []; + if (widthEm != null) args.add('widthEm: $widthEm'); if (heightEm != null) args.add('heightEm: $heightEm'); if (topEm != null) args.add('topEm: $topEm'); if (marginRightEm != null) args.add('marginRightEm: $marginRightEm'); @@ -893,6 +905,7 @@ class KatexSpanStyles { } KatexSpanStyles filter({ + bool widthEm = true, bool heightEm = true, bool verticalAlignEm = true, bool topEm = true, @@ -906,6 +919,7 @@ class KatexSpanStyles { bool color = true, }) { return KatexSpanStyles( + widthEm: widthEm ? this.widthEm : null, heightEm: heightEm ? this.heightEm : null, topEm: topEm ? this.topEm : null, marginRightEm: marginRightEm ? this.marginRightEm : null, diff --git a/lib/widgets/katex.dart b/lib/widgets/katex.dart index 2cae2ce5fe..36f4dc4485 100644 --- a/lib/widgets/katex.dart +++ b/lib/widgets/katex.dart @@ -160,6 +160,9 @@ class _KatexSpan extends StatelessWidget { } widget = SizedBox( + width: styles.widthEm != null + ? styles.widthEm! * em + : null, height: styles.heightEm != null ? styles.heightEm! * em : null, diff --git a/test/model/katex_test.dart b/test/model/katex_test.dart index 7c28d013d3..894cad0392 100644 --- a/test/model/katex_test.dart +++ b/test/model/katex_test.dart @@ -643,6 +643,38 @@ class KatexExample extends ContentExample { text: '∗'), ]), ]); + + static final nulldelimiter = KatexExample.block( + r'\{left,middle,right}. : spans with "nulldelimiter" class', + // https://chat.zulip.org/#narrow/channel/7-test-here/topic/Rajesh/near/2205534 + r'\left. a \middle. b \right.', + '

' + '' + 'a.b\\left. a \\middle. b \\right.' + '

', [ + KatexSpanNode(nodes: [ + KatexStrutNode(heightEm: 0.6944, verticalAlignEm: null), + KatexSpanNode(nodes: [ + KatexSpanNode(styles: KatexSpanStyles(widthEm: 0.12), nodes: []), + KatexSpanNode( + styles: KatexSpanStyles(fontFamily: 'KaTeX_Math', fontStyle: KatexSpanFontStyle.italic), + text: 'a'), + KatexSpanNode(styles: KatexSpanStyles(widthEm: 0.12), nodes: []), + KatexSpanNode( + styles: KatexSpanStyles(fontFamily: 'KaTeX_Math', fontStyle: KatexSpanFontStyle.italic), + text: 'b'), + KatexSpanNode(styles: KatexSpanStyles(widthEm: 0.12), nodes: []), + ]), + ]), + ]); } void main() async { @@ -663,6 +695,7 @@ void main() async { testParseExample(KatexExample.textColor); testParseExample(KatexExample.customColorMacro); testParseExample(KatexExample.phantom); + testParseExample(KatexExample.nulldelimiter); group('parseCssHexColor', () { const testCases = [ diff --git a/test/widgets/katex_test.dart b/test/widgets/katex_test.dart index 11af76c9eb..657757ab61 100644 --- a/test/widgets/katex_test.dart +++ b/test/widgets/katex_test.dart @@ -73,6 +73,10 @@ void main() { ('X', Offset(0.00, 7.04), Size(17.03, 25.00)), ('n', Offset(17.03, 15.90), Size(8.63, 17.00)), ]), + (KatexExample.nulldelimiter, skip: false, [ + ('a', Offset(2.47, 3.36), Size(10.88, 25.00)), + ('b', Offset(15.81, 3.36), Size(8.82, 25.00)), + ]), ]; for (final testCase in testCases) {