Files
OpenMAIC/lib
wyucandClaude Opus 5.5 a0e2c0e02b fix: typeset inline math in render-service previews and export it cleanly to PPTX (#1904)
* fix(render-service): typeset inline math in slide previews

Slide prose now stores an inline formula as its LaTeX source
(<span data-inline-math="SRC">SRC</span>) and leaves typesetting to the
renderer. render-service pinned @openmaic/renderer 0.1.4, which predates
that, so a slide preview showed the raw source (for example
"\frac{a}{b}") instead of the formula.

- Bump @openmaic/renderer to 0.1.14 and @openmaic/dsl to 0.11.3. The
  changes in between are additive for this service: SlideCanvas props are
  unchanged, the new dsl exports are math hardening and chart style types,
  and charts still render with the lazily loaded ECharts runtime.
- Call completeInlineMath after mounting the slide. The live renderer
  typesets at most 100 formulas per pass before paint and leaves the rest
  to idle time; a capture needs all of them.
- Ship KaTeX's stylesheet with slide previews. KaTeX HTML needs its CSS and
  math fonts: without them, typeset formulas lose their layout (a/b reads
  "ba"). The preview document is an about:blank page, so each font face is
  inlined as its woff2 data URL. The CSS is read from the KaTeX copy the
  renderer resolves, once per process. This also gives LaTeX elements that
  carry a KaTeX HTML snapshot the styles they were missing.

Tests: the stylesheet inlines every face, and a real Chromium preview of
150 stored formulas, with idle callbacks disabled, typesets all of them in
KaTeX fonts before capture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(export): write inline formulas to PPTX as their LaTeX source

A stored inline formula (<span data-inline-math="SRC">SRC</span>)
already exports as its source text, since the span's text is the source.
Prose that has not been saved yet still carries the editor's rendered
KaTeX tree, and the PPTX text walk wrote every text node in it: the
MathML text, the TeX annotation and each layout glyph as separate runs,
so E=mc^2 became "E=mc2E=mc^2E=mc2". KaTeX from a PPTX import (only a
TeX annotation, no attribute) came out the same way, and table cells
were written verbatim, tags and character references included.

- Treat an inline formula as one run holding its LaTeX source, with the
  same parse rules as the editor: span[data-inline-math], else span.katex
  with a TeX annotation. The run keeps the surrounding text style.
- Write table cell text as plain text: tags dropped, character
  references decoded (stored cells hold "R&amp;D"), breaks and paragraphs
  as newlines, formulas as their source. Cells without markup are
  unchanged.

Formulas stay LaTeX text, not native equations: inline OMML in a text
run needs PowerPoint's AlternateContent wrapper per text shape, which is
left for a separate change that can be checked in PowerPoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(export): keep table cell lines when converting cells for PPTX

The table cell conversion sent any cell containing `&` through the HTML
path, which dropped newlines: plain text "R&D\nSales" exported as one
paragraph "R&DSales" instead of two. It also dropped empty paragraphs, so
<p>A</p><p></p><p>B</p> lost its blank line.

- Only text with a tag or comment takes the HTML path. Plain text has its
  character references decoded and keeps its lines.
- In markup, a newline in the text starts a new line, as the slide
  renderer shows it (it turns cell newlines into line breaks), and so do
  <br> and each paragraph. An empty paragraph is an empty line; a
  paragraph that already ended on a break (a trailing <br>, a nested
  block) adds no further line.

Tests read the paragraphs of each exported table cell from the slide XML.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(slide-renderer): keep the uncacheable inline math test fast on a loaded runner

The app slide renderer's "formulas too large to cache" test typeset six
1,360-character matrices (about 170 KB of markup each) in two elements and
polled wall-clock timers for idle work. On a loaded CI runner it ran past
the 5 s test timeout. Apply the approach the renderer package's own tests
already use, keeping what the test pins:

- Each formula is 40 radicals padded with trailing spaces to 1,900 source
  characters. Six still cross the 4,000-character per-pass budget, and
  each render is still over the typeset cache's 64,000-character
  per-entry limit, now asserted, so every re-typeset stays full price.
- Idle work runs through a stubbed idle queue that the test flushes,
  instead of polling timers.
- The test now also asserts that the first pass leaves formulas for later.

The other tests in the file typeset one short formula each and are
unchanged. Under CPU load (12 busy loops plus 12 concurrent runs on 12
cores) the test takes about 2.0 s, down from about 4.1 s; unloaded,
0.32 s, down from 1.0 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:49:01 +08:00
..