@@ -209,11 +209,102 @@ class _KatexParser {
209209 debugHtmlNode: debugHtmlNode);
210210 }
211211
212+ if (element.className == 'vlist-t'
213+ || element.className == 'vlist-t vlist-t2' ) {
214+ final vlistT = element;
215+ if (vlistT.nodes.isEmpty) throw _KatexHtmlParseError ();
216+ if (vlistT.attributes.containsKey ('style' )) throw _KatexHtmlParseError ();
217+
218+ final hasTwoVlistR = vlistT.className == 'vlist-t vlist-t2' ;
219+ if (! hasTwoVlistR && vlistT.nodes.length != 1 ) throw _KatexHtmlParseError ();
220+
221+ if (hasTwoVlistR) {
222+ if (vlistT.nodes case [
223+ _,
224+ dom.Element (localName: 'span' , className: 'vlist-r' , nodes: [
225+ dom.Element (localName: 'span' , className: 'vlist' , nodes: [
226+ dom.Element (localName: 'span' , className: '' , nodes: []),
227+ ]),
228+ ]),
229+ ]) {
230+ // Do nothing.
231+ } else {
232+ throw _KatexHtmlParseError ();
233+ }
234+ }
235+
236+ if (vlistT.nodes.first
237+ case dom.Element (localName: 'span' , className: 'vlist-r' ) &&
238+ final vlistR) {
239+ if (vlistR.attributes.containsKey ('style' )) throw _KatexHtmlParseError ();
240+
241+ if (vlistR.nodes.first
242+ case dom.Element (localName: 'span' , className: 'vlist' ) &&
243+ final vlist) {
244+ final rows = < KatexVlistRowNode > [];
245+
246+ for (final innerSpan in vlist.nodes) {
247+ if (innerSpan case dom.Element (
248+ localName: 'span' ,
249+ nodes: [
250+ dom.Element (localName: 'span' , className: 'pstrut' ) &&
251+ final pstrutSpan,
252+ ...final otherSpans,
253+ ],
254+ )) {
255+ if (innerSpan.className != '' ) {
256+ throw _KatexHtmlParseError ('unexpected CSS class for '
257+ 'vlist inner span: ${innerSpan .className }' );
258+ }
259+
260+ var styles = _parseSpanInlineStyles (innerSpan);
261+ if (styles == null ) throw _KatexHtmlParseError ();
262+ if (styles.verticalAlignEm != null ) throw _KatexHtmlParseError ();
263+ final topEm = styles.topEm ?? 0 ;
264+
265+ styles = styles.filter (topEm: false );
266+
267+ final pstrutStyles = _parseSpanInlineStyles (pstrutSpan);
268+ if (pstrutStyles == null ) throw _KatexHtmlParseError ();
269+ if (pstrutStyles.filter (heightEm: false )
270+ != const KatexSpanStyles ()) {
271+ throw _KatexHtmlParseError ();
272+ }
273+ final pstrutHeight = pstrutStyles.heightEm ?? 0 ;
274+
275+ rows.add (KatexVlistRowNode (
276+ verticalOffsetEm: topEm + pstrutHeight,
277+ debugHtmlNode: kDebugMode ? innerSpan : null ,
278+ node: KatexSpanNode (
279+ styles: styles,
280+ text: null ,
281+ nodes: _parseChildSpans (otherSpans))));
282+ } else {
283+ throw _KatexHtmlParseError ();
284+ }
285+ }
286+
287+ return KatexVlistNode (
288+ rows: rows,
289+ debugHtmlNode: kDebugMode ? vlistT : null ,
290+ );
291+ } else {
292+ throw _KatexHtmlParseError ();
293+ }
294+ } else {
295+ throw _KatexHtmlParseError ();
296+ }
297+ }
298+
212299 final inlineStyles = _parseSpanInlineStyles (element);
213300 if (inlineStyles != null ) {
214301 // We expect `vertical-align` inline style to be only present on a
215302 // `strut` span, for which we emit `KatexStrutNode` separately.
216303 if (inlineStyles.verticalAlignEm != null ) throw _KatexHtmlParseError ();
304+
305+ // Currently, we expect `top` to only be inside a vlist, and
306+ // we handle that case separately above.
307+ if (inlineStyles.topEm != null ) throw _KatexHtmlParseError ();
217308 }
218309
219310 // Aggregate the CSS styles that apply, in the same order as the CSS
@@ -224,7 +315,9 @@ class _KatexParser {
224315 // https://github.com/KaTeX/KaTeX/blob/2fe1941b/src/styles/katex.scss
225316 // A copy of class definition (where possible) is accompanied in a comment
226317 // with each case statement to keep track of updates.
227- final spanClasses = List <String >.unmodifiable (element.className.split (' ' ));
318+ final spanClasses = element.className != ''
319+ ? List <String >.unmodifiable (element.className.split (' ' ))
320+ : const < String > [];
228321 String ? fontFamily;
229322 double ? fontSizeEm;
230323 KatexSpanFontWeight ? fontWeight;
@@ -492,6 +585,7 @@ class _KatexParser {
492585 if (stylesheet.topLevels case [css_visitor.RuleSet () && final rule]) {
493586 double ? heightEm;
494587 double ? verticalAlignEm;
588+ double ? topEm;
495589 double ? marginRightEm;
496590 double ? marginLeftEm;
497591
@@ -510,6 +604,10 @@ class _KatexParser {
510604 verticalAlignEm = _getEm (expression);
511605 if (verticalAlignEm != null ) continue ;
512606
607+ case 'top' :
608+ topEm = _getEm (expression);
609+ if (topEm != null ) continue ;
610+
513611 case 'margin-right' :
514612 marginRightEm = _getEm (expression);
515613 if (marginRightEm != null ) {
@@ -537,6 +635,7 @@ class _KatexParser {
537635
538636 return KatexSpanStyles (
539637 heightEm: heightEm,
638+ topEm: topEm,
540639 verticalAlignEm: verticalAlignEm,
541640 marginRightEm: marginRightEm,
542641 marginLeftEm: marginLeftEm,
@@ -578,6 +677,8 @@ class KatexSpanStyles {
578677 final double ? heightEm;
579678 final double ? verticalAlignEm;
580679
680+ final double ? topEm;
681+
581682 final double ? marginRightEm;
582683 final double ? marginLeftEm;
583684
@@ -590,6 +691,7 @@ class KatexSpanStyles {
590691 const KatexSpanStyles ({
591692 this .heightEm,
592693 this .verticalAlignEm,
694+ this .topEm,
593695 this .marginRightEm,
594696 this .marginLeftEm,
595697 this .fontFamily,
@@ -604,6 +706,7 @@ class KatexSpanStyles {
604706 'KatexSpanStyles' ,
605707 heightEm,
606708 verticalAlignEm,
709+ topEm,
607710 marginRightEm,
608711 marginLeftEm,
609712 fontFamily,
@@ -618,6 +721,7 @@ class KatexSpanStyles {
618721 return other is KatexSpanStyles &&
619722 other.heightEm == heightEm &&
620723 other.verticalAlignEm == verticalAlignEm &&
724+ other.topEm == topEm &&
621725 other.marginRightEm == marginRightEm &&
622726 other.marginLeftEm == marginLeftEm &&
623727 other.fontFamily == fontFamily &&
@@ -632,6 +736,7 @@ class KatexSpanStyles {
632736 final args = < String > [];
633737 if (heightEm != null ) args.add ('heightEm: $heightEm ' );
634738 if (verticalAlignEm != null ) args.add ('verticalAlignEm: $verticalAlignEm ' );
739+ if (topEm != null ) args.add ('topEm: $topEm ' );
635740 if (marginRightEm != null ) args.add ('marginRightEm: $marginRightEm ' );
636741 if (marginLeftEm != null ) args.add ('marginLeftEm: $marginLeftEm ' );
637742 if (fontFamily != null ) args.add ('fontFamily: $fontFamily ' );
@@ -653,6 +758,7 @@ class KatexSpanStyles {
653758 return KatexSpanStyles (
654759 heightEm: other.heightEm ?? heightEm,
655760 verticalAlignEm: other.verticalAlignEm ?? verticalAlignEm,
761+ topEm: other.topEm ?? topEm,
656762 marginRightEm: other.marginRightEm ?? marginRightEm,
657763 marginLeftEm: other.marginLeftEm ?? marginLeftEm,
658764 fontFamily: other.fontFamily ?? fontFamily,
@@ -666,6 +772,7 @@ class KatexSpanStyles {
666772 KatexSpanStyles filter ({
667773 bool heightEm = true ,
668774 bool verticalAlignEm = true ,
775+ bool topEm = true ,
669776 bool marginRightEm = true ,
670777 bool marginLeftEm = true ,
671778 bool fontFamily = true ,
@@ -677,6 +784,7 @@ class KatexSpanStyles {
677784 return KatexSpanStyles (
678785 heightEm: heightEm ? this .heightEm : null ,
679786 verticalAlignEm: verticalAlignEm ? this .verticalAlignEm : null ,
787+ topEm: topEm ? this .topEm : null ,
680788 marginRightEm: marginRightEm ? this .marginRightEm : null ,
681789 marginLeftEm: marginLeftEm ? this .marginLeftEm : null ,
682790 fontFamily: fontFamily ? this .fontFamily : null ,
0 commit comments