@@ -209,11 +209,98 @@ 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+ className: '' ,
250+ nodes: [
251+ dom.Element (localName: 'span' , className: 'pstrut' ) &&
252+ final pstrutSpan,
253+ ...final otherSpans,
254+ ],
255+ )) {
256+ var styles = _parseSpanInlineStyles (innerSpan);
257+ if (styles == null ) throw _KatexHtmlParseError ();
258+ if (styles.verticalAlignEm != null ) throw _KatexHtmlParseError ();
259+ final topEm = styles.topEm ?? 0 ;
260+
261+ styles = styles.filter (topEm: false );
262+
263+ final pstrutStyles = _parseSpanInlineStyles (pstrutSpan);
264+ if (pstrutStyles == null ) throw _KatexHtmlParseError ();
265+ if (pstrutStyles.filter (heightEm: false )
266+ != const KatexSpanStyles ()) {
267+ throw _KatexHtmlParseError ();
268+ }
269+ final pstrutHeight = pstrutStyles.heightEm ?? 0 ;
270+
271+ rows.add (KatexVlistRowNode (
272+ verticalOffsetEm: topEm + pstrutHeight,
273+ debugHtmlNode: kDebugMode ? innerSpan : null ,
274+ node: KatexSpanNode (
275+ styles: styles,
276+ text: null ,
277+ nodes: _parseChildSpans (otherSpans))));
278+ } else {
279+ throw _KatexHtmlParseError ();
280+ }
281+ }
282+
283+ return KatexVlistNode (
284+ rows: rows,
285+ debugHtmlNode: kDebugMode ? vlistT : null ,
286+ );
287+ } else {
288+ throw _KatexHtmlParseError ();
289+ }
290+ } else {
291+ throw _KatexHtmlParseError ();
292+ }
293+ }
294+
212295 final inlineStyles = _parseSpanInlineStyles (element);
213296 if (inlineStyles != null ) {
214297 // We expect `vertical-align` inline style to be only present on a
215298 // `strut` span, for which we emit `KatexStrutNode` separately.
216299 if (inlineStyles.verticalAlignEm != null ) throw _KatexHtmlParseError ();
300+
301+ // Currently, we expect `top` to only be inside a vlist, and
302+ // we handle that case separately above.
303+ if (inlineStyles.topEm != null ) throw _KatexHtmlParseError ();
217304 }
218305
219306 // Aggregate the CSS styles that apply, in the same order as the CSS
@@ -224,7 +311,9 @@ class _KatexParser {
224311 // https://github.com/KaTeX/KaTeX/blob/2fe1941b/src/styles/katex.scss
225312 // A copy of class definition (where possible) is accompanied in a comment
226313 // with each case statement to keep track of updates.
227- final spanClasses = List <String >.unmodifiable (element.className.split (' ' ));
314+ final spanClasses = element.className != ''
315+ ? List <String >.unmodifiable (element.className.split (' ' ))
316+ : const < String > [];
228317 String ? fontFamily;
229318 double ? fontSizeEm;
230319 KatexSpanFontWeight ? fontWeight;
@@ -492,6 +581,7 @@ class _KatexParser {
492581 if (stylesheet.topLevels case [css_visitor.RuleSet () && final rule]) {
493582 double ? heightEm;
494583 double ? verticalAlignEm;
584+ double ? topEm;
495585 double ? marginRightEm;
496586 double ? marginLeftEm;
497587
@@ -510,6 +600,10 @@ class _KatexParser {
510600 verticalAlignEm = _getEm (expression);
511601 if (verticalAlignEm != null ) continue ;
512602
603+ case 'top' :
604+ topEm = _getEm (expression);
605+ if (topEm != null ) continue ;
606+
513607 case 'margin-right' :
514608 marginRightEm = _getEm (expression);
515609 if (marginRightEm != null ) {
@@ -537,6 +631,7 @@ class _KatexParser {
537631
538632 return KatexSpanStyles (
539633 heightEm: heightEm,
634+ topEm: topEm,
540635 verticalAlignEm: verticalAlignEm,
541636 marginRightEm: marginRightEm,
542637 marginLeftEm: marginLeftEm,
@@ -578,6 +673,8 @@ class KatexSpanStyles {
578673 final double ? heightEm;
579674 final double ? verticalAlignEm;
580675
676+ final double ? topEm;
677+
581678 final double ? marginRightEm;
582679 final double ? marginLeftEm;
583680
@@ -590,6 +687,7 @@ class KatexSpanStyles {
590687 const KatexSpanStyles ({
591688 this .heightEm,
592689 this .verticalAlignEm,
690+ this .topEm,
593691 this .marginRightEm,
594692 this .marginLeftEm,
595693 this .fontFamily,
@@ -604,6 +702,7 @@ class KatexSpanStyles {
604702 'KatexSpanStyles' ,
605703 heightEm,
606704 verticalAlignEm,
705+ topEm,
607706 marginRightEm,
608707 marginLeftEm,
609708 fontFamily,
@@ -618,6 +717,7 @@ class KatexSpanStyles {
618717 return other is KatexSpanStyles &&
619718 other.heightEm == heightEm &&
620719 other.verticalAlignEm == verticalAlignEm &&
720+ other.topEm == topEm &&
621721 other.marginRightEm == marginRightEm &&
622722 other.marginLeftEm == marginLeftEm &&
623723 other.fontFamily == fontFamily &&
@@ -632,6 +732,7 @@ class KatexSpanStyles {
632732 final args = < String > [];
633733 if (heightEm != null ) args.add ('heightEm: $heightEm ' );
634734 if (verticalAlignEm != null ) args.add ('verticalAlignEm: $verticalAlignEm ' );
735+ if (topEm != null ) args.add ('topEm: $topEm ' );
635736 if (marginRightEm != null ) args.add ('marginRightEm: $marginRightEm ' );
636737 if (marginLeftEm != null ) args.add ('marginLeftEm: $marginLeftEm ' );
637738 if (fontFamily != null ) args.add ('fontFamily: $fontFamily ' );
@@ -653,6 +754,7 @@ class KatexSpanStyles {
653754 return KatexSpanStyles (
654755 heightEm: other.heightEm ?? heightEm,
655756 verticalAlignEm: other.verticalAlignEm ?? verticalAlignEm,
757+ topEm: other.topEm ?? topEm,
656758 marginRightEm: other.marginRightEm ?? marginRightEm,
657759 marginLeftEm: other.marginLeftEm ?? marginLeftEm,
658760 fontFamily: other.fontFamily ?? fontFamily,
@@ -666,6 +768,7 @@ class KatexSpanStyles {
666768 KatexSpanStyles filter ({
667769 bool heightEm = true ,
668770 bool verticalAlignEm = true ,
771+ bool topEm = true ,
669772 bool marginRightEm = true ,
670773 bool marginLeftEm = true ,
671774 bool fontFamily = true ,
@@ -677,6 +780,7 @@ class KatexSpanStyles {
677780 return KatexSpanStyles (
678781 heightEm: heightEm ? this .heightEm : null ,
679782 verticalAlignEm: verticalAlignEm ? this .verticalAlignEm : null ,
783+ topEm: topEm ? this .topEm : null ,
680784 marginRightEm: marginRightEm ? this .marginRightEm : null ,
681785 marginLeftEm: marginLeftEm ? this .marginLeftEm : null ,
682786 fontFamily: fontFamily ? this .fontFamily : null ,
0 commit comments